1 /*
2 **
3 ** $Id$
4 **
5 ** Multi-Pattern Search Engine
6 **
7 ** Aho-Corasick State Machine - uses a Deterministic Finite Automata - DFA
8 **
9 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
10 ** Copyright (C) 2002-2013 Sourcefire, Inc.
11 ** Marc Norton
12 **
13 **
14 ** This program is free software; you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License Version 2 as
16 ** published by the Free Software Foundation. You may not use, modify or
17 ** distribute this program under any other version of the GNU General
18 ** Public License.
19 **
20 ** This program is distributed in the hope that it will be useful,
21 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ** GNU General Public License for more details.
24 **
25 ** You should have received a copy of the GNU General Public License
26 ** along with this program; if not, write to the Free Software
27 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 **
29 **
30 ** Reference - Efficient String matching: An Aid to Bibliographic Search
31 ** Alfred V Aho and Margaret J Corasick
32 ** Bell Labratories
33 ** Copyright(C) 1975 Association for Computing Machinery,Inc
34 **
35 ** Implemented from the 4 algorithms in the paper by Aho & Corasick
36 ** and some implementation ideas from 'Practical Algorithms in C'
37 **
38 ** Notes:
39 ** 1) This version uses about 1024 bytes per pattern character - heavy on the memory.
40 ** 2) This algorithm finds all occurrences of all patterns within a
41 ** body of text.
42 ** 3) Support is included to handle upper and lower case matching.
43 ** 4) Some comopilers optimize the search routine well, others don't, this makes all the difference.
44 ** 5) Aho inspects all bytes of the search text, but only once so it's very efficient,
45 ** if the patterns are all large than the Modified Wu-Manbar method is often faster.
46 ** 6) I don't subscribe to any one method is best for all searching needs,
47 ** the data decides which method is best,
48 ** and we don't know until after the search method has been tested on the specific data sets.
49 **
50 **
51 ** May 2002 : Marc Norton 1st Version
52 ** June 2002 : Modified interface for SNORT, added case support
53 ** Aug 2002 : Cleaned up comments, and removed dead code.
54 ** Nov 2,2002: Fixed queue_init() , added count=0
55 **
56 **
57 */
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <ctype.h>
63
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
67
68 #include "acsmx.h"
69 #include "util.h"
70 #include "snort_debug.h"
71
72 #ifdef DYNAMIC_PREPROC_CONTEXT
73 #include "sf_dynamic_preprocessor.h"
74 #endif //DYNAMIC_PREPROC_CONTEXT
75
76 #define MEMASSERT(p,s) if(!p){fprintf(stderr,"ACSM-No Memory: %s!\n",s);exit(0);}
77
78 #ifdef DEBUG_AC
79 static int max_memory = 0;
80 #endif
81
82 /*static void Print_DFA( ACSM_STRUCT * acsm );*/
83
84 /*
85 *
86 */
87 static void *
AC_MALLOC(int n)88 AC_MALLOC (int n)
89 {
90 void *p;
91 p = calloc (1,n);
92 #ifdef DEBUG_AC
93 if (p)
94 max_memory += n;
95 #endif
96 return p;
97 }
98
99
100 /*
101 *
102 */
103 static void
AC_FREE(void * p)104 AC_FREE (void *p)
105 {
106 if (p)
107 free (p);
108 }
109
110
111 /*
112 * Simple QUEUE NODE
113 */
114 typedef struct _qnode
115 {
116 int state;
117 struct _qnode *next;
118 }
119 QNODE;
120
121 /*
122 * Simple QUEUE Structure
123 */
124 typedef struct _queue
125 {
126 QNODE * head, *tail;
127 int count;
128 }
129 QUEUE;
130
131 /*
132 *
133 */
134 static void
queue_init(QUEUE * s)135 queue_init (QUEUE * s)
136 {
137 s->head = s->tail = 0;
138 s->count = 0;
139 }
140
141
142 /*
143 * Add Tail Item to queue
144 */
145 static void
queue_add(QUEUE * s,int state)146 queue_add (QUEUE * s, int state)
147 {
148 QNODE * q;
149 if (!s->head)
150 {
151 q = s->tail = s->head = (QNODE *) AC_MALLOC (sizeof (QNODE));
152 MEMASSERT (q, "queue_add");
153 q->state = state;
154 q->next = 0;
155 }
156 else
157 {
158 q = (QNODE *) AC_MALLOC (sizeof (QNODE));
159 MEMASSERT (q, "queue_add");
160 q->state = state;
161 q->next = 0;
162 s->tail->next = q;
163 s->tail = q;
164 }
165 s->count++;
166 }
167
168
169 /*
170 * Remove Head Item from queue
171 */
172 static int
queue_remove(QUEUE * s)173 queue_remove (QUEUE * s)
174 {
175 int state = 0;
176 QNODE * q;
177 if (s->head)
178 {
179 q = s->head;
180 state = q->state;
181 s->head = s->head->next;
182 s->count--;
183 if (!s->head)
184 {
185 s->tail = 0;
186 s->count = 0;
187 }
188 AC_FREE (q);
189 }
190 return state;
191 }
192
193
194 /*
195 *
196 */
197 static int
queue_count(QUEUE * s)198 queue_count (QUEUE * s)
199 {
200 return s->count;
201 }
202
203
204 /*
205 *
206 */
207 static void
queue_free(QUEUE * s)208 queue_free (QUEUE * s)
209 {
210 while (queue_count (s))
211 {
212 queue_remove (s);
213 }
214 }
215
216
217 /*
218 ** Case Translation Table
219 */
220 static unsigned char xlatcase[256];
221
222 /*
223 *
224 */
225 static void
init_xlatcase()226 init_xlatcase ()
227 {
228 int i;
229 for (i = 0; i < 256; i++)
230 {
231 xlatcase[i] = (unsigned char)toupper (i);
232 }
233 }
234
235
236 /*
237 *
238 */
239 static inline void
ConvertCaseEx(unsigned char * d,unsigned char * s,int m)240 ConvertCaseEx (unsigned char *d, unsigned char *s, int m)
241 {
242 int i;
243 for (i = 0; i < m; i++)
244 {
245 d[i] = xlatcase[s[i]];
246 }
247 }
248
249
250 /*
251 *
252 */
253 static ACSM_PATTERN *
CopyMatchListEntry(ACSM_PATTERN * px)254 CopyMatchListEntry (ACSM_PATTERN * px)
255 {
256 ACSM_PATTERN * p;
257 p = (ACSM_PATTERN *) AC_MALLOC (sizeof (ACSM_PATTERN));
258 MEMASSERT (p, "CopyMatchListEntry");
259 memcpy (p, px, sizeof (ACSM_PATTERN));
260 px->udata->ref_count++;
261 p->next = 0;
262 return p;
263 }
264
265
266 /*
267 * Add a pattern to the list of patterns terminated at this state.
268 * Insert at front of list.
269 */
270 static void
AddMatchListEntry(ACSM_STRUCT * acsm,int state,ACSM_PATTERN * px)271 AddMatchListEntry (ACSM_STRUCT * acsm, int state, ACSM_PATTERN * px)
272 {
273 ACSM_PATTERN * p;
274 p = (ACSM_PATTERN *) AC_MALLOC (sizeof (ACSM_PATTERN));
275 MEMASSERT (p, "AddMatchListEntry");
276 memcpy (p, px, sizeof (ACSM_PATTERN));
277 p->next = acsm->acsmStateTable[state].MatchList;
278 acsm->acsmStateTable[state].MatchList = p;
279 }
280
281
282 /*
283 Add Pattern States
284 */
285 static void
AddPatternStates(ACSM_STRUCT * acsm,ACSM_PATTERN * p)286 AddPatternStates (ACSM_STRUCT * acsm, ACSM_PATTERN * p)
287 {
288 unsigned char *pattern;
289 int state=0, next, n;
290 n = p->n;
291 pattern = p->patrn;
292
293 /*
294 * Match up pattern with existing states
295 */
296 for (; n > 0; pattern++, n--)
297 {
298 next = acsm->acsmStateTable[state].NextState[*pattern];
299 if (next == ACSM_FAIL_STATE)
300 break;
301 state = next;
302 }
303
304 /*
305 * Add new states for the rest of the pattern bytes, 1 state per byte
306 */
307 for (; n > 0; pattern++, n--)
308 {
309 acsm->acsmNumStates++;
310 acsm->acsmStateTable[state].NextState[*pattern] = acsm->acsmNumStates;
311 state = acsm->acsmNumStates;
312 }
313
314 AddMatchListEntry (acsm, state, p);
315 }
316
317
318 /*
319 * Build Non-Deterministic Finite Automata
320 */
321 static void
Build_NFA(ACSM_STRUCT * acsm)322 Build_NFA (ACSM_STRUCT * acsm)
323 {
324 int r, s;
325 int i;
326 QUEUE q, *queue = &q;
327 ACSM_PATTERN * mlist=0;
328 ACSM_PATTERN * px=0;
329
330 /* Init a Queue */
331 queue_init (queue);
332
333 /* Add the state 0 transitions 1st */
334 for (i = 0; i < ALPHABET_SIZE; i++)
335 {
336 s = acsm->acsmStateTable[0].NextState[i];
337 if (s)
338 {
339 queue_add (queue, s);
340 acsm->acsmStateTable[s].FailState = 0;
341 }
342 }
343
344 /* Build the fail state transitions for each valid state */
345 while (queue_count (queue) > 0)
346 {
347 r = queue_remove (queue);
348
349 /* Find Final States for any Failure */
350 for (i = 0; i < ALPHABET_SIZE; i++)
351 {
352 int fs, next;
353 if ((s = acsm->acsmStateTable[r].NextState[i]) != ACSM_FAIL_STATE)
354 {
355 queue_add (queue, s);
356 fs = acsm->acsmStateTable[r].FailState;
357
358 /*
359 * Locate the next valid state for 'i' starting at s
360 */
361 while ((next=acsm->acsmStateTable[fs].NextState[i]) ==
362 ACSM_FAIL_STATE)
363 {
364 fs = acsm->acsmStateTable[fs].FailState;
365 }
366
367 /*
368 * Update 's' state failure state to point to the next valid state
369 */
370 acsm->acsmStateTable[s].FailState = next;
371
372 /*
373 * Copy 'next'states MatchList to 's' states MatchList,
374 * we copy them so each list can be AC_FREE'd later,
375 * else we could just manipulate pointers to fake the copy.
376 */
377 for (mlist = acsm->acsmStateTable[next].MatchList;
378 mlist != NULL ;
379 mlist = mlist->next)
380 {
381 px = CopyMatchListEntry (mlist);
382
383 if( !px )
384 {
385 FatalError("*** Out of memory Initializing Aho Corasick in acsmx.c ****");
386 }
387
388 /* Insert at front of MatchList */
389 px->next = acsm->acsmStateTable[s].MatchList;
390 acsm->acsmStateTable[s].MatchList = px;
391 }
392 }
393 }
394 }
395
396 /* Clean up the queue */
397 queue_free (queue);
398 }
399
400
401 /*
402 * Build Deterministic Finite Automata from NFA
403 */
404 static void
Convert_NFA_To_DFA(ACSM_STRUCT * acsm)405 Convert_NFA_To_DFA (ACSM_STRUCT * acsm)
406 {
407 int r, s;
408 int i;
409 QUEUE q, *queue = &q;
410
411 /* Init a Queue */
412 queue_init (queue);
413
414 /* Add the state 0 transitions 1st */
415 for (i = 0; i < ALPHABET_SIZE; i++)
416 {
417 s = acsm->acsmStateTable[0].NextState[i];
418 if (s)
419 {
420 queue_add (queue, s);
421 }
422 }
423
424 /* Start building the next layer of transitions */
425 while (queue_count (queue) > 0)
426 {
427 r = queue_remove (queue);
428
429 /* State is a branch state */
430 for (i = 0; i < ALPHABET_SIZE; i++)
431 {
432 if ((s = acsm->acsmStateTable[r].NextState[i]) != ACSM_FAIL_STATE)
433 {
434 queue_add (queue, s);
435 }
436 else
437 {
438 acsm->acsmStateTable[r].NextState[i] =
439 acsm->acsmStateTable[acsm->acsmStateTable[r].FailState].
440 NextState[i];
441 }
442 }
443 }
444
445 /* Clean up the queue */
446 queue_free (queue);
447 }
448
449
450 /*
451 *
452 */
acsmNew(void (* userfree)(void * p),void (* optiontreefree)(void ** p),void (* neg_list_free)(void ** p))453 ACSM_STRUCT * acsmNew (void (*userfree)(void *p),
454 void (*optiontreefree)(void **p),
455 void (*neg_list_free)(void **p))
456 {
457 ACSM_STRUCT * p;
458 init_xlatcase ();
459 p = (ACSM_STRUCT *) AC_MALLOC (sizeof (ACSM_STRUCT));
460 MEMASSERT (p, "acsmNew");
461 if (p)
462 {
463 memset (p, 0, sizeof (ACSM_STRUCT));
464 p->userfree = userfree;
465 p->optiontreefree = optiontreefree;
466 p->neg_list_free = neg_list_free;
467 }
468 return p;
469 }
470
471
472 /*
473 * Add a pattern to the list of patterns for this state machine
474 */
475 int
acsmAddPattern(ACSM_STRUCT * p,unsigned char * pat,int n,int nocase,int offset,int depth,int negative,void * id,int iid)476 acsmAddPattern (ACSM_STRUCT * p, unsigned char *pat, int n, int nocase,
477 int offset, int depth, int negative, void * id, int iid)
478 {
479 ACSM_PATTERN * plist;
480 plist = (ACSM_PATTERN *) AC_MALLOC (sizeof (ACSM_PATTERN));
481 MEMASSERT (plist, "acsmAddPattern");
482 plist->patrn = (unsigned char *) AC_MALLOC (n);
483 ConvertCaseEx (plist->patrn, pat, n);
484 plist->casepatrn = (unsigned char *) AC_MALLOC (n);
485 memcpy (plist->casepatrn, pat, n);
486
487 plist->udata = (ACSM_USERDATA *)AC_MALLOC(sizeof(ACSM_USERDATA));
488 MEMASSERT (plist->udata, "acsmAddPattern");
489 plist->udata->ref_count = 1;
490 plist->udata->id = id;
491
492 plist->n = n;
493 plist->nocase = nocase;
494 plist->negative = negative;
495 plist->offset = offset;
496 plist->depth = depth;
497 plist->iid = iid;
498 plist->next = p->acsmPatterns;
499 p->acsmPatterns = plist;
500 p->numPatterns++;
501 return 0;
502 }
503
acsmBuildMatchStateTrees(ACSM_STRUCT * acsm,int (* build_tree)(void * id,void ** existing_tree),int (* neg_list_func)(void * id,void ** list))504 static int acsmBuildMatchStateTrees( ACSM_STRUCT * acsm,
505 int (*build_tree)(void * id, void **existing_tree),
506 int (*neg_list_func)(void *id, void **list) )
507 {
508 int i, cnt = 0;
509 ACSM_PATTERN * mlist;
510
511 /* Find the states that have a MatchList */
512 for (i = 0; i < acsm->acsmMaxStates; i++)
513 {
514 for ( mlist=acsm->acsmStateTable[i].MatchList;
515 mlist!=NULL;
516 mlist=mlist->next )
517 {
518 if (mlist->udata->id)
519 {
520 if (mlist->negative)
521 {
522 neg_list_func(mlist->udata->id, &acsm->acsmStateTable[i].MatchList->neg_list);
523 }
524 else
525 {
526 build_tree(mlist->udata->id, &acsm->acsmStateTable[i].MatchList->rule_option_tree);
527 }
528 }
529
530 cnt++;
531 }
532
533 if (acsm->acsmStateTable[i].MatchList)
534 {
535 /* Last call to finalize the tree */
536 build_tree(NULL, &acsm->acsmStateTable[i].MatchList->rule_option_tree);
537 }
538 }
539
540 return cnt;
541 }
542
acsmBuildMatchStateTreesWithSnortConf(struct _SnortConfig * sc,ACSM_STRUCT * acsm,int (* build_tree)(struct _SnortConfig *,void * id,void ** existing_tree),int (* neg_list_func)(void * id,void ** list))543 static int acsmBuildMatchStateTreesWithSnortConf( struct _SnortConfig *sc, ACSM_STRUCT * acsm,
544 int (*build_tree)(struct _SnortConfig *, void * id, void **existing_tree),
545 int (*neg_list_func)(void *id, void **list) )
546 {
547 int i, cnt = 0;
548 ACSM_PATTERN * mlist;
549
550 /* Find the states that have a MatchList */
551 for (i = 0; i < acsm->acsmMaxStates; i++)
552 {
553 for ( mlist=acsm->acsmStateTable[i].MatchList;
554 mlist!=NULL;
555 mlist=mlist->next )
556 {
557 if (mlist->udata->id)
558 {
559 if (mlist->negative)
560 {
561 neg_list_func(mlist->udata->id, &acsm->acsmStateTable[i].MatchList->neg_list);
562 }
563 else
564 {
565 build_tree(sc, mlist->udata->id, &acsm->acsmStateTable[i].MatchList->rule_option_tree);
566 }
567 }
568
569 cnt++;
570 }
571
572 if (acsm->acsmStateTable[i].MatchList)
573 {
574 /* Last call to finalize the tree */
575 build_tree(sc, NULL, &acsm->acsmStateTable[i].MatchList->rule_option_tree);
576 }
577 }
578
579 return cnt;
580 }
581
582
583 /*
584 * Compile State Machine
585 */
586 static inline int
_acsmCompile(ACSM_STRUCT * acsm)587 _acsmCompile (ACSM_STRUCT * acsm)
588 {
589 int i, k;
590 ACSM_PATTERN * plist;
591
592 /* Count number of states */
593 acsm->acsmMaxStates = 1;
594 for (plist = acsm->acsmPatterns; plist != NULL; plist = plist->next)
595 {
596 acsm->acsmMaxStates += plist->n;
597 }
598 acsm->acsmStateTable =
599 (ACSM_STATETABLE *) AC_MALLOC (sizeof (ACSM_STATETABLE) *
600 acsm->acsmMaxStates);
601 MEMASSERT (acsm->acsmStateTable, "acsmCompile");
602 memset (acsm->acsmStateTable, 0,
603 sizeof (ACSM_STATETABLE) * acsm->acsmMaxStates);
604
605 /* Initialize state zero as a branch */
606 acsm->acsmNumStates = 0;
607
608 /* Initialize all States NextStates to FAILED */
609 for (k = 0; k < acsm->acsmMaxStates; k++)
610 {
611 for (i = 0; i < ALPHABET_SIZE; i++)
612 {
613 acsm->acsmStateTable[k].NextState[i] = ACSM_FAIL_STATE;
614 }
615 }
616
617 /* Add each Pattern to the State Table */
618 for (plist = acsm->acsmPatterns; plist != NULL; plist = plist->next)
619 {
620 AddPatternStates (acsm, plist);
621 }
622
623 /* Set all failed state transitions to return to the 0'th state */
624 for (i = 0; i < ALPHABET_SIZE; i++)
625 {
626 if (acsm->acsmStateTable[0].NextState[i] == ACSM_FAIL_STATE)
627 {
628 acsm->acsmStateTable[0].NextState[i] = 0;
629 }
630 }
631
632 /* Build the NFA */
633 Build_NFA (acsm);
634
635 /* Convert the NFA to a DFA */
636 Convert_NFA_To_DFA (acsm);
637
638 /*
639 printf ("ACSMX-Max Memory: %d bytes, %d states\n", max_memory,
640 acsm->acsmMaxStates);
641 */
642
643 //Print_DFA( acsm );
644
645 return 0;
646 }
647
648 int
acsmCompile(ACSM_STRUCT * acsm,int (* build_tree)(void * id,void ** existing_tree),int (* neg_list_func)(void * id,void ** list))649 acsmCompile (ACSM_STRUCT * acsm,
650 int (*build_tree)(void * id, void **existing_tree),
651 int (*neg_list_func)(void *id, void **list))
652 {
653 int rval;
654
655 if ((rval = _acsmCompile (acsm)))
656 return rval;
657
658 if (build_tree && neg_list_func)
659 {
660 acsmBuildMatchStateTrees(acsm, build_tree, neg_list_func);
661 }
662
663 return 0;
664 }
665
666 int
acsmCompileWithSnortConf(struct _SnortConfig * sc,ACSM_STRUCT * acsm,int (* build_tree)(struct _SnortConfig *,void * id,void ** existing_tree),int (* neg_list_func)(void * id,void ** list))667 acsmCompileWithSnortConf (struct _SnortConfig *sc, ACSM_STRUCT * acsm,
668 int (*build_tree)(struct _SnortConfig *, void * id, void **existing_tree),
669 int (*neg_list_func)(void *id, void **list))
670 {
671 int rval;
672
673 if ((rval = _acsmCompile (acsm)))
674 return rval;
675
676 if (build_tree && neg_list_func)
677 {
678 acsmBuildMatchStateTreesWithSnortConf(sc, acsm, build_tree, neg_list_func);
679 }
680
681 return 0;
682 }
683
684 static unsigned char Tc[64*1024];
685
686 /*
687 * Search Text or Binary Data for Pattern matches
688 */
689 int
acsmSearch(ACSM_STRUCT * acsm,unsigned char * Tx,int n,int (* Match)(void * id,void * tree,int index,void * data,void * neg_list),void * data,int * current_state)690 acsmSearch (ACSM_STRUCT * acsm, unsigned char *Tx, int n,
691 int (*Match)(void * id, void *tree, int index, void *data, void *neg_list),
692 void *data, int* current_state )
693 {
694 int state = 0;
695 ACSM_PATTERN * mlist;
696 unsigned char *Tend;
697 ACSM_STATETABLE * StateTable = acsm->acsmStateTable;
698 int nfound = 0;
699 unsigned char *T;
700 int index;
701
702 /* Case conversion */
703 ConvertCaseEx (Tc, Tx, n);
704 T = Tc;
705 Tend = T + n;
706
707 if ( !current_state )
708 {
709 return 0;
710 }
711
712 state = *current_state;
713
714 for (; T < Tend; T++)
715 {
716 state = StateTable[state].NextState[*T];
717
718 if( StateTable[state].MatchList != NULL )
719 {
720 mlist = StateTable[state].MatchList;
721 index = T - mlist->n + 1 - Tc;
722 nfound++;
723 if (Match (mlist->udata->id, mlist->rule_option_tree, index, data, mlist->neg_list) > 0)
724 {
725 *current_state = state;
726 return nfound;
727 }
728 }
729 }
730 *current_state = state;
731 return nfound;
732 }
733
734
735 /*
736 * Free all memory
737 */
738 void
acsmFree(ACSM_STRUCT * acsm)739 acsmFree (ACSM_STRUCT * acsm)
740 {
741 int i;
742 ACSM_PATTERN * mlist, *ilist;
743 for (i = 0; i < acsm->acsmMaxStates; i++)
744 {
745 mlist = acsm->acsmStateTable[i].MatchList;
746 while (mlist)
747 {
748 ilist = mlist;
749 mlist = mlist->next;
750
751 ilist->udata->ref_count--;
752 if (ilist->udata->ref_count == 0)
753 {
754 if (acsm->userfree && ilist->udata->id)
755 acsm->userfree(ilist->udata->id);
756
757 AC_FREE(ilist->udata);
758 }
759
760 if (ilist->rule_option_tree && acsm->optiontreefree)
761 {
762 acsm->optiontreefree(&(ilist->rule_option_tree));
763 }
764
765 if (ilist->neg_list && acsm->neg_list_free)
766 {
767 acsm->neg_list_free(&(ilist->neg_list));
768 }
769
770 AC_FREE (ilist);
771 }
772 }
773 AC_FREE (acsm->acsmStateTable);
774 mlist = acsm->acsmPatterns;
775 while(mlist)
776 {
777 ilist = mlist;
778 mlist = mlist->next;
779 AC_FREE(ilist->patrn);
780 AC_FREE(ilist->casepatrn);
781 AC_FREE(ilist);
782 }
783 AC_FREE (acsm);
784 }
785
acsmPatternCount(ACSM_STRUCT * acsm)786 int acsmPatternCount ( ACSM_STRUCT * acsm )
787 {
788 return acsm->numPatterns;
789 }
790
791 /*
792 *
793 */
794 /*
795 static void Print_DFA( ACSM_STRUCT * acsm )
796 {
797 int k;
798 int i;
799 int next;
800
801 for (k = 0; k < acsm->acsmMaxStates; k++)
802 {
803 for (i = 0; i < ALPHABET_SIZE; i++)
804 {
805 next = acsm->acsmStateTable[k].NextState[i];
806
807 if( next == 0 || next == ACSM_FAIL_STATE )
808 {
809 if( isprint(i) )
810 printf("%3c->%-5d\t",i,next);
811 else
812 printf("%3d->%-5d\t",i,next);
813 }
814 }
815 printf("\n");
816 }
817
818 }
819 */
820
821
acsmPrintDetailInfo(ACSM_STRUCT * p)822 int acsmPrintDetailInfo(ACSM_STRUCT * p)
823 {
824 #ifdef WIN32
825 if(p)
826 p = p;
827 #endif
828 return 0;
829 }
830
acsmPrintSummaryInfo(void)831 int acsmPrintSummaryInfo(void)
832 {
833 #ifdef XXXXX
834 char * fsa[]={
835 "TRIE",
836 "NFA",
837 "DFA",
838 };
839
840 ACSM_STRUCT2 * p = &summary.acsm;
841
842 if( !summary.num_states )
843 return;
844
845 LogMessage("+--[Pattern Matcher:Aho-Corasick Summary]----------------------\n");
846 LogMessage("| Alphabet Size : %d Chars\n",p->acsmAlphabetSize);
847 LogMessage("| Sizeof State : %d bytes\n",sizeof(acstate_t));
848 LogMessage("| Storage Format : %s \n",sf[ p->acsmFormat ]);
849 LogMessage("| Num States : %d\n",summary.num_states);
850 LogMessage("| Num Transitions : %d\n",summary.num_transitions);
851 LogMessage("| State Density : %.1f%%\n",100.0*(double)summary.num_transitions/(summary.num_states*p->acsmAlphabetSize));
852 LogMessage("| Finite Automatum : %s\n", fsa[p->acsmFSA]);
853 if( max_memory < 1024*1024 )
854 LogMessage("| Memory : %.2fKbytes\n", (float)max_memory/1024 );
855 else
856 LogMessage("| Memory : %.2fMbytes\n", (float)max_memory/(1024*1024) );
857 LogMessage("+-------------------------------------------------------------\n");
858
859 #endif
860 return 0;
861 }
862
863
864 #ifdef ACSMX_MAIN
865
866 /*
867 * Text Data Buffer
868 */
869 unsigned char text[512];
870
871 /*
872 * A Match is found
873 */
874 int
MatchFound(unsigned id,int index,void * data)875 MatchFound (unsigned id, int index, void *data)
876 {
877 fprintf (stdout, "%s\n", (char *) id);
878 return 0;
879 }
880
881
882 /*
883 *
884 */
885 int
main(int argc,char ** argv)886 main (int argc, char **argv)
887 {
888 int i, nocase = 0;
889 ACSM_STRUCT * acsm;
890 if (argc < 3)
891
892 {
893 fprintf (stderr,
894 "Usage: acsmx pattern word-1 word-2 ... word-n -nocase\n");
895 exit (0);
896 }
897 acsm = acsmNew ();
898 strncpy (text, argv[1], sizeof(text) - 1);
899 text[sizeof(text) - 1] = '\0';
900 for (i = 1; i < argc; i++)
901 if (strcmp (argv[i], "-nocase") == 0)
902 nocase = 1;
903 for (i = 2; i < argc; i++)
904
905 {
906 if (argv[i][0] == '-')
907 continue;
908 acsmAddPattern (acsm, argv[i], strlen (argv[i]), nocase, 0, 0,
909 argv[i], i - 2);
910 }
911 acsmCompile (acsm);
912 acsmSearch (acsm, text, strlen (text), MatchFound, (void *) 0);
913 acsmFree (acsm);
914 printf ("normal pgm end\n");
915 return (0);
916 }
917 #endif /* */
918
919