From 87f88867f4ee5f855a92bcfefa4bdffcbc79a23f Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 14 Sep 2010 14:01:58 +0200 Subject: [PATCH] Further improve B2gc. Add B2gm. Improve memory layout. --- src/Makefile.am | 2 + src/detect-engine-mpm.c | 1 + src/detect-engine.c | 1 + src/util-mpm-b2g.c | 2 - src/util-mpm-b2g.h | 2 +- src/util-mpm-b2gc.c | 816 ++++++++---- src/util-mpm-b2gc.h | 55 +- src/util-mpm-b2gm.c | 2749 +++++++++++++++++++++++++++++++++++++++ src/util-mpm-b2gm.h | 143 ++ src/util-mpm-b3g.c | 2 - src/util-mpm-wumanber.c | 2 - src/util-mpm.c | 2 + src/util-mpm.h | 10 +- src/util-optimize.h | 31 + suricata.yaml | 12 +- 15 files changed, 3557 insertions(+), 273 deletions(-) create mode 100644 src/util-mpm-b2gm.c create mode 100644 src/util-mpm-b2gm.h create mode 100644 src/util-optimize.h diff --git a/src/Makefile.am b/src/Makefile.am index f2533de3f6..d6d047af07 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -141,6 +141,7 @@ util-mpm-b2g.c util-mpm-b2g.h \ util-mpm-b2g-cuda.c util-mpm-b2g-cuda.h \ util-mpm-b3g.c util-mpm-b3g.h \ util-mpm-b2gc.c util-mpm-b2gc.h \ +util-mpm-b2gm.c util-mpm-b2gm.h \ util-cidr.c util-cidr.h \ util-unittest.c util-unittest.h \ util-unittest-helper.c util-unittest-helper.h \ @@ -169,6 +170,7 @@ util-strlcatu.c \ util-strlcpyu.c \ util-cuda.c util-cuda.h \ util-cuda-handlers.c util-cuda-handlers.h \ +util-optimize.h \ util-privs.c util-privs.h \ util-decode-asn1.c util-decode-asn1.h \ util-ringbuffer.c util-ringbuffer.h \ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index c2dea2e2fb..5a8034b20c 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -74,6 +74,7 @@ SCEnumCharMap sc_mpm_algo_map[] = { { "b2g_cuda", MPM_B2G_CUDA }, #endif { "b2gc", MPM_B2GC }, + { "b2gm", MPM_B2GM }, }; /** diff --git a/src/detect-engine.c b/src/detect-engine.c index 5d0ce14e99..a92a501176 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -335,6 +335,7 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { * table is always big enough */ PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); + PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx)); PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher, DetectUricontentMaxId(de_ctx)); //PmqSetup(&det_ctx->pmq, DetectEngineGetMaxSigId(de_ctx), DetectContentMaxId(de_ctx)); diff --git a/src/util-mpm-b2g.c b/src/util-mpm-b2g.c index 18d7b94887..ca08f19cad 100644 --- a/src/util-mpm-b2g.c +++ b/src/util-mpm-b2g.c @@ -119,7 +119,6 @@ void B2gPrintInfo(MpmCtx *mpm_ctx) { printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); printf(" B2gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Total Patterns: %" PRIu32 "\n", mpm_ctx->total_pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); @@ -353,7 +352,6 @@ static int B2gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } - mpm_ctx->total_pattern_cnt++; return 0; error: diff --git a/src/util-mpm-b2g.h b/src/util-mpm-b2g.h index 5255a844ac..ab2bcad95a 100644 --- a/src/util-mpm-b2g.h +++ b/src/util-mpm-b2g.h @@ -55,9 +55,9 @@ typedef struct B2gPattern_ { uint16_t len; /**< \todo we're limited to 32/64 byte lengths, uint8_t would be fine here */ uint8_t flags; uint8_t pad0; + uint32_t id; uint8_t *ci; /* case INsensitive */ uint8_t *cs; /* case sensitive */ - uint32_t id; struct B2gPattern_ *next; } B2gPattern; diff --git a/src/util-mpm-b2gc.c b/src/util-mpm-b2gc.c index 7746020e78..63c8ec9f50 100644 --- a/src/util-mpm-b2gc.c +++ b/src/util-mpm-b2gc.c @@ -21,9 +21,11 @@ * \author Victor Julien * * Implementation of the SBNDMq pattern matching algorithm that tries - * to be very CPU cache efficient. + * to be very limiting memory use and CPU cache efficient. * - * \todo Try to get the S0 calculation right. + * Things to try: + * - 1 byte pattern checks use lowercase *buf for hash, limiting the hash + * - lookup array with pminlen and pminlenb like in B2gm */ //#define PRINTMATCH @@ -31,12 +33,14 @@ #include "suricata-common.h" #include "suricata.h" #include "detect.h" + #include "util-mpm-b2gc.h" #include "util-print.h" - +#include "util-bloomfilter.h" #include "util-debug.h" #include "util-unittest.h" #include "util-hashlist.h" +#include "util-optimize.h" #include "conf.h" @@ -47,10 +51,21 @@ #define COUNT(counter) #endif /* B2GC_COUNTERS */ -static uint32_t b2g_hash_size = 0; +/* Hash table used at ctx initialization to keep and ordered list of + * patterns. The ordered list is used to build the ordered lookup + * array. */ +static uint32_t b2gc_hash_size = 0; static int8_t b2gc_hash_shift = 0; +static uint32_t b2gc_bloom_size = 0; static void *b2g_func; +#define B2GC_HASH16(a,b) (((a) << b2gc_hash_shift) | (b)) + +#define B2GC_PMINLEN_MAX 8 + +/* align pattern storage to these bytes. 1 disables. */ +#define B2GC_ALIGN_PATTERNS 16 + void B2gcInitCtx (MpmCtx *, int); void B2gcThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); void B2gcDestroyCtx(MpmCtx *); @@ -110,7 +125,6 @@ void B2gcPrintInfo(MpmCtx *mpm_ctx) { printf(" B2gcCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcCtx)); printf(" B2gcPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gcPattern)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Total Patterns: %" PRIu32 "\n", mpm_ctx->total_pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); @@ -118,14 +132,31 @@ void B2gcPrintInfo(MpmCtx *mpm_ctx) { } static inline int -memcmp_lowercase(uint8_t *s1, uint8_t *s2, uint16_t n) { +memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) { size_t i; /* check backwards because we already tested the first * 2 to 4 chars. This way we are more likely to detect * a miss and thus speed up a little... */ for (i = n - 1; i; i--) { - if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) + //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) + if (s1[i] != u8_tolower(*(s2+i))) + return 1; + } + + return 0; +} + +static inline int +memcmp_lowercase2(uint8_t *s1, uint8_t *s2, uint16_t n) { + size_t i; + + /* check backwards because we already tested the first + * 2 to 4 chars. This way we are more likely to detect + * a miss and thus speed up a little... */ + for (i = n - 1; i; i--) { + //if (u8_tolower(*(s2+i)) != u8_tolower(s1[i])) + if (u8_tolower(s1[i]) != u8_tolower(*(s2+i))) return 1; } @@ -154,13 +185,13 @@ static inline B2gcPattern *B2gcAllocPattern(MpmCtx *mpm_ctx) { * \brief Free a init hash pattern */ static void B2gcFreePattern(MpmCtx *mpm_ctx, B2gcPattern *p) { - if (p && p->pat) { - SCFree(p->pat); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= p->len; - } + if (p != NULL) { + if (p->pat != NULL) { + SCFree(p->pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } - if (p) { SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gcPattern); @@ -184,42 +215,47 @@ static int B2gcAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16 if (patlen == 0) return 0; - /* get a memory piece */ - B2gcPattern *p; - SCLogDebug("allocing new pattern"); - - p = B2gcAllocPattern(mpm_ctx); - if (p == NULL) - goto error; + /* detect duplicate pattern adds */ + B2gcPattern lookup_p = { patlen, flags, 0, pid, pat }; - p->len = patlen; - p->flags = flags; - p->id = pid; + /* get a memory piece */ + B2gcPattern *p = HashListTableLookup(ctx->b2gc_init_hash, (void *)&lookup_p, sizeof(B2gcPattern)); + if (p == NULL) { + SCLogDebug("allocing new pattern"); - /* setup the case insensitive part of the pattern */ - p->pat = SCMalloc(patlen); - if (p->pat == NULL) - goto error; + p = B2gcAllocPattern(mpm_ctx); + if (p == NULL) + goto error; - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += patlen; + p->len = patlen; + p->flags = flags; + p->id = pid; - memcpy(p->pat, pat, patlen); + p->pat = SCMalloc(patlen); + if (p->pat == NULL) + goto error; - /* put in the pattern hash */ - HashListTableAdd(ctx->b2gc_init_hash, (void *)p, sizeof(B2gcPattern)); + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; - if (mpm_ctx->pattern_cnt == 65535) { - printf("Max search words reached\n"); - exit(1); - } - mpm_ctx->pattern_cnt++; + memcpy(p->pat, pat, patlen); - if (mpm_ctx->maxlen < patlen) mpm_ctx->maxlen = patlen; - if (mpm_ctx->minlen == 0) mpm_ctx->minlen = patlen; - else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; + /* put in the pattern hash */ + HashListTableAdd(ctx->b2gc_init_hash, (void *)p, sizeof(B2gcPattern)); - mpm_ctx->total_pattern_cnt++; + if (mpm_ctx->pattern_cnt == 65535) { + printf("Max search words reached\n"); + exit(1); + } + mpm_ctx->pattern_cnt++; + + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + if (mpm_ctx->minlen == 0) + mpm_ctx->minlen = patlen; + else if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; +} return 0; error: @@ -240,6 +276,21 @@ int B2gcAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, return B2gcAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); } +static inline uint32_t B2gcBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { + uint8_t *d = (uint8_t *)data; + uint16_t i; + uint32_t hash = (uint32_t)u8_tolower(*d); + + for (i = 1; i < datalen; i++) { + d++; + hash += (u8_tolower(*d)) ^ i; + } + hash <<= (iter+1); + + hash %= hash_size; + return hash; +} + static uint32_t B2gcHashPatternInitHash(HashListTable *ht, void *pattern, uint16_t len) { BUG_ON(len != sizeof(B2gcPattern)); BUG_ON(pattern == NULL); @@ -255,15 +306,33 @@ static uint32_t B2gcHashPatternInitHash(HashListTable *ht, void *pattern, uint16 return hash % ht->array_size; } +#define B2GC_SORTHASH_MODE_LL 0 +#define B2GC_SORTHASH_MODE_LU 1 +#define B2GC_SORTHASH_MODE_UL 2 +#define B2GC_SORTHASH_MODE_UU 3 +#define B2GC_SORTHASH_MODE_CS 4 + /* copy of ctx->m for use in B2gcHashPatternSortHash */ static B2GC_TYPE m; +static int b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; static uint32_t B2gcHashPatternSortHash(HashListTable *ht, void *pattern, uint16_t len) { BUG_ON(len != sizeof(B2gcPattern)); BUG_ON(pattern == NULL); B2gcPattern *p = (B2gcPattern *)pattern; - uint32_t hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); + uint32_t hash = 0; + if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LL) { + hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); + } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_LU) { + hash = B2GC_HASH16(u8_tolower(p->pat[m - 2]), toupper(p->pat[m - 1])); + } else if(b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UL) { + hash = B2GC_HASH16(toupper(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); + } else if (b2gc_sorthash_mode == B2GC_SORTHASH_MODE_UU) { + hash = B2GC_HASH16(toupper(p->pat[m - 2]), toupper(p->pat[m - 1])); + } else { + hash = B2GC_HASH16(p->pat[m - 2], p->pat[m - 1]); + } SCReturnUInt(hash); } @@ -283,11 +352,7 @@ static char B2gcHashPatternCompare(void *pattern1, uint16_t len1, B2gcPattern *p1 = (B2gcPattern *)pattern1; B2gcPattern *p2 = (B2gcPattern *)pattern2; - if (p1->len != p2->len) { - return 0; - } - - if (memcmp_lowercase(p1->pat, p2->pat, p1->len) != 0) { + if (p1->id != p2->id) { return 0; } @@ -295,20 +360,166 @@ static char B2gcHashPatternCompare(void *pattern1, uint16_t len1, } static void B2gcHashPatternFree(void *pattern) { + B2gcPattern *p = (B2gcPattern *)pattern; + + SCFree(p->pat); + SCFree(pattern); } +static void B2gcAddToMatchArray(MpmCtx *mpm_ctx, B2gcPattern *p, int j) { + B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; + + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + /* u, u */ + uint16_t uuidx = B2GC_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); + ctx->B2GC[uuidx] = ctx->B2GC[uuidx] | (1 << (ctx->m - j)); + + /* l, l */ + uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); + if (llidx != uuidx) { + ctx->B2GC[llidx] = ctx->B2GC[llidx] | (1 << (ctx->m - j)); + } + /* u, l */ + uint16_t ulidx = B2GC_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); + if (ulidx != llidx && ulidx != uuidx) { + ctx->B2GC[ulidx] = ctx->B2GC[ulidx] | (1 << (ctx->m - j)); + } + /* l, u */ + uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); + if (luidx != ulidx && luidx != llidx && luidx != uuidx) { + ctx->B2GC[luidx] = ctx->B2GC[luidx] | (1 << (ctx->m - j)); + } + + SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); + } +} + +int B2gcBuildMatchArray(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash) { + SCEnter(); + B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; + + ctx->B2GC = SCMalloc(sizeof(B2GC_TYPE) * ctx->hash_size); + if (ctx->B2GC == NULL) + return -1; + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (sizeof(B2GC_TYPE) * ctx->hash_size); + + memset(ctx->B2GC, 0x00, (b2gc_hash_size * sizeof(B2GC_TYPE))); + + uint32_t j; + + /* fill the match array */ + for (j = 0; j <= (ctx->m - B2GC_Q); j++) { + HashListTableBucket *next = NULL; + HashListTableBucket *buck = HashListTableGetListHead(b2gc_sort_hash); + + while (buck != NULL) { + /* get the next before we free "buck" */ + next = HashListTableGetListNext(buck); + + B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); + BUG_ON(p == NULL); + + if (p->len < ctx->m) + goto next; + + uint16_t h; + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + B2gcAddToMatchArray(mpm_ctx, p, j); + } else { + h = B2GC_HASH16(p->pat[j],p->pat[j+1]); + ctx->B2GC[h] = ctx->B2GC[h] | (1 << (ctx->m - j)); + SCLogDebug("h %"PRIu16", ctx->B2GC[h] %"PRIu32" (cs)", h, ctx->B2GC[h]); + } + next: + buck = next; + } + } + + SCReturnInt(0); +} + +static void B2gcAddCopyToHash(MpmCtx *mpm_ctx, HashListTable *ht, B2gcPattern *p) { + B2gcPattern *pcopy = B2gcAllocPattern(mpm_ctx); + BUG_ON(pcopy == NULL); + pcopy->id = p->id; + pcopy->flags = p->flags; + pcopy->len = p->len; + + pcopy->pat = SCMalloc(pcopy->len); + BUG_ON(pcopy->pat == NULL); + + memcpy(pcopy->pat, p->pat, pcopy->len); + + HashListTableAdd(ht, (void *)pcopy, sizeof(B2gcPattern)); +} + +static int B2gcAddToHash(MpmCtx *mpm_ctx, HashListTable *b2gc_sort_hash, B2gcPattern *p) { + B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; + int added = 0; + //printf("%c.%c\n", p->pat[ctx->m - 2], p->pat[ctx->m - 1]); + + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + /* u, u */ + uint16_t uuidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); + b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UU; + HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); + added++; + + /* l, l */ + uint16_t llidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); + if (llidx != uuidx) { + b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LL; + B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); + added++; + } + /* u, l */ + uint16_t ulidx = B2GC_HASH16(toupper(p->pat[ctx->m - 2]), u8_tolower(p->pat[ctx->m - 1])); + if (ulidx != llidx && ulidx != uuidx) { + b2gc_sorthash_mode = B2GC_SORTHASH_MODE_UL; + B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); + added++; + } + /* l, u */ + uint16_t luidx = B2GC_HASH16(u8_tolower(p->pat[ctx->m - 2]), toupper(p->pat[ctx->m - 1])); + if (luidx != ulidx && luidx != llidx && luidx != uuidx) { + b2gc_sorthash_mode = B2GC_SORTHASH_MODE_LU; + B2gcAddCopyToHash(mpm_ctx, b2gc_sort_hash, p); + added++; + } + + SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); + } + + return added; +} + static void B2gcPrepareHash(MpmCtx *mpm_ctx) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; + HashListTable *b2gc_sort_hash = NULL; + HashListTable *b2gc_sort_hash1 = NULL; /* make sure ctx->m is set */ BUG_ON(ctx->m == 0); m = ctx->m; /* convert b2gc_init_hash to b2gc_sort_hash and count size */ - uint32_t size = 1; + uint32_t size = B2GC_ALIGN_PATTERNS; uint16_t size1 = 1; + /* only used at init */ + b2gc_sort_hash = HashListTableInit(b2gc_hash_size, B2gcHashPatternSortHash, B2gcHashPatternCompare, B2gcHashPatternFree); + if (b2gc_sort_hash == NULL) { + exit(EXIT_FAILURE); + } + + b2gc_sort_hash1 = HashListTableInit(256, B2gcHashPatternSortHash1, B2gcHashPatternCompare, B2gcHashPatternFree); + if (b2gc_sort_hash1 == NULL) { + exit(EXIT_FAILURE); + } + HashListTableBucket *next = NULL; HashListTableBucket *buck = HashListTableGetListHead(ctx->b2gc_init_hash); while (buck != NULL) { @@ -320,10 +531,25 @@ static void B2gcPrepareHash(MpmCtx *mpm_ctx) { //printf("init_hash: "); prt(p->pat,p->len);printf("\n"); if (p->len > 1) { - HashListTableAdd(ctx->b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); - size += (p->len + sizeof(B2gcPatternHdr)); + uint32_t psize; + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + //prt(p->pat, p->len);printf(" (m %u)\n", m); + int added = B2gcAddToHash(mpm_ctx, b2gc_sort_hash, p); + SCLogDebug("nocase pattern was added under different hash values %d times", added); + + uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS))); + //uint32_t one = sizeof(B2gcPatternHdr) + ((p->len + (p->len % B2GC_ALIGN_PATTERNS)) * 2); + psize = one * added; + } else { + b2gc_sorthash_mode = B2GC_SORTHASH_MODE_CS; + HashListTableAdd(b2gc_sort_hash, (void *)p, sizeof(B2gcPattern)); + + psize = (sizeof(B2gcPatternHdr) + p->len + (p->len % B2GC_ALIGN_PATTERNS)); + } + + size += psize; } else { - HashListTableAdd(ctx->b2gc_sort_hash1, (void *)p, sizeof(B2gcPattern)); + HashListTableAdd(b2gc_sort_hash1, (void *)p, sizeof(B2gcPattern)); size1 += (sizeof(B2gcPattern1)); } @@ -332,6 +558,8 @@ static void B2gcPrepareHash(MpmCtx *mpm_ctx) { HashListTableFree(ctx->b2gc_init_hash); ctx->b2gc_init_hash = NULL; + SCLogDebug("size %u", size); + /* alloc buf of size */ ctx->patterns = SCMalloc(size); BUG_ON(ctx->patterns == NULL); @@ -344,20 +572,31 @@ static void B2gcPrepareHash(MpmCtx *mpm_ctx) { /* loop through sort list and copy to buf */ /* skip the first byte of the buffer */ - uint32_t offset = 1; + uint32_t offset = B2GC_ALIGN_PATTERNS; /* the hashlist is not sorted, it's in the order of insertion. * We need it to be sorted by hash, so here we do something * unclean: we bypass the hashlist api. */ uint32_t a = 0; - for (a = 0; a < ctx->b2gc_sort_hash->array_size; a++) { - if ((buck = ctx->b2gc_sort_hash->array[a]) != NULL) { + for (a = 0; a < b2gc_sort_hash->array_size; a++) { + if ((buck = b2gc_sort_hash->array[a]) != NULL) { while (buck != NULL) { if (buck->data != NULL) { + uint32_t prev_offset = offset; B2gcPattern *p = (B2gcPattern *) (buck->data); BUG_ON(p == NULL); BUG_ON(p->len == 1); + uint16_t hash = a;//= B2GC_HASH16(u8_tolower(p->pat[m - 2]), u8_tolower(p->pat[m - 1])); + if (ctx->pminlen[hash] == 0) { + ctx->pminlen[hash] = p->len; + } else if (p->len < ctx->pminlen[hash]) { + ctx->pminlen[hash] = p->len; + } + + if (ctx->ha[hash] == 0) + ctx->ha[hash] = offset; + /* copy */ B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; h->id = p->id; @@ -365,8 +604,19 @@ static void B2gcPrepareHash(MpmCtx *mpm_ctx) { if (p->flags & MPM_PATTERN_FLAG_NOCASE) { h->flags |= B2GC_FLAG_NOCASE; } - memcpy(&ctx->patterns[offset + sizeof(B2gcPatternHdr)], p->pat, p->len); - offset += (sizeof(B2gcPatternHdr) + p->len); + + offset += sizeof(B2gcPatternHdr); + + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + memcpy_tolower(&ctx->patterns[offset], p->pat, p->len); + } else { + memcpy(&ctx->patterns[offset], p->pat, p->len); + } + offset += (p->len + (p->len % B2GC_ALIGN_PATTERNS)); + + h->np_offset = offset - prev_offset; + + SCLogDebug("h->offset %u", offset); ctx->pat_x_cnt++; @@ -377,52 +627,71 @@ static void B2gcPrepareHash(MpmCtx *mpm_ctx) { } /* build the hash containing idx' to the pattern array */ - offset = 1; + for (a = 0; a < b2gc_hash_size; a++) { + uint32_t offset = ctx->ha[a]; + uint32_t next_offset = 0; - B2gcPatternHdr *ph = NULL; - uint16_t prevhash = 0; - while (offset < size) { - B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; + if (offset > 0) { + uint32_t b = a + 1; + while (b < b2gc_hash_size) { + if (ctx->ha[b] > 0) { + next_offset = ctx->ha[b]; + break; + } - SCLogDebug("h %p, h->len %u", h, h->len); + b++; + } + } + + while (offset > 0) { + B2gcPatternHdr *h = (B2gcPatternHdr *)&ctx->patterns[offset]; + BUG_ON(h == NULL); + BUG_ON(h->len <= 1); - if (h->len > 1) { uint8_t *pattern = (uint8_t *)&ctx->patterns[offset + sizeof(B2gcPatternHdr)]; BUG_ON(pattern == NULL); - //printf("sort_hash: ");prt(pattern,h->len);printf("\n"); - uint16_t hash = B2GC_HASH16(u8_tolower(pattern[m - 2]), u8_tolower(pattern[m - 1])); - - if (ctx->ha[hash] == 0) - ctx->ha[hash] = offset; - - /* check the prev pattern for setting the final flag */ - SCLogDebug("ph %p", ph); - if (ph != NULL) { - SCLogDebug("hash %u, prevhash %u", hash, prevhash); - if (hash != prevhash) { - SCLogDebug("setting final flag on %p", ph); - ph->flags |= B2GC_FLAG_FINAL; - } + //printf("hash %u (offset %u, h %u) sort_hash: ", a, offset, ctx->ha[a]);prt(pattern,h->len);printf("\n"); + + uint16_t hash = a; + + SCLogDebug("hash %u, offset %u", hash, offset); + + if (ctx->bloom[hash] == NULL) { + ctx->bloom[hash] = BloomFilterInit(b2gc_bloom_size, 2, B2gcBloomHash); + SCLogDebug("bloom created for hash %u", hash); + BUG_ON(ctx->bloom[hash] == NULL); + mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->bloom[hash]); + mpm_ctx->memory_size += BloomFilterMemorySize(ctx->bloom[hash]); } - prevhash = hash; - ph = h; - SCLogDebug("ph %p, h %p", ph, h); - } - offset += (sizeof(B2gcPatternHdr) + h->len); + if (ctx->pminlen[hash] > B2GC_PMINLEN_MAX) + ctx->pminlen[hash] = B2GC_PMINLEN_MAX; - /* last item is "final" too */ - if (offset == size) { - SCLogDebug("final pattern in the array"); - h->flags |= B2GC_FLAG_FINAL; + BloomFilterAdd(ctx->bloom[hash], pattern, ctx->pminlen[hash]); + + offset += h->np_offset; + + /* last item in the pattern storage is "final" too */ + if (offset == size) { + SCLogDebug("final pattern in the array"); + h->flags |= B2GC_FLAG_FINAL; + break; + } + + /* next_offset points to next hash */ + if (next_offset > 0 && offset == next_offset) { + SCLogDebug("last pattern for this hash"); + h->flags |= B2GC_FLAG_FINAL; + break; + } } } /* skip the first byte of the buffer */ uint16_t offset1 = 1; - for (a = 0; a < ctx->b2gc_sort_hash1->array_size; a++) { - buck = ctx->b2gc_sort_hash1->array[a]; + for (a = 0; a < b2gc_sort_hash1->array_size; a++) { + buck = b2gc_sort_hash1->array[a]; if (buck != NULL) { while (buck != NULL) { if (buck->data != NULL) { @@ -476,49 +745,15 @@ static void B2gcPrepareHash(MpmCtx *mpm_ctx) { h->flags |= B2GC_FLAG_FINAL; } } -} -int B2gcBuildMatchArray(MpmCtx *mpm_ctx) { - SCEnter(); - B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; + B2gcBuildMatchArray(mpm_ctx, b2gc_sort_hash); - ctx->B2G = SCMalloc(sizeof(B2GC_TYPE) * ctx->hash_size); - if (ctx->B2G == NULL) - return -1; - - mpm_ctx->memory_cnt++; - mpm_ctx->memory_size += (sizeof(B2GC_TYPE) * ctx->hash_size); - - memset(ctx->B2G, 0x00, (b2g_hash_size * sizeof(B2GC_TYPE))); - - uint32_t j; - - /* fill the match array */ - for (j = 0; j <= (ctx->m - B2GC_Q); j++) { - HashListTableBucket *next = NULL; - HashListTableBucket *buck = HashListTableGetListHead(ctx->b2gc_sort_hash); - - while (buck != NULL) { - /* get the next before we free "buck" */ - next = HashListTableGetListNext(buck); - - B2gcPattern *p = (B2gcPattern *) HashListTableGetListData(buck); - BUG_ON(p == NULL); - - if (p->len < ctx->m) - goto next; - - uint16_t h = B2GC_HASH16(u8_tolower(p->pat[j]),u8_tolower(p->pat[j+1])); - ctx->B2G[h] = ctx->B2G[h] | (1 << (ctx->m - j)); - - SCLogDebug("h %"PRIu16", ctx->B2G[h] %"PRIu32"", h, ctx->B2G[h]); - - next: - buck = next; - } - } + /* free the hashes only used at init */ + HashListTableFree(b2gc_sort_hash); + b2gc_sort_hash = NULL; - SCReturnInt(0); + HashListTableFree(b2gc_sort_hash1); + b2gc_sort_hash1 = NULL; } int B2gcPreparePatterns(MpmCtx *mpm_ctx) { @@ -535,37 +770,36 @@ int B2gcPreparePatterns(MpmCtx *mpm_ctx) { if (ctx->m < 2) ctx->m = 2; - ctx->hash_size = b2g_hash_size; + ctx->hash_size = b2gc_hash_size; /* alloc the hashes */ - ctx->ha = SCMalloc(b2g_hash_size * sizeof(uint32_t)); + ctx->ha = SCMalloc(b2gc_hash_size * sizeof(uint32_t)); BUG_ON(ctx->ha == NULL); - memset(ctx->ha, 0x00, b2g_hash_size * sizeof(uint32_t)); + memset(ctx->ha, 0x00, b2gc_hash_size * sizeof(uint32_t)); ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); BUG_ON(ctx->ha1 == NULL); memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); - /* only used at init */ - ctx->b2gc_sort_hash = HashListTableInit(b2g_hash_size, B2gcHashPatternSortHash, B2gcHashPatternCompare, B2gcHashPatternFree); - if (ctx->b2gc_sort_hash == NULL) { + /* alloc the bloom array */ + ctx->bloom = (BloomFilter **)SCMalloc(sizeof(BloomFilter *) * ctx->hash_size); + if (ctx->bloom == NULL) exit(EXIT_FAILURE); - } + memset(ctx->bloom, 0, sizeof(BloomFilter *) * ctx->hash_size); - ctx->b2gc_sort_hash1 = HashListTableInit(256, B2gcHashPatternSortHash1, B2gcHashPatternCompare, B2gcHashPatternFree); - if (ctx->b2gc_sort_hash1 == NULL) { - exit(EXIT_FAILURE); - } + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (sizeof(BloomFilter *) * ctx->hash_size); - B2gcPrepareHash(mpm_ctx); - B2gcBuildMatchArray(mpm_ctx); + /* alloc the pminlen array */ + ctx->pminlen = (uint8_t *)SCMalloc(sizeof(uint8_t) * ctx->hash_size); + if (ctx->pminlen == NULL) + exit(EXIT_FAILURE); + memset(ctx->pminlen, 0, sizeof(uint8_t) * ctx->hash_size); - /* free the hashes only used at init */ - HashListTableFree(ctx->b2gc_sort_hash); - ctx->b2gc_sort_hash = NULL; + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (sizeof(uint8_t) * ctx->hash_size); - HashListTableFree(ctx->b2gc_sort_hash1); - ctx->b2gc_sort_hash1 = NULL; + B2gcPrepareHash(mpm_ctx); SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); if (ctx->pat_1_cnt) { @@ -575,8 +809,6 @@ int B2gcPreparePatterns(MpmCtx *mpm_ctx) { } return 0; -error: - return -1; } void B2gcPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { @@ -604,10 +836,13 @@ static void B2gcGetConfig() { ConfNode *b2g_conf; const char *hash_val = NULL; + const char *bloom_val = NULL; const char *algo = NULL; /* init defaults */ - b2g_hash_size = HASHSIZE_LOW; + b2gc_hash_size = HASHSIZE_LOW; + b2gc_hash_shift = B2GC_HASHSHIFT_LOW; + b2gc_bloom_size = BLOOMSIZE_MEDIUM; b2g_func = B2GC_SEARCHFUNC; ConfNode *pm = ConfGetNode("pattern-matcher"); @@ -615,12 +850,14 @@ static void B2gcGetConfig() if (pm != NULL) { TAILQ_FOREACH(b2g_conf, &pm->head, next) { - if (strncmp(b2g_conf->val, "b2g", 3) == 0) { + if (strncmp(b2g_conf->val, "b2gc", 4) == 0) { algo = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "algo"); hash_val = ConfNodeLookupChildValue (b2g_conf->head.tqh_first, "hash_size"); + bloom_val = ConfNodeLookupChildValue + (b2g_conf->head.tqh_first, "bf_size"); if (algo != NULL) { if (strcmp(algo, "B2gcSearch") == 0) { @@ -630,10 +867,34 @@ static void B2gcGetConfig() } } - if (hash_val != NULL) - b2g_hash_size = MpmGetHashSize(hash_val); + if (hash_val != NULL) { + b2gc_hash_size = MpmGetHashSize(hash_val); + switch (b2gc_hash_size) { + case HASHSIZE_LOWEST: + b2gc_hash_shift = B2GC_HASHSHIFT_LOWEST; + break; + case HASHSIZE_LOW: + b2gc_hash_shift = B2GC_HASHSHIFT_LOW; + break; + case HASHSIZE_MEDIUM: + b2gc_hash_shift = B2GC_HASHSHIFT_MEDIUM; + break; + case HASHSIZE_HIGH: + b2gc_hash_shift = B2GC_HASHSHIFT_HIGH; + break; + case HASHSIZE_HIGHEST: + b2gc_hash_shift = B2GC_HASHSHIFT_HIGHEST; + break; + case HASHSIZE_MAX: + b2gc_hash_shift = B2GC_HASHSHIFT_MAX; + break; + } + } + if (bloom_val != NULL) + b2gc_bloom_size = MpmGetBloomSize(bloom_val); - SCLogDebug("hash size is %"PRIu32, b2g_hash_size); + SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", + b2gc_hash_size, b2gc_bloom_size); } } } @@ -658,7 +919,7 @@ void B2gcInitCtx (MpmCtx *mpm_ctx, int module_handle) { /* Initialize the defaults value from the config file. The given check make sure that we query config file only once for config values */ - if (b2g_hash_size == 0) + if (b2gc_hash_size == 0) B2gcGetConfig(); /* initialize the hash we use to speed up pattern insertions */ @@ -676,54 +937,66 @@ void B2gcInitCtx (MpmCtx *mpm_ctx, int module_handle) { } void B2gcDestroyCtx(MpmCtx *mpm_ctx) { -#if 0 + SCLogDebug("mpm_ctx %p", mpm_ctx); B2gcCtx *ctx = (B2gcCtx *)mpm_ctx->ctx; if (ctx == NULL) return; - if (ctx->b2gc_init_hash) { + if (ctx->b2gc_init_hash != NULL) { HashListTableFree(ctx->b2gc_init_hash); } - if (ctx->parray) { - uint32_t i; - for (i = 0; i < mpm_ctx->pattern_cnt; i++) { - if (ctx->parray[i] != NULL) { - B2gcFreePattern(mpm_ctx, ctx->parray[i]); - } - } - - SCFree(ctx->parray); + if (ctx->B2GC != NULL) { + SCFree(ctx->B2GC); mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gcPattern)); + mpm_ctx->memory_size -= (sizeof(B2GC_TYPE) * ctx->hash_size); } - if (ctx->B2G) { - SCFree(ctx->B2G); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2GC_TYPE) * ctx->hash_size); + if (ctx->ha != NULL) { + SCFree(ctx->ha); } - if (ctx->hash) { + if (ctx->ha1 != NULL) { + SCFree(ctx->ha1); + } + + if (ctx->patterns != NULL) { + SCFree(ctx->patterns); + } + + if (ctx->patterns1 != NULL) { + SCFree(ctx->patterns1); + } + + if (ctx->bloom) { uint32_t h; for (h = 0; h < ctx->hash_size; h++) { - if (ctx->hash[h] == NULL) + if (ctx->bloom[h] == NULL) continue; - B2gcHashFree(mpm_ctx, ctx->hash[h]); + mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->bloom[h]); + mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->bloom[h]); + + BloomFilterFree(ctx->bloom[h]); } - SCFree(ctx->hash); + SCFree(ctx->bloom); + mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= (sizeof(B2gcPattern) * ctx->hash_size); + mpm_ctx->memory_size -= (sizeof(BloomFilter *) * ctx->hash_size); + } + + if (ctx->pminlen) { + SCFree(ctx->pminlen); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (sizeof(uint8_t) * ctx->hash_size); } SCFree(mpm_ctx->ctx); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(B2gcCtx); -#endif } void B2gcThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { @@ -782,8 +1055,9 @@ uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM return 0; while (pos <= (uint32_t)(buflen - B2GC_Q + 1)) { - uint16_t h = B2GC_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); - d = ctx->B2G[h]; + //uint16_t h = B2GC_HASH16(u8_tolower(buf[pos - 1]),u8_tolower(buf[pos])); + uint16_t h = B2GC_HASH16(buf[pos - 1], buf[pos]); + d = ctx->B2GC[h]; if (d != 0) { COUNT(tctx->stat_d0++); @@ -798,43 +1072,43 @@ uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM pos = j; else { /* get our patterns from the hash */ - h = B2GC_HASH16(u8_tolower(buf[j + ctx->m - 2]),u8_tolower(buf[j + ctx->m - 1])); -//__builtin_prefetch((void *)&ctx->ha[h], 0, 3); -//__builtin_prefetch((void *)&ctx->patterns[ctx->ha[h]], 0, 3); - uint32_t offset = ctx->ha[h]; - SCLogDebug("offset %u", offset); - - if (offset > 0) { + h = B2GC_HASH16(buf[j + ctx->m - 2], buf[j + ctx->m - 1]); + if (ctx->pminlen[h] > 0 && (buflen - j) >= ctx->pminlen[h] && + BloomFilterTest(ctx->bloom[h], buf+pos-1, ctx->pminlen[h]) == 1) + { + uint32_t offset = ctx->ha[h]; + SCLogDebug("offset %u, hash %u", offset, h); do { B2gcPatternHdr *hdr = (B2gcPatternHdr *)&ctx->patterns[offset]; -// BUG_ON(hdr == NULL); - - SCLogDebug("hdr %p flags %02x, len %u, id %u", hdr, hdr->flags, hdr->len, hdr->id); - - uint8_t *pattern = (uint8_t *)&ctx->patterns[offset + sizeof(B2gcPatternHdr)]; -// BUG_ON(pattern == NULL); - - #ifdef PRINTMATCH - prt(pattern, hdr->len); printf("\n"); - prt(buf+pos-1, hdr->len); printf("\n"); - #endif - - if (hdr->flags & B2GC_FLAG_NOCASE) { - SCLogDebug("nocase compare"); - - if ((buflen - j) >= hdr->len && memcmp_lowercase(pattern, buf+pos-1, hdr->len) == 0) { - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } - } else { - SCLogDebug("case sensitive compare"); - - if ((buflen - j) >= hdr->len && memcmp(pattern, buf+pos-1, hdr->len) == 0) { - matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); + //BUG_ON(hdr->len <= 1); + offset += hdr->np_offset; + SCLogDebug("next offset %u", offset); + + if (hdr->len <= (buflen - j)) { + if (hdr->flags & B2GC_FLAG_NOCASE) { + uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); + //uint8_t *pattern = (uint8_t *)hdr + hdr->nc_offset; + SCLogDebug("nocase compare"); +#ifdef PRINTMATCH + prt(pattern, hdr->len);printf("\n"); + prt(buf+pos-1, hdr->len);printf("\n"); +#endif + if (memcmp_lowercase(pattern, buf+pos-1, hdr->len) == 0) { + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); + } + } else { + uint8_t *pattern = (uint8_t *)hdr + sizeof(B2gcPatternHdr); + SCLogDebug("case sensitive compare"); +#ifdef PRINTMATCH + prt(pattern, hdr->len);printf("\n"); + prt(buf+pos-1, hdr->len);printf("\n"); +#endif + if (memcmp(pattern, buf+pos-1, hdr->len) == 0) { + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); + } } } - offset += (sizeof(B2gcPatternHdr) + hdr->len); - if (hdr->flags & B2GC_FLAG_FINAL) { SCLogDebug("final flag set, done matching"); break; @@ -848,8 +1122,8 @@ uint32_t B2gcSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternM break; } - h = B2GC_HASH16(u8_tolower(buf[j - 1]),u8_tolower(buf[j])); - d = (d << 1) & ctx->B2G[h]; + h = B2GC_HASH16(buf[j - 1], buf[j]); + d = (d << 1) & ctx->B2GC[h]; } while (d != 0); } COUNT(tctx->stat_num_shift++); @@ -884,7 +1158,7 @@ uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche do { uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); - d = ((d << 1) & ctx->B2G[h]); + d = ((d << 1) & ctx->B2GC[h]); j = j - 1; } while (d != 0 && j != 0); @@ -893,9 +1167,9 @@ uint32_t B2gcSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatche COUNT(tctx->stat_d0++); //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); +#if 0 /* get our patterns from the hash */ uint16_t h = B2GC_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); -#if 0 B2gcPattern *hi = ctx->hash[h], *thi; for (thi = hi; thi != NULL; thi = thi->next) { COUNT(tctx->stat_d0_hashloop++); @@ -946,8 +1220,6 @@ uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatch uint8_t *bufmin = buf; uint8_t *bufend = buf + buflen - 1; uint32_t cnt = 0; -// B2gcPattern *p; - B2gcPattern *thi, *hi; if (buflen == 0) SCReturnUInt(0); @@ -956,23 +1228,20 @@ uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatch while (buf <= bufend) { uint8_t h = u8_tolower(*buf); -//__builtin_prefetch((void *)&ctx->patterns1[ctx->ha1[h]], 0, 3); uint16_t offset = ctx->ha1[h]; SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); if (offset > 0) { do { B2gcPattern1 *hdr = (B2gcPattern1 *)&ctx->patterns1[offset]; -// BUG_ON(hdr == NULL); + offset += (sizeof(B2gcPattern1)); SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); if (hdr->flags & B2GC_FLAG_NOCASE) { SCLogDebug("nocase compare, %02X", *buf); - if (u8_tolower(*buf) == u8_tolower(hdr->pat)) { - cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); - } + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); } else { SCLogDebug("case sensitive compare, %02X", *buf); @@ -981,8 +1250,6 @@ uint32_t B2gcSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatch } } - offset += (sizeof(B2gcPattern1)); - if (hdr->flags & B2GC_FLAG_FINAL) break; } while(1); @@ -1299,6 +1566,88 @@ static int B2gcTestSearch05a (void) { return result; } +static int B2gcTestSearch05b (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); + B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; + + B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ + B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 2, 0, 0); /* 1 match */ + B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 3, 0, 0); /* 1 match */ + B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 4, 0, 0); /* 1 match */ + B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abXD", 4, 0, 0, 5, 0, 0); /* 0 match */ + + B2gcPreparePatterns(&mpm_ctx); + B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 5) + result = 1; + else + printf("5 != %" PRIu32 " ",cnt); + + B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gcDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gcTestSearch05c (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); + B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; + + B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 1, 0, 0); /* 1 match */ + + B2gcPreparePatterns(&mpm_ctx); + B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ",cnt); + + B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gcDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gcTestSearch05d (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GC, -1); + B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; + + B2gcAddPatternCI(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 1, 0, 0); /* 1 match */ + + B2gcPreparePatterns(&mpm_ctx); + B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 6 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ABCD", 4); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ",cnt); + + B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gcDestroyCtx(&mpm_ctx); + return result; +} + static int B2gcTestSearch06 (void) { int result = 0; MpmCtx mpm_ctx; @@ -1368,7 +1717,10 @@ static int B2gcTestSearch07 (void) { B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); - uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); + uint32_t cnt; + int i; + for (i = 0; i<100000;i++) + cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); if (cnt == 135) result = 1; @@ -1494,7 +1846,7 @@ static int B2gcTestSearch11 (void) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ - B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ + B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); @@ -1520,7 +1872,7 @@ static int B2gcTestSearch12 (void) { B2gcCtx *ctx = (B2gcCtx *)mpm_ctx.ctx; B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ - B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ + B2gcAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0); /* 1 match */ B2gcPreparePatterns(&mpm_ctx); B2gcThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); @@ -1765,7 +2117,7 @@ static int B2gcTestSearch21 (void) { } #endif /* UNITTESTS */ -#if 0 +//#if 0 static int B2gcTestSearchXX (void) { MpmCtx mpm_ctx; memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); @@ -1780,7 +2132,7 @@ static int B2gcTestSearchXX (void) { char *word; char line[128]; int w = 0; - int w_max = 10000; + int w_max = 4000; while((word = fgets(line, sizeof(line), fp)) != NULL) { word[strlen(word) - 1] = '\0'; @@ -2472,6 +2824,7 @@ static int B2gcTestSearchXX (void) { for (i = 0; i < 100; i++) { cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); } + printf("cnt %u ", cnt); B2gcThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); B2gcDestroyCtx(&mpm_ctx); @@ -2479,7 +2832,7 @@ static int B2gcTestSearchXX (void) { return 1; } -#endif +//#endif void B2gcRegisterTests(void) { #ifdef UNITTESTS @@ -2498,6 +2851,9 @@ void B2gcRegisterTests(void) { UtRegisterTest("B2gcTestSearch04", B2gcTestSearch04, 1); UtRegisterTest("B2gcTestSearch05", B2gcTestSearch05, 1); UtRegisterTest("B2gcTestSearch05a", B2gcTestSearch05a, 1); + UtRegisterTest("B2gcTestSearch05b", B2gcTestSearch05b, 1); + UtRegisterTest("B2gcTestSearch05c", B2gcTestSearch05c, 1); + UtRegisterTest("B2gcTestSearch05d", B2gcTestSearch05d, 1); UtRegisterTest("B2gcTestSearch06", B2gcTestSearch06, 1); UtRegisterTest("B2gcTestSearch06a", B2gcTestSearch06a, 1); UtRegisterTest("B2gcTestSearch07", B2gcTestSearch07, 1); @@ -2518,7 +2874,7 @@ void B2gcRegisterTests(void) { UtRegisterTest("B2gcTestSearch21", B2gcTestSearch21, 1); /* */ -// UtRegisterTest("B2gcTestSearchXX", B2gcTestSearchXX, 1); + UtRegisterTest("B2gcTestSearchXX", B2gcTestSearchXX, 1); #endif /* UNITTESTS */ } diff --git a/src/util-mpm-b2gc.h b/src/util-mpm-b2gc.h index 826ca702f8..7ec46d5e9d 100644 --- a/src/util-mpm-b2gc.h +++ b/src/util-mpm-b2gc.h @@ -27,6 +27,13 @@ #include "util-mpm.h" #include "util-bloomfilter.h" +#define B2GC_HASHSHIFT_MAX 8 +#define B2GC_HASHSHIFT_HIGHEST 7 +#define B2GC_HASHSHIFT_HIGH 6 +#define B2GC_HASHSHIFT_MEDIUM 5 +#define B2GC_HASHSHIFT_LOW 4 +#define B2GC_HASHSHIFT_LOWEST 3 + //#define B2GC_HASHSHIFT 8 //#define B2GC_HASHSHIFT 7 //#define B2GC_HASHSHIFT 6 @@ -43,7 +50,6 @@ //#define B2GC_WORD_SIZE 16 //#define B2GC_WORD_SIZE 8 -#define B2GC_HASH16(a,b) (((a)<flags) @@ -78,10 +85,9 @@ typedef struct B2gcPatternHdr_ { */ typedef struct B2gcPattern1_ { - uint32_t flags:4; /**< 4 flags max */ - uint32_t id:18; /**< pattern id, max 262143 */ - uint32_t pad:2; /**< 2 bits of padding */ - uint32_t pat:8; /**< character to match */ + uint8_t flags; + uint8_t pat; + uint16_t id; } B2gcPattern1; #define B2GC1_GET_FLAGS(hdr) ((hdr)->flags) @@ -93,41 +99,34 @@ typedef struct B2gcPattern_ { uint16_t len; uint8_t flags; uint8_t pad0; - uint8_t *pat; uint32_t id; + uint8_t *pat; } B2gcPattern; typedef struct B2gcCtx_ { - B2GC_TYPE m; - B2GC_TYPE *B2G; - + /* we store our own multi byte search func ptr here for B2gcSearch1 */ + uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); /* hash for looking up the idx in the pattern array */ uint16_t *ha1; uint8_t *patterns1; uint32_t pat_x_cnt; + uint32_t pat_1_cnt; + /* we store our own multi byte search func ptr here for B2gcSearch1 */ + uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t *ha; - /* patterns in the format |hdr|pattern|hdr|pattern|... */ - uint8_t *patterns; - + B2GC_TYPE m; uint32_t hash_size; + B2GC_TYPE *B2GC; - /* we store our own multi byte search func ptr here for B2gcSearch1 */ - uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); + uint8_t *pminlen; /* array containing the minimal length */ + BloomFilter **bloom; - /* we store our own multi byte search func ptr here for B2gcSearch1 */ - uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); - uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); + uint32_t *ha; + /* patterns in the format |hdr|pattern|hdr|pattern|... */ + uint8_t *patterns; - /* Hash table used at ctx initialization to keep and ordered list of - * patterns. The ordered list is used to build the ordered lookup - * array. */ HashListTable *b2gc_init_hash; - HashListTable *b2gc_sort_hash; - HashListTable *b2gc_sort_hash1; - uint32_t pat_1_cnt; - } B2gcCtx; typedef struct B2gcThreadCtx_ { diff --git a/src/util-mpm-b2gm.c b/src/util-mpm-b2gm.c new file mode 100644 index 0000000000..e505aeb09c --- /dev/null +++ b/src/util-mpm-b2gm.c @@ -0,0 +1,2749 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + * + * Implementation of the SBNDMq pattern matching algorithm. + * + * Future work: + * - parray contains 1 byte patterns while they are not used + * - 1 byte search hashes on tolower(*buf) reducing hash value + * + */ + +//#define PRINTMATCH + +#include "suricata-common.h" +#include "suricata.h" +#include "detect.h" +#include "util-bloomfilter.h" +#include "util-mpm-b2gm.h" +#include "util-print.h" +#include "util-hashlist.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "util-optimize.h" +#include "conf.h" + +#define INIT_HASH_SIZE 65536 + +#ifdef B2GM_COUNTERS +#define COUNT(counter) \ + (counter) +#else +#define COUNT(counter) +#endif /* B2GM_COUNTERS */ + +static uint32_t b2gm_hash_size = 0; +static uint32_t b2gm_bloom_size = 0; +static uint8_t b2gm_hash_shift = 0; +static void *b2g_func; + +#define B2GM_HASH16(a,b) (((a) << b2gm_hash_shift) | (b)) + +void B2gmInitCtx (MpmCtx *, int); +void B2gmThreadInitCtx(MpmCtx *, MpmThreadCtx *, uint32_t); +void B2gmDestroyCtx(MpmCtx *); +void B2gmThreadDestroyCtx(MpmCtx *, MpmThreadCtx *); +int B2gmAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); +int B2gmAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, uint32_t, uint8_t); +int B2gmPreparePatterns(MpmCtx *mpm_ctx); +uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); +uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); +#ifdef B2GM_SEARCH2 +uint32_t B2gmSearch2(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); +#endif +uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *, uint8_t *buf, uint16_t buflen); +uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen); +void B2gmPrintInfo(MpmCtx *mpm_ctx); +void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx); +void B2gmRegisterTests(void); + +void MpmB2gmRegister (void) { + mpm_table[MPM_B2GM].name = "b2gm"; + mpm_table[MPM_B2GM].max_pattern_length = B2GM_WORD_SIZE; + + mpm_table[MPM_B2GM].InitCtx = B2gmInitCtx; + mpm_table[MPM_B2GM].InitThreadCtx = B2gmThreadInitCtx; + mpm_table[MPM_B2GM].DestroyCtx = B2gmDestroyCtx; + mpm_table[MPM_B2GM].DestroyThreadCtx = B2gmThreadDestroyCtx; + mpm_table[MPM_B2GM].AddPattern = B2gmAddPatternCS; + mpm_table[MPM_B2GM].AddPatternNocase = B2gmAddPatternCI; + mpm_table[MPM_B2GM].Prepare = B2gmPreparePatterns; + mpm_table[MPM_B2GM].Search = B2gmSearchWrap; + mpm_table[MPM_B2GM].Cleanup = NULL; + mpm_table[MPM_B2GM].PrintCtx = B2gmPrintInfo; + mpm_table[MPM_B2GM].PrintThreadCtx = B2gmPrintSearchStats; + mpm_table[MPM_B2GM].RegisterUnittests = B2gmRegisterTests; +} + +#ifdef PRINTMATCH +static void prt (uint8_t *buf, uint16_t buflen) { + uint16_t i; + + for (i = 0; i < buflen; i++) { + if (isprint(buf[i])) printf("%c", buf[i]); + else printf("\\x%02X", buf[i]); + } + //printf("\n"); +} +#endif + +void B2gmPrintInfo(MpmCtx *mpm_ctx) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + + printf("MPM B2gm Information:\n"); + printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt); + printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size); + printf(" Sizeofs:\n"); + printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx)); + printf(" B2gmCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmCtx)); + printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); + printf(" B2gmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B2gmPattern)); + printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); + printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); + printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); + printf("Hash size: %" PRIu32 "\n", ctx->hash_size); + printf("\n"); +} + +static inline B2gmPattern *B2gmAllocPattern(MpmCtx *mpm_ctx) { + B2gmPattern *p = SCMalloc(sizeof(B2gmPattern)); + if (p == NULL) + return NULL; + memset(p,0,sizeof(B2gmPattern)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(B2gmPattern); + return p; +} + +static inline B2gmPattern * +B2gmAllocHashItem(MpmCtx *mpm_ctx) { + B2gmPattern *hi = SCMalloc(sizeof(B2gmPattern)); + if (hi == NULL) + return NULL; + memset(hi,0,sizeof(B2gmPattern)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(B2gmPattern); + return hi; +} + +static void B2gmHashFree(MpmCtx *mpm_ctx, B2gmPattern *hi) { + if (hi == NULL) + return; + + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(B2gmPattern); + B2gmPattern *t = hi->next; + SCFree(hi); + + B2gmHashFree(mpm_ctx, t); +} + +static inline void memcpy_tolower(uint8_t *d, uint8_t *s, uint16_t len) { + uint16_t i; + for (i = 0; i < len; i++) { + d[i] = u8_tolower(s[i]); + } +} + +/* + * INIT HASH START + */ +static inline uint32_t B2gmInitHash(B2gmPattern *p) { + uint32_t hash = p->len * p->pat[0]; + if (p->len > 1) + hash += p->pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +static inline uint32_t B2gmInitHashRaw(uint8_t *pat, uint16_t patlen) { + uint32_t hash = patlen * pat[0]; + if (patlen > 1) + hash += pat[1]; + + return (hash % INIT_HASH_SIZE); +} + +static inline int B2gmInitHashAdd(B2gmCtx *ctx, B2gmPattern *p) { + uint32_t hash = B2gmInitHash(p); + + if (ctx->init_hash[hash] == NULL) { + ctx->init_hash[hash] = p; + return 0; + } + + B2gmPattern *tt = NULL; + B2gmPattern *t = ctx->init_hash[hash]; + + /* get the list tail */ + do { + tt = t; + t = t->next; + } while (t != NULL); + + tt->next = p; + + return 0; +} + +static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags); + +static inline B2gmPattern *B2gmInitHashLookup(B2gmCtx *ctx, uint8_t *pat, uint16_t patlen, char flags) { + uint32_t hash = B2gmInitHashRaw(pat,patlen); + + if (ctx->init_hash[hash] == NULL) { + return NULL; + } + + B2gmPattern *t = ctx->init_hash[hash]; + for ( ; t != NULL; t = t->next) { + if (B2gmCmpPattern(t,pat,patlen,flags) == 1) + return t; + } + + return NULL; +} + +static inline int B2gmCmpPattern(B2gmPattern *p, uint8_t *pat, uint16_t patlen, char flags) { + if (p->len != patlen) + return 0; + + if (p->flags != flags) + return 0; + + if (memcmp(p->pat, pat, patlen) != 0) + return 0; + + return 1; +} + +/* + * INIT HASH END + */ + +void B2gmFreePattern(MpmCtx *mpm_ctx, B2gmPattern *p) { + if (p != NULL) { + if (p->pat != NULL) { + SCFree(p->pat); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= p->len; + } + + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(B2gmPattern); + } +} + +/** \internal + * \brief add a pattern to the mpm/b2g context + * + * \param pat ptr to the pattern + * \param patlen length of the pattern + * \param pid pattern id + * \param sid signature id (internal id) + * \param flags pattern MPM_PATTERN_* flags + */ +static int B2gmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + + SCLogDebug("ctx %p len %"PRIu16" pid %" PRIu32, ctx, patlen, pid); + + if (patlen == 0) + return 0; + + /* get a memory piece */ + B2gmPattern *p = B2gmInitHashLookup(ctx, pat, patlen, flags); + if (p == NULL) { + SCLogDebug("allocing new pattern"); + + B2gmPattern *p = B2gmAllocPattern(mpm_ctx); + if (p == NULL) + goto error; + + p->len = patlen; + p->flags = flags; + p->id = pid; + + /* setup the case insensitive part of the pattern */ + p->pat = SCMalloc(patlen); + if (p->pat == NULL) + goto error; + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += patlen; + + /* setup the case sensitive part of the pattern */ + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + memcpy_tolower(p->pat, pat, patlen); + } else { + memcpy(p->pat, pat, patlen); + } + + /* put in the pattern hash */ + B2gmInitHashAdd(ctx, p); + + if (mpm_ctx->pattern_cnt == 65535) { + printf("Max search words reached\n"); + exit(1); + } + + mpm_ctx->pattern_cnt++; + + if (patlen == 1) { + ctx->pat_1_cnt++; + } else { + ctx->pat_x_cnt++; + } + + if (mpm_ctx->maxlen < patlen) + mpm_ctx->maxlen = patlen; + if (mpm_ctx->minlen == 0) + mpm_ctx->minlen = patlen; + else if (mpm_ctx->minlen > patlen) + mpm_ctx->minlen = patlen; + } + + return 0; + +error: + B2gmFreePattern(mpm_ctx, p); + return -1; +} + +int B2gmAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) +{ + flags |= MPM_PATTERN_FLAG_NOCASE; + return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +int B2gmAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, + uint16_t offset, uint16_t depth, uint32_t pid, uint32_t sid, uint8_t flags) +{ + return B2gmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +static uint32_t B2gmHashPatternSortHash1(HashListTable *ht, void *pattern, uint16_t len) { + BUG_ON(len != sizeof(B2gmPattern)); + BUG_ON(pattern == NULL); + + B2gmPattern *p = (B2gmPattern *)pattern; + return (uint32_t)p->pat[0]; +} + +static char B2gmHashPatternCompare(void *pattern1, uint16_t len1, + void *pattern2, uint16_t len2) { + BUG_ON(len1 != sizeof(B2gmPattern)); + BUG_ON(len2 != sizeof(B2gmPattern)); + + B2gmPattern *p1 = (B2gmPattern *)pattern1; + B2gmPattern *p2 = (B2gmPattern *)pattern2; + + if (p1->id != p2->id) { + return 0; + } + + return 1; +} + +static void B2gmHashPatternFree(void *pattern) { + B2gmPattern *p = (B2gmPattern *)pattern; + + SCFree(p->pat); + + SCFree(pattern); +} + +static inline uint32_t B2gmBloomHash(void *data, uint16_t datalen, uint8_t iter, uint32_t hash_size) { + uint8_t *d = (uint8_t *)data; + uint16_t i; + uint32_t hash = (uint32_t)u8_tolower(*d); + + for (i = 1; i < datalen; i++) { + d++; + hash += (u8_tolower(*d)) ^ i; + } + hash <<= (iter+1); + + hash %= hash_size; + return hash; +} + +static void B2gmPrepareHashAddPattern(MpmCtx *mpm_ctx, uint16_t idx, uint32_t i) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + + if (ctx->lookup[idx].hash == NULL) { + B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); + if (hi == NULL) + goto error; + + hi->len = ctx->parray[i]->len; + hi->flags |= ctx->parray[i]->flags; + hi->id = ctx->parray[i]->id; + hi->pat = ctx->parray[i]->pat; + + ctx->lookup[idx].pminlen = ctx->parray[i]->len; + + ctx->lookup[idx].hash = hi; + } else { + B2gmPattern *hi = B2gmAllocHashItem(mpm_ctx); + if (hi == NULL) + goto error; + + hi->len = ctx->parray[i]->len; + hi->flags |= ctx->parray[i]->flags; + hi->id = ctx->parray[i]->id; + hi->pat = ctx->parray[i]->pat; + + if (ctx->parray[i]->len < ctx->lookup[idx].pminlen) + ctx->lookup[idx].pminlen = ctx->parray[i]->len; + + /* Append this HashItem to the list */ + B2gmPattern *thi = ctx->lookup[idx].hash; + while (thi->next) + thi = thi->next; + thi->next = hi; + } + return; +error: + return; +} + +static void B2gmPrepareHash(MpmCtx *mpm_ctx) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + uint16_t i; + uint16_t size1 = 1; + + HashListTable *b2gm_sort_hash1 = HashListTableInit(256, B2gmHashPatternSortHash1, B2gmHashPatternCompare, NULL); + if (b2gm_sort_hash1 == NULL) { + exit(EXIT_FAILURE); + } + + for (i = 0; i < mpm_ctx->pattern_cnt; i++) + { + SCLogDebug("ctx->parray[i]->len %u", ctx->parray[i]->len); + + if(ctx->parray[i]->len == 1) { + HashListTableAdd(b2gm_sort_hash1, (void *)ctx->parray[i], sizeof(B2gmPattern)); + size1 += (sizeof(B2gmPattern1)); + } else { + if (ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE) { + /* u, u */ + uint16_t uuidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); + B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); + + /* l, l */ + uint16_t llidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); + if (llidx != uuidx) { + B2gmPrepareHashAddPattern(mpm_ctx, llidx, i); + } + /* u, l */ + uint16_t ulidx = B2GM_HASH16(toupper(ctx->parray[i]->pat[ctx->m - 2]), tolower(ctx->parray[i]->pat[ctx->m - 1])); + if (ulidx != llidx && ulidx != uuidx) { + B2gmPrepareHashAddPattern(mpm_ctx, ulidx, i); + } + /* l, u */ + uint16_t luidx = B2GM_HASH16(tolower(ctx->parray[i]->pat[ctx->m - 2]), toupper(ctx->parray[i]->pat[ctx->m - 1])); + if (luidx != ulidx && luidx != llidx && luidx != uuidx) { + B2gmPrepareHashAddPattern(mpm_ctx, luidx, i); + } + } else { + uint16_t uuidx = B2GM_HASH16(ctx->parray[i]->pat[ctx->m - 2], ctx->parray[i]->pat[ctx->m - 1]); + B2gmPrepareHashAddPattern(mpm_ctx, uuidx, i); + } + } + } + + uint32_t h; + for (h = 0; h < ctx->hash_size; h++) { + B2gmPattern *hi = ctx->lookup[h].hash; + if (hi == NULL) + continue; + + ctx->lookup[h].bloom = BloomFilterInit(b2gm_bloom_size, 2, B2gmBloomHash); + if (ctx->lookup[h].bloom == NULL) + continue; + + mpm_ctx->memory_cnt += BloomFilterMemoryCnt(ctx->lookup[h].bloom); + mpm_ctx->memory_size += BloomFilterMemorySize(ctx->lookup[h].bloom); + + if (ctx->lookup[h].pminlen > 8) + ctx->lookup[h].pminlenb = 8; + else + ctx->lookup[h].pminlenb = (uint8_t)ctx->lookup[h].pminlen; + + B2gmPattern *thi = hi; + do { + SCLogDebug("adding \"%c%c\" to the bloom", thi->pat[0], thi->pat[1]); + BloomFilterAdd(ctx->lookup[h].bloom, thi->pat, ctx->lookup[h].pminlenb); + thi = thi->next; + } while (thi != NULL); + } + + /* build the 1 byte match array */ + SCLogDebug("size1 %u", size1); + ctx->patterns1 = SCMalloc(size1); + BUG_ON(ctx->patterns1 == NULL); + memset(ctx->patterns1, 0x00, size1); + + /* skip the first byte of the buffer */ + uint16_t offset1 = 1; + + uint32_t a; + for (a = 0; a < b2gm_sort_hash1->array_size; a++) { + HashListTableBucket *buck = b2gm_sort_hash1->array[a]; + if (buck != NULL) { + while (buck != NULL) { + if (buck->data != NULL) { + B2gmPattern *p = (B2gmPattern *) (buck->data); + BUG_ON(p == NULL); + BUG_ON(p->len != 1); + + B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; + h->id = p->id; + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + h->flags |= B2GM_FLAG_NOCASE; + h->pat = p->pat[0]; + } else { + h->pat = p->pat[0]; + } + + offset1 += (sizeof(B2gmPattern1)); + } + buck = buck->bucknext; + } + } + } + + /* build the hash containing idx' to the pattern array */ + offset1 = 1; + + B2gmPattern1 *ph1 = NULL; + uint8_t prevhash1 = 0; + while (offset1 < size1) { + B2gmPattern1 *h = (B2gmPattern1 *)&ctx->patterns1[offset1]; + + if (ctx->ha1[u8_tolower(h->pat)] == 0) + ctx->ha1[u8_tolower(h->pat)] = offset1; + + /* check the prev pattern for setting the final flag */ + if (ph1 != NULL) { + if (u8_tolower(h->pat) != prevhash1) { + SCLogDebug("setting final flag on %p", ph1); + ph1->flags |= B2GM_FLAG_FINAL; + } + } + + prevhash1 = u8_tolower(h->pat); + ph1 = h; + + offset1 += (sizeof(B2gmPattern1)); + + /* last item is "final" too */ + if (offset1 == size1) { + SCLogDebug("final pattern in the array"); + h->flags |= B2GM_FLAG_FINAL; + } + + SCLogDebug("offset %u, size %u", offset1, size1); + } + + HashListTableFree(b2gm_sort_hash1); + b2gm_sort_hash1 = NULL; + return; +} + +static void B2gmAddToMatchArray(MpmCtx *mpm_ctx, B2gmPattern *p, int j) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + + if (p->flags & MPM_PATTERN_FLAG_NOCASE) { + /* u, u */ + uint16_t uuidx = B2GM_HASH16(toupper(p->pat[j]), toupper(p->pat[j + 1])); + ctx->B2GM[uuidx] = ctx->B2GM[uuidx] | (1 << (ctx->m - j)); + + /* l, l */ + uint16_t llidx = B2GM_HASH16(u8_tolower(p->pat[j]), u8_tolower(p->pat[j + 1])); + if (llidx != uuidx) { + ctx->B2GM[llidx] = ctx->B2GM[llidx] | (1 << (ctx->m - j)); + } + /* u, l */ + uint16_t ulidx = B2GM_HASH16(toupper(p->pat[j]), u8_tolower(p->pat[j + 1])); + if (ulidx != llidx && ulidx != uuidx) { + ctx->B2GM[ulidx] = ctx->B2GM[ulidx] | (1 << (ctx->m - j)); + } + /* l, u */ + uint16_t luidx = B2GM_HASH16(u8_tolower(p->pat[j]), toupper(p->pat[j + 1])); + if (luidx != ulidx && luidx != llidx && luidx != uuidx) { + ctx->B2GM[luidx] = ctx->B2GM[luidx] | (1 << (ctx->m - j)); + } + + SCLogDebug("uuidx %u, ulidx %u, luidx %u, llidx %u", uuidx, ulidx, luidx, llidx); + } +} + +int B2gmBuildMatchArray(MpmCtx *mpm_ctx) { + SCEnter(); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + + ctx->B2GM = SCMalloc(sizeof(B2GM_TYPE) * ctx->hash_size); + if (ctx->B2GM == NULL) + return -1; + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (sizeof(B2GM_TYPE) * ctx->hash_size); + + memset(ctx->B2GM,0, b2gm_hash_size * sizeof(B2GM_TYPE)); + + uint32_t j; + uint32_t a; + + /* fill the match array */ + for (j = 0; j <= (ctx->m - B2GM_Q); j++) { + for (a = 0; a < ctx->pat_x_cnt; a++) { + if (ctx->parray[a]->len < ctx->m) + continue; + + uint16_t h; + if (ctx->parray[a]->flags & MPM_PATTERN_FLAG_NOCASE) { + B2gmAddToMatchArray(mpm_ctx, ctx->parray[a], j); + } else { + h = B2GM_HASH16(ctx->parray[a]->pat[j], ctx->parray[a]->pat[j+1]); + ctx->B2GM[h] = ctx->B2GM[h] | (1 << (ctx->m - j)); + SCLogDebug("h %"PRIu16", ctx->B2GM[h] %"PRIu32" (cs)", h, ctx->B2GM[h]); + } + } + } + + //ctx->s0 = 1; + SCReturnInt(0); +} + +int B2gmPreparePatterns(MpmCtx *mpm_ctx) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + + /* alloc the lookup array */ + ctx->lookup = SCMalloc(b2gm_hash_size * sizeof(B2gmLookup)); + if (ctx->lookup == NULL) + goto error; + memset(ctx->lookup, 0x00, b2gm_hash_size * sizeof(B2gmLookup)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (b2gm_hash_size * sizeof(B2gmLookup)); + + /* alloc the pattern array */ + ctx->parray = (B2gmPattern **)SCMalloc(mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); + if (ctx->parray == NULL) + goto error; + memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(B2gmPattern *)); + + /* populate it with the patterns in the hash */ + uint32_t i = 0; + uint32_t p = 0; + + for (i = 0; i < INIT_HASH_SIZE; i++) { + B2gmPattern *node = ctx->init_hash[i]; + B2gmPattern *nnode = NULL; + + for ( ; node != NULL; ) { + nnode = node->next; + node->next = NULL; + + ctx->parray[p] = node; + p++; + + node = nnode; + } + } + /* we no longer need the hash, so free it's memory */ + SCFree(ctx->init_hash); + ctx->init_hash = NULL; + + /* set 'm' to the smallest pattern size */ + ctx->m = mpm_ctx->minlen; + + /* make sure 'm' stays in bounds + m can be max WORD_SIZE - 1 */ + if (ctx->m >= B2GM_WORD_SIZE) { + ctx->m = B2GM_WORD_SIZE - 1; + } + if (ctx->m < 2) + ctx->m = 2; + + ctx->hash_size = b2gm_hash_size; + B2gmPrepareHash(mpm_ctx); + B2gmBuildMatchArray(mpm_ctx); + + SCLogDebug("ctx->pat_1_cnt %"PRIu16"", ctx->pat_1_cnt); + if (ctx->pat_1_cnt) { + ctx->Search = B2gmSearch1; + ctx->MBSearch = b2g_func; + } + + return 0; +error: + return -1; +} + +void B2gmPrintSearchStats(MpmThreadCtx *mpm_thread_ctx) { +#ifdef B2GM_COUNTERS + B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; + + printf("B2gm Thread Search stats (tctx %p)\n", tctx); + printf("Total calls: %" PRIu32 "\n", tctx->stat_calls); + printf("Avg m/search: %0.2f\n", tctx->stat_calls ? (float)((float)tctx->stat_m_total / (float)tctx->stat_calls) : 0); + printf("D != 0 (possible match): %" PRIu32 "\n", tctx->stat_d0); + printf("Avg hash items per bucket %0.2f (%" PRIu32 ")\n", tctx->stat_d0 ? (float)((float)tctx->stat_d0_hashloop / (float)tctx->stat_d0) : 0, tctx->stat_d0_hashloop); + printf("Loop match: %" PRIu32 "\n", tctx->stat_loop_match); + printf("Loop no match: %" PRIu32 "\n", tctx->stat_loop_no_match); + printf("Num shifts: %" PRIu32 "\n", tctx->stat_num_shift); + printf("Total shifts: %" PRIu32 "\n", tctx->stat_total_shift); + printf("Avg shifts: %0.2f\n", tctx->stat_num_shift ? (float)((float)tctx->stat_total_shift / (float)tctx->stat_num_shift) : 0); + printf("Total BloomFilter checks: %" PRIu32 "\n", tctx->stat_bloom_calls); + printf("BloomFilter hits: %0.4f%% (%" PRIu32 ")\n", tctx->stat_bloom_calls ? (float)((float)((float)tctx->stat_bloom_hits / (float)tctx->stat_bloom_calls)*(float)100) : 0, tctx->stat_bloom_hits); + printf("Avg pminlen: %0.2f\n", tctx->stat_pminlen_calls ? (float)((float)tctx->stat_pminlen_total / (float)tctx->stat_pminlen_calls) : 0); + printf("Test bug %"PRIu32"\n", tctx->stat_test_buf); + printf("Test bug ok %"PRIu32"\n", tctx->stat_test_buf_ok); + printf("Test bug fail %"PRIu32"\n\n", tctx->stat_test_buf_fail); +#endif /* B2GM_COUNTERS */ +} + +static inline int +memcmp_lowercase(const uint8_t *s1, const uint8_t *s2, const uint16_t n) { +#if 0 + uint8_t buf[256]; + + uint16_t u = 0; + for ( ; u < n; u++) { + buf[u] = u8_tolower(s2[u]); + } + + return memcmp(s1, buf, n); +#endif +//#if 0 + size_t i; + + /* check backwards because we already tested the first + * 2 to 4 chars. This way we are more likely to detect + * a miss and thus speed up a little... */ + for (i = n - 1; i; i--) { + if (s1[i] != u8_tolower(*(s2+i))) + return 1; + } + + return 0; +//#endif +} + +/** + * \brief Function to get the user defined values for b2g algorithm from the + * config file 'suricata.yaml' + */ +static void B2gmGetConfig() +{ + ConfNode *b2g_conf; + const char *hash_val = NULL; + const char *bloom_val = NULL; + const char *algo = NULL; + + /* init defaults */ + b2gm_hash_size = HASHSIZE_LOW; + b2gm_hash_shift = B2GM_HASHSHIFT_LOW; + b2gm_bloom_size = BLOOMSIZE_MEDIUM; + b2g_func = B2GM_SEARCHFUNC; + + ConfNode *pm = ConfGetNode("pattern-matcher"); + if (pm != NULL) { + TAILQ_FOREACH(b2g_conf, &pm->head, next) { + if (strcmp(b2g_conf->val, "b2gm") == 0) { + + algo = ConfNodeLookupChildValue + (b2g_conf->head.tqh_first, "algo"); + hash_val = ConfNodeLookupChildValue + (b2g_conf->head.tqh_first, "hash_size"); + bloom_val = ConfNodeLookupChildValue + (b2g_conf->head.tqh_first, "bf_size"); + + if (algo != NULL) { + if (strcmp(algo, "B2gmSearch") == 0) { + b2g_func = B2gmSearch; + } else if (strcmp(algo, "B2gmSearchBNDMq") == 0) { + b2g_func = B2gmSearchBNDMq; + } + } + + if (hash_val != NULL) { + b2gm_hash_size = MpmGetHashSize(hash_val); + switch (b2gm_hash_size) { + case HASHSIZE_LOWEST: + b2gm_hash_shift = B2GM_HASHSHIFT_LOWEST; + break; + case HASHSIZE_LOW: + b2gm_hash_shift = B2GM_HASHSHIFT_LOW; + break; + case HASHSIZE_MEDIUM: + b2gm_hash_shift = B2GM_HASHSHIFT_MEDIUM; + break; + case HASHSIZE_HIGH: + b2gm_hash_shift = B2GM_HASHSHIFT_HIGH; + break; + case HASHSIZE_HIGHEST: + b2gm_hash_shift = B2GM_HASHSHIFT_HIGHEST; + break; + case HASHSIZE_MAX: + b2gm_hash_shift = B2GM_HASHSHIFT_MAX; + break; + } + } + + if (bloom_val != NULL) + b2gm_bloom_size = MpmGetBloomSize(bloom_val); + + SCLogDebug("hash size is %"PRIu32" and bloom size is %"PRIu32"", + b2gm_hash_size, b2gm_bloom_size); + } + } + } +} + +void B2gmInitCtx (MpmCtx *mpm_ctx, int module_handle) { + SCLogDebug("mpm_ctx %p, ctx %p", mpm_ctx, mpm_ctx->ctx); + + BUG_ON(mpm_ctx->ctx != NULL); + + mpm_ctx->ctx = SCMalloc(sizeof(B2gmCtx)); + if (mpm_ctx->ctx == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " + "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)(sizeof(B2gmCtx))); + exit(EXIT_FAILURE); + } + + memset(mpm_ctx->ctx, 0, sizeof(B2gmCtx)); + + mpm_ctx->memory_cnt++; + mpm_ctx->memory_size += sizeof(B2gmCtx); + + /* initialize the hash we use to speed up pattern insertions */ + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + ctx->init_hash = SCMalloc(sizeof(B2gmPattern *) * INIT_HASH_SIZE); + if (ctx->init_hash == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " + "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)(sizeof(B2gmPattern *) * INIT_HASH_SIZE)); + exit(EXIT_FAILURE); + } + + memset(ctx->init_hash, 0, sizeof(B2gmPattern *) * INIT_HASH_SIZE); + + /* Initialize the defaults value from the config file. The given check make + sure that we query config file only once for config values */ + if (b2gm_hash_size == 0) + B2gmGetConfig(); + + ctx->ha1 = SCMalloc(256 * sizeof(uint16_t)); + BUG_ON(ctx->ha1 == NULL); + memset(ctx->ha1, 0x00, 256 * sizeof(uint16_t)); + + /* init defaults search functions */ + ctx->Search = b2g_func; + + SCReturn; +} + +void B2gmDestroyCtx(MpmCtx *mpm_ctx) { + SCLogDebug("mpm_ctx %p", mpm_ctx); + + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + if (ctx == NULL) + return; + + if (ctx->init_hash != NULL) { + SCFree(ctx->init_hash); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(B2gmPattern *)); + } + + if (ctx->parray != NULL) { + uint32_t i; + for (i = 0; i < mpm_ctx->pattern_cnt; i++) { + if (ctx->parray[i] != NULL) { + B2gmFreePattern(mpm_ctx, ctx->parray[i]); + } + } + + SCFree(ctx->parray); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(B2gmPattern)); + } + + if (ctx->B2GM != NULL) { + SCFree(ctx->B2GM); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (sizeof(B2GM_TYPE) * ctx->hash_size); + } + + if (ctx->lookup != NULL) { + uint32_t h; + for (h = 0; h < ctx->hash_size; h++) { + if (ctx->lookup[h].bloom == NULL) + continue; + + B2gmHashFree(mpm_ctx, ctx->lookup[h].hash); + + mpm_ctx->memory_cnt -= BloomFilterMemoryCnt(ctx->lookup[h].bloom); + mpm_ctx->memory_size -= BloomFilterMemorySize(ctx->lookup[h].bloom); + + BloomFilterFree(ctx->lookup[h].bloom); + } + + SCFree(ctx->lookup); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= (sizeof(B2gmLookup) * ctx->hash_size); + } + + SCFree(mpm_ctx->ctx); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(B2gmCtx); +} + +void B2gmThreadInitCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, uint32_t matchsize) { + memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + + if (sizeof(B2gmThreadCtx) > 0) { /* size can be null when optimized */ + mpm_thread_ctx->ctx = SCMalloc(sizeof(B2gmThreadCtx)); + if (mpm_thread_ctx->ctx == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " + "to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)(sizeof(B2gmThreadCtx))); + exit(EXIT_FAILURE); + } + + memset(mpm_thread_ctx->ctx, 0, sizeof(B2gmThreadCtx)); + + mpm_thread_ctx->memory_cnt++; + mpm_thread_ctx->memory_size += sizeof(B2gmThreadCtx); + } +} + +void B2gmThreadDestroyCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx) { + B2gmThreadCtx *ctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; + + B2gmPrintSearchStats(mpm_thread_ctx); + + if (ctx != NULL) { /* can be NULL if B2gmThreadCtx is optimized to 0 */ + mpm_thread_ctx->memory_cnt--; + mpm_thread_ctx->memory_size -= sizeof(B2gmThreadCtx); + SCFree(mpm_thread_ctx->ctx); + } +} + +uint32_t B2gmSearchWrap(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + return ctx ? ctx->Search(mpm_ctx, mpm_thread_ctx, pmq, buf, buflen) : 0; +} + +uint32_t B2gmSearchBNDMq(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; +#ifdef B2GM_COUNTERS + B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; +#endif + uint32_t pos = ctx->m - B2GM_Q + 1, matches = 0; + B2GM_TYPE d; + + //printf("\n"); + //PrintRawDataFp(stdout, buf, buflen); + + SCLogDebug("buflen %"PRIu16", ctx->m %"PRIu32", pos %"PRIu32"", buflen, + ctx->m, pos); + + COUNT(tctx->stat_calls++); + COUNT(tctx->stat_m_total+=ctx->m); + + if (buflen < ctx->m) + return 0; + + while (pos <= (uint32_t)(buflen - B2GM_Q + 1)) { + uint16_t h = B2GM_HASH16(buf[pos - 1],buf[pos]); + d = ctx->B2GM[h]; + + if (d != 0) { + COUNT(tctx->stat_d0++); + uint32_t j = pos; + uint32_t first = pos - (ctx->m - B2GM_Q + 1); + + do { + j = j - 1; + + if (d >= (uint32_t)(1 << (ctx->m - 1))) { + if (j > first) + pos = j; + else { + COUNT(tctx->stat_test_buf++); + h = B2GM_HASH16(buf[j + ctx->m - 2],buf[j + ctx->m - 1]); + + if (unlikely(ctx->lookup[h].pminlen > 0 && (buflen - j) >= ctx->lookup[h].pminlen && + BloomFilterTest(ctx->lookup[h].bloom, buf+j, ctx->lookup[h].pminlenb) == 1)) + { + COUNT(tctx->stat_test_buf_ok++); + /* get our patterns from the hash */ + B2gmPattern *hi = ctx->lookup[h].hash, *thi; + for (thi = hi; thi != NULL; thi = thi->next) { + if ((buflen - j) >= thi->len) { + + if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { + + if (unlikely(memcmp_lowercase(thi->pat, buf+j, thi->len) == 0)) { +#ifdef PRINTMATCH + printf("CI Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); +#endif + COUNT(tctx->stat_loop_match++); + + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + } else { + COUNT(tctx->stat_loop_no_match++); + } + } else { + if (unlikely(memcmp(thi->pat, buf+j, thi->len) == 0)) { +#ifdef PRINTMATCH + printf("CS Exact match: "); prt(thi->pat, thi->len); printf(" (id %u)\n", thi->id); +#endif + COUNT(tctx->stat_loop_match++); + + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + } else { + COUNT(tctx->stat_loop_no_match++); + } + } + } + } + } else { + COUNT(tctx->stat_test_buf_fail++); + } + } + } + + if (j == 0) { + break; + } + + h = B2GM_HASH16(buf[j - 1],buf[j]); + d = (d << 1) & ctx->B2GM[h]; + } while (d != 0); + } + COUNT(tctx->stat_num_shift++); + COUNT(tctx->stat_total_shift += (ctx->m - B2GM_Q + 1)); + pos = pos + ctx->m - B2GM_Q + 1; + + SCLogDebug("pos %"PRIu32"", pos); + } + + SCLogDebug("matches %"PRIu32"", matches); + return matches; +} + +uint32_t B2gmSearch(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; +#ifdef B2GM_COUNTERS + B2gmThreadCtx *tctx = (B2gmThreadCtx *)mpm_thread_ctx->ctx; +#endif + uint32_t pos = 0, matches = 0; + B2GM_TYPE d; + uint32_t j; + + COUNT(tctx->stat_calls++); + COUNT(tctx->stat_m_total+=ctx->m); + + if (buflen < ctx->m) + return 0; + + while (pos <= (buflen - ctx->m)) { + j = ctx->m - 1; + d = ~0; + + do { + uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + j - 1]),u8_tolower(buf[pos + j])); + d = ((d << 1) & ctx->B2GM[h]); + j = j - 1; + } while (d != 0 && j != 0); + + /* (partial) match, move on to verification */ + if (d != 0) { + COUNT(tctx->stat_d0++); + //printf("output at pos %" PRIu32 ": ", pos); prt(buf + pos, ctx->m); printf("\n"); + + /* get our patterns from the hash */ + uint16_t h = B2GM_HASH16(u8_tolower(buf[pos + ctx->m - 2]),u8_tolower(buf[pos + ctx->m - 1])); + + if (ctx->lookup[h].pminlen > 0) { + COUNT(tctx->stat_pminlen_calls++); + + if ((buflen - pos) < ctx->lookup[h].pminlen) { + goto skip_loop; + } else { + COUNT(tctx->stat_bloom_calls++); + + if (BloomFilterTest(ctx->lookup[h].bloom, buf+pos, ctx->lookup[h].pminlenb) == 0) { + COUNT(tctx->stat_bloom_hits++); + + //printf("Bloom: %p, buflen %" PRIu32 ", pos %" PRIu32 ", p_min_len %" PRIu32 "\n", ctx->bloom[h], buflen, pos, ctx->pminlen[h]); + goto skip_loop; + } + } + + B2gmPattern *hi = ctx->lookup[h].hash, *thi; + for (thi = hi; thi != NULL; thi = thi->next) { + COUNT(tctx->stat_d0_hashloop++); + //B2gmPattern *p = ctx->parray[thi->idx]; + + if (buflen - pos < thi->len) + continue; + + if (thi->flags & MPM_PATTERN_FLAG_NOCASE) { + + if (memcmp_lowercase(thi->pat, buf+pos, thi->len) == 0) { + COUNT(tctx->stat_loop_match++); + + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + } else { + COUNT(tctx->stat_loop_no_match++); + } + } else { + if (memcmp(thi->pat, buf+pos, thi->len) == 0) { + COUNT(tctx->stat_loop_match++); + + matches += MpmVerifyMatch(mpm_thread_ctx, pmq, thi->id); + } else { + COUNT(tctx->stat_loop_no_match++); + } + } + } + } + +skip_loop: + //pos = pos + ctx->s0; + pos = pos + 1; + } else { + COUNT(tctx->stat_num_shift++); + COUNT(tctx->stat_total_shift += (j + 1)); + + pos = pos + j + 1; + } + } + + //printf("Total matches %" PRIu32 "\n", matches); + return matches; +} + +uint32_t B2gmSearch1(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PatternMatcherQueue *pmq, uint8_t *buf, uint16_t buflen) { + SCEnter(); + + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx->ctx; + uint8_t *bufmin = buf; + uint8_t *bufend = buf + buflen - 1; + uint32_t cnt = 0; + + if (buflen == 0) + SCReturnUInt(0); + + //printf("BUF "); prt(buf,buflen); printf("\n"); + + while (buf <= bufend) { + uint8_t h = u8_tolower(*buf); + uint16_t offset = ctx->ha1[h]; + SCLogDebug("offset %u, h %02X, buf %02X", offset, h, *buf); + + if (offset > 0) { + do { + B2gmPattern1 *hdr = (B2gmPattern1 *)&ctx->patterns1[offset]; + offset += (sizeof(B2gmPattern1)); + + SCLogDebug("hdr flags %02x, id %u, pat %02X", hdr->flags, hdr->id, hdr->pat); + + if (hdr->flags & B2GM_FLAG_NOCASE) { + SCLogDebug("nocase compare, %02X", *buf); + + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); + } else { + SCLogDebug("case sensitive compare, %02X", *buf); + + if (*buf == hdr->pat) { + cnt += MpmVerifyMatch(mpm_thread_ctx, pmq, hdr->id); + } + } + + if (hdr->flags & B2GM_FLAG_FINAL) + break; + } while(1); + } + buf += 1; + } + + //printf("B2gcSearch1: after 1byte cnt %" PRIu32 "\n", cnt); + if (ctx->pat_x_cnt) { + cnt += ctx->MBSearch(mpm_ctx, mpm_thread_ctx, pmq, bufmin, buflen); + } + SCReturnUInt(cnt); +} + +/* + * TESTS + */ + +#ifdef UNITTESTS +static int B2gmTestInit01 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + + if (ctx->m == 4) + result = 1; + else + printf("4 != %" PRIu32 " ", ctx->m); + + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +#if 0 +static int B2gmTestS0Init01 (void) { + int result = 0; + MpmCtx mpm_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + + if (ctx->s0 == 4) + result = 1; + else + printf("4 != %" PRIu32 " ", ctx->s0); + + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestS0Init02 (void) { + int result = 0; + MpmCtx mpm_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"cdef", 4, 0, 0, 1, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + + if (ctx->s0 == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", ctx->s0); + + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestS0Init03 (void) { + int result = 0; + MpmCtx mpm_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + + if (ctx->s0 == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", ctx->s0); + + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestS0Init04 (void) { + int result = 0; + MpmCtx mpm_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abab", 4, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + + if (ctx->s0 == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", ctx->s0); + + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestS0Init05 (void) { + int result = 0; + MpmCtx mpm_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcab", 5, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + + if (ctx->s0 == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", ctx->s0); + + B2gmDestroyCtx(&mpm_ctx); + return result; +} +#endif + +static int B2gmTestSearch01 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch02 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch02a (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch02b (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch03 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch03a (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"a", 1, 0, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"b", 1, 0, 0, 1, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"f", 1, 0, 0, 2, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +/* test patterns longer than 'm'. M is 4 here. */ +static int B2gmTestSearch04 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +/* case insensitive test patterns longer than 'm'. M is 4 here. */ +static int B2gmTestSearch05 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 3 /* 3 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch05a (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0); /* 1 match */ + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abCD", 4, 0, 0, 3, 0, 0); /* no match */ + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"abcD", 4, 0, 0, 4, 0, 0); /* 1 match */ + B2gmAddPatternCI(&mpm_ctx, (uint8_t *)"abCd", 4, 0, 0, 5, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghjiklmnopqrstuvwxyz", 26); + + if (cnt == 5) + result = 1; + else + printf("5 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch06 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcd", 4); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch07 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0); /* should match 30 times */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0); /* should match 29 times */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0); /* should match 28 times */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0); /* 26 */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0); /* 21 */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 5, 0, 0); /* 1 */ + /* total matches: 135 */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 6 /* 6 patterns */); + + uint32_t cnt = 0 ; + int i; + for (i = 0; i<1000;i++) + cnt= ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); + + if (cnt == 135) + result = 1; + else + printf("135 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch08 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"a", 1); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch09 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"ab", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch10 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + char *buf = "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "abcdefgh" + "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch11 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch12 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0); /* 1 match */ + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 2 /* 2 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyz", 26); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch13 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCD", 30); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch14 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDE", 31); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch15 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABCDEF", 32); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch16 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzABC", 29); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch17 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcdefghijklmnopqrstuvwxyzAB", 28); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch18 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26, 0, 0, 0, 0, 0); /* 1 match */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 pattern */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"abcde""fghij""klmno""pqrst""uvwxy""z", 26); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch19 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30, 0, 0, 0, 0, 0); /* 1 */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch20 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32, 0, 0, 0, 0, 0); /* 1 */ + //B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32, 0, 0, 0, 0, 0); /* 1 */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); + + //uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 32); + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA", 32); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} + +static int B2gmTestSearch21 (void) { + int result = 0; + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); /* 1 */ + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); + + uint32_t cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)"AA", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ",cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + return result; +} +#endif /* UNITTESTS */ + +//#if 0 +static int B2gmTestSearchXX (void) { + MpmCtx mpm_ctx; + memset(&mpm_ctx, 0x00, sizeof(MpmCtx)); + MpmThreadCtx mpm_thread_ctx; + MpmInitCtx(&mpm_ctx, MPM_B2GM, -1); + B2gmCtx *ctx = (B2gmCtx *)mpm_ctx.ctx; + + FILE *fp = fopen("/usr/share/dict/words", "r"); + if (fp == NULL) + exit(1); + + char *word; + char line[128]; + int w = 0; + int w_max = 4000; + + while((word = fgets(line, sizeof(line), fp)) != NULL) { + word[strlen(word) - 1] = '\0'; + + B2gmAddPatternCS(&mpm_ctx, (uint8_t *)word, strlen(word), 0, 0, (uint32_t)w, 0, 0); + + w++; + + if (w_max == w) + break; + } + + B2gmPreparePatterns(&mpm_ctx); + B2gmThreadInitCtx(&mpm_ctx, &mpm_thread_ctx, 1 /* 1 patterns */); + + char *text = "Yes this is a text, it is not very long. But, it is still sufficient for testing our search! " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "flkflkjjoijda893ur9r89h98hf9shflj;adm.,amnd,mna,mndabdayyugeq9e8u0q90-euajd;lsaldakljdlkajdl" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "we're adding a lot more text lines etc." + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "dlajd01438798749023749792739479ye9q8eu3291739847983274987e928u928eu98u3298eu982u938383888888 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + "Bjdhfahflkahsf;phf[hfihasfkhsfkjhalhflkafljhfkhakhfkahfkahfkjhdkffkjhafkhafkjakjfhkjahf;aj;jh"; + uint32_t len = strlen(text) - 1; + + int i; + uint32_t cnt; + for (i = 0; i < 100; i++) { + cnt = ctx->Search(&mpm_ctx, &mpm_thread_ctx, NULL, (uint8_t *)text, len); + } + + printf("cnt %u ", cnt); + + B2gmThreadDestroyCtx(&mpm_ctx, &mpm_thread_ctx); + B2gmDestroyCtx(&mpm_ctx); + fclose(fp); + + return 1; +} +//#endif + +void B2gmRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("B2gmTestInit01", B2gmTestInit01, 1); +/* + UtRegisterTest("B2gmTestS0Init01", B2gmTestS0Init01, 1); + UtRegisterTest("B2gmTestS0Init02", B2gmTestS0Init02, 1); + UtRegisterTest("B2gmTestS0Init03", B2gmTestS0Init03, 1); + UtRegisterTest("B2gmTestS0Init04", B2gmTestS0Init04, 1); + UtRegisterTest("B2gmTestS0Init05", B2gmTestS0Init05, 1); +*/ + UtRegisterTest("B2gmTestSearch01", B2gmTestSearch01, 1); + UtRegisterTest("B2gmTestSearch02", B2gmTestSearch02, 1); + UtRegisterTest("B2gmTestSearch02a", B2gmTestSearch02a, 1); + UtRegisterTest("B2gmTestSearch02b", B2gmTestSearch02b, 1); + UtRegisterTest("B2gmTestSearch03", B2gmTestSearch03, 1); + UtRegisterTest("B2gmTestSearch03a", B2gmTestSearch03a, 1); + UtRegisterTest("B2gmTestSearch04", B2gmTestSearch04, 1); + UtRegisterTest("B2gmTestSearch05", B2gmTestSearch05, 1); + UtRegisterTest("B2gmTestSearch05a", B2gmTestSearch05a, 1); + UtRegisterTest("B2gmTestSearch06", B2gmTestSearch06, 1); + UtRegisterTest("B2gmTestSearch07", B2gmTestSearch07, 1); + UtRegisterTest("B2gmTestSearch08", B2gmTestSearch08, 1); + UtRegisterTest("B2gmTestSearch09", B2gmTestSearch09, 1); + UtRegisterTest("B2gmTestSearch10", B2gmTestSearch10, 1); + UtRegisterTest("B2gmTestSearch11", B2gmTestSearch11, 1); + UtRegisterTest("B2gmTestSearch12", B2gmTestSearch12, 1); + UtRegisterTest("B2gmTestSearch13", B2gmTestSearch13, 1); + UtRegisterTest("B2gmTestSearch14", B2gmTestSearch14, 1); + UtRegisterTest("B2gmTestSearch15", B2gmTestSearch15, 1); + UtRegisterTest("B2gmTestSearch16", B2gmTestSearch16, 1); + UtRegisterTest("B2gmTestSearch17", B2gmTestSearch17, 1); + UtRegisterTest("B2gmTestSearch18", B2gmTestSearch18, 1); + UtRegisterTest("B2gmTestSearch19", B2gmTestSearch19, 1); + UtRegisterTest("B2gmTestSearch20", B2gmTestSearch20, 1); + UtRegisterTest("B2gmTestSearch21", B2gmTestSearch21, 1); + UtRegisterTest("B2gmTestSearchXX", B2gmTestSearchXX, 1); +#endif /* UNITTESTS */ +} + diff --git a/src/util-mpm-b2gm.h b/src/util-mpm-b2gm.h new file mode 100644 index 0000000000..94dd2a5fed --- /dev/null +++ b/src/util-mpm-b2gm.h @@ -0,0 +1,143 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __UTIL_MPM_B2GM_H__ +#define __UTIL_MPM_B2GM_H__ + +#include "util-mpm.h" +#include "util-bloomfilter.h" + +#define B2GM_HASHSHIFT_MAX 8 +#define B2GM_HASHSHIFT_HIGHEST 7 +#define B2GM_HASHSHIFT_HIGH 6 +#define B2GM_HASHSHIFT_MEDIUM 5 +#define B2GM_HASHSHIFT_LOW 4 +#define B2GM_HASHSHIFT_LOWEST 3 + +//#define B2GM_TYPE uint64_t +#define B2GM_TYPE uint32_t +//#define B2GM_TYPE uint16_t +//#define B2GM_TYPE uint8_t + +//#define B2GM_WORD_SIZE 64 +#define B2GM_WORD_SIZE 32 +//#define B2GM_WORD_SIZE 16 +//#define B2GM_WORD_SIZE 8 + +#define B2GM_Q 2 + +#define B2GM_SEARCHFUNC B2gmSearchBNDMq +//#define B2GM_SEARCHFUNC B2gmSearch + +//#define B2GM_COUNTERS + +#define B2GM_FLAG_NOCASE 0x01 +#define B2GM_FLAG_FINAL 0x02 + +typedef struct B2gmPattern_ { + uint8_t len; + uint8_t flags; + uint16_t id; +#if __WORDSIZE == 64 + uint32_t pad; +#endif + uint8_t *pat; + struct B2gmPattern_ *next; +} B2gmPattern; + +typedef struct B2gmPattern1_ { + uint8_t flags; + uint8_t pat; + uint16_t id; +} B2gmPattern1; + +typedef struct B2gmLookup_ { + uint16_t pminlen; + uint8_t pminlenb; /* bloom */ + uint8_t pad0; +#if __WORDSIZE == 64 + uint32_t pad1; +#endif + BloomFilter *bloom; + B2gmPattern *hash; +} B2gmLookup; + +typedef struct B2gmCtx_ { + /* we store our own multi byte search func ptr here for B2gmSearch1 */ + uint32_t (*Search)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); + + /* hash for looking up the idx in the pattern array */ + uint16_t *ha1; + uint8_t *patterns1; + + /* we store our own multi byte search func ptr here for B2gmSearch1 */ + //uint32_t (*MBSearch2)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); + uint32_t (*MBSearch)(struct MpmCtx_ *, struct MpmThreadCtx_ *, PatternMatcherQueue *, uint8_t *, uint16_t); + + uint16_t pat_1_cnt; + uint16_t pat_x_cnt; +#if __WORDSIZE == 64 + uint32_t pad1; +#endif + + B2GM_TYPE *B2GM; + B2GM_TYPE m; +#if __WORDSIZE == 64 + uint32_t pad0; +#endif + + B2gmLookup *lookup; + + /* pattern arrays */ + B2gmPattern **parray; + + /* hash used during ctx initialization */ + B2gmPattern **init_hash; + //uint8_t s0; + uint32_t hash_size; +} B2gmCtx; + +typedef struct B2gmThreadCtx_ { +#ifdef B2GM_COUNTERS + uint32_t stat_pminlen_calls; + uint32_t stat_pminlen_total; + uint32_t stat_bloom_calls; + uint32_t stat_bloom_hits; + uint32_t stat_calls; + uint32_t stat_m_total; + uint32_t stat_d0; + uint32_t stat_d0_hashloop; + uint32_t stat_loop_match; + uint32_t stat_loop_no_match; + uint32_t stat_num_shift; + uint32_t stat_total_shift; + uint32_t stat_test_buf; + uint32_t stat_test_buf_ok; + uint32_t stat_test_buf_fail; +#endif /* B2GM_COUNTERS */ +} B2gmThreadCtx; + +void MpmB2gmRegister(void); + +#endif /* __UTIL_MPM_B2GM_H__ */ + diff --git a/src/util-mpm-b3g.c b/src/util-mpm-b3g.c index f2be4cc440..2b45c61770 100644 --- a/src/util-mpm-b3g.c +++ b/src/util-mpm-b3g.c @@ -110,7 +110,6 @@ void B3gPrintInfo(MpmCtx *mpm_ctx) { printf(" B3gPattern %" PRIuMAX "\n", (uintmax_t)sizeof(B3gPattern)); printf(" B3gHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(B3gHashItem)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Total Patterns: %" PRIu32 "\n", mpm_ctx->total_pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Hash size: %" PRIu32 "\n", ctx->hash_size); @@ -332,7 +331,6 @@ static int B3gAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_ else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } - mpm_ctx->total_pattern_cnt++; return 0; error: diff --git a/src/util-mpm-wumanber.c b/src/util-mpm-wumanber.c index 93efe1c0eb..17197bb544 100644 --- a/src/util-mpm-wumanber.c +++ b/src/util-mpm-wumanber.c @@ -137,7 +137,6 @@ void WmPrintInfo(MpmCtx *mpm_ctx) { printf(" WmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(WmPattern)); printf(" WmHashItem %" PRIuMAX "\n", (uintmax_t)sizeof(WmHashItem)); printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt); - printf("Total Patterns: %" PRIu32 "\n", mpm_ctx->total_pattern_cnt); printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen); printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen); printf("Max shiftlen: %" PRIu32 "\n", ctx->shiftlen); @@ -385,7 +384,6 @@ static int WmAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t else if (mpm_ctx->minlen > patlen) mpm_ctx->minlen = patlen; } - mpm_ctx->total_pattern_cnt++; return 0; error: diff --git a/src/util-mpm.c b/src/util-mpm.c index 25d3933a25..24a7d7d3ef 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -33,6 +33,7 @@ #include "util-mpm-b2g-cuda.h" #include "util-mpm-b3g.h" #include "util-mpm-b2gc.h" +#include "util-mpm-b2gm.h" #include "util-hashlist.h" /** @@ -218,6 +219,7 @@ void MpmTableSetup(void) { #endif MpmB3gRegister(); MpmB2gcRegister(); + MpmB2gmRegister(); } /** \brief Function to return the default hash size for the mpm algorithm, diff --git a/src/util-mpm.h b/src/util-mpm.h index efb79b40e1..f9b0a1ba42 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -60,6 +60,7 @@ enum { #endif MPM_B3G, MPM_B2GC, + MPM_B2GM, /* table size */ MPM_TABLE_SIZE, @@ -94,14 +95,13 @@ typedef struct MpmCtx_ { void *ctx; uint16_t mpm_type; - uint32_t memory_cnt; - uint32_t memory_size; - - uint32_t pattern_cnt; /* unique patterns */ - uint32_t total_pattern_cnt; /* total patterns added */ + uint16_t pattern_cnt; /* unique patterns */ uint16_t minlen; uint16_t maxlen; + + uint32_t memory_cnt; + uint32_t memory_size; } MpmCtx; /** pattern is case insensitive */ diff --git a/src/util-optimize.h b/src/util-optimize.h new file mode 100644 index 0000000000..ccf3cc2466 --- /dev/null +++ b/src/util-optimize.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2010 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __UTIL_OPTIMIZE_H__ +#define __UTIL_OPTIMIZE_H__ + +/** + * \file + * + * \author Victor Julien + */ + +#define likely(expr) __builtin_expect(!!(expr), 1) +#define unlikely(expr) __builtin_expect(!!(expr), 0) + +#endif /* __UTIL_OPTIMIZE_H__ */ + diff --git a/suricata.yaml b/suricata.yaml index 6bd60f7fce..465e320924 100644 --- a/suricata.yaml +++ b/suricata.yaml @@ -133,7 +133,7 @@ cuda: # compiled with --enable-cuda: b2g_cuda. Make sure to update your # max-pending-packets setting above as well if you use b2g_cuda. -mpm-algo: b2gc +mpm-algo: b2g # The memory settings for hash size of these algorithms can vary from lowest # (2048) - low (4096) - medium (8192) - high (16384) - highest (32768) - max @@ -152,13 +152,19 @@ mpm-algo: b2gc # settings. pattern-matcher: + - b2gc: + search_algo: B2gSearchBNDMq + hash_size: low + bf_size: medium + - b2gm: + search_algo: B2gSearchBNDMq + hash_size: low + bf_size: medium - b2g: - scan_algo: B2gScanBNDMq search_algo: B2gSearchBNDMq hash_size: low bf_size: medium - b3g: - scan_algo: B3gScanBNDMq search_algo: B3gSearchBNDMq hash_size: low bf_size: medium