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