[llvm-commits] [test-suite] r46573 [3/3] - in /test-suite/trunk/MultiSource/Applications: ./ ClamAV/ ClamAV/dbdir/ ClamAV/inputs/ ClamAV/inputs/rtf-test/ ClamAV/scripts/

Evan Cheng evan.cheng at apple.com
Wed Jan 30 13:17:12 PST 2008


Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1942 @@
+/*
+ *  Match a string against a list of patterns/regexes.
+ *
+ *  Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifndef CL_DEBUG
+#define NDEBUG
+#endif
+
+#ifdef CL_THREAD_SAFE
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#endif
+
+
+/* TODO: when implementation of new version is complete, enable it in CL_EXPERIMENTAL */
+#ifdef CL_EXPERIMENTAL
+/*#define USE_NEW_VERSION*/
+#endif
+
+#ifndef USE_NEW_VERSION
+/*this is the old version of regex_list.c
+ *reason for redesign: there is only one node type that has to handle all the cases: binary search among children, alternatives list, match.
+ * This design is very error-prone.*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <limits.h>
+#include <sys/types.h>
+
+#include "regex.h"
+
+
+#include "clamav.h"
+#include "others.h"
+#include "regex_list.h"
+#include "matcher-ac.h"
+#include "str.h"
+
+/*Tree*/
+enum token_op_t {OP_CHAR,OP_STDCLASS,OP_CUSTOMCLASS,OP_DOT,OP_LEAF,OP_ROOT,OP_PARCLOSE};
+typedef unsigned char* char_bitmap_p;
+/*
+ *
+ * OP_CHAR: 1 character, c = character
+ * complex stuff:
+ * OP_STDCLASS: standard character class, c = char class, class: 1<<(index into std_class of class name)
+ * OP_CUSTOMCLASS: custom character class, first pointer in ptr array is a pointer to the bitmap table for this class
+ * OP_DOT: single . matching any character except \n
+ * OP_LEAF: this is a leaf node, reinterpret structure
+ */
+struct tree_node {
+	struct tree_node* next;/* next regex/complex sibling, or parent, if no more siblings , can't be NULL except for root node*/
+	unsigned char c;
+	enum token_op_t op;
+	char alternatives;/* number of (non-regex) children of node, i.e. sizeof(children)*/
+	char listend;/* no more siblings, next pointer is pointer to parent*/
+	union {
+		struct tree_node** children;/* alternatives nr. of children, followed by (a null pointer terminated) regex leaf node pointers) */
+		char_bitmap_p* bitmap;
+		struct leaf_info*  leaf;
+	} u;
+};
+
+struct leaf_info {
+	char* info;/* what does it mean that we reached the leaf...*/
+	regex_t* preg;/* this is NULL if leaf node, and non-regex*/
+};
+
+/* Character classes */
+static const char* std_class[] = {
+	"[:alnum:]",
+	"[:digit:]",
+	"[:punct:]",
+	"[:alpha:]",
+	"[:graph:]",
+	"[:space:]",
+	"[:blank:]",
+	"[:lower:]", 
+	"[:upper:]",
+	"[:cntrl:]",
+	"[:print:]",
+	"[:xdigit:]"
+	/* don't change the order of these strings, unless you change them in generate_tables.c too, and regenerate the tables*/
+};
+
+
+#define STD_CLASS_CNT sizeof(std_class)/sizeof(std_class[0])
+
+/* generated by contrib/phishing/generate_tables.c */
+static const unsigned char char_class_bitmap[STD_CLASS_CNT][32] = {
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 
+         0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0xfc, 
+         0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x78, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 
+         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 
+         0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static const unsigned short int char_class[256] = {
+        0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x260, 0x220, 0x220, 0x220, 0x220, 0x200, 0x200, 
+        0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 
+        0x460, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 
+        0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 
+        0x414, 0xd19, 0xd19, 0xd19, 0xd19, 0xd19, 0xd19, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 
+        0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x414, 0x414, 0x414, 0x414, 0x414, 
+        0x414, 0xc99, 0xc99, 0xc99, 0xc99, 0xc99, 0xc99, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 
+        0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x414, 0x414, 0x414, 0x414, 0x200, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 
+        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
+};
+
+static const size_t std_class_cnt =  sizeof(std_class)/sizeof(std_class[0]);
+
+/* Prototypes */
+static int add_pattern(struct regex_matcher* matcher,const unsigned char* pat,const char* info,int hostOnly);
+static int match_node(struct tree_node* node,const unsigned char* c,size_t len,const char** info);
+static void destroy_tree(struct regex_matcher* matcher);
+static struct tree_node* tree_root_alloc(void);
+static int build_regex_list(struct regex_matcher* matcher);
+static void stack_destroy(struct node_stack* stack);
+
+#ifndef NDEBUG
+void dump_tree(struct tree_node* root);
+#endif
+
+#define MATCH_SUCCESS 0 
+#define MATCH_FAILED  -1
+
+/*
+ * Call this function when an unrecoverable error has occured, (instead of exit).
+ */
+static void fatal_error(struct regex_matcher* matcher)
+{
+	regex_list_done(matcher);
+	matcher->list_inited = -1;/* the phishing module will know we tried to load a whitelist, and failed, so it will disable itself too*/
+}
+
+
+static inline size_t get_char_at_pos_with_skip(const struct pre_fixup_info* info, const char* buffer, size_t pos)
+{
+	const char* str;
+	size_t realpos = 0;
+	if(!info) {
+		return (pos <= strlen(buffer)) ? buffer[pos>0 ? pos-1:0] : '\0';
+	}
+	str = info->pre_displayLink.data;
+	cli_dbgmsg("calc_pos_with_skip: skip:%lu, %lu - %lu \"%s\",\"%s\"\n", pos, info->host_start, info->host_end, str, buffer);
+	pos += info->host_start;
+	while(str[realpos] && !isalnum(str[realpos])) realpos++;
+	for(; str[realpos] && (pos>0); pos--) {
+		while(str[realpos]==' ') realpos++;
+		realpos++;
+	}
+	while(str[realpos]==' ') realpos++;
+	cli_dbgmsg("calc_pos_with_skip:%s\n",str+realpos);	
+	return (pos>0 && !str[realpos]) ? '\0' : str[realpos>0?realpos-1:0];
+}
+
+/*
+ * @matcher - matcher structure to use
+ * @real_url - href target
+ * @display_url - <a> tag contents
+ * @hostOnly - if you want to match only the host part
+ * @is_whitelist - is this a lookup in whitelist?
+ *
+ * @return - CL_SUCCESS - url doesn't match
+ *         - CL_VIRUS - url matches list
+ *
+ * Do not send NULL pointers to this function!!
+ *
+ */
+int regex_list_match(struct regex_matcher* matcher,char* real_url,const char* display_url,const struct pre_fixup_info* pre_fixup,int hostOnly,const char** info,int is_whitelist)
+{
+	massert(matcher);
+	massert(real_url);
+	massert(display_url);
+	massert(info);
+	if(!matcher->list_inited)
+		return 0;
+	massert(matcher->list_built);
+	{
+		size_t real_len    = strlen(real_url);
+		size_t display_len = strlen(display_url);
+		size_t buffer_len  = (hostOnly && !is_whitelist) ? real_len : real_len + display_len + 1 + (is_whitelist ? 1 : 0);
+		char*  buffer = cli_malloc(buffer_len+1);
+		size_t i;
+		int rc = 0;
+		struct cli_ac_data mdata;
+
+		if(!buffer)
+			return CL_EMEM;
+
+		strncpy(buffer,real_url,real_len);
+		buffer[real_len]= (!is_whitelist && hostOnly) ? '\0' : ':';
+		if(!hostOnly || is_whitelist) {
+			strncpy(buffer+real_len+1,display_url,display_len);
+			if(is_whitelist) 
+				buffer[buffer_len - 1] = '/';
+			buffer[buffer_len]=0;
+		}
+		cli_dbgmsg("Looking up in regex_list: %s\n", buffer);
+
+		if(hostOnly) {
+			if((rc = cli_ac_initdata(&mdata, 0, AC_DEFAULT_TRACKLEN)))
+				return rc;
+			rc = 0;
+
+			for(i = 0; i < matcher->root_hosts_cnt; i++) {
+				/* doesn't need to match terminating \0*/
+				rc = cli_ac_scanbuff((unsigned char*)buffer,buffer_len,info, &matcher->root_hosts[i] ,&mdata,0,0,0,-1,NULL);
+				cli_ac_freedata(&mdata);
+				if(rc) {
+					char c;
+					const char* matched = strchr(*info,':');	
+					const size_t match_len = matched ? strlen(matched+1) : 0;
+					if(((c=get_char_at_pos_with_skip(pre_fixup,buffer,buffer_len+1))==' ' || c=='\0' || c=='/' || c=='?') &&
+						(match_len == buffer_len || /* full match */
+					        (match_len < buffer_len &&
+						((c=get_char_at_pos_with_skip(pre_fixup,buffer,buffer_len-match_len))=='.' || (c==' ')) ) 
+						/* subdomain matched*/)) {
+
+						cli_dbgmsg("Got a match: %s with %s\n",buffer,*info);
+						cli_dbgmsg("Before inserting .: %s\n",real_url);
+						if(real_len >= match_len + 1) {
+							real_url[real_len-match_len-1]='.';
+							cli_dbgmsg("After inserting .: %s\n",real_url);
+						}
+						break;
+					}
+					cli_dbgmsg("Ignoring false match: %s with %s,%c\n",buffer,*info,c);
+					rc=0;
+				}
+			}
+		} else
+			rc = 0;
+    
+		if(!rc) 
+			rc = match_node(hostOnly ? matcher->root_regex_hostonly : matcher->root_regex,(unsigned char*)buffer,buffer_len,info) == MATCH_SUCCESS ? CL_VIRUS : CL_SUCCESS;
+		free(buffer);
+		if(!rc)
+			cli_dbgmsg("Lookup result: not in regex list\n");
+		else
+			cli_dbgmsg("Lookup result: in regex list\n");
+		return rc;
+	}
+}
+
+/* node stack */
+#define NODE_STACK_INITIAL 1024
+#define NODE_STACK_GROW    4096
+/* Initialize @stack */
+static int stack_init(struct node_stack* stack)
+{
+	massert(stack);
+
+	stack->cnt = 0;
+	stack->capacity = NODE_STACK_INITIAL;
+	stack->data = cli_malloc(stack->capacity * sizeof(*stack->data));
+	if(!stack->data)
+		return CL_EMEM;
+	else
+		return CL_SUCCESS;
+}
+
+/* Reset @stack pointer, but don't realloc */
+static void stack_reset(struct node_stack* stack)
+{
+	massert(stack);
+
+	stack->cnt = 0;
+}
+
+/* Push @node on @stack, growing it if necessarry */
+static int stack_push(struct node_stack* stack,struct tree_node* node)
+{
+	massert(stack);
+	massert(stack->data);
+
+	if(stack->cnt == stack->capacity) {
+		stack->capacity += NODE_STACK_GROW;
+		stack->data = cli_realloc2(stack->data,stack->capacity*sizeof(*stack->data));
+		if(!stack->data)
+			return CL_EMEM;
+	}
+	stack->data[stack->cnt++] = node;
+	return CL_SUCCESS;
+}
+
+/* Pops node from @stack, doesn't realloc */
+static struct tree_node* stack_pop(struct node_stack* stack)
+{
+	massert(stack);
+	massert(stack->data);
+	massert(stack->cnt);/*don't pop from empty stack */
+
+	return stack->cnt ? stack->data[--stack->cnt] : NULL;
+}
+
+/* Initialization & loading */
+/* Initializes @matcher, allocating necesarry substructures */
+int init_regex_list(struct regex_matcher* matcher)
+{
+	int rc;
+
+	massert(matcher);
+	matcher->list_inited = 0;
+ 	matcher->root_hosts_cnt = 0;
+ 	matcher->root_hosts = NULL;
+ 	matcher->root_hosts_cnt = 0;
+
+	matcher->root_regex = tree_root_alloc();
+	if(!matcher->root_regex) {
+		return CL_EMEM;
+	}
+
+	matcher->root_regex_hostonly = tree_root_alloc();
+	if(!matcher->root_regex_hostonly) {
+		free(matcher->root_regex);
+		return CL_EMEM;
+	}
+
+	if(( rc = stack_init(&matcher->node_stack) )) {
+		free(matcher->root_regex_hostonly);
+		free(matcher->root_regex);
+		return rc;
+	}
+	if(( rc = stack_init(&matcher->node_stack_alt) )) {
+		free(matcher->root_regex_hostonly);
+		free(matcher->root_regex);
+		stack_destroy(&matcher->node_stack);
+		return rc;
+	}
+
+	matcher->list_inited=1;
+	matcher->list_built=1;/* its empty, but pretend its built, so that load_ will realloc root_hosts */
+	matcher->list_loaded=0;
+
+	return CL_SUCCESS;
+}
+
+/* inserts @pattern into @root, using ac-matcher 
+ * although the name might be confusing, @pattern is not a regex!*/
+static int add_regex_list_element(struct cli_matcher* root,const char* pattern,char* info)
+{
+       int ret;
+       struct cli_ac_patt *new = cli_calloc(1,sizeof(*new));
+       size_t len,i;
+
+       if(!new)
+	       return CL_EMEM;
+       massert(root);
+       massert(pattern);
+
+       len = strlen(pattern);
+       /* need not to match \0 too */
+       new->type = 0;
+       new->sigid = 0;
+       new->parts = 0;
+       new->partno = 0;
+       new->mindist = 0;
+       new->maxdist = 0;
+       new->offset = 0;
+       new->target = 0;
+       new->length = len;
+       if(new->length > root->maxpatlen)
+               root->maxpatlen = new->length;
+
+       new->pattern = cli_malloc(sizeof(new->pattern[0])*len);
+       if(!new->pattern) {
+	       free(new);
+	       return CL_EMEM;
+       }
+       for(i=0;i<len;i++)
+	       new->pattern[i]=pattern[i];/*new->pattern is short int* */
+
+	
+       new->virname = cli_strdup(info);
+       if((ret = cli_ac_addpatt(root,new))) {
+	       free(new->virname);
+               free(new->pattern);
+               free(new);
+               return ret;
+       }
+       return CL_SUCCESS;
+}
+
+static int functionality_level_check(char* line)
+{
+	char* ptmin;
+	char* ptmax;
+	size_t j;
+
+	ptmin = strrchr(line,':');
+	if(!ptmin) 
+		return CL_SUCCESS;
+	
+	ptmin++;
+
+	ptmax = strchr(ptmin,'-');
+	if(!ptmax) 
+		return CL_SUCCESS;/* there is no functionality level specified, so we're ok */
+	else {
+		size_t min, max;
+		ptmax++;
+		for(j=0;j+ptmin+1 < ptmax;j++)
+			if(!isdigit(ptmin[j])) 
+				return CL_SUCCESS;/* not numbers, not functionality level */
+		for(j=0;j<strlen(ptmax);j++)
+			if(!isdigit(ptmax[j])) 
+				return CL_SUCCESS;/* see above */
+		ptmax[-1]='\0';
+		min = atoi(ptmin);
+		if(strlen(ptmax)==0)
+ 			max = INT_MAX; 		
+		else
+			max = atoi(ptmax);
+
+		if(min > cl_retflevel()) {
+			cli_dbgmsg("regex list line %s not loaded (required f-level: %u)\n",line,(unsigned int)min);
+			return CL_EMALFDB; 
+		}
+
+		if(max < cl_retflevel()) 
+			return CL_EMALFDB;
+		ptmin[-1]='\0';
+		return CL_SUCCESS;
+	}		
+}
+
+
+/* Load patterns/regexes from file */
+int load_regex_matcher(struct regex_matcher* matcher,FILE* fd,unsigned int options,int is_whitelist)
+{
+	int rc,line=0;
+	char buffer[FILEBUFF];
+
+	massert(matcher);
+	massert(fd);
+
+	if(matcher->list_inited==-1)
+		return CL_EMALFDB; /* already failed to load */
+/*	if(matcher->list_loaded) {
+		cli_warnmsg("Regex list has already been loaded, ignoring further requests for load\n");
+		return CL_SUCCESS;
+	}*/
+	if(!fd) {
+		cli_errmsg("Unable to load regex list (null file)\n");
+		return CL_EIO;
+	}
+
+	cli_dbgmsg("Loading regex_list\n");
+	if(!matcher->list_inited) {
+		rc = init_regex_list(matcher);
+		if (!matcher->list_inited) {
+			cli_errmsg("Regex list failed to initialize!\n");
+			fatal_error(matcher);
+			return rc;
+		}
+		/*atexit(regex_list_done); TODO: destroy this in manager.c */
+	}
+	/*
+	 * Regexlist db format (common to .wdb(whitelist) and .pdb(domainlist) files:
+	 * Multiple lines of form, (empty lines are skipped):
+ 	 * Flags RealURL DisplayedURL
+	 * Where:
+	 * Flags: 
+	 *
+	 * .pdb files:
+	 * R - regex, H - host-only, followed by (optional) 3-digit hexnumber representing 
+	 * flags that should be filtered.
+	 * [i.e. phishcheck urls.flags that we don't want to be done for this particular host]
+	 * 
+	 * .wdb files:
+	 * X - full URL regex 
+	 * Y - host-only regex
+	 * M - host simple pattern
+	 *
+	 * If a line in the file doesn't conform to this format, loading fails
+	 * 
+	 */
+	while(fgets(buffer,FILEBUFF,fd)) {
+		char* pattern;
+		char* flags;
+		cli_chomp(buffer);
+		if(!*buffer)
+			continue;/* skip empty lines */
+
+		if(functionality_level_check(buffer)) 
+			continue;
+
+		line++;
+		pattern = strchr(buffer,':');
+		if(!pattern) {
+			cli_errmsg("Malformed regex list line %d\n",line);
+			fatal_error(matcher);
+			return CL_EMALFDB;
+		}
+		/*pattern[0]='\0';*/
+		flags = buffer+1;
+		pattern++;
+
+		if(is_whitelist) {
+			const size_t pattern_len = strlen(pattern);
+			if(pattern_len < FILEBUFF) {
+				pattern[pattern_len] = '/';
+				pattern[pattern_len+1] = '\0';
+			}
+			else {
+				cli_errmsg("Overlong regex line %d\n",line);
+				fatal_error(matcher);
+				return CL_EMALFDB;
+			}
+		}
+
+		if((buffer[0] == 'R' && !is_whitelist) || ((buffer[0] == 'X' || buffer[0] == 'Y') && is_whitelist)) {/*regex*/
+			if(( rc = add_pattern(matcher,(const unsigned char*)pattern,flags, buffer[0] == 'Y') ))
+				return rc==CL_EMEM ? CL_EMEM : CL_EMALFDB;
+		}
+		else if( ( buffer[0] == 'H' && !is_whitelist) || (buffer[0] == 'M' && is_whitelist)) {/*matches displayed host*/
+			struct cli_matcher* root;
+ 			if(matcher->list_built) {
+ 				struct cli_matcher* old_hosts = matcher->root_hosts;
+ 				matcher->root_hosts_cnt++;
+ 
+ 				matcher->root_hosts = cli_realloc(matcher->root_hosts, matcher->root_hosts_cnt * sizeof(*matcher->root_hosts));
+ 				if(!matcher->root_hosts) {
+ 					matcher->root_hosts = old_hosts;/* according to manpage this must still be valid*/
+ 					return CL_EMEM;
+				} 
+
+				root = &matcher->root_hosts[matcher->root_hosts_cnt-1];
+ 				memset(root, 0, sizeof(struct cli_matcher));
+
+				cli_dbgmsg("regex_list: Initialising AC pattern matcher\n");
+				if((rc = cli_ac_init(root, cli_ac_mindepth, cli_ac_maxdepth))) {
+					/* no need to free previously allocated memory here */
+					cli_errmsg("regex_list: Can't initialise AC pattern matcher\n");
+					return rc;
+				}
+ 				matcher->list_built = 0;
+ 			}
+			else {
+				root = &matcher->root_hosts[matcher->root_hosts_cnt-1];
+			}
+ 			if(( rc = add_regex_list_element(root,pattern,flags) ))
+				return rc==CL_EMEM ? CL_EMEM : CL_EMALFDB;
+		}
+		else {
+			return CL_EMALFDB;
+			/* this is useless, we have host, and regex matches
+			if(( rc = add_regex_list_element(matcher->root_urls,pattern,flags) ))
+				return rc==CL_EMEM ? CL_EMEM : CL_EMALFDB;*/
+		}
+	}
+	matcher->list_loaded = 1;
+	if(( rc = build_regex_list(matcher) ))
+		return rc;
+
+#ifndef NDEBUG
+/*			dump_tree(matcher->root_regex);*/
+#endif
+	if(!matcher->list_built) {
+		cli_errmsg("Regex list not loaded: build failed!\n");
+		fatal_error(matcher);
+		return CL_EMALFDB;
+	}
+	regex_list_cleanup(matcher);
+	return CL_SUCCESS;
+}
+
+
+static struct tree_node ** tree_node_get_children(const struct tree_node* node)
+{
+	return node->op==OP_CUSTOMCLASS ? (node->u.children[1] ? node->u.children+1 : NULL) :node->u.children;
+}
+
+/* Build the matcher list */
+static int build_regex_list(struct regex_matcher* matcher)
+{
+	int rc;
+	if(!matcher->list_inited || !matcher->list_loaded) {
+		cli_errmsg("Regex list not loaded!\n");
+		return -1;/*TODO: better error code */
+	}
+	cli_dbgmsg("Building regex list\n");
+	if(matcher->root_hosts)
+		if(( rc = cli_ac_buildtrie(&matcher->root_hosts[matcher->root_hosts_cnt-1]) ))
+ 			return rc;
+	matcher->list_built=1;
+
+	return CL_SUCCESS;
+}
+
+/* Done with this matcher, free resources */
+void regex_list_done(struct regex_matcher* matcher)
+{
+	massert(matcher);
+
+	regex_list_cleanup(matcher);
+	if(matcher->list_loaded) {
+		if(matcher->root_hosts) {
+			size_t i;
+			for(i=0;i<matcher->root_hosts_cnt;i++) 
+				cli_ac_free(&matcher->root_hosts[i]);
+			free(matcher->root_hosts);
+			matcher->root_hosts=NULL;
+		}
+
+		matcher->root_hosts_cnt=0;
+		matcher->list_built=0;
+		destroy_tree(matcher);
+		matcher->list_loaded=0;
+	}
+	if(matcher->list_inited) {
+		matcher->list_inited=0;
+	}
+	stack_destroy(&matcher->node_stack);
+	stack_destroy(&matcher->node_stack_alt);
+}
+
+/* Tree matcher algorithm */
+struct token_t
+{
+	union {
+		const unsigned char* start;
+		char_bitmap_p  bitmap;
+		unsigned char  c;
+	} u;
+	size_t len;
+	char   type;
+};
+
+enum {TOKEN_CHAR,TOKEN_DOT,TOKEN_PAR_OPEN,TOKEN_PAR_CLOSE,TOKEN_BRACKET,TOKEN_ALT,TOKEN_REGEX,TOKEN_DONE};
+
+static const unsigned char* getNextToken(const unsigned char* pat,struct token_t* token)
+{
+	massert(pat);
+	massert(token);
+
+	switch(*pat) {
+		case '\\':
+			token->type=TOKEN_CHAR;
+			token->u.c = *(++pat);
+			if(islower(token->u.c)) {
+				/* handle \n, \t, etc. */
+				char fmt[3] = {'\\', '\0', '\0'};
+				char c;
+
+				fmt[1] = token->u.c;
+				if(snprintf(&c,1,fmt)!=1) {
+					token->type=TOKEN_REGEX;
+					token->u.start = pat;
+				}
+				else
+					token->u.c=c;
+			}
+			token->len = 1;
+			break;
+		case '|':
+			token->type=TOKEN_ALT;
+			break;
+		case '*':
+		case '+':
+		case '?':
+		case '{':
+		case '}':
+			token->type=TOKEN_REGEX;
+			break;
+		case '[':
+			{
+			/*TODO: implement*/
+			/*see if it is something simple like a list of characters, a range, or negated ...*/
+			const unsigned char* old=pat++;/* save this in case we change our mind and decide this is too complicated for us to handle*/
+			unsigned char range_start=0;
+			int hasprev = 0;
+			char_bitmap_p bitmap = cli_malloc(32);
+			if(!bitmap)
+				return NULL;
+			if (*pat=='^') {
+				memset(bitmap,0xFF,32);/*match chars not in brackets*/
+				pat++;
+			}
+			else
+				memset(bitmap,0x00,32);
+			do {
+				/* literal ] can be first character, so test for it at the end of the loop, for example: []] */
+				if (*pat=='-' && hasprev) {
+					/* it is a range*/
+					unsigned char range_end;
+					unsigned int c;
+					massert(range_start);
+					pat++;
+					if (pat[0]=='[')
+						if (pat[1]=='.') {
+							if(pat[2]=='-' && pat[3]=='.' && pat[4]==']')
+								range_end = '-';
+							else {
+								/* this is getting complicated, bail out */
+								cli_warnmsg("confused about collating sequences in regex,bailing out");
+								pat=old;
+								token->type=TOKEN_REGEX;
+								break;
+							}
+						}
+						else 
+							range_end = *pat;
+					else
+						range_end = *pat;
+					for(c=range_start+1;c<=range_end;c++)
+						bitmap[c>>3] ^= 1<<(c&0x7);
+					hasprev = 0;
+				}
+				else if (pat[0]=='[' && pat[1]==':') {
+							const unsigned char* end;
+							int len,found=-1;
+							size_t i;
+
+							pat+=2;
+							end=(unsigned char*)strstr((const char*)pat,":]");
+							if(!end) {
+								cli_warnmsg("confused about std char class syntax regex,bailing out");
+								pat=old;
+								token->type=TOKEN_REGEX;
+								break;
+							}
+
+							len = end-pat;
+							for(i=0;i<std_class_cnt;i++)
+								if(!strncmp((const char*)pat,std_class[i],len)) {
+									found=i;
+									break;
+								}
+							if(found!=-1) {
+								for(i=0;i<256;i++)
+									if(char_class[i]&(1<<found))
+										bitmap[i>>3] ^= 1<<(i&0x7);
+							}
+							else {
+								/*unknown class*/
+								cli_warnmsg("confused about regex bracket expression, bailing out");
+								pat=old;
+								token->type=TOKEN_REGEX;
+								break;
+							}
+						}
+				else {
+					bitmap[*pat>>3] ^= 1<<(*pat&0x7);
+					pat++;
+					range_start = *pat;
+					hasprev = 1;
+				}
+			} while(*pat!=']');
+			/*TODO: see if this bitmap already exists, then reuse*/			
+			token->type = TOKEN_BRACKET;
+			token->u.bitmap = bitmap;
+			break;
+			}
+		case ']':
+			massert(0 && "Encountered ] without matching [");
+			/* bad state */
+			break;
+		case '.':
+			token->type=TOKEN_DOT;
+			break;
+		case '(':
+			token->type=TOKEN_PAR_OPEN;
+			break;
+		case ')':
+			token->type=TOKEN_PAR_CLOSE;
+			break;
+		default:
+			token->type=TOKEN_CHAR;
+			token->u.c = *pat;
+			token->len=1;
+			break;
+	}
+	return ++pat;
+}
+
+#define INITIAL_ALT_STACK 10
+#define ALT_STACK_GROW 20
+
+static const unsigned char* find_regex_start(const unsigned char* pat)
+{
+	struct token_t token;
+	/*TODO: find where the regex part begins, for ex:
+	 * abcd+, regex begins at 'd'
+	 * */
+	const unsigned char* last=NULL;
+	const unsigned char* tmp=NULL;
+	const unsigned char** altpositions = cli_malloc(INITIAL_ALT_STACK*sizeof(*altpositions));
+	size_t altpositions_capacity = INITIAL_ALT_STACK;
+	size_t altpositions_cnt = 0;
+	char lasttype = -1;
+	if(!altpositions)
+		return NULL;
+	massert(pat);
+
+	/* Try to parse pattern till special regex chars are encountered, that the tree-matcher doesn't handle, like: +,*,{}.
+	 * The tricky part is that once we encounter these, the previous 'atom' has to be passed on to the regex matcher, so we have to
+	 * back up to the last known good position
+	 * Example, if we have: abc(defg)+, then only abc can be handled by tree parser, so we have to return the position of (.
+	 * Another example: abc(defg|xyz|oz+|pdo), the last known good position is |, after xyz
+	 * TODO: what about open parantheses? maybe once we found a special char, we have top back out before the first (?
+	 * */
+	do {	
+		tmp = pat;
+		pat = getNextToken(pat,&token);
+		if(token.type!=TOKEN_REGEX) {
+			last = tmp;
+			lasttype = token.type;
+			if(token.type==TOKEN_BRACKET && token.u.bitmap)
+				free(token.u.bitmap);
+			if(token.type==TOKEN_ALT || token.type==TOKEN_PAR_OPEN) {
+				/* save this position on stack, succesfully parsed till here*/
+				if(altpositions_cnt && altpositions[altpositions_cnt-1][0]=='|')
+					/* encountered another alternate (|) operator, override previous | position stored */
+					altpositions[altpositions_cnt-1]=last;
+				else {
+					altpositions[altpositions_cnt++] = last;
+					if(altpositions_cnt == altpositions_capacity) {
+						altpositions_capacity += ALT_STACK_GROW;
+						altpositions = cli_realloc2(altpositions,altpositions_capacity*sizeof(*altpositions));
+						if(!altpositions)
+							return NULL;
+					}
+				}
+			} else if (lasttype==TOKEN_PAR_CLOSE) {
+				/* remove last stored position from stack, succesfully this last group */
+				altpositions_cnt--;
+				massert(altpositions_cnt>0);
+			}
+		}
+		else {
+			if(altpositions_cnt)
+				last = altpositions[0 /*altpositions_cnt-1*/];/*TODO: which index here?, see above TODO... */
+			/*last stored 'safe' position where no special (+,*,{}) regex chars were encountered*/
+		}
+	} while(*pat && token.type!=TOKEN_REGEX);
+	free(altpositions);
+	return *pat ? last : last+1;
+}
+
+static struct tree_node* tree_node_alloc(struct tree_node* next,char listend)
+{
+	struct tree_node* node = cli_malloc(sizeof(*node));
+	if(node) {
+		node->alternatives=0;
+		node->next=next;
+		node->listend=listend;
+		node->u.children=NULL;
+	}
+	return node;
+}
+
+static struct tree_node* tree_root_alloc(void)
+{
+	struct tree_node* root=tree_node_alloc(NULL,1);
+	if(root) {
+		root->op=OP_ROOT;
+		root->c=0;
+		root->next=NULL;
+		root->listend=1;
+	}
+	return root;
+}
+
+static struct tree_node* tree_node_char_binsearch(const struct tree_node* node,const char csearch,int* left)
+{
+	int right;
+	struct tree_node **children;
+	massert(node);
+	massert(left);
+
+	children = tree_node_get_children(node);
+	right = node->alternatives-1;
+	*left = 0;
+	if(!node->alternatives)
+		return NULL;
+	massert(children);
+	while(*left<=right) {
+		int mid  = *left+(right-*left)/2;
+		if(children[mid]->c == csearch)
+			return children[mid]; 
+		else if(children[mid]->c < csearch)
+			*left=mid+1;
+		else
+			right=mid-1;
+	}
+	return NULL;
+}
+
+static struct tree_node* tree_get_next(struct tree_node* node)
+{
+	struct tree_node** children;
+	massert(node);
+	children = tree_node_get_children(node);
+
+	if(!node->alternatives && children && children[0])
+		return children[0];
+	else if(node->alternatives<=1)
+		return node;
+	else
+		return children[0]->next;
+}
+
+static size_t tree_node_get_array_size(const struct tree_node* node)
+{
+	massert(node);
+	/* if op is CUSTOMCLASS, then first pointer is pointer to bitmap, so array size is +1 */
+	return (node->alternatives + (node->op==OP_CUSTOMCLASS ? 1 : 0)) * sizeof(node->u.children[0]);
+}
+
+static struct tree_node* tree_node_char_insert(struct tree_node* node,const char c,int left)
+{
+	struct tree_node* new, *alt = tree_get_next(node);
+	struct tree_node **children;
+	node->alternatives++;
+	node->u.children = cli_realloc2(node->u.children,tree_node_get_array_size(node));
+	if(!node->u.children)
+		return NULL;
+
+	children = node->op==OP_CUSTOMCLASS ? node->u.children+1 : node->u.children;
+
+	new = tree_node_alloc(alt , node == alt );
+	if(new) {
+		new->op=OP_CHAR;
+		new->c=c;
+	}
+
+	if(node->alternatives-left-1>0)
+			memmove(&children[left+1],&children[left],(node->alternatives-left-1)*sizeof(node->u.children[0]));
+	children[left] = new;	
+
+	return new;
+}
+
+static void tree_node_insert_nonbin(struct tree_node* node, struct tree_node* new)
+{
+	struct tree_node **children;
+	massert(node);
+	massert(new);
+
+	children = tree_node_get_children(node);
+	if(node->alternatives) {
+		massert(children);
+	       	if(children[0]->next == node) {
+			int i;
+			new->listend = 1;
+			for(i=0;i<node->alternatives;i++) {
+				children[i]->next = new;
+				children[i]->listend = 0;
+			}
+		}
+		else {
+			struct tree_node* p;
+			for(p = children[0]->next ; p->next != node ; p = p->next)
+				massert(!p->listend);
+			new->listend = 1;
+			p->listend = 0;
+			p->next = new;
+		}
+	}
+	else {
+		int idx = node->op==OP_CUSTOMCLASS ? 1 : 0;
+		if(node->u.children)
+			if(node->u.children[idx]) {
+				node = node->u.children[idx];
+				while(node->next && !node->listend)
+					node = node->next;
+				node->listend = 0;
+				new->next = node->next;
+				node->next = new;
+				new->listend=1;
+				return;
+			}
+		node->u.children = cli_realloc2(node->u.children,sizeof(node->u.children[0])*(2));
+		if(node->u.children) {
+			node->u.children[idx] = new;
+		}
+	}
+}
+
+static unsigned char char_getclass(const unsigned char* bitmap)
+{
+	size_t i;
+	massert(bitmap);
+
+	for(i=0;i<std_class_cnt;i++)
+		if(!memcmp(bitmap,char_class_bitmap[i],256>>3))
+			return i;
+	return std_class_cnt;
+}
+
+static void stack_destroy(struct node_stack* stack)
+{
+	massert(stack);
+	if(stack->data)
+		free(stack->data);
+	stack->data = NULL;
+	stack->capacity = 0;
+}
+
+/* call this after whitelist load is complete, and the tree is no longer going to be modified */
+void regex_list_cleanup(struct regex_matcher* matcher)
+{
+	massert(matcher);
+
+	stack_destroy(&matcher->node_stack);
+	stack_destroy(&matcher->node_stack_alt);
+	stack_init(&matcher->node_stack);
+	stack_init(&matcher->node_stack_alt);
+}
+
+int is_regex_ok(struct regex_matcher* matcher)
+{
+	massert(matcher);
+	return (!matcher->list_inited || matcher->list_inited!=-1);/* either we don't have a regexlist, or we initialized it successfully */
+}
+
+/* returns 0 on success, regexec error code otherwise */						
+static int add_pattern(struct regex_matcher* matcher,const unsigned char* pat,const char* info, int hostonly)
+{
+	int bol=1;
+	const unsigned char* pat_end = find_regex_start(pat);
+	struct token_t token;
+	struct tree_node* node;
+	
+	massert(matcher);
+
+	node = hostonly ? matcher->root_regex_hostonly : matcher->root_regex;
+
+	stack_reset(&matcher->node_stack);
+	stack_reset(&matcher->node_stack_alt);
+	stack_push(&matcher->node_stack,node);
+
+	for(;node->op!=OP_LEAF;){
+		if(pat<pat_end)
+			pat  = getNextToken(pat,&token);
+		else if(*pat) {
+			token.type = TOKEN_REGEX;
+			token.u.start=pat;
+		}
+		else
+			token.type = TOKEN_DONE;
+
+		switch(token.type) {
+			case TOKEN_CHAR: 
+				{
+					/* search for char in tree */
+					int left;
+					struct tree_node* newnode = tree_node_char_binsearch(node,token.u.c,&left);
+					if(newnode)
+						node = newnode;
+					else {
+						/* not found, insert it */
+						node = tree_node_char_insert(node,token.u.c,left);
+					}
+					break;
+				}
+
+			case TOKEN_PAR_OPEN:
+				stack_push(&matcher->node_stack_alt,NULL);/* marker */
+				stack_push(&matcher->node_stack,node);
+				break;
+
+			case TOKEN_PAR_CLOSE: {
+						      /*TODO: test this!!!*/
+						      struct tree_node* node_alt = node;
+						      node = tree_node_alloc(NULL,1);
+						      node->op=OP_PARCLOSE;
+						      node->c=0;
+						      node->listend=1;
+						      tree_node_insert_nonbin(node_alt,node);
+						      while (( node_alt = stack_pop(&matcher->node_stack_alt) )) {
+							      tree_node_insert_nonbin(node_alt,node);
+						      }
+				      		      stack_pop(&matcher->node_stack);					      
+		      				      break;
+					      }
+
+			case TOKEN_ALT:
+				stack_push(&matcher->node_stack_alt,node);
+				node = stack_pop(&matcher->node_stack);
+				stack_push(&matcher->node_stack,node);
+				break;
+
+			case TOKEN_BRACKET:
+				{
+					struct tree_node* new = tree_node_alloc(tree_get_next(node),1);
+					unsigned char charclass = char_getclass(token.u.bitmap);
+					if(charclass == std_class_cnt) {/*not a std char class*/
+						new->op = OP_CUSTOMCLASS;
+						new->u.children = cli_malloc(sizeof(new->u.children[0])*2);
+						if(!new->u.children)
+							return CL_EMEM;
+						new->u.bitmap[0] = token.u.bitmap;
+						new->u.bitmap[1] = NULL;
+						tree_node_insert_nonbin(node,new);
+						node = new;
+					}
+					else {
+						new->op = OP_STDCLASS;
+						new->c = charclass;
+						tree_node_insert_nonbin(node,new);
+						node=new;
+					}
+					break;
+				}
+
+			case TOKEN_DOT:
+				{
+					struct tree_node* new = tree_node_alloc(tree_get_next(node),1);
+					new->op = OP_DOT;
+					tree_node_insert_nonbin(node,new);
+					node=new;
+					break;
+				}
+
+			case TOKEN_REGEX:
+			case TOKEN_DONE: {
+						 struct leaf_info* leaf=cli_malloc(sizeof(*leaf));
+						 if(!leaf)
+							 return CL_EMEM;
+						 leaf->info = cli_strdup(info);
+						 if(token.type==TOKEN_REGEX) {
+							 int rc;
+							 struct tree_node* new;
+							 regex_t* preg;
+							 preg=cli_malloc(sizeof(*preg));
+							 if(!preg)
+								 return CL_EMEM;
+							 rc = cli_regcomp(preg,(const char*)token.u.start,REG_EXTENDED|(bol?0:REG_NOTBOL));
+							 leaf->preg=preg;
+							 if(rc)
+								 return rc;
+							 new=cli_malloc(sizeof(*new));
+							 if(!new)
+								 return CL_EMEM;
+							 new->op=OP_LEAF;
+							 new->next=node;
+							 new->alternatives=0;
+							 new->u.leaf=leaf;
+							 new->listend=1;
+							 tree_node_insert_nonbin(node,new);
+						 }
+						 else {
+							 leaf->preg=NULL;
+							 node->alternatives=0;
+							 node->u.leaf=leaf;
+							 node->op=OP_LEAF;
+						 }
+						 return 0;
+					 }
+		}
+
+		bol=0;
+	}
+	return 0;
+}
+
+/* c has to be unsigned char here!! */
+static int match_node(struct tree_node* node,const unsigned char* c,size_t len,const char** info)
+{
+	struct tree_node** children;
+	int rc;
+
+	massert(node);
+	massert(c);
+	massert(info);
+
+	if(!node->u.children)
+		return MATCH_FAILED;/* tree empty */
+	*info = NULL;
+	len++;
+	c--;
+	for(;;) {
+		massert(node);
+		children = node->u.children;
+		switch(node->op) {
+			case OP_ROOT:
+				rc=1;
+				break;
+			case OP_PARCLOSE:
+				/*this isn't a real character, so don't move*/
+				c--;
+				len++;
+				rc=1;
+				break;
+			case OP_CHAR:
+				massert(*c==node->c && "We know this has to match");
+				rc = 1;/* *c==node->c;- we know it has matched */
+				break;
+			case OP_DOT:	
+				rc = *c!='\n';
+				break;
+			case OP_STDCLASS:
+				rc = char_class[*c]&(node->c);
+				break;
+			case OP_CUSTOMCLASS:
+			{
+				char_bitmap_p bitmap;
+				massert(children);
+				bitmap = (char_bitmap_p)node->u.bitmap[0];
+				children++;
+				rc = bitmap[*c>>3]&(1<<(*c&0x7));
+				break;
+			}
+			case OP_LEAF:
+			{
+				const struct leaf_info* leaf = node->u.leaf;
+				/*isleaf = 1;*/
+				if(leaf->preg) {
+					rc = !cli_regexec(leaf->preg,(const char*)c,0,NULL,0);
+				}
+				else  {
+					massert(*c==node->c && "We know this has to match[2]");
+					rc = 1;
+				}
+				if(rc) {
+					*info = leaf->info;
+					return MATCH_SUCCESS;
+				}
+				break;
+			}
+			default:
+				/* impossible */
+				cli_errmsg("Encountered invalid operator in tree:%d\n",node->op);
+				exit(1);
+		}
+		len--;
+		if(!len) rc=0;
+		c++;
+		if(rc) {
+			const char csearch = *c;
+			int left = 0,right = node->alternatives-1;
+			int mid;
+			/*matched so far, go deeper*/
+			/*do a binary search between children */
+			massert(children);
+			while(left<=right) {
+				mid  = left+(right-left)/2;
+				if (children[mid]->c == csearch)
+					break;
+				else if(children[mid]->c < csearch)
+					left=mid+1;
+				else
+					right=mid-1;
+			}
+			if(left<=right) {
+				node = children[mid];
+				massert(node);
+			}
+			else {
+				if(node->alternatives) {
+					if(!children[0]->listend) {
+						node = children[0];
+						c++;
+						len--;
+					}
+					while(node && node->listend) {
+						node = node->next;/* climb up */
+						c--;
+						len++;
+					}
+					if(!node || !node->next) 
+						return MATCH_FAILED;/* reached root node */
+					node=node->next;
+					c--;
+					len++;
+				}
+				else if(node->u.children) {
+					struct tree_node* rewrite_next = NULL;
+					if(node->op==OP_PARCLOSE) 
+						rewrite_next = node;
+					node = children[0];
+					massert(node);
+					massert(node->op!=OP_CHAR);
+					if(rewrite_next)
+						node->next = rewrite_next;/* this node is pointed to by several parent nodes, 
+									     we need to know 
+									     from which one we came, so we can find out way back
+									     should we fail to match somewhere deeper*/
+				}
+			}
+		}
+		else {
+			/* this node didn't match, try sibling, or parent (if no more siblings) */
+			while(node && node->listend) {
+				node = node->next;/* sibling of parent */
+				c--;
+				len++;
+			}
+			if(!node || !node->next) /* reached root node, it has no next */
+				return MATCH_FAILED;
+			else {
+				c--;
+				len++;
+				node=node->next;
+			}
+		}
+	}
+	return MATCH_FAILED;
+}
+
+/* push node on stack, only if it isn't there already */
+static void stack_push_once(struct node_stack* stack,struct tree_node* node)
+{
+	size_t i;
+	massert(stack);
+	massert(node);
+
+	for(i=0;i < stack->cnt;i++)
+		if(stack->data[i]==node)
+			return;
+	stack_push(stack,node);
+}
+
+static void destroy_tree_internal(struct regex_matcher* matcher,struct tree_node* node)
+{
+	struct tree_node **children;
+	massert(matcher);
+	massert(node);
+
+	children = tree_node_get_children(node);
+	if(node->op==OP_LEAF) {
+		struct leaf_info* leaf = node->u.leaf;
+		if(node->next && !node->listend)
+			destroy_tree_internal(matcher,node->next);
+		stack_push_once(&matcher->node_stack,(struct tree_node*)node->u.leaf);/* cast to make compiler happy, and to not make another stack implementation for storing void* */
+		stack_push_once(&matcher->node_stack,node);
+		if(leaf->preg) {
+			cli_regfree(leaf->preg);
+			free(leaf->preg);
+			leaf->preg=NULL;
+		}
+		if(leaf->info) {
+			free(leaf->info);
+			leaf->info=NULL;
+		}
+	/*	return;*/
+	}
+	if(node->alternatives) {
+		int i;
+		struct tree_node* p;
+		massert(children);
+		p = children[0]->op==OP_LEAF ? NULL : children[0]->next;
+		for(i=0;i<node->alternatives;i++)
+			destroy_tree_internal(matcher,children[i]);
+		if(p && p!=node)
+			destroy_tree_internal(matcher,p);/*?? is this ok, or without _internal?*/
+	}
+	else {
+		if(children) {
+			if(children[0])
+				destroy_tree_internal(matcher,children[0]);		
+		}
+	}
+	if(node->op!=OP_LEAF && node->next && !node->listend)
+		destroy_tree_internal(matcher,node->next);
+	if(node->u.children)
+		stack_push_once(&matcher->node_stack,(struct tree_node*)node->u.children);/* cast to make compiler happy, it isn't really a tree_node* */
+	if(node->op==OP_CUSTOMCLASS && node->u.children[0]) {
+		free(node->u.children[0]);
+		node->u.children[0]=NULL;
+	}
+	stack_push_once(&matcher->node_stack,node);
+}
+
+static void destroy_tree(struct regex_matcher* matcher)
+{
+	/* we might have the same node linked by different nodes, so a recursive walk&free doesn't work in all situations,
+	 * i.e. it might double-free, so instead of freeing, just push the nodes on a stack, and later free the nodes in that stack,
+	 * (and push to stack only if it doesn't contain it already*/
+	massert(matcher);
+
+	stack_reset(&matcher->node_stack);
+	destroy_tree_internal(matcher,matcher->root_regex);
+	destroy_tree_internal(matcher,matcher->root_regex_hostonly);
+	while (matcher->node_stack.cnt) {
+		struct tree_node* node = stack_pop(&matcher->node_stack);
+		if(node)
+			free(node);
+	}
+}
+#ifndef NDEBUG
+static void dump_node(struct tree_node* node)
+{
+	int i;
+	struct tree_node* p,**children;
+	massert(node);
+	if(node->op==OP_LEAF) {
+		if(node->u.leaf->preg)
+			printf("n%p [label=\"regex\\nleaf\"]",(void*)node);
+		else
+			printf("n%p [label=\"%c\\nleaf\"];\n",(void*)node,node->c);
+		if(node->next && !node->listend) {
+			printf("n%p -> n%p;\n",(void*)node,(void*)node->next);
+			dump_node(node->next);
+		}
+		return;
+	}
+	printf("n%p [label=\"%c\\n%d\\nlistend:%d\"];\n",(void*)node,(node->op==OP_ROOT||node->op==OP_PARCLOSE) ?'@' :node->c,node->op,node->listend);
+	if(node->next)
+		printf("n%p -> n%p;\n",(void*)node,(void*)node->next);
+	printf("n%p -> {",(void*)node);/*using address of node as id*/
+	children = tree_node_get_children(node);
+	if(node->alternatives)
+		massert(children);
+	for(i=0;i<node->alternatives;i++)
+		printf("n%p ",(void*)children[i]);
+	if(node->alternatives && children[0]->op!=OP_LEAF)
+		for(p=children[0]->next;p!=node;p=p->next)
+		{
+			massert(p);
+			printf("n%p ",(void*)p);
+			if(p->op==OP_LEAF || p->listend)
+				break;
+		}
+	if(!node->alternatives && children && children[0])
+		printf("n%p ",(void*)children[0]);
+	printf("};\n");
+	printf("{rank=same;");
+	for(i=0;i<node->alternatives;i++)
+		printf("n%p ",(void*)node->u.children[i]);
+	if(node->alternatives && children[0]->op!=OP_LEAF)
+		for(p=children[0]->next;p!=node;p=p->next) 
+		{
+			printf("n%p ",(void*)p);	
+			if(p->op==OP_LEAF || p->listend)
+				break;
+		}
+	if(!node->alternatives && children && children[0])
+		printf("n%p ",(void*)children[0]);
+	printf("};\n");
+	for(i=0;i<node->alternatives;i++)
+		dump_node(children[i]);
+	if(node->alternatives && children[0]->op!=OP_LEAF)
+		for(p=children[0]->next;p!=node;p=p->next)
+		{
+			dump_node(p);
+			if(p->op==OP_LEAF || p->listend)
+				break;
+		}
+	if(!node->alternatives && children && children[0])
+		dump_node(children[0]);
+}
+
+void dump_tree(struct tree_node* root)
+{
+	/*use dot/dotty from graphviz to view it*/
+	massert(root);
+	printf("digraph tree {\n");
+	dump_node(root);
+	printf("}\n");
+}
+#endif
+
+
+#else
+/*------------------------New version of regex_list.c------------------------*/
+
+/* Regex_list.c: 
+ * A scalable, trie-based implementation for matching against 
+ * a list of regular expressions.
+ *
+ * A trivial way to implement matching against a list of regular expressions 
+ * would have been to construct a single regular expression, by concatenating 
+ * the list with the alternate (|) operator.
+ * BUT a usual DFA implementation of regular expression matching (eg.: GNU libc)
+ * leads to "state explosion" when there are many (5000+) alternate (|) operators.
+ * This is the reason for using a trie-based implementation.
+ *
+ *
+ * Design considerations:
+ *
+ * Recursive call points: there are situations when match has to be retried on a different sub-trie, or with a different repeat count.
+ * Alternate operators, and repeat/range operators (+,*,{}) are recursiv call points. When a failure is encountered during a match,
+ * the function simply returns from the recursive call, and ends up at a failure point (recursive call point).
+ *
+ * "go to parent" below actually means, return from recursive call.
+ *
+ * fail_action: we need to return to closest failure point (recursive call point),
+ *  and switch current node to node pointed by fail_action
+ *
+ * Node types:
+ * 	OP_ROOT: contains information that applies to the entire trie.
+ * 		it can only appear as root node, and not as child node.
+ * 		On child fail: match has failed
+ * 		This is NOT a recursive call point
+ * 	OP_CHAR_BINARY_SEARCH: chooses a sub-trie, based on current character; 
+ * 			using binary-search
+ * 			On fail: go to node indicated by fail_action, or if 
+ * 				fail_action is NULL, to parent
+ * 			On child fail: execute fail of current node
+ * 	OP_ALTERNATIVES: try matching each sub-trie, if all fails execute fail
+ * 		action of current node. This is a recursive call point
+ * 	OP_CHAR_REPEAT: repeat specified character a number of times in range:
+ *		[min_range, max_range]; 
+ *			min_range: 0 for * operator
+ *				   1 for + operator
+ *			max_range: remaining length of current string for *,+ operator
+ *			OR: min_range, max_range as specified by the {min,max} operator
+ *		On fail: fail_action, or parent if NULL
+ *		On child fail: reduce match repeat count, try again on child, if
+ *			repeat count<min_range, execute fail of current node
+ *		Also has a bitmap on what characters are accepted beyond it,
+ *		as an optimizations for the case, when a maximum match isn't possible
+ *		Not recomended to use this when min_range=max_range=1
+ *		This is a recursive call point
+ *	OP_DOT_REPEAT: like OP_CHAR_REPEAT but accept any character
+ *		Not recomended to use this when min_range=max_range=1
+ *		This is a recursive call point
+ *	OP_GROUP_START: start of a group "(", also specifies group flags:
+ *		repeat: is_repeat, min_range, max_range
+ *		This is a recursive call point if is_repeat
+ *	OP_GROUP_END: end of group ")"
+ *      OP_STRCMP: compare with specified string,
+ *      	   it has an array of fail actions, one for each character
+ *      	   default fail action: go to parent
+ *      	   This was introduced from memory- and speed-efficiency
+ *      	   considerations. 
+ *      OP_CHAR_CLASS_REPEAT: match character with character class
+ *      	min_range, max_range
+ *      	For a single character class min_range=max_range=1
+ *	OP_MATCH_OK: match has succeeded
+ *
+ * TODO: maybe we'll need a more efficient way to choose between character classes.
+ *       OP_DOT_REPEAT/OP_CHAR_REPEAT needs a more efficient specification of its failure function, instead of using
+ *       backtracking approach.
+ *
+ * The failure function/action is just for optimization, the match algorithms works even without it.
+ * TODO:In this first draft fail action will always be NULL, in a later version I'll implement fail actions too.
+ *
+ *
+ */ 
+
+#include <string.h>
+#include "cltypes.h"
+#include "others.h"
+
+/* offsetof is not ANSI C */
+#ifndef offsetof
+#   define offsetof(type,memb) ((size_t)&((type*)0)->memb)
+#endif
+
+#define container_of(ptr, type, member) ( (type *) ((char *)ptr - offsetof(type, member)) )
+#define container_of_const(ptr, type, member) ( (type *) ((const char *)ptr - offsetof(type, member)) )
+
+enum trie_node_type {
+	OP_ROOT,
+	OP_CHAR_BINARY_SEARCH,
+	OP_ALTERNATIVES,
+	OP_CHAR_REPEAT,
+	OP_DOT_REPEAT,
+	OP_CHAR_CLASS_REPEAT,
+	OP_STRCMP,
+	OP_GROUP_START,
+	OP_GROUP_END,
+	OP_MATCH_OK
+};
+
+
+/* the comon definition of a trie node */
+struct trie_node
+{
+	enum trie_node_type type;
+};
+
+struct trie_node_match {
+	struct trie_node node;
+	/* additional match info */
+};
+
+struct trie_node_root
+{
+	struct trie_node node;
+	struct trie_node* child;
+};
+
+struct trie_node_binary_search
+{
+	struct trie_node node;
+	uint8_t children_count;/* number of children to search among -1! 255 = 256 children*/	
+	struct trie_node* fail_action;
+	unsigned char* char_choices;/* children_count elements */
+	struct trie_node** children;/*children_count elements */
+};
+
+struct trie_node_alternatives
+{
+	struct trie_node node;
+	uint32_t alternatives_count;
+	/* need to support node with lots of alternatives, 
+	 * for a worst-case scenario where each line ends up as a sub-trie of OP_ALTERNATIVES*/
+	struct trie_node* fail_action;
+	struct trie_node** children;
+};
+
+struct trie_node_char_repeat
+{
+	struct trie_node node;
+	unsigned char character;
+	uint8_t range_min, range_max;/* according to POSIX we need not support more than 255 repetitions*/
+	struct char_bitmap* bitmap_accept_after;/* bitmap of characters accepted after this, 
+						   to optimize repeat < max_range case; if its NULL
+						   there is no optimization*/
+	struct trie_node* child;
+	struct trie_node* fail_action;
+};
+
+struct trie_node_dot_repeat
+{
+	struct trie_node node;
+	uint8_t range_min, range_max;/* according to POSIX we need not support more than 255 repetitions*/
+	struct char_bitmap* bitmap_accept_after;/* bitmap of characters accepted after this, 
+						   to optimize repeat < max_range case; if its NULL
+						   there is no optimization*/
+	struct trie_node* child;
+	struct trie_node* fail_action;
+};
+
+struct trie_node_group_start
+{
+	struct trie_node node;
+	uint8_t range_min, range_max;/* if range_min==range_max==1, then this is NOT a repeat, thus not a recursive call point*/
+	struct trie_node* child;
+	struct trie_node* fail_action;	
+};
+
+struct trie_node_group_end
+{
+	struct trie_node node;
+	struct trie_node* child;
+};
+
+struct trie_node_strcmp
+{
+	struct trie_node node;
+	uint8_t string_length;/* for longer strings a sequence of node_strcmp should be used */
+	unsigned char* string;
+	struct trie_node* child;
+	struct trie_node** fail_actions;/* this has string_length elements, or NULL if no fail_actions are computed */
+};
+
+struct trie_node_char_class_repeat
+{
+	struct trie_node node;
+	struct char_bitmap* bitmap;
+	struct char_bitmap* bitmap_accept_after;
+	uint8_t range_min, range_max;
+	struct trie_node* child;
+	struct trie_node* fail_action;
+};
+
+static inline int bitmap_accepts(const struct char_bitmap* bitmap, const char c)
+{
+	/* TODO: check if c is accepted by bitmap */
+	return 0;
+}
+
+#define MATCH_FAILED 0
+#define MATCH_OK     1
+
+#define FAIL_ACTION( fail_node ) (*fail_action = (fail_node), MATCH_FAILED)
+
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#endif
+
+static int match_node(const struct trie_node* node, const unsigned char* text, const unsigned char* text_end, const struct trie_node** fail_action);
+
+static int match_repeat(const unsigned char* text, const unsigned char* text_end, const size_t range_min, const size_t repeat_start, 
+		const struct char_bitmap* bitmap_accept_after, const struct trie_node* child, const struct trie_node** fail_action,
+		const struct trie_node* this_fail_action)
+{
+	size_t i;
+	for(i = repeat_start;i > range_min;i--) {
+		if(!bitmap_accept_after || bitmap_accepts( bitmap_accept_after, text[i-1])) {
+			int rc = match_node(child, &text[i], text_end, fail_action);
+			/* ignore fail_action for now, we have the bitmap_accepts_after optimization */
+			if(rc) {
+				return MATCH_OK;
+			}
+		}						
+	}
+	if(!range_min) {
+		/* this match is optional, try child only */
+		int rc = match_node(child, text, text_end, fail_action);
+		if(rc) {
+			return MATCH_OK;
+		}
+	}
+	return FAIL_ACTION(this_fail_action);
+}
+
+/* text_end points to \0 in text */
+static int match_node(const struct trie_node* node, const unsigned char* text, const unsigned char* text_end, const struct trie_node** fail_action)
+{
+	while(node && text < text_end) {	
+		switch(node->type) {
+			case OP_ROOT:
+				{	
+					const struct trie_node_root* root_node = container_of_const(node, const struct trie_node_root, node);
+					node = root_node->child;
+					break;
+				}
+			case OP_CHAR_BINARY_SEARCH:
+				{					
+					const struct trie_node_binary_search* bin_node = container_of_const(node, const struct trie_node_binary_search, node);
+					const unsigned char csearch = *text;
+					size_t mid, left = 0, right = bin_node->children_count-1;					
+					while(left<=right) {
+						mid = left+(right-left)/2;
+						if(bin_node->char_choices[mid] == csearch)
+							break;
+						else if(bin_node->char_choices[mid] < csearch)
+							left = mid+1;
+						else
+							right = mid-1;
+					}
+					if(left <= right) {
+						/* match successful */
+						node = bin_node->children[mid];
+						++text;
+					}
+					else {
+						return FAIL_ACTION( bin_node->fail_action );
+					}
+					break;
+				}
+			case OP_ALTERNATIVES:
+				{
+					const struct trie_node_alternatives* alt_node = container_of_const(node, const struct trie_node_alternatives, node);
+					size_t i;
+					*fail_action = NULL;
+					for(i=0;i < alt_node->alternatives_count;i++) {
+						int rc = match_node(alt_node->children[i], text, text_end, fail_action);
+						if(rc) {							
+							return MATCH_OK;
+						}
+						/* supporting fail_actions is tricky,
+						 *  if we just go to the node specified, what happens if the match fails, and no
+						 *  further fail_action is specified? We should know where to continue the search.
+						 * For now fail_action isn't supported for OP_ALTERNATIVES*/						
+					}
+					break;
+				}
+			case OP_CHAR_REPEAT:
+				{
+					const struct trie_node_char_repeat* char_rep_node = container_of_const(node, const struct trie_node_char_repeat, node);
+					const size_t max_len = MIN( text_end - text, char_rep_node->range_max-1);
+					/* todo: what about the 8 bit limitation of range_max, and what about inf (+,*)? */
+					const char caccept = char_rep_node->character;
+					size_t rep;
+
+					if(max_len < char_rep_node->range_min)
+						return FAIL_ACTION(char_rep_node->fail_action);
+
+					for(rep=0;rep < max_len;rep++) {
+						if(text[rep] != caccept) {
+							break;
+						}
+					}
+
+					return match_repeat(text, text_end, char_rep_node->range_min, rep,
+							char_rep_node->bitmap_accept_after, char_rep_node->child, fail_action,
+							char_rep_node->fail_action);
+				}
+			case OP_DOT_REPEAT:
+				{
+					const struct trie_node_dot_repeat* dot_rep_node = container_of_const(node, const struct trie_node_dot_repeat, node);
+					const size_t max_len = MIN( text_end - text, dot_rep_node->range_max-1);
+					/* todo: what about the 8 bit limitation of range_max, and what about inf (+,*)? */
+
+					if(max_len < dot_rep_node->range_min)
+						return FAIL_ACTION(dot_rep_node->fail_action);
+
+					return match_repeat(text, text_end, dot_rep_node->range_min, max_len,
+							dot_rep_node->bitmap_accept_after, dot_rep_node->child, fail_action,
+							dot_rep_node->fail_action);
+				}
+			case OP_CHAR_CLASS_REPEAT:
+				{
+					const struct trie_node_char_class_repeat* class_rep_node = container_of_const(node, const struct trie_node_char_class_repeat, node);
+					const size_t max_len = MIN( text_end - text, class_rep_node->range_max-1);
+					/* todo: what about the 8 bit limitation of range_max, and what about inf (+,*)? */
+					size_t rep;
+
+					if(max_len < class_rep_node->range_min)
+						return FAIL_ACTION(class_rep_node->fail_action);
+
+					for(rep=0;rep < max_len;rep++) {
+						if(!bitmap_accepts( class_rep_node->bitmap, text[rep])) {
+							break;
+						}
+					}
+
+					return match_repeat(text, text_end, class_rep_node->range_min, rep,
+							class_rep_node->bitmap_accept_after, class_rep_node->child, fail_action,
+							class_rep_node->fail_action);
+					break;
+				}
+			case OP_STRCMP:
+				{
+					const struct trie_node_strcmp* strcmp_node = container_of_const(node, const struct trie_node_strcmp, node);
+					size_t i;
+					if(strcmp_node->fail_actions) {
+						const size_t max_len = MIN(strcmp_node->string_length, text_end-text);
+						/* we don't use strncmp, because we need the exact match-fail point */
+						for(i=0;i < max_len;i++) {
+							if(text[i] != strcmp_node->string[i]) {
+								return FAIL_ACTION( strcmp_node->fail_actions[i] );
+							}
+						}
+						if(max_len < strcmp_node->string_length) {
+							/* failed, because text was shorter */
+							return FAIL_ACTION( strcmp_node->fail_actions[max_len] );
+						}
+					}
+					else {
+						/* no fail_actions computed, some shortcuts possible on compare */
+						if((text_end - text < strcmp_node->string_length) ||
+								strncmp((const char*)text, (const char*)strcmp_node->string, strcmp_node->string_length)) {
+
+							return FAIL_ACTION( NULL );
+						}
+					}
+					/* match successful */
+					node = strcmp_node->child;
+					text += strcmp_node->string_length;
+					break;
+				}
+			case OP_GROUP_START:
+				{
+					const struct trie_node_group_start* group_start_node = container_of_const(node, const struct trie_node_group_start, node);
+					/* TODO: implement */
+					break;
+				}
+			case OP_GROUP_END:
+				{					
+					const struct trie_node_group_end* group_end_node = container_of_const(node, const struct trie_node_group_end, node);
+					/* TODO: implement */
+					break;
+				}
+			case OP_MATCH_OK:
+				{
+					return MATCH_OK;
+				}
+		}
+	}
+	/* if fail_action was NULL, or text ended*/
+	return MATCH_FAILED;
+}
+
+#endif
+

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1525 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regcomp.c	8.5 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+	char *next;		/* next character in RE */
+	char *end;		/* end of string (-> NUL normally) */
+	int error;		/* has an error been seen? */
+	sop *strip;		/* malloced strip */
+	sopno ssize;		/* malloced strip size (allocated) */
+	sopno slen;		/* malloced strip length (used) */
+	int ncsalloc;		/* number of csets allocated */
+	struct re_guts *g;
+#	define	NPAREN	10	/* we need to remember () 1-9 for back refs */
+	sopno pbegin[NPAREN];	/* -> ( ([0] unused) */
+	sopno pend[NPAREN];	/* -> ) ([0] unused) */
+};
+
+static void p_ere(struct parse *, int);
+static void p_ere_exp(struct parse *);
+static void p_str(struct parse *);
+static void p_bre(struct parse *, int, int);
+static int p_simp_re(struct parse *, int);
+static int p_count(struct parse *);
+static void p_bracket(struct parse *);
+static void p_b_term(struct parse *, cset *);
+static void p_b_cclass(struct parse *, cset *);
+static void p_b_eclass(struct parse *, cset *);
+static char p_b_symbol(struct parse *);
+static char p_b_coll_elem(struct parse *, int);
+static char othercase(int);
+static void bothcases(struct parse *, int);
+static void ordinary(struct parse *, int);
+static void nonnewline(struct parse *);
+static void repeat(struct parse *, sopno, int, int);
+static int seterr(struct parse *, int);
+static cset *allocset(struct parse *);
+static void freeset(struct parse *, cset *);
+static int freezeset(struct parse *, cset *);
+static int firstch(struct parse *, cset *);
+static int nch(struct parse *, cset *);
+static void mcadd(struct parse *, cset *, const char *);
+static void mcinvert(struct parse *, cset *);
+static void mccase(struct parse *, cset *);
+static int isinsets(struct re_guts *, int);
+static int samesets(struct re_guts *, int, int);
+static void categorize(struct parse *, struct re_guts *);
+static sopno dupl(struct parse *, sopno, sopno);
+static void doemit(struct parse *, sop, size_t);
+static void doinsert(struct parse *, sop, size_t, sopno);
+static void dofwd(struct parse *, sopno, sop);
+static void enlarge(struct parse *, sopno);
+static void stripsnug(struct parse *, struct re_guts *);
+static void findmust(struct parse *, struct re_guts *);
+static sopno pluscount(struct parse *, struct re_guts *);
+
+static char nuls[10];		/* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE:  these know that the parse structure is named `p' !!!
+ */
+#define	PEEK()	(*p->next)
+#define	PEEK2()	(*(p->next+1))
+#define	MORE()	(p->next < p->end)
+#define	MORE2()	(p->next+1 < p->end)
+#define	SEE(c)	(MORE() && PEEK() == (c))
+#define	SEETWO(a, b)	(MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define	EAT(c)	((SEE(c)) ? (NEXT(), 1) : 0)
+#define	EATTWO(a, b)	((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define	NEXT()	(p->next++)
+#define	NEXT2()	(p->next += 2)
+#define	NEXTn(n)	(p->next += (n))
+#define	GETNEXT()	(*p->next++)
+#define	SETERROR(e)	seterr(p, (e))
+#define	REQUIRE(co, e)	(void)((co) || SETERROR(e))
+#define	MUSTSEE(c, e)	(REQUIRE(MORE() && PEEK() == (c), e))
+#define	MUSTEAT(c, e)	(REQUIRE(MORE() && GETNEXT() == (c), e))
+#define	MUSTNOTSEE(c, e)	(REQUIRE(!MORE() || PEEK() != (c), e))
+#define	EMIT(op, sopnd)	doemit(p, (sop)(op), (size_t)(sopnd))
+#define	INSERT(op, pos)	doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define	AHEAD(pos)		dofwd(p, pos, HERE()-(pos))
+#define	ASTERN(sop, pos)	EMIT(sop, HERE()-pos)
+#define	HERE()		(p->slen)
+#define	THERE()		(p->slen - 1)
+#define	THERETHERE()	(p->slen - 2)
+#define	DROP(n)	(p->slen -= (n))
+
+#ifdef	_POSIX2_RE_DUP_MAX
+#define	DUPMAX	_POSIX2_RE_DUP_MAX
+#else
+#define	DUPMAX	255
+#endif
+
+#ifndef NDEBUG
+static int never = 0;		/* for use in asserts; shuts lint up */
+#else
+#define	never	0		/* some <assert.h>s have bugs too */
+#endif
+
+/*
+ - cli_regcomp - interface for parser and compilation
+ */
+int				/* 0 success, otherwise REG_something */
+cli_regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+	struct parse pa;
+	struct re_guts *g;
+	struct parse *p = &pa;
+	int i;
+	size_t len;
+#ifdef REDEBUG
+#	define	GOODFLAGS(f)	(f)
+#else
+#	define	GOODFLAGS(f)	((f)&~REG_DUMP)
+#endif
+
+	cflags = GOODFLAGS(cflags);
+	if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
+		return(REG_INVARG);
+
+	if (cflags&REG_PEND) {
+		if (preg->re_endp < pattern)
+			return(REG_INVARG);
+		len = preg->re_endp - pattern;
+	} else
+		len = strlen((const char *)pattern);
+
+	/* do the mallocs early so failure handling is easy */
+	g = (struct re_guts *)cli_malloc(sizeof(struct re_guts) +
+							(NC-1)*sizeof(cat_t));
+	if (g == NULL)
+		return(REG_ESPACE);
+	p->ssize = len/(size_t)2*(size_t)3 + (size_t)1;	/* ugh */
+	p->strip = (sop *)cli_calloc(p->ssize, sizeof(sop));
+	p->slen = 0;
+	if (p->strip == NULL) {
+		free((char *)g);
+		return(REG_ESPACE);
+	}
+
+	/* set things up */
+	p->g = g;
+	p->next = (char *)pattern;	/* convenience; we do not modify it */
+	p->end = p->next + len;
+	p->error = 0;
+	p->ncsalloc = 0;
+	for (i = 0; i < NPAREN; i++) {
+		p->pbegin[i] = 0;
+		p->pend[i] = 0;
+	}
+	g->csetsize = NC;
+	g->sets = NULL;
+	g->setbits = NULL;
+	g->ncsets = 0;
+	g->cflags = cflags;
+	g->iflags = 0;
+	g->nbol = 0;
+	g->neol = 0;
+	g->must = NULL;
+	g->mlen = 0;
+	g->nsub = 0;
+	g->ncategories = 1;	/* category 0 is "everything else" */
+	g->categories = &g->catspace[-(CHAR_MIN)];
+	(void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+	g->backrefs = 0;
+
+	/* do it */
+	EMIT(OEND, 0);
+	g->firststate = THERE();
+	if (cflags&REG_EXTENDED)
+		p_ere(p, OUT);
+	else if (cflags&REG_NOSPEC)
+		p_str(p);
+	else
+		p_bre(p, OUT, OUT);
+	EMIT(OEND, 0);
+	g->laststate = THERE();
+
+	/* tidy up loose ends and fill things in */
+	categorize(p, g);
+	stripsnug(p, g);
+	findmust(p, g);
+	g->nplus = pluscount(p, g);
+	g->magic = MAGIC2;
+	preg->re_nsub = g->nsub;
+	preg->re_g = g;
+	preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+	/* not debugging, so can't rely on the assert() in cli_regexec() */
+	if (g->iflags&BAD)
+		SETERROR(REG_ASSERT);
+#endif
+
+	/* win or lose, we're done */
+	if (p->error != 0)	/* lose */
+		cli_regfree(preg);
+	return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ */
+static void
+p_ere(struct parse *p, int stop)	/* character this ERE should end at */
+{
+	char c;
+	sopno prevback;
+	sopno prevfwd;
+	sopno conc;
+	int first = 1;		/* is this the first alternative? */
+
+	for (;;) {
+		/* do a bunch of concatenated expressions */
+		conc = HERE();
+		while (MORE() && (c = PEEK()) != '|' && c != stop)
+			p_ere_exp(p);
+		REQUIRE(HERE() != conc, REG_EMPTY);	/* require nonempty */
+
+		if (!EAT('|'))
+			break;		/* NOTE BREAK OUT */
+
+		if (first) {
+			INSERT(OCH_, conc);	/* offset is wrong */
+			prevfwd = conc;
+			prevback = conc;
+			first = 0;
+		}
+		ASTERN(OOR1, prevback);
+		prevback = THERE();
+		AHEAD(prevfwd);			/* fix previous offset */
+		prevfwd = HERE();
+		EMIT(OOR2, 0);			/* offset is very wrong */
+	}
+
+	if (!first) {		/* tail-end fixups */
+		AHEAD(prevfwd);
+		ASTERN(O_CH, prevback);
+	}
+
+	assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ */
+static void
+p_ere_exp(struct parse *p)
+{
+	char c;
+	sopno pos;
+	int count;
+	int count2;
+	sopno subno;
+	int wascaret = 0;
+
+	assert(MORE());		/* caller should have ensured this */
+	c = GETNEXT();
+
+	pos = HERE();
+	switch (c) {
+	case '(':
+		REQUIRE(MORE(), REG_EPAREN);
+		p->g->nsub++;
+		subno = p->g->nsub;
+		if (subno < NPAREN)
+			p->pbegin[subno] = HERE();
+		EMIT(OLPAREN, subno);
+		if (!SEE(')'))
+			p_ere(p, ')');
+		if (subno < NPAREN) {
+			p->pend[subno] = HERE();
+			assert(p->pend[subno] != 0);
+		}
+		EMIT(ORPAREN, subno);
+		MUSTEAT(')', REG_EPAREN);
+		break;
+#ifndef POSIX_MISTAKE
+	case ')':		/* happens only if no current unmatched ( */
+		/*
+		 * You may ask, why the ifndef?  Because I didn't notice
+		 * this until slightly too late for 1003.2, and none of the
+		 * other 1003.2 regular-expression reviewers noticed it at
+		 * all.  So an unmatched ) is legal POSIX, at least until
+		 * we can get it fixed.
+		 */
+		SETERROR(REG_EPAREN);
+		break;
+#endif
+	case '^':
+		EMIT(OBOL, 0);
+		p->g->iflags |= USEBOL;
+		p->g->nbol++;
+		wascaret = 1;
+		break;
+	case '$':
+		EMIT(OEOL, 0);
+		p->g->iflags |= USEEOL;
+		p->g->neol++;
+		break;
+	case '|':
+		SETERROR(REG_EMPTY);
+		break;
+	case '*':
+	case '+':
+	case '?':
+		SETERROR(REG_BADRPT);
+		break;
+	case '.':
+		if (p->g->cflags&REG_NEWLINE)
+			nonnewline(p);
+		else
+			EMIT(OANY, 0);
+		break;
+	case '[':
+		p_bracket(p);
+		break;
+	case '\\':
+		REQUIRE(MORE(), REG_EESCAPE);
+		c = GETNEXT();
+		ordinary(p, c);
+		break;
+	case '{':		/* okay as ordinary except if digit follows */
+		REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT);
+		/* FALLTHROUGH */
+	default:
+		ordinary(p, c);
+		break;
+	}
+
+	if (!MORE())
+		return;
+	c = PEEK();
+	/* we call { a repetition if followed by a digit */
+	if (!( c == '*' || c == '+' || c == '?' ||
+				(c == '{' && MORE2() && isdigit((uch)PEEK2())) ))
+		return;		/* no repetition, we're done */
+	NEXT();
+
+	REQUIRE(!wascaret, REG_BADRPT);
+	switch (c) {
+	case '*':	/* implemented as +? */
+		/* this case does not require the (y|) trick, noKLUDGE */
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		INSERT(OQUEST_, pos);
+		ASTERN(O_QUEST, pos);
+		break;
+	case '+':
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		break;
+	case '?':
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, pos);		/* offset slightly wrong */
+		ASTERN(OOR1, pos);		/* this one's right */
+		AHEAD(pos);			/* fix the OCH_ */
+		EMIT(OOR2, 0);			/* offset very wrong... */
+		AHEAD(THERE());			/* ...so fix it */
+		ASTERN(O_CH, THERETHERE());
+		break;
+	case '{':
+		count = p_count(p);
+		if (EAT(',')) {
+			if (isdigit((uch)PEEK())) {
+				count2 = p_count(p);
+				REQUIRE(count <= count2, REG_BADBR);
+			} else		/* single number with comma */
+				count2 = INFINITY;
+		} else		/* just a single number */
+			count2 = count;
+		repeat(p, pos, count, count2);
+		if (!EAT('}')) {	/* error heuristics */
+			while (MORE() && PEEK() != '}')
+				NEXT();
+			REQUIRE(MORE(), REG_EBRACE);
+			SETERROR(REG_BADBR);
+		}
+		break;
+	}
+
+	if (!MORE())
+		return;
+	c = PEEK();
+	if (!( c == '*' || c == '+' || c == '?' ||
+				(c == '{' && MORE2() && isdigit((uch)PEEK2())) ) )
+		return;
+	SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ */
+static void
+p_str(struct parse *p)
+{
+	REQUIRE(MORE(), REG_EMPTY);
+	while (MORE())
+		ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor.  The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases.  This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(struct parse *p,
+    int end1,		/* first terminating character */
+    int end2)		/* second terminating character */
+{
+	sopno start = HERE();
+	int first = 1;			/* first subexpression? */
+	int wasdollar = 0;
+
+	if (EAT('^')) {
+		EMIT(OBOL, 0);
+		p->g->iflags |= USEBOL;
+		p->g->nbol++;
+	}
+	while (MORE() && !SEETWO(end1, end2)) {
+		wasdollar = p_simp_re(p, first);
+		first = 0;
+	}
+	if (wasdollar) {	/* oops, that was a trailing anchor */
+		DROP(1);
+		EMIT(OEOL, 0);
+		p->g->iflags |= USEEOL;
+		p->g->neol++;
+	}
+
+	REQUIRE(HERE() != start, REG_EMPTY);	/* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ */
+static int			/* was the simple RE an unbackslashed $? */
+p_simp_re(struct parse *p,
+    int starordinary)		/* is a leading * an ordinary character? */
+{
+	int c;
+	int count;
+	int count2;
+	sopno pos;
+	int i;
+	sopno subno;
+#	define	BACKSL	(1<<CHAR_BIT)
+
+	pos = HERE();		/* repetion op, if any, covers from here */
+
+	assert(MORE());		/* caller should have ensured this */
+	c = GETNEXT();
+	if (c == '\\') {
+		REQUIRE(MORE(), REG_EESCAPE);
+		c = BACKSL | GETNEXT();
+	}
+	switch (c) {
+	case '.':
+		if (p->g->cflags&REG_NEWLINE)
+			nonnewline(p);
+		else
+			EMIT(OANY, 0);
+		break;
+	case '[':
+		p_bracket(p);
+		break;
+	case BACKSL|'{':
+		SETERROR(REG_BADRPT);
+		break;
+	case BACKSL|'(':
+		p->g->nsub++;
+		subno = p->g->nsub;
+		if (subno < NPAREN)
+			p->pbegin[subno] = HERE();
+		EMIT(OLPAREN, subno);
+		/* the MORE here is an error heuristic */
+		if (MORE() && !SEETWO('\\', ')'))
+			p_bre(p, '\\', ')');
+		if (subno < NPAREN) {
+			p->pend[subno] = HERE();
+			assert(p->pend[subno] != 0);
+		}
+		EMIT(ORPAREN, subno);
+		REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+		break;
+	case BACKSL|')':	/* should not get here -- must be user */
+	case BACKSL|'}':
+		SETERROR(REG_EPAREN);
+		break;
+	case BACKSL|'1':
+	case BACKSL|'2':
+	case BACKSL|'3':
+	case BACKSL|'4':
+	case BACKSL|'5':
+	case BACKSL|'6':
+	case BACKSL|'7':
+	case BACKSL|'8':
+	case BACKSL|'9':
+		i = (c&~BACKSL) - '0';
+		assert(i < NPAREN);
+		if (p->pend[i] != 0) {
+			assert(i <= p->g->nsub);
+			EMIT(OBACK_, i);
+			assert(p->pbegin[i] != 0);
+			assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+			assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+			(void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+			EMIT(O_BACK, i);
+		} else
+			SETERROR(REG_ESUBREG);
+		p->g->backrefs = 1;
+		break;
+	case '*':
+		REQUIRE(starordinary, REG_BADRPT);
+		/* FALLTHROUGH */
+	default:
+		ordinary(p, (char)c);
+		break;
+	}
+
+	if (EAT('*')) {		/* implemented as +? */
+		/* this case does not require the (y|) trick, noKLUDGE */
+		INSERT(OPLUS_, pos);
+		ASTERN(O_PLUS, pos);
+		INSERT(OQUEST_, pos);
+		ASTERN(O_QUEST, pos);
+	} else if (EATTWO('\\', '{')) {
+		count = p_count(p);
+		if (EAT(',')) {
+			if (MORE() && isdigit((uch)PEEK())) {
+				count2 = p_count(p);
+				REQUIRE(count <= count2, REG_BADBR);
+			} else		/* single number with comma */
+				count2 = INFINITY;
+		} else		/* just a single number */
+			count2 = count;
+		repeat(p, pos, count, count2);
+		if (!EATTWO('\\', '}')) {	/* error heuristics */
+			while (MORE() && !SEETWO('\\', '}'))
+				NEXT();
+			REQUIRE(MORE(), REG_EBRACE);
+			SETERROR(REG_BADBR);
+		}
+	} else if (c == '$')	/* $ (but not \$) ends it */
+		return(1);
+
+	return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ */
+static int			/* the value */
+p_count(struct parse *p)
+{
+	int count = 0;
+	int ndigits = 0;
+
+	while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) {
+		count = count*10 + (GETNEXT() - '0');
+		ndigits++;
+	}
+
+	REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+	return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ *
+ * Note a significant property of this code:  if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(struct parse *p)
+{
+	cset *cs;
+	int invert = 0;
+
+	/* Dept of Truly Sickening Special-Case Kludges */
+	if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+		EMIT(OBOW, 0);
+		NEXTn(6);
+		return;
+	}
+	if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+		EMIT(OEOW, 0);
+		NEXTn(6);
+		return;
+	}
+
+	if ((cs = allocset(p)) == NULL) {
+		/* allocset did set error status in p */
+		return;
+	}
+
+	if (EAT('^'))
+		invert++;	/* make note to invert set at end */
+	if (EAT(']'))
+		CHadd(cs, ']');
+	else if (EAT('-'))
+		CHadd(cs, '-');
+	while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+		p_b_term(p, cs);
+	if (EAT('-'))
+		CHadd(cs, '-');
+	MUSTEAT(']', REG_EBRACK);
+
+	if (p->error != 0) {	/* don't mess things up further */
+		freeset(p, cs);
+		return;
+	}
+
+	if (p->g->cflags&REG_ICASE) {
+		int i;
+		int ci;
+
+		for (i = p->g->csetsize - 1; i >= 0; i--)
+			if (CHIN(cs, i) && isalpha(i)) {
+				ci = othercase(i);
+				if (ci != i)
+					CHadd(cs, ci);
+			}
+		if (cs->multis != NULL)
+			mccase(p, cs);
+	}
+	if (invert) {
+		int i;
+
+		for (i = p->g->csetsize - 1; i >= 0; i--)
+			if (CHIN(cs, i))
+				CHsub(cs, i);
+			else
+				CHadd(cs, i);
+		if (p->g->cflags&REG_NEWLINE)
+			CHsub(cs, '\n');
+		if (cs->multis != NULL)
+			mcinvert(p, cs);
+	}
+
+	assert(cs->multis == NULL);		/* xxx */
+
+	if (nch(p, cs) == 1) {		/* optimize singleton sets */
+		ordinary(p, firstch(p, cs));
+		freeset(p, cs);
+	} else
+		EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ */
+static void
+p_b_term(struct parse *p, cset *cs)
+{
+	char c;
+	char start, finish;
+	int i;
+
+	/* classify what we've got */
+	switch ((MORE()) ? PEEK() : '\0') {
+	case '[':
+		c = (MORE2()) ? PEEK2() : '\0';
+		break;
+	case '-':
+		SETERROR(REG_ERANGE);
+		return;			/* NOTE RETURN */
+		break;
+	default:
+		c = '\0';
+		break;
+	}
+
+	switch (c) {
+	case ':':		/* character class */
+		NEXT2();
+		REQUIRE(MORE(), REG_EBRACK);
+		c = PEEK();
+		REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+		p_b_cclass(p, cs);
+		REQUIRE(MORE(), REG_EBRACK);
+		REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+		break;
+	case '=':		/* equivalence class */
+		NEXT2();
+		REQUIRE(MORE(), REG_EBRACK);
+		c = PEEK();
+		REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+		p_b_eclass(p, cs);
+		REQUIRE(MORE(), REG_EBRACK);
+		REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+		break;
+	default:		/* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+		start = p_b_symbol(p);
+		if (SEE('-') && MORE2() && PEEK2() != ']') {
+			/* range */
+			NEXT();
+			if (EAT('-'))
+				finish = '-';
+			else
+				finish = p_b_symbol(p);
+		} else
+			finish = start;
+/* xxx what about signed chars here... */
+		REQUIRE(start <= finish, REG_ERANGE);
+		for (i = start; i <= finish; i++)
+			CHadd(cs, i);
+		break;
+	}
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ */
+static void
+p_b_cclass(struct parse *p, cset *cs)
+{
+	char *sp = p->next;
+	struct cclass *cp;
+	size_t len;
+	const char *u;
+	char c;
+
+	while (MORE() && isalpha(PEEK()))
+		NEXT();
+	len = p->next - sp;
+	for (cp = cclasses; cp->name != NULL; cp++)
+		if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+			break;
+	if (cp->name == NULL) {
+		/* oops, didn't find it */
+		SETERROR(REG_ECTYPE);
+		return;
+	}
+
+	u = cp->chars;
+	while ((c = *u++) != '\0')
+		CHadd(cs, c);
+	for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+		MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(struct parse *p, cset *cs)
+{
+	char c;
+
+	c = p_b_coll_elem(p, '=');
+	CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ */
+static char			/* value of symbol */
+p_b_symbol(struct parse *p)
+{
+	char value;
+
+	REQUIRE(MORE(), REG_EBRACK);
+	if (!EATTWO('[', '.'))
+		return(GETNEXT());
+
+	/* collating symbol */
+	value = p_b_coll_elem(p, '.');
+	REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+	return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ */
+static char			/* value of collating element */
+p_b_coll_elem(struct parse *p,
+    int endc)			/* name ended by endc,']' */
+{
+	char *sp = p->next;
+	struct cname *cp;
+	int len;
+
+	while (MORE() && !SEETWO(endc, ']'))
+		NEXT();
+	if (!MORE()) {
+		SETERROR(REG_EBRACK);
+		return(0);
+	}
+	len = p->next - sp;
+	for (cp = cnames; cp->name != NULL; cp++)
+		if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+			return(cp->code);	/* known name */
+	if (len == 1)
+		return(*sp);	/* single character */
+	SETERROR(REG_ECOLLATE);			/* neither */
+	return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ */
+static char			/* if no counterpart, return ch */
+othercase(int ch)
+{
+	ch = (uch)ch;
+	assert(isalpha(ch));
+	if (isupper(ch))
+		return ((uch)tolower(ch));
+	else if (islower(ch))
+		return ((uch)toupper(ch));
+	else			/* peculiar, but could happen */
+		return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(struct parse *p, int ch)
+{
+	char *oldnext = p->next;
+	char *oldend = p->end;
+	char bracket[3];
+
+	ch = (uch)ch;
+	assert(othercase(ch) != ch);	/* p_bracket() would recurse */
+	p->next = bracket;
+	p->end = bracket+2;
+	bracket[0] = ch;
+	bracket[1] = ']';
+	bracket[2] = '\0';
+	p_bracket(p);
+	assert(p->next == bracket+2);
+	p->next = oldnext;
+	p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ */
+static void
+ordinary(struct parse *p, int ch)
+{
+	cat_t *cap = p->g->categories;
+
+	if ((p->g->cflags&REG_ICASE) && isalpha((uch)ch) && othercase(ch) != ch)
+		bothcases(p, ch);
+	else {
+		EMIT(OCHAR, (uch)ch);
+		if (cap[ch] == 0)
+			cap[ch] = p->g->ncategories++;
+	}
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(struct parse *p)
+{
+	char *oldnext = p->next;
+	char *oldend = p->end;
+	char bracket[4];
+
+	p->next = bracket;
+	p->end = bracket+3;
+	bracket[0] = '^';
+	bracket[1] = '\n';
+	bracket[2] = ']';
+	bracket[3] = '\0';
+	p_bracket(p);
+	assert(p->next == bracket+3);
+	p->next = oldnext;
+	p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ */
+static void
+repeat(struct parse *p,
+    sopno start,		/* operand from here to end of strip */
+    int from,			/* repeated from this number */
+    int to)			/* to this number of times (maybe INFINITY) */
+{
+	sopno finish = HERE();
+#	define	N	2
+#	define	INF	3
+#	define	REP(f, t)	((f)*8 + (t))
+#	define	MAP(n)	(((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+	sopno copy;
+
+	if (p->error != 0)	/* head off possible runaway recursion */
+		return;
+
+	assert(from <= to);
+
+	switch (REP(MAP(from), MAP(to))) {
+	case REP(0, 0):			/* must be user doing this */
+		DROP(finish-start);	/* drop the operand */
+		break;
+	case REP(0, 1):			/* as x{1,1}? */
+	case REP(0, N):			/* as x{1,n}? */
+	case REP(0, INF):		/* as x{1,}? */
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, start);		/* offset is wrong... */
+		repeat(p, start+1, 1, to);
+		ASTERN(OOR1, start);
+		AHEAD(start);			/* ... fix it */
+		EMIT(OOR2, 0);
+		AHEAD(THERE());
+		ASTERN(O_CH, THERETHERE());
+		break;
+	case REP(1, 1):			/* trivial case */
+		/* done */
+		break;
+	case REP(1, N):			/* as x?x{1,n-1} */
+		/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+		INSERT(OCH_, start);
+		ASTERN(OOR1, start);
+		AHEAD(start);
+		EMIT(OOR2, 0);			/* offset very wrong... */
+		AHEAD(THERE());			/* ...so fix it */
+		ASTERN(O_CH, THERETHERE());
+		copy = dupl(p, start+1, finish+1);
+		assert(copy == finish+4);
+		repeat(p, copy, 1, to-1);
+		break;
+	case REP(1, INF):		/* as x+ */
+		INSERT(OPLUS_, start);
+		ASTERN(O_PLUS, start);
+		break;
+	case REP(N, N):			/* as xx{m-1,n-1} */
+		copy = dupl(p, start, finish);
+		repeat(p, copy, from-1, to-1);
+		break;
+	case REP(N, INF):		/* as xx{n-1,INF} */
+		copy = dupl(p, start, finish);
+		repeat(p, copy, from-1, to);
+		break;
+	default:			/* "can't happen" */
+		SETERROR(REG_ASSERT);	/* just in case */
+		break;
+	}
+}
+
+/*
+ - seterr - set an error condition
+ */
+static int			/* useless but makes type checking happy */
+seterr(struct parse *p, int e)
+{
+	if (p->error == 0)	/* keep earliest error condition */
+		p->error = e;
+	p->next = nuls;		/* try to bring things to a halt */
+	p->end = nuls;
+	return(0);		/* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ */
+static cset *
+allocset(struct parse *p)
+{
+	int no = p->g->ncsets++;
+	size_t nc;
+	size_t nbytes;
+	cset *cs;
+	size_t css = (size_t)p->g->csetsize;
+	int i;
+
+	if (no >= p->ncsalloc) {	/* need another column of space */
+		void *ptr;
+
+		p->ncsalloc += CHAR_BIT;
+		nc = p->ncsalloc;
+		assert(nc % CHAR_BIT == 0);
+		nbytes = nc / CHAR_BIT * css;
+
+		ptr = (cset *)cli_realloc((char *)p->g->sets, nc * sizeof(cset));
+		if (ptr == NULL)
+			goto nomem;
+		p->g->sets = ptr;
+
+		ptr = (uch *)cli_realloc((char *)p->g->setbits, nbytes);
+		if (ptr == NULL)
+			goto nomem;
+		p->g->setbits = ptr;
+
+		for (i = 0; i < no; i++)
+			p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+
+		(void) memset((char *)p->g->setbits + (nbytes - css), 0, css);
+	}
+
+	cs = &p->g->sets[no];
+	cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+	cs->mask = 1 << ((no) % CHAR_BIT);
+	cs->hash = 0;
+	cs->smultis = 0;
+	cs->multis = NULL;
+
+	return(cs);
+nomem:
+	free(p->g->sets);
+	p->g->sets = NULL;
+	free(p->g->setbits);
+	p->g->setbits = NULL;
+
+	SETERROR(REG_ESPACE);
+	/* caller's responsibility not to do set ops */
+	return(NULL);
+}
+
+/*
+ - freeset - free a now-unused set
+ */
+static void
+freeset(struct parse *p, cset *cs)
+{
+	size_t i;
+	cset *top = &p->g->sets[p->g->ncsets];
+	size_t css = (size_t)p->g->csetsize;
+
+	for (i = 0; i < css; i++)
+		CHsub(cs, i);
+	if (cs == top-1)	/* recover only the easy case */
+		p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ *
+ * The main task here is merging identical sets.  This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used.  REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int			/* set number */
+freezeset(struct parse *p, cset *cs)
+{
+	uch h = cs->hash;
+	size_t i;
+	cset *top = &p->g->sets[p->g->ncsets];
+	cset *cs2;
+	size_t css = (size_t)p->g->csetsize;
+
+	/* look for an earlier one which is the same */
+	for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+		if (cs2->hash == h && cs2 != cs) {
+			/* maybe */
+			for (i = 0; i < css; i++)
+				if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+					break;		/* no */
+			if (i == css)
+				break;			/* yes */
+		}
+
+	if (cs2 < top) {	/* found one */
+		freeset(p, cs);
+		cs = cs2;
+	}
+
+	return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ */
+static int			/* character; there is no "none" value */
+firstch(struct parse *p, cset *cs)
+{
+	size_t i;
+	size_t css = (size_t)p->g->csetsize;
+
+	for (i = 0; i < css; i++)
+		if (CHIN(cs, i))
+			return((char)i);
+	assert(never);
+	return(0);		/* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ */
+static int
+nch(struct parse *p, cset *cs)
+{
+	size_t i;
+	size_t css = (size_t)p->g->csetsize;
+	int n = 0;
+
+	for (i = 0; i < css; i++)
+		if (CHIN(cs, i))
+			n++;
+	return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ */
+static void
+mcadd( struct parse *p, cset *cs, const char *cp)
+{
+	size_t oldend = cs->smultis;
+	void *np;
+
+	cs->smultis += strlen(cp) + 1;
+	if (cs->multis == NULL)
+		np = cli_malloc(cs->smultis);
+	else
+		np = cli_realloc(cs->multis, cs->smultis);
+	if (np == NULL) {
+		if (cs->multis)
+			free(cs->multis);
+		cs->multis = NULL;
+		SETERROR(REG_ESPACE);
+		return;
+	}
+	cs->multis = np;
+
+	cli_strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1);
+}
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+/* ARGSUSED */
+static void
+mcinvert(struct parse *p, cset *cs)
+{
+	assert(cs->multis == NULL);	/* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ *
+ * This would have to know the set of possibilities.  Implementation
+ * is deferred.
+ */
+/* ARGSUSED */
+static void
+mccase(struct parse *p, cset *cs)
+{
+	assert(cs->multis == NULL);	/* xxx */
+}
+
+/*
+ - isinsets - is this character in any sets?
+ */
+static int			/* predicate */
+isinsets(struct re_guts *g, int c)
+{
+	uch *col;
+	int i;
+	int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+	unsigned uc = (uch)c;
+
+	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+		if (col[uc] != 0)
+			return(1);
+	return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ */
+static int			/* predicate */
+samesets(struct re_guts *g, int c1, int c2)
+{
+	uch *col;
+	int i;
+	int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+	unsigned uc1 = (uch)c1;
+	unsigned uc2 = (uch)c2;
+
+	for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+		if (col[uc1] != col[uc2])
+			return(0);
+	return(1);
+}
+
+/*
+ - categorize - sort out character categories
+ */
+static void
+categorize(struct parse *p, struct re_guts *g)
+{
+	cat_t *cats = g->categories;
+	int c;
+	int c2;
+	cat_t cat;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+		if (cats[c] == 0 && isinsets(g, c)) {
+			cat = g->ncategories++;
+			cats[c] = cat;
+			for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+				if (cats[c2] == 0 && samesets(g, c, c2))
+					cats[c2] = cat;
+		}
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ */
+static sopno			/* start of duplicate */
+dupl(struct parse *p,
+    sopno start,		/* from here */
+    sopno finish)		/* to this less one */
+{
+	sopno ret = HERE();
+	sopno len = finish - start;
+
+	assert(finish >= start);
+	if (len == 0)
+		return(ret);
+	enlarge(p, p->ssize + len);	/* this many unexpected additions */
+	assert(p->ssize >= p->slen + len);
+	(void) memmove((char *)(p->strip + p->slen),
+		(char *)(p->strip + start), (size_t)len*sizeof(sop));
+	p->slen += len;
+	return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures.  Maybe later.
+ */
+static void
+doemit(struct parse *p, sop op, size_t opnd)
+{
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	/* deal with oversize operands ("can't happen", more or less) */
+	assert(opnd < 1<<OPSHIFT);
+
+	/* deal with undersized strip */
+	if (p->slen >= p->ssize)
+		enlarge(p, (p->ssize+1) / 2 * 3);	/* +50% */
+	assert(p->slen < p->ssize);
+
+	/* finally, it's all reduced to the easy case */
+	p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ */
+static void
+doinsert(struct parse *p, sop op, size_t opnd, sopno pos)
+{
+	sopno sn;
+	sop s;
+	int i;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	sn = HERE();
+	EMIT(op, opnd);		/* do checks, ensure space */
+	assert(HERE() == sn+1);
+	s = p->strip[sn];
+
+	/* adjust paren pointers */
+	assert(pos > 0);
+	for (i = 1; i < NPAREN; i++) {
+		if (p->pbegin[i] >= pos) {
+			p->pbegin[i]++;
+		}
+		if (p->pend[i] >= pos) {
+			p->pend[i]++;
+		}
+	}
+
+	memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+						(HERE()-pos-1)*sizeof(sop));
+	p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ */
+static void
+dofwd(struct parse *p, sopno pos, sop value)
+{
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	assert(value < 1<<OPSHIFT);
+	p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ */
+static void
+enlarge(struct parse *p, sopno size)
+{
+	sop *sp;
+
+	if (p->ssize >= size)
+		return;
+
+	sp = (sop *)cli_realloc(p->strip, size*sizeof(sop));
+	if (sp == NULL) {
+		SETERROR(REG_ESPACE);
+		return;
+	}
+	p->strip = sp;
+	p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ */
+static void
+stripsnug(struct parse *p, struct re_guts *g)
+{
+	g->nstates = p->slen;
+	g->strip = (sop *)cli_realloc((char *)p->strip, p->slen * sizeof(sop));
+	if (g->strip == NULL) {
+		SETERROR(REG_ESPACE);
+		g->strip = p->strip;
+	}
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences.  Someday.  This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(struct parse *p, struct re_guts *g)
+{
+	sop *scan;
+	sop *start;
+	sop *newstart;
+	sopno newlen;
+	sop s;
+	char *cp;
+	sopno i;
+
+	/* avoid making error situations worse */
+	if (p->error != 0)
+		return;
+
+	/* find the longest OCHAR sequence in strip */
+	newlen = 0;
+	scan = g->strip + 1;
+	do {
+		s = *scan++;
+		switch (OP(s)) {
+		case OCHAR:		/* sequence member */
+			if (newlen == 0)		/* new sequence */
+				newstart = scan - 1;
+			newlen++;
+			break;
+		case OPLUS_:		/* things that don't break one */
+		case OLPAREN:
+		case ORPAREN:
+			break;
+		case OQUEST_:		/* things that must be skipped */
+		case OCH_:
+			scan--;
+			do {
+				scan += OPND(s);
+				s = *scan;
+				/* assert() interferes w debug printouts */
+				if (OP(s) != O_QUEST && OP(s) != O_CH &&
+							OP(s) != OOR2) {
+					g->iflags |= BAD;
+					return;
+				}
+			} while (OP(s) != O_QUEST && OP(s) != O_CH);
+			/* fallthrough */
+		default:		/* things that break a sequence */
+			if (newlen > g->mlen) {		/* ends one */
+				start = newstart;
+				g->mlen = newlen;
+			}
+			newlen = 0;
+			break;
+		}
+	} while (OP(s) != OEND);
+
+	if (g->mlen == 0)		/* there isn't one */
+		return;
+
+	/* turn it into a character string */
+	g->must = cli_malloc((size_t)g->mlen + 1);
+	if (g->must == NULL) {		/* argh; just forget it */
+		g->mlen = 0;
+		return;
+	}
+	cp = g->must;
+	scan = start;
+	for (i = g->mlen; i > 0; i--) {
+		while (OP(s = *scan++) != OCHAR)
+			continue;
+		assert(cp < g->must + g->mlen);
+		*cp++ = (char)OPND(s);
+	}
+	assert(cp == g->must + g->mlen);
+	*cp++ = '\0';		/* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ */
+static sopno			/* nesting depth */
+pluscount(struct parse *p, struct re_guts *g)
+{
+	sop *scan;
+	sop s;
+	sopno plusnest = 0;
+	sopno maxnest = 0;
+
+	if (p->error != 0)
+		return(0);	/* there may not be an OEND */
+
+	scan = g->strip + 1;
+	do {
+		s = *scan++;
+		switch (OP(s)) {
+		case OPLUS_:
+			plusnest++;
+			break;
+		case O_PLUS:
+			if (plusnest > maxnest)
+				maxnest = plusnest;
+			plusnest--;
+			break;
+		}
+	} while (OP(s) != OEND);
+	if (plusnest != 0)
+		g->iflags |= BAD;
+	return(maxnest);
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,132 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regerror.c	8.4 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+
+static const char *regatoi(const regex_t *, char *, int);
+
+static struct rerr {
+	int code;
+	const char *name;
+	const char *explain;
+} rerrs[] = {
+	{ REG_NOMATCH,	"REG_NOMATCH",	"cli_regexec() failed to match" },
+	{ REG_BADPAT,	"REG_BADPAT",	"invalid regular expression" },
+	{ REG_ECOLLATE,	"REG_ECOLLATE",	"invalid collating element" },
+	{ REG_ECTYPE,	"REG_ECTYPE",	"invalid character class" },
+	{ REG_EESCAPE,	"REG_EESCAPE",	"trailing backslash (\\)" },
+	{ REG_ESUBREG,	"REG_ESUBREG",	"invalid backreference number" },
+	{ REG_EBRACK,	"REG_EBRACK",	"brackets ([ ]) not balanced" },
+	{ REG_EPAREN,	"REG_EPAREN",	"parentheses not balanced" },
+	{ REG_EBRACE,	"REG_EBRACE",	"braces not balanced" },
+	{ REG_BADBR,	"REG_BADBR",	"invalid repetition count(s)" },
+	{ REG_ERANGE,	"REG_ERANGE",	"invalid character range" },
+	{ REG_ESPACE,	"REG_ESPACE",	"out of memory" },
+	{ REG_BADRPT,	"REG_BADRPT",	"repetition-operator operand invalid" },
+	{ REG_EMPTY,	"REG_EMPTY",	"empty (sub)expression" },
+	{ REG_ASSERT,	"REG_ASSERT",	"\"can't happen\" -- you found a bug" },
+	{ REG_INVARG,	"REG_INVARG",	"invalid argument to regex routine" },
+	{ 0,		"",		"*** unknown regexp error code ***" }
+};
+
+/*
+ - cli_regerror - the interface to error numbers
+ = extern size_t cli_regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+cli_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+	struct rerr *r;
+	size_t len;
+	int target = errcode &~ REG_ITOA;
+	const char *s;
+	char convbuf[50];
+
+	if (errcode == REG_ATOI)
+		s = regatoi(preg, convbuf, sizeof convbuf);
+	else {
+		for (r = rerrs; r->code != 0; r++)
+			if (r->code == target)
+				break;
+	
+		if (errcode&REG_ITOA) {
+			if (r->code != 0) {
+				assert(strlen(r->name) < sizeof(convbuf));
+				(void) cli_strlcpy(convbuf, r->name, sizeof convbuf);
+			} else
+				(void)snprintf(convbuf, sizeof convbuf,
+				    "REG_0x%x", target);
+			s = convbuf;
+		} else
+			s = r->explain;
+	}
+
+	len = strlen(s) + 1;
+	if (errbuf_size > 0) {
+		cli_strlcpy(errbuf, s, errbuf_size);
+	}
+
+	return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ */
+static const char *
+regatoi(const regex_t *preg, char *localbuf, int localbufsize)
+{
+	struct rerr *r;
+
+	for (r = rerrs; r->code != 0; r++)
+		if (strcmp(r->name, preg->re_endp) == 0)
+			break;
+	if (r->code == 0)
+		return("0");
+
+	(void)snprintf(localbuf, localbufsize, "%d", r->code);
+	return(localbuf);
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,162 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regexec.c	8.3 (Berkeley) 3/20/94
+ */
+
+/*
+ * the outer shell of cli_regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses.  This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+#include "regex2.h"
+
+/* macros for manipulating states, small version */
+#define	states	long
+#define	states1	states		/* for later use in cli_regexec() decision */
+#define	CLEAR(v)	((v) = 0)
+#define	SET0(v, n)	((v) &= ~((unsigned long)1 << (n)))
+#define	SET1(v, n)	((v) |= (unsigned long)1 << (n))
+#define	ISSET(v, n)	(((v) & ((unsigned long)1 << (n))) != 0)
+#define	ASSIGN(d, s)	((d) = (s))
+#define	EQ(a, b)	((a) == (b))
+#define	STATEVARS	long dummy	/* dummy version */
+#define	STATESETUP(m, n)	/* nothing */
+#define	STATETEARDOWN(m)	/* nothing */
+#define	SETUP(v)	((v) = 0)
+#define	onestate	long
+#define	INIT(o, n)	((o) = (unsigned long)1 << (n))
+#define	INC(o)		((o) <<= 1)
+#define	ISSTATEIN(v, o)	(((v) & (o)) != 0)
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define	FWD(dst, src, n)	((dst) |= ((unsigned long)(src)&(here)) << (n))
+#define	BACK(dst, src, n)	((dst) |= ((unsigned long)(src)&(here)) >> (n))
+#define	ISSETBACK(v, n)		(((v) & ((unsigned long)here >> (n))) != 0)
+/* function names */
+#define SNAMES			/* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef	states
+#undef	CLEAR
+#undef	SET0
+#undef	SET1
+#undef	ISSET
+#undef	ASSIGN
+#undef	EQ
+#undef	STATEVARS
+#undef	STATESETUP
+#undef	STATETEARDOWN
+#undef	SETUP
+#undef	onestate
+#undef	INIT
+#undef	INC
+#undef	ISSTATEIN
+#undef	FWD
+#undef	BACK
+#undef	ISSETBACK
+#undef	SNAMES
+
+/* macros for manipulating states, large version */
+#define	states	char *
+#define	CLEAR(v)	memset(v, 0, m->g->nstates)
+#define	SET0(v, n)	((v)[n] = 0)
+#define	SET1(v, n)	((v)[n] = 1)
+#define	ISSET(v, n)	((v)[n])
+#define	ASSIGN(d, s)	memmove(d, s, m->g->nstates)
+#define	EQ(a, b)	(memcmp(a, b, m->g->nstates) == 0)
+#define	STATEVARS	long vn; char *space
+#define	STATESETUP(m, nv)	{ (m)->space = cli_malloc((nv)*(m)->g->nstates); \
+				if ((m)->space == NULL) return(REG_ESPACE); \
+				(m)->vn = 0; }
+#define	STATETEARDOWN(m)	{ free((m)->space); }
+#define	SETUP(v)	((v) = &m->space[m->vn++ * m->g->nstates])
+#define	onestate	long
+#define	INIT(o, n)	((o) = (n))
+#define	INC(o)	((o)++)
+#define	ISSTATEIN(v, o)	((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define	FWD(dst, src, n)	((dst)[here+(n)] |= (src)[here])
+#define	BACK(dst, src, n)	((dst)[here-(n)] |= (src)[here])
+#define	ISSETBACK(v, n)	((v)[here - (n)])
+/* function names */
+#define	LNAMES			/* flag */
+
+#include "engine.c"
+
+/*
+ - cli_regexec - interface for matching
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call.  Also, by this point the matchers
+ * have been prototyped.
+ */
+int				/* 0 success, REG_NOMATCH failure */
+cli_regexec(const regex_t *preg, const char *string, size_t nmatch,
+    regmatch_t pmatch[], int eflags)
+{
+	struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+#	define	GOODFLAGS(f)	(f)
+#else
+#	define	GOODFLAGS(f)	((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+	if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+		return(REG_BADPAT);
+	assert(!(g->iflags&BAD));
+	if (g->iflags&BAD)		/* backstop for no-debug case */
+		return(REG_BADPAT);
+	eflags = GOODFLAGS(eflags);
+
+	if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
+		return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+	else
+		return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,73 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regfree.c	8.3 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - cli_regfree - free everything
+ */
+void
+cli_regfree(regex_t *preg)
+{
+	struct re_guts *g;
+
+	if (preg->re_magic != MAGIC1)	/* oops */
+		return;			/* nice to complain, but hard */
+
+	g = preg->re_g;
+	if (g == NULL || g->magic != MAGIC2)	/* oops again */
+		return;
+	preg->re_magic = 0;		/* mark it invalid */
+	g->magic = 0;			/* mark it invalid */
+
+	if (g->strip != NULL)
+		free((char *)g->strip);
+	if (g->sets != NULL)
+		free((char *)g->sets);
+	if (g->setbits != NULL)
+		free((char *)g->setbits);
+	if (g->must != NULL)
+		free(g->must);
+	free((char *)g);
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,52 @@
+/*
+ * This code is derived from OpenBSD's libc, original license follows:
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller at courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "regex.h"
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+cli_strlcpy(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0) {
+		while (--n != 0) {
+			if ((*d++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,695 @@
+/*
+ *  Copyright (C) 2006 Török Edwin <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "others.h"
+#include "rtf.h"
+#include "clamav.h"
+#include "table.h"
+#include "scanners.h"
+#include "vba_extract.h"
+
+enum parse_state { PARSE_MAIN, PARSE_CONTROL_, PARSE_CONTROL_WORD, PARSE_CONTROL_SYMBOL, PARSE_CONTROL_WORD_PARAM, PARSE_INTERPRET_CONTROLWORD };
+
+enum rtf_action
+{
+	RTF_OBJECT,
+	RTF_OBJECT_DATA
+};
+
+struct rtf_state;
+typedef int (*rtf_callback_begin)(struct rtf_state*, cli_ctx* ctx,const char* tmpdir);
+typedef int (*rtf_callback_process)(struct rtf_state*, const unsigned char* data,const size_t len);
+typedef int (*rtf_callback_end)(struct rtf_state*, cli_ctx*);
+
+struct rtf_state {
+	size_t default_elements;
+	size_t controlword_cnt;
+	ssize_t controlword_param;
+	enum parse_state parse_state;
+	int  controlword_param_sign;
+	int  encounteredTopLevel;/* encountered top-level control words that we care about */
+	char controlword[33];
+	rtf_callback_begin cb_begin;/* must be non-null if you want cb_process, and cb_end to be called, also it must change cb_data to non-null */
+	rtf_callback_process cb_process;
+	rtf_callback_end cb_end;
+	void* cb_data;/* data set up by cb_begin, used by cb_process, and cleaned up by cb_end. typically state data */
+};
+
+static const struct rtf_state base_state = {
+	0,0,0,PARSE_MAIN,0,0,"                              ",NULL,NULL,NULL,NULL
+};
+
+struct stack {
+	struct rtf_state* states;
+	size_t elements;
+	size_t stack_cnt;
+	size_t stack_size;
+	int    warned;
+};
+
+static const struct rtf_action_mapping {
+	const char* controlword;
+	const enum rtf_action action;
+} rtf_action_mapping [] = 
+{
+	{"object", RTF_OBJECT},
+	{"objdata ",RTF_OBJECT_DATA}
+};
+
+static const size_t rtf_action_mapping_cnt = sizeof(rtf_action_mapping)/sizeof(rtf_action_mapping[0]);
+
+enum rtf_objdata_state {WAIT_MAGIC, WAIT_DESC_LEN, WAIT_DESC, WAIT_ZERO, WAIT_DATA_SIZE, DUMP_DATA, DUMP_DISCARD};
+static const unsigned char rtf_data_magic[] = {0x01, 0x05, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};/* is this a magic number, or does it mean something */
+static const size_t rtf_data_magic_len  = sizeof(rtf_data_magic);
+
+struct rtf_object_data {
+	char* name;
+	int  fd;
+	int partial;
+	int has_partial;
+	enum rtf_objdata_state internal_state;
+	char* desc_name;
+	const char* tmpdir;
+	cli_ctx*    ctx;
+	size_t desc_len;
+	size_t bread;
+};
+
+#define BUFF_SIZE 8192
+/* generated by contrib/phishing/generate_tables.c */
+static const short int hextable[256] = {
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
+       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
+};
+
+static void init_rtf_state(struct rtf_state* state)
+{
+	*state = base_state;
+	state->parse_state = PARSE_MAIN;
+	state->controlword_cnt = 0;
+}
+
+static int compare_state(const struct rtf_state* a,const struct rtf_state* b)
+{
+	return (a->controlword_param == b->controlword_param && 
+			a->parse_state == b->parse_state &&
+			a->encounteredTopLevel == b->encounteredTopLevel &&
+			memcmp(a->controlword,b->controlword,33)==0 &&
+			a->cb_begin == b->cb_begin &&
+			a->cb_process == b->cb_process &&
+			a->cb_end == b->cb_end &&
+			a->cb_data == b->cb_data);
+}
+
+
+static int push_state(struct stack* stack,struct rtf_state* state)
+{
+	int toplevel;
+	size_t defelements;
+
+	stack->elements++;
+	if( compare_state(state,&base_state)) { 
+		state->default_elements++;
+		return 0;/* this is default state, don't push it, we'll know when we pop it that it was the default one,
+			  we store in the state how many default elements we have on the stack */
+	}
+	if(stack->stack_cnt >= stack->stack_size) {
+		/* grow stack */
+		stack->stack_size += 128;
+		stack->states = cli_realloc2(stack->states, stack->stack_size*sizeof(*stack->states));
+		if(!stack->states)
+			return CL_EMEM;
+	}
+	stack->states[stack->stack_cnt++] = *state;
+	toplevel = state->encounteredTopLevel;
+	defelements = state->default_elements;
+
+	*state = base_state;
+
+	state->encounteredTopLevel = toplevel;
+	state->default_elements = defelements;
+	return 0; 
+}
+
+
+static int pop_state(struct stack* stack,struct rtf_state* state)
+{
+	stack->elements--;
+	if(state->default_elements) {
+		const size_t default_elements = state->default_elements-1;
+		const int toplevel = state->encounteredTopLevel;
+		*state = base_state;
+		state->default_elements = default_elements;
+		state->encounteredTopLevel = toplevel;
+		return 0;/* this is a default 'state'*/
+	}
+	if(!stack->stack_cnt) {
+		if(!stack->warned) {
+			cli_dbgmsg("Warning: attempt to pop from empty stack!\n");
+			stack->warned = 1;
+		}
+		*state = base_state;/* lets assume we give it a base state */
+		return 0;
+	}
+	*state = stack->states[--stack->stack_cnt];
+	return 0;
+}
+
+
+static int load_actions(table_t* t)
+{
+	size_t i;
+	for(i=0; i<rtf_action_mapping_cnt; i++)
+		if(tableInsert(t, rtf_action_mapping[i].controlword, rtf_action_mapping[i].action) == -1)
+			return -1;
+	return 0;
+}
+
+static int rtf_object_begin(struct rtf_state* state,cli_ctx* ctx,const char* tmpdir)
+{
+	struct rtf_object_data* data = cli_malloc(sizeof(*data));
+	if(!data)
+		return CL_EMEM;
+	data->fd = -1;
+	data->partial = 0;
+	data->has_partial = 0;
+	data->bread = 0;
+	data->internal_state = WAIT_MAGIC;
+	data->tmpdir = tmpdir;
+	data->ctx    = ctx;
+	data->name   = NULL;
+	data->desc_name = NULL;
+
+	state->cb_data = data;
+	return 0;
+}
+
+
+static int decode_and_scan(struct rtf_object_data* data, cli_ctx* ctx)
+{
+	int ofd, ret=0;
+
+	cli_dbgmsg("RTF:Scanning embedded object:%s\n",data->name);
+	if(data->bread == 1 && data->fd > 0) {
+		cli_dbgmsg("Decoding ole object\n");
+		lseek(data->fd,0,SEEK_SET);
+		ofd = cli_decode_ole_object(data->fd,data->tmpdir);
+		if (ofd >= 0) {
+			ret = cli_magic_scandesc(ofd, ctx);
+			close(ofd);
+		}
+	}
+	else if(data->fd > 0)
+		ret = cli_magic_scandesc(data->fd,ctx);
+	if(data->fd > 0)
+	close(data->fd);
+	data->fd = -1;
+	if(data->name) {
+		if(!cli_leavetemps_flag)
+			unlink(data->name);
+		free(data->name);
+		data->name = NULL;
+	}
+
+	if(ret != CL_CLEAN)
+		return ret;
+	return 0;
+}
+
+static int rtf_object_process(struct rtf_state* state, const unsigned char* input,const size_t len)
+{
+	struct rtf_object_data* data = state->cb_data;
+	unsigned char outdata[BUFF_SIZE];
+	const unsigned char* out_data;
+	size_t out_cnt = 0;
+	size_t i;
+	int ret;
+
+	if(!data || !len)
+		return 0;
+
+	if(data->has_partial) {
+		for(i=0;i<len && !isxdigit(input[i]);i++)
+			;
+		if(i<len) {
+			outdata[out_cnt++] = data->partial | hextable[input[i++]];
+			data->has_partial = 0;
+		}
+		else
+			return 0;
+	}
+	else
+		i = 0;
+
+	for(;i<len;i++) {
+		if(isxdigit(input[i])) {
+				const unsigned char byte = hextable[ input[i++] ] << 4;
+				while(i<len && !isxdigit(input[i]))
+					i++;
+				if(i == len) {
+					data->partial = byte;
+					data->has_partial = 1;
+					break;
+				}
+				outdata[out_cnt++] = byte | hextable[ input[i] ];
+		}
+	}
+
+	out_data = outdata;
+	while(out_data && out_cnt) {
+		switch(data->internal_state) {
+			case WAIT_MAGIC: {
+						 cli_dbgmsg("RTF: waiting for magic\n");
+						 for(i=0; i<out_cnt && data->bread < rtf_data_magic_len; i++, data->bread++)
+							 if(rtf_data_magic[data->bread] != out_data[i]) {
+								 cli_dbgmsg("Warning: rtf objdata magic number not matched, expected:%d, got: %d, at pos:%lu\n",rtf_data_magic[i],out_data[i],data->bread);
+							 }
+						 out_cnt  -= i;
+						 if(data->bread == rtf_data_magic_len) {
+							 out_data += i;
+							 data->bread = 0;
+							 data->internal_state = WAIT_DESC_LEN;						 
+						 }
+						 break;
+					 }
+			case WAIT_DESC_LEN: {
+						    if(data->bread == 0)
+							    data->desc_len = 0;
+						    for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++)
+							    data->desc_len  |=  ((size_t)out_data[i]) << (data->bread*8);
+						    out_cnt  -= i;
+						    if(data->bread == 4) {
+							    out_data += i;
+							    data->bread=0;
+							    if(data->desc_len > 64) {
+								    cli_dbgmsg("Description length too big (%lu), showing only 64 bytes of it\n",data->desc_len);
+								    data->desc_name = cli_malloc(65);
+							    }
+							    else
+								    data->desc_name = cli_malloc(data->desc_len+1);
+							    if(!data->desc_name) {
+								    return CL_EMEM;
+							    }
+							    data->internal_state = WAIT_DESC;
+							    cli_dbgmsg("RTF: description length:%lu\n",data->desc_len);
+						    }
+						    break;
+					    }
+			case WAIT_DESC:{
+					       cli_dbgmsg("RTF: in WAIT_DESC\n");
+					       for(i=0;i<out_cnt && data->bread < data->desc_len && data->bread < 64;i++, data->bread++)
+						       data->desc_name[data->bread] = out_data[i];
+					       out_cnt -= i;
+					       out_data += i;
+					       if(data->bread < data->desc_len && data->bread < 64) {
+						       cli_dbgmsg("RTF: waiting for more data(1)\n");
+						       return 0;/* wait for more data */
+					       }
+						       data->desc_name[data->bread] = '\0';
+					       if(data->desc_len - data->bread > out_cnt) {
+						       data->desc_len -= out_cnt;
+						       cli_dbgmsg("RTF: waiting for more data(2)\n");
+						       return 0;/* wait for more data */
+					       }
+					       out_cnt  -= data->desc_len - data->bread;
+					       if(data->bread >= data->desc_len) {
+						       out_data += data->desc_len - data->bread;
+						       data->bread = 0;
+						       cli_dbgmsg("Preparing to dump rtf embedded object, description:%s\n",data->desc_name);
+						       free(data->desc_name);
+						       data->desc_name = NULL;
+						       data->internal_state = WAIT_ZERO;
+					       }
+					       break;
+				       }
+			case WAIT_ZERO:{
+					       if(out_cnt < 8-data->bread) {
+						       out_cnt = 0;
+						       data->bread += out_cnt;
+					       }
+					       else {
+						       out_cnt  -= 8-data->bread;
+						       data->bread = 8;
+					       }
+					       if(data->bread == 8) {
+						       out_data += 8;
+						       data->bread = 0;
+						       cli_dbgmsg("RTF: next state: wait_data_size\n");
+						       data->internal_state = WAIT_DATA_SIZE;
+					       }
+					       break;
+				       }
+
+			case WAIT_DATA_SIZE: {
+						     cli_dbgmsg("RTF: in WAIT_DATA_SIZE\n");
+						    if(data->bread == 0)
+							    data->desc_len = 0;
+						    for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++)
+							    data->desc_len  |= ((size_t)out_data[i]) << (8*data->bread);
+						    out_cnt  -= i;
+						    if(data->bread == 4) {
+							    out_data += i;
+							    data->bread=0;
+							    cli_dbgmsg("Dumping rtf embedded object of size:%lu\n",data->desc_len);
+							    if((ret = cli_gentempfd(data->tmpdir, &data->name, &data->fd)))
+								    return ret;
+							    data->internal_state = DUMP_DATA;
+	    						    cli_dbgmsg("RTF: next state: DUMP_DATA\n");
+						    }
+						    break;
+					     }
+			case DUMP_DATA: {
+						ssize_t out_want = out_cnt < data->desc_len ? out_cnt : data->desc_len;
+						if(!data->bread) {
+							if(out_data[0] != 0xd0 || out_data[1]!=0xcf) {
+								/* this is not an ole2 doc, but some ole (stream?) to be
+								 * decoded by cli_decode_ole_object*/
+							    char out[4];
+							    data->bread = 1;/* flag to indicate this needs to be scanned with cli_decode_ole_object*/
+							    cli_writeint32(out,data->desc_len);
+							    if(cli_writen(data->fd,out,4)!=4)
+								    return CL_EIO; 
+							}
+							else
+								data->bread = 2;
+						}
+
+						data->desc_len -= out_want;
+						if(cli_writen(data->fd,out_data,out_want) != out_want) {
+							return CL_EIO;
+						}
+						out_data += out_want;
+						out_cnt  -= out_want;
+						if(!data->desc_len) { 
+							int rc;
+							if(( rc = decode_and_scan(data, data->ctx) ))
+								return rc;
+							data->bread=0;
+							data->internal_state = WAIT_MAGIC;
+						}
+						break;					
+					}				    
+			case DUMP_DISCARD:
+			default:
+					out_cnt = 0;
+					;
+		}
+	}
+	return 0;
+}
+
+
+
+static int rtf_object_end(struct rtf_state* state,cli_ctx* ctx)
+{
+	struct rtf_object_data* data = state->cb_data;
+	int rc = 0;
+	if(!data)
+		return 0;
+	if(data->fd > 0) { 
+		rc = decode_and_scan(data, ctx);
+	}
+	if(data->name)
+		free(data->name);
+	if(data->desc_name)
+		free(data->desc_name);
+	free(data);
+	state->cb_data = NULL;
+	return rc;
+}
+
+
+static void rtf_action(struct rtf_state* state,long action)
+{
+	switch(action) {
+		case RTF_OBJECT:
+			state->encounteredTopLevel |= 1<<RTF_OBJECT;
+			break;
+		case RTF_OBJECT_DATA:
+			if(state->encounteredTopLevel & (1<<RTF_OBJECT) ) {
+				state->cb_begin = rtf_object_begin;
+				state->cb_process = rtf_object_process;
+				state->cb_end = rtf_object_end;
+			}
+			break;
+	};
+}
+
+static void cleanup_stack(struct stack* stack,struct rtf_state* state,cli_ctx* ctx)
+{
+	while(stack && stack->stack_cnt /* && state->default_elements*/) {
+		pop_state(stack,state);
+		if(state->cb_data && state->cb_end)
+			state->cb_end(state,ctx);
+	}
+}
+
+
+#define SCAN_CLEANUP \
+	if(state.cb_data && state.cb_end)\
+		state.cb_end(&state,ctx);\
+	tableDestroy(actiontable);\
+	cleanup_stack(&stack,&state,ctx);\
+	free(buff);\
+        if(!cli_leavetemps_flag)\
+		cli_rmdirs(tempname);\
+	free(tempname);\
+	free(stack.states);
+
+int cli_scanrtf(int desc, cli_ctx *ctx)
+{
+	char* tempname;
+	const unsigned char* ptr;
+	const unsigned char* ptr_end;
+	unsigned char* buff;
+	int ret = CL_CLEAN;
+	struct rtf_state state;
+	struct stack stack;
+	ssize_t bread;
+	table_t* actiontable;
+	uint8_t main_symbols[256];
+
+	cli_dbgmsg("in cli_scanrtf()\n");
+
+	memset(main_symbols, 0, 256);
+	main_symbols['{']=1;
+	main_symbols['}']=1;
+	main_symbols['\\']=1;
+
+	stack.stack_cnt = 0;
+	stack.stack_size = 16;
+	stack.elements = 0;
+	stack.warned = 0;
+	stack.states = cli_malloc(stack.stack_size*sizeof(*stack.states));
+
+	if(!stack.states)
+		return CL_EMEM;
+
+	buff = cli_malloc(BUFF_SIZE);
+	if(!buff) {
+		free(stack.states);
+		return CL_EMEM;
+	}
+
+	tempname = cli_gentemp(NULL);
+
+	if(mkdir(tempname, 0700)) {
+	    	cli_dbgmsg("ScanRTF -> Can't create temporary directory %s\n", tempname);
+		free(stack.states);
+		free(buff);
+		free(tempname);
+		return CL_ETMPDIR;
+	}
+
+	actiontable = tableCreate();
+	if((ret = load_actions(actiontable))) {
+		cli_dbgmsg("RTF: Unable to load rtf action table\n");
+		free(stack.states);
+		free(buff);
+		if(!cli_leavetemps_flag)
+			cli_rmdirs(tempname);
+		free(tempname);
+		tableDestroy(actiontable);
+		return ret;
+	}
+
+	init_rtf_state(&state);
+
+	while(( bread = cli_readn(desc, buff, BUFF_SIZE) ) > 0) {
+		ptr = buff;
+		ptr_end = buff + bread;
+		while(ptr < ptr_end) {
+			switch(state.parse_state) {
+				case PARSE_MAIN: 
+					switch(*ptr++) {
+						case '{':
+							if(( ret = push_state(&stack,&state) )) {
+								cli_dbgmsg("RTF:Push failure!\n");
+								SCAN_CLEANUP;
+								return ret;
+							}
+							break;
+						case '}':
+							if(state.cb_data && state.cb_end)
+								if(( ret = state.cb_end(&state, ctx) )) {
+									SCAN_CLEANUP;
+									return ret;
+								}
+							if(( ret = pop_state(&stack,&state) )) {
+								cli_dbgmsg("RTF:pop failure!\n");
+								SCAN_CLEANUP;
+								return ret;
+							}
+							break;
+						case '\\':
+							state.parse_state = PARSE_CONTROL_;
+							break;
+						default:
+							ptr--;
+							{
+								size_t i;
+								size_t left = ptr_end - ptr;
+								size_t use = left;
+								for(i = 1;i < left; i++)
+									if(main_symbols[ptr[i]]) {
+										use = i;
+										break;
+									}
+								if(state.cb_begin) {
+									if(!state.cb_data)
+										 if(( ret = state.cb_begin(&state, ctx,tempname) )) {
+											 SCAN_CLEANUP;
+											 return ret;
+										}
+									if(( ret = state.cb_process(&state, ptr, use) )) {
+										if(state.cb_end) {
+											state.cb_end(&state,ctx);
+										}
+										SCAN_CLEANUP;
+										return ret;
+									}
+								}
+								ptr += use;
+							}
+					}
+					break;
+				case PARSE_CONTROL_:					
+					if(isalpha(*ptr))  {
+						state.parse_state = PARSE_CONTROL_WORD;
+						state.controlword_cnt = 0;
+					}
+					else
+						state.parse_state = PARSE_CONTROL_SYMBOL;
+					break;
+				case PARSE_CONTROL_SYMBOL:
+					ptr++;	/* Do nothing */
+					state.parse_state = PARSE_MAIN;
+					break;
+				case PARSE_CONTROL_WORD:
+					if(state.controlword_cnt == 32) {
+						cli_dbgmsg("Invalid control word: maximum size exceeded:%s\n",state.controlword);
+						state.parse_state = PARSE_MAIN;
+					}
+					else if(isalpha(*ptr))
+						state.controlword[state.controlword_cnt++] = *ptr++;
+					else {
+						if(isspace(*ptr)) {
+							state.controlword[state.controlword_cnt++] = *ptr++;
+							state.parse_state = PARSE_INTERPRET_CONTROLWORD;
+						}
+						else if (isdigit(*ptr)) {
+							state.parse_state = PARSE_CONTROL_WORD_PARAM;
+							state.controlword_param = 0;
+							state.controlword_param_sign = 1;
+						}
+						else if(*ptr == '-') {
+							ptr++;
+							state.parse_state = PARSE_CONTROL_WORD_PARAM;
+							state.controlword_param = 0;
+							state.controlword_param_sign = -1;
+						}
+						else {
+							state.parse_state = PARSE_INTERPRET_CONTROLWORD;
+						}
+					}
+					break;
+				case PARSE_CONTROL_WORD_PARAM:
+					if(isdigit(*ptr)) {
+						state.controlword_param = state.controlword_param*10 + *ptr++ - '0';
+					}
+					else if(isalpha(*ptr)) {
+						ptr++;
+					}
+					else {
+						if(state.controlword_param_sign < 0)
+							state.controlword_param = -state.controlword_param;
+						state.parse_state = PARSE_INTERPRET_CONTROLWORD;
+					}
+					break;
+				case PARSE_INTERPRET_CONTROLWORD:
+					{
+						int action;
+
+						state.controlword[state.controlword_cnt] = '\0';
+						action = tableFind(actiontable, state.controlword);
+						if(action != -1) {
+							if(state.cb_data && state.cb_end) {/* premature end of previous block */
+								state.cb_end(&state,ctx);
+								state.cb_begin = NULL;
+								state.cb_end = NULL;
+								state.cb_data = NULL;
+							}
+							rtf_action(&state,action);
+						}
+						state.parse_state = PARSE_MAIN;
+						break;
+					}
+			}
+		}
+	}
+
+	SCAN_CLEANUP;
+	return ret;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,2326 @@
+/*
+ *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef	HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <fcntl.h>
+#ifndef	C_WINDOWS
+#include <dirent.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_MMAP
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#else /* HAVE_SYS_MMAN_H */
+#undef HAVE_MMAP
+#endif
+#endif
+
+#ifndef	O_BINARY
+#define	O_BINARY	0
+#endif
+
+
+#define DCONF_ARCH  ctx->dconf->archive
+#define DCONF_DOC   ctx->dconf->doc
+#define DCONF_MAIL  ctx->dconf->mail
+#define DCONF_OTHER ctx->dconf->other
+
+#include "clamav.h"
+#include "others.h"
+#include "dconf.h"
+#include "scanners.h"
+#include "matcher-ac.h"
+#include "matcher-bm.h"
+#include "matcher.h"
+#include "ole2_extract.h"
+#include "vba_extract.h"
+#include "msexpand.h"
+#include "mbox.h"
+#include "chmunpack.h"
+#include "pe.h"
+#include "elf.h"
+#include "filetypes.h"
+#include "htmlnorm.h"
+#include "untar.h"
+#include "special.h"
+#include "binhex.h"
+/* #include "uuencode.h" */
+#include "tnef.h"
+#include "pst.h"
+#include "sis.h"
+#include "pdf.h"
+#include "str.h"
+#include "mspack.h"
+#include "cab.h"
+#include "rtf.h"
+#include "unarj.h"
+#include "nulsft.h"
+#include "autoit.h"
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#include "unzip.h"
+#endif
+
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+
+#ifdef ENABLE_UNRAR
+#include "unrar_iface.h"
+#endif
+
+#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
+#include <limits.h>
+#include <stddef.h>
+#endif
+
+#define MAX_MAIL_RECURSION  15
+
+
+static int cli_scanfile(const char *filename, cli_ctx *ctx);
+
+#ifdef ENABLE_UNRAR
+static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
+{
+	int ret = CL_SUCCESS;
+	struct cli_meta_node* mdata;
+
+
+    if(files == 1 && sfx_check) {
+	if(*sfx_check == metadata->crc)
+	    return CL_BREAK;/* break extract loop */
+	else
+	    *sfx_check = metadata->crc;
+    }
+
+    cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u (max: %u)\n",
+	metadata->filename, metadata->crc, metadata->encrypted, (unsigned int) metadata->pack_size,
+	(unsigned int) metadata->unpack_size, metadata->method,
+	metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0, ctx->limits ? ctx->limits->maxratio : 0);
+
+    /* Scan metadata */
+    mdata = ctx->engine->rar_mlist;
+    if(mdata) do {
+	if(mdata->encrypted != metadata->encrypted)
+	    continue;
+
+	if(mdata->crc32 && (unsigned int) mdata->crc32 != metadata->crc)
+	    continue;
+
+	if(mdata->csize > 0 && (unsigned int) mdata->csize != metadata->pack_size)
+	    continue;
+
+	if(mdata->size >= 0 && (unsigned int) mdata->size != metadata->unpack_size)
+	    continue;
+
+	if(mdata->method >= 0 && mdata->method != metadata->method)
+	    continue;
+
+	if(mdata->fileno && mdata->fileno != files)
+	    continue;
+
+	if(mdata->maxdepth && ctx->arec > mdata->maxdepth)
+	    continue;
+
+	/* TODO add support for regex */
+	/*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
+	if(mdata->filename && strcmp((char *) metadata->filename, mdata->filename))
+	    continue;
+
+	break; /* matched */
+
+    } while((mdata = mdata->next));
+
+    if(mdata) {
+	*ctx->virname = mdata->virname;
+	return CL_VIRUS;	   
+    }
+
+    if(DETECT_ENCRYPTED && metadata->encrypted) {
+	cli_dbgmsg("RAR: Encrypted files found in archive.\n");
+	lseek(desc, 0, SEEK_SET);
+	ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL);
+	if(ret != CL_VIRUS) {
+	    *ctx->virname = "Encrypted.RAR";
+	    return CL_VIRUS;
+	}
+    }
+
+/*
+    TROG - TODO: multi-volume files
+    if((rarlist->item.Flags & 0x03) != 0) {
+	cli_dbgmsg("RAR: Skipping %s (split)\n", rarlist->item.Name);
+	rarlist = rarlist->next;
+	continue;
+    }
+*/
+    return ret;
+}
+
+static int cli_unrar_checklimits(const cli_ctx *ctx, const unrar_metadata_t *metadata, unsigned int files)
+{
+    if(ctx->limits) {
+	if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) {
+	    if(metadata->unpack_size / metadata->pack_size >= ctx->limits->maxratio) {
+		cli_dbgmsg("RAR: Max ratio reached (%u, max: %u)\n", (unsigned int) (metadata->unpack_size / metadata->pack_size), ctx->limits->maxratio);
+		if(BLOCKMAX) {
+		    *ctx->virname = "Oversized.RAR";
+		    return CL_VIRUS;
+		}
+		return CL_EMAXSIZE;
+	    }
+	}
+
+	if(ctx->limits->maxfilesize && (metadata->unpack_size > ctx->limits->maxfilesize)) {
+	    cli_dbgmsg("RAR: %s: Size exceeded (%lu, max: %lu)\n", metadata->filename, (unsigned long int) metadata->unpack_size, ctx->limits->maxfilesize);
+	    if(BLOCKMAX) {
+		*ctx->virname = "RAR.ExceededFileSize";
+		return CL_VIRUS;
+	    }
+	    return CL_EMAXSIZE;
+	}
+
+	if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+	    cli_dbgmsg("RAR: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+	    if(BLOCKMAX) {
+		*ctx->virname = "RAR.ExceededFilesLimit";
+		return CL_VIRUS;
+	    }
+	    return CL_EMAXFILES;
+	}
+    }
+
+    return CL_SUCCESS;
+}
+
+static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
+{
+	int ret = CL_CLEAN;
+	unrar_metadata_t *metadata, *metadata_tmp;
+	char *dir;
+	unrar_state_t rar_state;
+
+
+    cli_dbgmsg("in scanrar()\n");
+
+    /* generate the temporary directory */
+    dir = cli_gentemp(NULL);
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    if(sfx_offset)
+	lseek(desc, sfx_offset, SEEK_SET);
+
+    if((ret = unrar_open(desc, dir, &rar_state)) != UNRAR_OK) {
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(dir);
+	free(dir);
+	if(ret == UNRAR_EMEM)
+	    return CL_EMEM;
+	else
+	    return CL_ERAR;
+    }
+
+    do {
+	int rc;
+	rar_state.ofd = -1;
+	ret = unrar_extract_next_prepare(&rar_state,dir);
+	if(ret != UNRAR_OK) {
+	    if(ret == UNRAR_BREAK)
+		ret = CL_BREAK;
+	    else if(ret == UNRAR_EMEM)
+		ret = CL_EMEM;
+	    else
+		ret = CL_ERAR;
+	    break;
+	}
+	ret = cli_unrar_checklimits(ctx, rar_state.metadata_tail, rar_state.file_count);
+	if(ret && ret != CL_VIRUS) {
+	    free(rar_state.file_header->filename);
+	    free(rar_state.file_header);
+	    ret = CL_CLEAN;
+	    continue;
+	} else if(ret == CL_VIRUS) {
+	    /* needed since we didn't reach unrar_extract_next to clean this up*/
+	    free(rar_state.file_header->filename);
+	    free(rar_state.file_header);	   
+	    break;
+	}
+	ret = unrar_extract_next(&rar_state,dir);
+	if(ret == UNRAR_OK)
+	    ret = CL_SUCCESS;
+	else if(ret == UNRAR_EMEM)
+	    ret = CL_EMEM;
+	else
+	    ret = CL_ERAR;
+
+	if(rar_state.ofd > 0) {
+	    lseek(rar_state.ofd,0,SEEK_SET);
+	    rc = cli_magic_scandesc(rar_state.ofd,ctx);
+	    close(rar_state.ofd);
+	    if(!cli_leavetemps_flag) 
+		unlink(rar_state.filename);
+	    if(rc == CL_VIRUS ) {
+		cli_dbgmsg("RAR: infected with %s\n",*ctx->virname);
+		ret = CL_VIRUS;
+		break;
+	    }
+	}
+
+	if(ret == CL_SUCCESS)
+	    ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
+
+    } while(ret == CL_SUCCESS);
+
+    if(ret == CL_BREAK)
+	ret = CL_CLEAN;
+
+    metadata = metadata_tmp = rar_state.metadata; 
+
+    if(cli_scandir(rar_state.comment_dir, ctx) == CL_VIRUS)
+	ret = CL_VIRUS;
+
+    unrar_close(&rar_state);
+
+    if(!cli_leavetemps_flag)
+        cli_rmdirs(dir);
+
+    free(dir);
+
+    metadata = metadata_tmp;
+    while (metadata) {
+    	metadata_tmp = metadata->next;
+    	free(metadata->filename);
+    	free(metadata);
+    	metadata = metadata_tmp;
+    }
+    cli_dbgmsg("RAR: Exit code: %d\n", ret);
+
+    return ret;
+}
+#endif /* ENABLE_UNRAR */
+
+static int cli_unarj_checklimits(const cli_ctx *ctx, const arj_metadata_t *metadata, unsigned int files)
+{
+    if (ctx->limits) {
+	if (ctx->limits->maxfilesize && (metadata->orig_size > ctx->limits->maxfilesize)) {
+	    cli_dbgmsg("ARJ: %s: Size exceeded (%lu, max: %lu)\n", metadata->filename ? metadata->filename : "(none)",
+	    		(unsigned long int) metadata->orig_size, ctx->limits->maxfilesize);
+	    if (BLOCKMAX) {
+		*ctx->virname = "ARJ.ExceededFileSize";
+		return CL_VIRUS;
+	    }
+	    return CL_EMAXSIZE;
+	}
+	
+	if (ctx->limits->maxratio && metadata->orig_size && metadata->comp_size) {
+	    if (metadata->orig_size / metadata->comp_size >= ctx->limits->maxratio) {
+		cli_dbgmsg("ARJ: Max ratio reached (%u, max: %u)\n", (unsigned int) (metadata->orig_size / metadata->comp_size), ctx->limits->maxratio);
+		if (ctx->limits->maxfilesize && (metadata->orig_size <= ctx->limits->maxfilesize)) {
+		    cli_dbgmsg("ARJ: Ignoring ratio limit (file size doesn't hit limits)\n");
+		} else {
+		    if(BLOCKMAX) {
+		    	*ctx->virname = "Oversized.ARJ";
+			return CL_VIRUS;
+		    }
+		}
+	    }
+	}
+	
+	if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+	    cli_dbgmsg("ARJ: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+	    if (BLOCKMAX) {
+	    	*ctx->virname = "ARJ.ExceededFilesLimit";
+		return CL_VIRUS;
+	    }
+	    return CL_EMAXFILES;
+	}
+    }
+    
+    return CL_SUCCESS;
+}
+
+static int cli_scanarj(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
+{
+	int ret = CL_CLEAN, rc;
+	arj_metadata_t metadata;
+	char *dir;
+	unsigned int file_count = 1;
+
+    cli_dbgmsg("in cli_scanarj()\n");
+
+     /* generate the temporary directory */
+    dir = cli_gentemp(NULL);
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    if(sfx_offset)
+	lseek(desc, sfx_offset, SEEK_SET);
+
+    ret = cli_unarj_open(desc, dir);
+    if (ret != CL_SUCCESS) {
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(dir);
+	free(dir);
+	cli_dbgmsg("ARJ: Error: %s\n", cl_strerror(ret));
+	return ret;
+    }
+    
+   metadata.filename = NULL;
+
+   do {
+	ret = cli_unarj_prepare_file(desc, dir, &metadata);
+	if (ret != CL_SUCCESS) {
+	   break;
+	}
+	ret = cli_unarj_checklimits(ctx, &metadata, file_count);
+	if (ret == CL_VIRUS) {
+		break;
+	}
+	ret = cli_unarj_extract_file(desc, dir, &metadata);
+	if (metadata.ofd >= 0) {
+	    lseek(metadata.ofd, 0, SEEK_SET);
+	    rc = cli_magic_scandesc(metadata.ofd, ctx);
+	    close(metadata.ofd);
+	    if (rc == CL_VIRUS) {
+		cli_dbgmsg("ARJ: infected with %s\n",*ctx->virname);
+		ret = CL_VIRUS;
+		break;
+	    }
+	}
+	if (metadata.filename) {
+		free(metadata.filename);
+		metadata.filename = NULL;
+	}
+
+    } while(ret == CL_SUCCESS);
+    
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    if (metadata.filename) {
+	free(metadata.filename);
+    }
+
+    cli_dbgmsg("ARJ: Exit code: %d\n", ret);
+    if (ret == CL_BREAK)
+	ret = CL_CLEAN;
+
+    return ret;
+}
+#ifdef HAVE_ZLIB_H
+static int cli_scanzip(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
+{
+	zip_dir *zdir;
+	zip_dirent zdirent;
+	zip_file *zfp;
+	char *tmpname = NULL, *buff;
+	int fd = -1, bytes, ret = CL_CLEAN;
+	unsigned long int size = 0;
+	unsigned int files = 0, encrypted, bfcnt;
+	struct stat source;
+	struct cli_meta_node *mdata;
+	int err;
+	uint8_t swarning = 0, fail, success;
+
+
+    cli_dbgmsg("in scanzip()\n");
+
+    if((zdir = zip_dir_open(desc, sfx_offset, &err)) == NULL) {
+	cli_dbgmsg("Zip: zip_dir_open() return code: %d\n", err);
+	/* no return with CL_EZIP due to password protected zips */
+	return CL_CLEAN;
+    }
+
+    fstat(desc, &source);
+
+    if(!(buff = (char *) cli_malloc(FILEBUFF))) {
+	cli_dbgmsg("Zip: unable to malloc(%u)\n", FILEBUFF);
+	zip_dir_close(zdir);
+	return CL_EMEM;
+    }
+
+    while(zip_dir_read(zdir, &zdirent)) {
+	files++;
+
+	if(files == 1 && sfx_check) {
+	    if(*sfx_check == zdirent.d_crc32)
+		break;
+	    else
+		*sfx_check = zdirent.d_crc32;
+	}
+
+	if(!zdirent.d_name) {
+	    cli_dbgmsg("Zip: zdirent.d_name == NULL\n");
+	    *ctx->virname = "Suspect.Zip";
+	    ret = CL_VIRUS;
+	    break;
+	}
+
+        /* Bit 0: file is encrypted
+	 * Bit 6: Strong encryption was used
+	 * Bit 13: Encrypted central directory
+	 */
+	encrypted = ((zdirent.d_flags & 0x2041) != 0);
+
+	cli_dbgmsg("Zip: %s, crc32: 0x%x, offset: %u, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u (max: %u)\n", zdirent.d_name, zdirent.d_crc32, zdirent.d_off, encrypted, zdirent.d_csize, zdirent.st_size, zdirent.d_compr, zdirent.d_csize ? (zdirent.st_size / zdirent.d_csize) : 0, ctx->limits ? ctx->limits->maxratio : 0);
+
+	if(!zdirent.st_size) {
+	    if(zdirent.d_crc32) {
+		cli_dbgmsg("Zip: Broken file or modified information in local header part of archive\n");
+		*ctx->virname = "Exploit.Zip.ModifiedHeaders";
+		ret = CL_VIRUS;
+		break;
+	    }
+	    continue;
+	}
+
+	/* Scan metadata */
+	mdata = ctx->engine->zip_mlist;
+	if(mdata) do {
+	    if(mdata->encrypted != encrypted)
+		continue;
+
+	    if(mdata->crc32 && mdata->crc32 != zdirent.d_crc32)
+		continue;
+
+	    if(mdata->csize > 0 && (uint32_t) mdata->csize != zdirent.d_csize)
+		continue;
+
+	    if(mdata->size >= 0 && (uint32_t) mdata->size != zdirent.st_size)
+		continue;
+
+	    if(mdata->method >= 0 && (uint16_t) mdata->method != zdirent.d_compr)
+		continue;
+
+	    if(mdata->fileno && mdata->fileno != files)
+		continue;
+
+	    if(mdata->maxdepth && ctx->arec > mdata->maxdepth)
+		continue;
+
+	    /* TODO add support for regex */
+	    /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
+	    if(mdata->filename && strcmp(zdirent.d_name, mdata->filename))
+		continue;
+
+	    break; /* matched */
+
+	} while((mdata = mdata->next));
+
+	if(mdata) {
+	    *ctx->virname = mdata->virname;
+	    ret = CL_VIRUS;
+	    break;
+	}
+
+	/* 
+	 * Workaround for archives created with ICEOWS.
+	 * ZZIP_DIRENT does not contain information on file type
+	 * so we try to determine a directory via a filename
+	 */
+	if(zdirent.d_name[strlen(zdirent.d_name) - 1] == '/') {
+	    cli_dbgmsg("Zip: Directory entry with st_size != 0\n");
+	    continue;
+	}
+
+	if(!zdirent.d_csize) {
+	    cli_dbgmsg("Zip: Malformed file (d_csize == 0 but st_size != 0)\n");
+	    *ctx->virname = "Suspect.Zip";
+	    ret = CL_VIRUS;
+	    break;
+	}
+
+	if(ctx->limits && ctx->limits->maxratio > 0 && ((unsigned) zdirent.st_size / (unsigned) zdirent.d_csize) >= ctx->limits->maxratio) {
+	    *ctx->virname = "Oversized.Zip";
+	    ret = CL_VIRUS;
+	    break;
+        }
+
+	if(encrypted) {
+	    if(DETECT_ENCRYPTED) {
+		cli_dbgmsg("Zip: Encrypted files found in archive.\n");
+		lseek(desc, 0, SEEK_SET);
+		ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL);
+		if(ret < 0) {
+		    break;
+		} else if(ret != CL_VIRUS) {
+		    *ctx->virname = "Encrypted.Zip";
+		    ret = CL_VIRUS;
+		}
+		break;
+	    } else continue;
+	}
+
+	if(ctx->limits) {
+	    if(ctx->limits->maxfilesize && ((unsigned int) zdirent.st_size > ctx->limits->maxfilesize)) {
+		cli_dbgmsg("Zip: %s: Size exceeded (%u, max: %lu)\n", zdirent.d_name, zdirent.st_size, ctx->limits->maxfilesize);
+		/* ret = CL_EMAXSIZE; */
+		if(BLOCKMAX) {
+		    *ctx->virname = "Zip.ExceededFileSize";
+		    ret = CL_VIRUS;
+		    break;
+		}
+		continue; /* continue scanning */
+	    }
+
+	    if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+		cli_dbgmsg("Zip: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+		if(BLOCKMAX) {
+		    *ctx->virname = "Zip.ExceededFilesLimit";
+		    ret = CL_VIRUS;
+		    break;
+		}
+		break;
+	    }
+	}
+
+	if((zfp = zip_file_open(zdir, zdirent.d_name, zdirent.d_off)) == NULL) {
+	    if(zdir->errcode == CL_ESUPPORT) {
+		ret = CL_ESUPPORT;
+		if(!swarning) {
+		    cli_warnmsg("Not supported compression method in one or more files\n");
+		    swarning = 1;
+		}
+		continue;
+	    } else {
+		cli_dbgmsg("Zip: Can't open file %s\n", zdirent.d_name);
+		ret = CL_EZIP;
+		break;
+	    }
+	}
+
+	bfcnt = 0;
+	success = 0;
+	while(1) {
+	    fail = 0;
+
+	    if((ret = cli_gentempfd(NULL, &tmpname, &fd)))
+		break;
+
+	    size = 0;
+	    while((bytes = zip_file_read(zfp, buff, FILEBUFF)) > 0) {
+		size += bytes;
+		if(cli_writen(fd, buff, bytes) != bytes) {
+		    cli_dbgmsg("Zip: Can't write to file.\n");
+		    ret = CL_EIO;
+		    break;
+		}
+	    }
+
+	    if(!encrypted) {
+		if(size != zdirent.st_size) {
+		    cli_dbgmsg("Zip: Incorrectly decompressed (%lu != %lu)\n", size, (unsigned long int) zdirent.st_size);
+		    if(zfp->bf[0] == -1) {
+			ret = CL_EZIP;
+			break;
+		    } else {
+			fail = 1;
+		    }
+		} else {
+		    cli_dbgmsg("Zip: File decompressed to %s\n", tmpname);
+		    success = 1;
+		}
+	    }
+
+	    if(!fail) {
+		if(fsync(fd) == -1) {
+		    cli_dbgmsg("Zip: fsync() failed\n");
+		    ret = CL_EFSYNC;
+		    break;
+		}
+		lseek(fd, 0, SEEK_SET);
+
+		if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
+		    cli_dbgmsg("Zip: Infected with %s\n", *ctx->virname);
+		    ret = CL_VIRUS;
+		    break;
+		}
+	    }
+
+	    close(fd);
+	    if(!cli_leavetemps_flag)
+		unlink(tmpname);
+	    free(tmpname);
+	    fd = -1;
+
+	    if(zfp->bf[bfcnt] == -1)
+		break;
+
+	    zfp->method = (uint16_t) zfp->bf[bfcnt];
+	    cli_dbgmsg("Zip: Brute force mode - checking compression method %u\n", zfp->method);
+	    bfcnt++;
+	}
+	zip_file_close(zfp);
+
+
+	if(!ret && !encrypted && !success) { /* brute-force decompression failed */
+	    cli_dbgmsg("Zip: All attempts to decompress file failed\n");
+	    ret = CL_EZIP;
+	}
+
+	if(ret) 
+	    break;
+    }
+
+    zip_dir_close(zdir);
+    if(fd != -1) {
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);
+    }
+
+    free(buff);
+    return ret;
+}
+
+static int cli_scangzip(int desc, cli_ctx *ctx)
+{
+	int fd, bytes, ret = CL_CLEAN;
+	unsigned long int size = 0;
+	char *buff;
+	char *tmpname;
+	gzFile gd;
+
+
+    cli_dbgmsg("in cli_scangzip()\n");
+
+    if((gd = gzdopen(dup(desc), "rb")) == NULL) {
+	cli_dbgmsg("GZip: Can't open descriptor %d\n", desc);
+	return CL_EGZIP;
+    }
+
+    if((ret = cli_gentempfd(NULL, &tmpname, &fd))) {
+	cli_dbgmsg("GZip: Can't generate temporary file.\n");
+	gzclose(gd);
+	return ret;
+    }
+
+    if(!(buff = (char *) cli_malloc(FILEBUFF))) {
+	cli_dbgmsg("GZip: Unable to malloc %u bytes.\n", FILEBUFF);
+	gzclose(gd);
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_EMEM;
+    }
+
+    while((bytes = gzread(gd, buff, FILEBUFF)) > 0) {
+	size += bytes;
+
+	if(ctx->limits)
+	    if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
+		cli_dbgmsg("GZip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
+		if(BLOCKMAX) {
+		    *ctx->virname = "GZip.ExceededFileSize";
+		    ret = CL_VIRUS;
+		}
+		break;
+	    }
+
+	if(cli_writen(fd, buff, bytes) != bytes) {
+	    cli_dbgmsg("GZip: Can't write to file.\n");
+	    close(fd);
+	    if(!cli_leavetemps_flag)
+		unlink(tmpname);
+	    free(tmpname);	
+	    gzclose(gd);
+	    free(buff);
+	    return CL_EGZIP;
+	}
+    }
+
+    free(buff);
+    gzclose(gd);
+
+    if(ret == CL_VIRUS) {
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return ret;
+    }
+
+    if(fsync(fd) == -1) {
+	cli_dbgmsg("GZip: Can't synchronise descriptor %d\n", fd);
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_EFSYNC;
+    }
+
+    lseek(fd, 0, SEEK_SET);
+    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
+	cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_VIRUS;
+    }
+    close(fd);
+    if(!cli_leavetemps_flag)
+	unlink(tmpname);
+    free(tmpname);	
+
+    return ret;
+}
+#endif
+
+#ifdef HAVE_BZLIB_H
+
+#ifdef NOBZ2PREFIX
+#define BZ2_bzReadOpen bzReadOpen
+#define BZ2_bzReadClose bzReadClose
+#define BZ2_bzRead bzRead
+#endif
+
+static int cli_scanbzip(int desc, cli_ctx *ctx)
+{
+	int fd, bytes, ret = CL_CLEAN, bzerror = 0;
+	short memlim = 0;
+	unsigned long int size = 0;
+	char *buff;
+	FILE *fs;
+	char *tmpname;
+	BZFILE *bfd;
+
+
+    if((fs = fdopen(dup(desc), "rb")) == NULL) {
+	cli_dbgmsg("Bzip: Can't open descriptor %d.\n", desc);
+	return CL_EBZIP;
+    }
+
+    if(ctx->limits)
+	if(ctx->limits->archivememlim)
+	    memlim = 1;
+
+    if((bfd = BZ2_bzReadOpen(&bzerror, fs, 0, memlim, NULL, 0)) == NULL) {
+	cli_dbgmsg("Bzip: Can't initialize bzip2 library (descriptor: %d).\n", desc);
+	fclose(fs);
+	return CL_EBZIP;
+    }
+
+    if((ret = cli_gentempfd(NULL, &tmpname, &fd))) {
+	cli_dbgmsg("Bzip: Can't generate temporary file.\n");
+	BZ2_bzReadClose(&bzerror, bfd);
+	fclose(fs);
+	return ret;
+    }
+
+    if(!(buff = (char *) cli_malloc(FILEBUFF))) {
+	cli_dbgmsg("Bzip: Unable to malloc %u bytes.\n", FILEBUFF);
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	fclose(fs);
+	BZ2_bzReadClose(&bzerror, bfd);
+	return CL_EMEM;
+    }
+
+    while((bytes = BZ2_bzRead(&bzerror, bfd, buff, FILEBUFF)) > 0) {
+	size += bytes;
+
+	if(ctx->limits)
+	    if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
+		cli_dbgmsg("Bzip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
+		if(BLOCKMAX) {
+		    *ctx->virname = "BZip.ExceededFileSize";
+		    ret = CL_VIRUS;
+		}
+		break;
+	    }
+
+	if(cli_writen(fd, buff, bytes) != bytes) {
+	    cli_dbgmsg("Bzip: Can't write to file.\n");
+	    BZ2_bzReadClose(&bzerror, bfd);
+	    close(fd);
+	    if(!cli_leavetemps_flag)
+		unlink(tmpname);
+	    free(tmpname);	
+	    free(buff);
+	    fclose(fs);
+	    return CL_EGZIP;
+	}
+    }
+
+    free(buff);
+    BZ2_bzReadClose(&bzerror, bfd);
+
+    if(ret == CL_VIRUS) {
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	fclose(fs);
+	return ret;
+    }
+
+    if(fsync(fd) == -1) {
+	cli_dbgmsg("Bzip: Synchronisation failed for descriptor %d\n", fd);
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	fclose(fs);
+	return CL_EFSYNC;
+    }
+
+    lseek(fd, 0, SEEK_SET);
+    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
+	cli_dbgmsg("Bzip: Infected with %s\n", *ctx->virname);
+    }
+    close(fd);
+    if(!cli_leavetemps_flag)
+	unlink(tmpname);
+    free(tmpname);	
+    fclose(fs);
+
+    return ret;
+}
+#endif
+
+/*
+static int cli_scanszdd(int desc, cli_ctx *ctx)
+{
+	int fd, ret = CL_CLEAN, dcpy;
+	FILE *tmp = NULL, *in;
+	char *tmpname;
+
+
+    cli_dbgmsg("in cli_scanszdd()\n");
+
+    if((dcpy = dup(desc)) == -1) {
+	cli_dbgmsg("SZDD: Can't duplicate descriptor %d\n", desc);
+	return CL_EIO;
+    }
+
+    if((in = fdopen(dcpy, "rb")) == NULL) {
+	cli_dbgmsg("SZDD: Can't open descriptor %d\n", desc);
+	close(dcpy);
+	return CL_EMSCOMP;
+    }
+
+    if((tmpname = cli_gentempstream(NULL, &tmp)) == NULL) {
+	cli_dbgmsg("SZDD: Can't generate temporary file.\n");
+	fclose(in);
+	return CL_ETMPFILE;
+    }
+
+    if(cli_msexpand(in, tmp) == -1) {
+	cli_dbgmsg("SZDD: msexpand failed.\n");
+	fclose(in);
+	fclose(tmp);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_EMSCOMP;
+    }
+
+    fclose(in);
+    if(fflush(tmp)) {
+	cli_dbgmsg("SZDD: fflush() failed.\n");
+	fclose(tmp);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_EFSYNC;
+    }
+
+    fd = fileno(tmp);
+    lseek(fd, 0, SEEK_SET);
+    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
+	cli_dbgmsg("SZDD: Infected with %s\n", *ctx->virname);
+	fclose(tmp);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_VIRUS;
+    }
+
+    fclose(tmp);
+    if(!cli_leavetemps_flag)
+	unlink(tmpname);
+    free(tmpname);	
+    return ret;
+}
+*/
+
+static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
+{
+	char *tempname;
+	int ret;
+	unsigned int files = 0;
+	struct cab_archive cab;
+	struct cab_file *file;
+
+
+    cli_dbgmsg("in cli_scanmscab()\n");
+
+    if((ret = cab_open(desc, sfx_offset, &cab)))
+	return ret;
+
+    for(file = cab.files; file; file = file->next) {
+	files++;
+
+	if(ctx->limits && ctx->limits->maxfilesize && (file->length > ctx->limits->maxfilesize)) {
+	    cli_dbgmsg("CAB: %s: Size exceeded (%u, max: %lu)\n", file->name, file->length, ctx->limits->maxfilesize);
+	    if(BLOCKMAX) {
+		*ctx->virname = "CAB.ExceededFileSize";
+		cab_free(&cab);
+		return CL_VIRUS;
+	    }
+	    continue;
+	}
+
+	if(ctx->limits && ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+	    cli_dbgmsg("CAB: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+            cab_free(&cab);
+	    if(BLOCKMAX) {
+		*ctx->virname = "CAB.ExceededFilesLimit";
+		return CL_VIRUS;
+	    }
+	    return CL_CLEAN;
+	}
+
+	tempname = cli_gentemp(NULL);
+	cli_dbgmsg("CAB: Extracting file %s to %s, size %u\n", file->name, tempname, file->length);
+	if((ret = cab_extract(file, tempname)))
+	    cli_dbgmsg("CAB: Failed to extract file: %s\n", cl_strerror(ret));
+	else
+	    ret = cli_scanfile(tempname, ctx);
+
+	if(!cli_leavetemps_flag)
+	    unlink(tempname);
+	free(tempname);
+	if(ret == CL_VIRUS)
+	    break;
+    }
+
+    cab_free(&cab);
+    return ret;
+}
+
+int cli_scandir(const char *dirname, cli_ctx *ctx)
+{
+	DIR *dd;
+	struct dirent *dent;
+#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
+	union {
+	    struct dirent d;
+	    char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
+	} result;
+#endif
+	struct stat statbuf;
+	char *fname;
+
+
+    if((dd = opendir(dirname)) != NULL) {
+#ifdef HAVE_READDIR_R_3
+	while(!readdir_r(dd, &result.d, &dent) && dent) {
+#elif defined(HAVE_READDIR_R_2)
+	while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
+#else
+	while((dent = readdir(dd))) {
+#endif
+#if	(!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
+	    if(dent->d_ino)
+#endif
+	    {
+		if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
+		    /* build the full name */
+		    fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
+		    if(!fname) {
+			closedir(dd);
+			return CL_EMEM;
+		    }
+
+		    sprintf(fname, "%s/%s", dirname, dent->d_name);
+
+		    /* stat the file */
+		    if(lstat(fname, &statbuf) != -1) {
+			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
+			    if (cli_scandir(fname, ctx) == CL_VIRUS) {
+				free(fname);
+				closedir(dd);
+				return CL_VIRUS;
+			    }
+			} else
+			    if(S_ISREG(statbuf.st_mode))
+				if(cli_scanfile(fname, ctx) == CL_VIRUS) {
+				    free(fname);
+				    closedir(dd);
+				    return CL_VIRUS;
+				}
+
+		    }
+		    free(fname);
+		}
+	    }
+	}
+    } else {
+	cli_dbgmsg("ScanDir: Can't open directory %s.\n", dirname);
+	return CL_EOPEN;
+    }
+
+    closedir(dd);
+    return 0;
+}
+
+static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
+{
+	int ret = CL_CLEAN, i, fd, ofd, data_len;
+	vba_project_t *vba_project;
+	DIR *dd;
+	struct dirent *dent;
+#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
+	union {
+	    struct dirent d;
+	    char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
+	} result;
+#endif
+	struct stat statbuf;
+	char *fname, *fullname;
+	unsigned char *data;
+
+
+    cli_dbgmsg("VBADir: %s\n", dirname);
+    if((vba_project = (vba_project_t *) vba56_dir_read(dirname))) {
+
+	for(i = 0; i < vba_project->count; i++) {
+	    fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
+	    if(!fullname) {
+		ret = CL_EMEM;
+		break;
+	    }
+	    sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
+	    fd = open(fullname, O_RDONLY|O_BINARY);
+	    if(fd == -1) {
+		cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
+		free(fullname);
+		ret = CL_EOPEN;
+		break;
+	    }
+	    free(fullname);
+            cli_dbgmsg("VBADir: Decompress VBA project '%s'\n", vba_project->name[i]);
+	    data = (unsigned char *) vba_decompress(fd, vba_project->offset[i], &data_len);
+	    close(fd);
+
+	    if(!data) {
+		cli_dbgmsg("VBADir: WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]);
+	    } else {
+		if(ctx->scanned)
+		    *ctx->scanned += data_len / CL_COUNT_PRECISION;
+
+		if(cli_scanbuff(data, data_len, ctx->virname, ctx->engine, CL_TYPE_MSOLE2) == CL_VIRUS) {
+		    free(data);
+		    ret = CL_VIRUS;
+		    break;
+		}
+
+		free(data);
+	    }
+	}
+
+	for(i = 0; i < vba_project->count; i++)
+	    free(vba_project->name[i]);
+	free(vba_project->name);
+	free(vba_project->dir);
+	free(vba_project->offset);
+	free(vba_project);
+    } else if ((fullname = ppt_vba_read(dirname))) {
+    	if(cli_scandir(fullname, ctx) == CL_VIRUS) {
+	    ret = CL_VIRUS;
+	}
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(fullname);
+    	free(fullname);
+    } else if ((vba_project = (vba_project_t *) wm_dir_read(dirname))) {
+    	for (i = 0; i < vba_project->count; i++) {
+		fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
+		if(!fullname) {
+		    ret = CL_EMEM;
+		    break;
+		}
+		sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
+		fd = open(fullname, O_RDONLY|O_BINARY);
+		if(fd == -1) {
+			cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
+			free(fullname);
+			ret = CL_EOPEN;
+			break;
+		}
+		free(fullname);
+		cli_dbgmsg("VBADir: Decompress WM project '%s' macro:%d key:%d length:%d\n", vba_project->name[i], i, vba_project->key[i], vba_project->length[i]);
+		if(vba_project->length[i])
+		    data = (unsigned char *) wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
+		else
+		    data = NULL;
+		close(fd);
+		
+		if(!data) {
+			cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
+		} else {
+			if(ctx->scanned)
+			    *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
+			if(cli_scanbuff(data, vba_project->length[i], ctx->virname, ctx->engine, CL_TYPE_MSOLE2) == CL_VIRUS) {
+				free(data);
+				ret = CL_VIRUS;
+				break;
+			}
+			free(data);
+		}
+	}
+	for(i = 0; i < vba_project->count; i++)
+	    free(vba_project->name[i]);
+	free(vba_project->key);
+	free(vba_project->length);
+	free(vba_project->offset);
+	free(vba_project->name);
+	free(vba_project->dir);
+	free(vba_project);
+    }
+
+    if(ret != CL_CLEAN)
+    	return ret;
+
+    /* Check directory for embedded OLE objects */
+    fullname = (char *) cli_malloc(strlen(dirname) + 16);
+    if(!fullname)
+	return CL_EMEM;
+
+    sprintf(fullname, "%s/_1_Ole10Native", dirname);
+    fd = open(fullname, O_RDONLY|O_BINARY);
+    free(fullname);
+    if (fd >= 0) {
+    	ofd = cli_decode_ole_object(fd, dirname);
+	if (ofd >= 0) {
+		ret = cli_scandesc(ofd, ctx, 0, 0, 0, NULL);
+		close(ofd);
+	}
+	close(fd);
+	if(ret != CL_CLEAN)
+	    return ret;
+    }
+
+    if((dd = opendir(dirname)) != NULL) {
+#ifdef HAVE_READDIR_R_3
+	while(!readdir_r(dd, &result.d, &dent) && dent) {
+#elif defined(HAVE_READDIR_R_2)
+	while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
+#else
+	while((dent = readdir(dd))) {
+#endif
+#if	(!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
+	    if(dent->d_ino)
+#endif
+	    {
+		if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
+		    /* build the full name */
+		    fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
+		    if(!fname) {
+			ret = CL_EMEM;
+			break;
+		    }
+		    sprintf(fname, "%s/%s", dirname, dent->d_name);
+
+		    /* stat the file */
+		    if(lstat(fname, &statbuf) != -1) {
+			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
+			    if (cli_vba_scandir(fname, ctx) == CL_VIRUS) {
+			    	ret = CL_VIRUS;
+				free(fname);
+				break;
+			    }
+		    }
+		    free(fname);
+		}
+	    }
+	}
+    } else {
+	cli_dbgmsg("VBADir: Can't open directory %s.\n", dirname);
+	return CL_EOPEN;
+    }
+
+    closedir(dd);
+    return ret;
+}
+
+static int cli_scanhtml(int desc, cli_ctx *ctx)
+{
+	char *tempname, fullname[1024];
+	int ret=CL_CLEAN, fd;
+	struct stat sb;
+
+
+    cli_dbgmsg("in cli_scanhtml()\n");
+
+    if(fstat(desc, &sb) == -1) {
+        cli_errmsg("cli_scanhtml: fstat() failed for descriptor %d\n", desc);
+	return CL_EIO;
+    }
+
+    /* Because HTML detection is FP-prone and html_normalise_fd() needs to
+     * mmap the file don't normalise files larger than 10 MB.
+     */
+    if(sb.st_size > 10485760) {
+	cli_dbgmsg("cli_scanhtml: exiting (file larger than 10 MB)\n");
+	return CL_CLEAN;
+    }
+
+    tempname = cli_gentemp(NULL);
+    if(mkdir(tempname, 0700)) {
+        cli_errmsg("cli_scanhtml: Can't create temporary directory %s\n", tempname);
+	free(tempname);
+        return CL_ETMPDIR;
+    }
+
+    html_normalise_fd(desc, tempname, NULL, ctx->dconf);
+    snprintf(fullname, 1024, "%s/comment.html", tempname);
+    fd = open(fullname, O_RDONLY|O_BINARY);
+    if (fd >= 0) {
+        ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
+	close(fd);
+    }
+
+    if(ret < 0 || ret == CL_VIRUS) {
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(tempname);
+	free(tempname);
+	return ret;
+    }
+
+    if (ret == CL_CLEAN) {
+	snprintf(fullname, 1024, "%s/nocomment.html", tempname);
+	fd = open(fullname, O_RDONLY|O_BINARY);
+	if (fd >= 0) {
+	    ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
+	    close(fd);
+	}
+    }
+
+    if(ret < 0 || ret == CL_VIRUS) {
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(tempname);
+	free(tempname);
+	return ret;
+    }
+
+    if (ret == CL_CLEAN) {
+	snprintf(fullname, 1024, "%s/script.html", tempname);
+	fd = open(fullname, O_RDONLY|O_BINARY);
+	if (fd >= 0) {
+	    ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
+	    close(fd);
+	}
+    }
+
+    if(ret < 0 || ret == CL_VIRUS) {
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(tempname);
+	free(tempname);
+	return ret;
+    }
+
+    if (ret == CL_CLEAN) {
+    	snprintf(fullname, 1024, "%s/rfc2397", tempname);
+    	ret = cli_scandir(fullname, ctx);
+    }
+
+    if(!cli_leavetemps_flag)
+        cli_rmdirs(tempname);
+
+    free(tempname);
+    return ret;
+}
+
+static int cli_scanhtml_utf16(int desc, cli_ctx *ctx)
+{
+	char *tempname, buff[512], *decoded;
+	int ret = CL_CLEAN, fd, bytes;
+
+
+    cli_dbgmsg("in cli_scanhtml_utf16()\n");
+
+    tempname = cli_gentemp(NULL);
+    if((fd = open(tempname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
+	cli_errmsg("cli_scanhtml_utf16: Can't create file %s\n", tempname);
+	free(tempname);
+	return CL_EIO;
+    }
+
+    while((bytes = read(desc, buff, sizeof(buff))) > 0) {
+	decoded = cli_utf16toascii(buff, bytes);
+	if(decoded) {
+	    if(write(fd, decoded, strlen(decoded)) == -1) {
+		cli_errmsg("cli_scanhtml_utf16: Can't write to file %s\n", tempname);
+		free(decoded);
+		unlink(tempname);
+		free(tempname);
+		close(fd);
+		return CL_EIO;
+	    }
+	    free(decoded);
+	}
+    }
+
+    fsync(fd);
+    lseek(fd, 0, SEEK_SET);
+    ret = cli_scanhtml(fd, ctx);
+    close(fd);
+
+    if(!cli_leavetemps_flag)
+	unlink(tempname);
+    else
+	cli_dbgmsg("cli_scanhtml_utf16: Decoded HTML data saved in %s\n", tempname);
+    free(tempname);
+
+    return ret;
+}
+
+static int cli_scanole2(int desc, cli_ctx *ctx)
+{
+	char *dir;
+	int ret = CL_CLEAN;
+
+
+    cli_dbgmsg("in cli_scanole2()\n");
+
+    /* generate the temporary directory */
+    dir = cli_gentemp(NULL);
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("OLE2: Can't create temporary directory %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    if((ret = cli_ole2_extract(desc, dir, ctx->limits))) {
+	cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(dir);
+	free(dir);
+	return ret;
+    }
+
+    if((ret = cli_vba_scandir(dir, ctx)) != CL_VIRUS) {
+	if(cli_scandir(dir, ctx) == CL_VIRUS) {
+	    ret = CL_VIRUS;
+	}
+    }
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+    free(dir);
+    return ret;
+}
+
+static int cli_scantar(int desc, cli_ctx *ctx, unsigned int posix)
+{
+	char *dir;
+	int ret = CL_CLEAN;
+
+
+    cli_dbgmsg("in cli_scantar()\n");
+
+    /* generate temporary directory */
+    dir = cli_gentemp(NULL);
+    if(mkdir(dir, 0700)) {
+	cli_errmsg("Tar: Can't create temporary directory %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    if((ret = cli_untar(dir, desc, posix, ctx->limits)))
+	cli_dbgmsg("Tar: %s\n", cl_strerror(ret));
+    else
+	ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    return ret;
+}
+
+static int cli_scanbinhex(int desc, cli_ctx *ctx)
+{
+	char *dir;
+	int ret = CL_CLEAN;
+
+
+    cli_dbgmsg("in cli_scanbinhex()\n");
+
+    /* generate temporary directory */
+    dir = cli_gentemp(NULL);
+
+    if(mkdir(dir, 0700)) {
+	cli_errmsg("Binhex: Can't create temporary directory %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    if((ret = cli_binhex(dir, desc)))
+	cli_dbgmsg("Binhex: %s\n", cl_strerror(ret));
+    else
+	ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    return ret;
+}
+
+static int cli_scanmschm(int desc, cli_ctx *ctx)
+{
+	char *tempname;
+	int ret = CL_CLEAN;
+
+
+    cli_dbgmsg("in cli_scanmschm()\n");	
+
+    tempname = cli_gentemp(NULL);
+    if(mkdir(tempname, 0700)) {
+	cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
+	free(tempname);
+	return CL_ETMPDIR;
+    }
+
+    if(chm_unpack(desc, tempname))
+	ret = cli_scandir(tempname, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(tempname);
+
+    free(tempname);
+    return ret;
+}
+
+static int cli_scanscrenc(int desc, cli_ctx *ctx)
+{
+	char *tempname;
+	int ret = CL_CLEAN;
+
+    cli_dbgmsg("in cli_scanscrenc()\n");
+
+    tempname = cli_gentemp(NULL);
+    if(mkdir(tempname, 0700)) {
+	cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
+	free(tempname);
+	return CL_ETMPDIR;
+    }
+
+    if (html_screnc_decode(desc, tempname))
+	ret = cli_scandir(tempname, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(tempname);
+
+    free(tempname);
+    return ret;
+}
+
+static int cli_scanriff(int desc, const char **virname)
+{
+	int ret = CL_CLEAN;
+
+    if(cli_check_riff_exploit(desc) == 2) {
+	ret = CL_VIRUS;
+	*virname = "Exploit.W32.MS05-002";
+    }
+
+    return ret;
+}
+
+static int cli_scanjpeg(int desc, const char **virname)
+{
+	int ret = CL_CLEAN;
+
+    if(cli_check_jpeg_exploit(desc) == 1) {
+	ret = CL_VIRUS;
+	*virname = "Exploit.W32.MS04-028";
+    }
+
+    return ret;
+}
+
+static int cli_scancryptff(int desc, cli_ctx *ctx)
+{
+	int ret = CL_CLEAN, ndesc;
+	unsigned int length, i;
+	unsigned char *src = NULL, *dest = NULL;
+	char *tempfile;
+	struct stat sb;
+
+
+    if(fstat(desc, &sb) == -1) {
+	cli_errmsg("CryptFF: Can't fstat descriptor %d\n", desc);
+	return CL_EIO;
+    }
+
+    /* Skip the CryptFF file header */
+    if(lseek(desc, 0x10, SEEK_SET) < 0) {
+	cli_errmsg("CryptFF: Can't lseek descriptor %d\n", desc);
+	return ret;
+    }
+
+    length = sb.st_size  - 0x10;
+ 
+    if((dest = (unsigned char *) cli_malloc(length)) == NULL) {
+	cli_dbgmsg("CryptFF: Can't allocate memory\n");
+        return CL_EMEM;
+    }
+
+    if((src = (unsigned char *) cli_malloc(length)) == NULL) {
+	cli_dbgmsg("CryptFF: Can't allocate memory\n");
+	free(dest);
+        return CL_EMEM;
+    }
+
+    if((unsigned int) read(desc, src, length) != length) {
+	cli_dbgmsg("CryptFF: Can't read from descriptor %d\n", desc);
+	free(dest);
+	free(src);
+	return CL_EIO;
+    }
+
+    for(i = 0; i < length; i++)
+	dest[i] = src[i] ^ (unsigned char) 0xff;
+
+    free(src);
+
+    tempfile = cli_gentemp(NULL);
+    if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
+	cli_errmsg("CryptFF: Can't create file %s\n", tempfile);
+	free(dest);
+	free(tempfile);
+	return CL_EIO;
+    }
+
+    if(write(ndesc, dest, length) == -1) {
+	cli_dbgmsg("CryptFF: Can't write to descriptor %d\n", ndesc);
+	free(dest);
+	close(ndesc);
+	free(tempfile);
+	return CL_EIO;
+    }
+
+    free(dest);
+
+    if(fsync(ndesc) == -1) {
+	cli_errmsg("CryptFF: Can't fsync descriptor %d\n", ndesc);
+	close(ndesc);
+	free(tempfile);
+	return CL_EIO;
+    }
+
+    lseek(ndesc, 0, SEEK_SET);
+
+    cli_dbgmsg("CryptFF: Scanning decrypted data\n");
+
+    if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
+	cli_dbgmsg("CryptFF: Infected with %s\n", *ctx->virname);
+
+    close(ndesc);
+
+    if(cli_leavetemps_flag)
+	cli_dbgmsg("CryptFF: Decompressed data saved in %s\n", tempfile);
+    else
+	unlink(tempfile);
+
+    free(tempfile);
+    return ret;
+}
+
+static int cli_scanpdf(int desc, cli_ctx *ctx)
+{
+	int ret;
+	char *dir = cli_gentemp(NULL);
+
+
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("Can't create temporary directory for PDF file %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    ret = cli_pdf(dir, desc, ctx);
+
+    if(ret == CL_CLEAN)
+	ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    return ret;
+}
+
+static int cli_scantnef(int desc, cli_ctx *ctx)
+{
+	int ret;
+	char *dir = cli_gentemp(NULL);
+
+
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("Can't create temporary directory for tnef file %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    ret = cli_tnef(dir, desc);
+
+    if(ret == CL_CLEAN)
+	ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    return ret;
+}
+
+static int cli_scanuuencoded(int desc, cli_ctx *ctx)
+{
+	int ret;
+	char *dir = cli_gentemp(NULL);
+
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("Can't create temporary directory for uuencoded file %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    ret = cli_uuencode(dir, desc);
+
+    if(ret == CL_CLEAN)
+	ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    return ret;
+}
+
+/* Outlook PST file */
+static int cli_scanpst(int desc, cli_ctx *ctx)
+{
+	int ret;
+	char *dir = cli_gentemp(NULL);
+
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("Can't create temporary directory for PST file %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    ret = cli_pst(dir, desc);
+
+    if(ret == CL_SUCCESS)
+	ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    return ret;
+}
+
+static int cli_scanmail(int desc, cli_ctx *ctx)
+{
+	char *dir;
+	int ret;
+
+
+    cli_dbgmsg("Starting cli_scanmail(), mrec == %u, arec == %u\n", ctx->mrec, ctx->arec);
+
+    /* generate the temporary directory */
+    dir = cli_gentemp(NULL);
+    if(mkdir(dir, 0700)) {
+	cli_dbgmsg("Mail: Can't create temporary directory %s\n", dir);
+	free(dir);
+	return CL_ETMPDIR;
+    }
+
+    /*
+     * Extract the attachments into the temporary directory
+     */
+    if((ret = cli_mbox(dir, desc, ctx))) {
+	if(!cli_leavetemps_flag)
+	    cli_rmdirs(dir);
+	free(dir);
+	return ret;
+    }
+
+    ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    return ret;
+}
+
+static int cli_scanembpe(int desc, cli_ctx *ctx)
+{
+	int fd, bytes, ret = CL_CLEAN;
+	unsigned long int size = 0;
+	char buff[512];
+	char *tmpname;
+
+
+    tmpname = cli_gentemp(NULL);
+    if(!tmpname)
+	return CL_EMEM;
+
+    if((fd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
+	cli_errmsg("cli_scanembpe: Can't create file %s\n", tmpname);
+	free(tmpname);
+	return CL_EIO;
+    }
+
+    while((bytes = read(desc, buff, sizeof(buff))) > 0) {
+	size += bytes;
+
+	if(ctx->limits && ctx->limits->maxfilesize && (size + sizeof(buff) > ctx->limits->maxfilesize)) {
+	    cli_dbgmsg("cli_scanembpe: Size exceeded (stopped at %lu, max: %lu)\n", size, ctx->limits->maxfilesize);
+	    /* BLOCKMAX should be ignored here */
+	    break;
+	}
+
+	if(cli_writen(fd, buff, bytes) != bytes) {
+	    cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
+	    close(fd);
+	    if(!cli_leavetemps_flag)
+		unlink(tmpname);
+	    free(tmpname);	
+	    return CL_EIO;
+	}
+    }
+
+    if(fsync(fd) == -1) {
+	cli_dbgmsg("cli_scanembpe: Can't synchronise descriptor %d\n", fd);
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_EFSYNC;
+    }
+
+    lseek(fd, 0, SEEK_SET);
+    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
+	cli_dbgmsg("cli_scanembpe: Infected with %s\n", *ctx->virname);
+	close(fd);
+	if(!cli_leavetemps_flag)
+	    unlink(tmpname);
+	free(tmpname);	
+	return CL_VIRUS;
+    }
+
+    close(fd);
+    if(!cli_leavetemps_flag)
+	unlink(tmpname);
+    free(tmpname);
+
+    /* intentionally ignore possible errors from cli_magic_scandesc */
+    return CL_CLEAN;
+}
+
+static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg)
+{
+	int ret = CL_CLEAN, nret = CL_CLEAN;
+	uint8_t ftrec = 0, break_loop = 0;
+	struct cli_matched_type *ftoffset = NULL, *fpt;
+	uint32_t lastzip, lastrar;
+	struct cli_exe_info peinfo;
+
+
+    if(typercg) switch(type) {
+	case CL_TYPE_UNKNOWN_TEXT:
+	case CL_TYPE_MSEXE:
+	case CL_TYPE_ZIP:
+	    ftrec = 1;
+	    break;
+	default:
+	    ftrec = 0;
+    }
+
+    if(lseek(desc, 0, SEEK_SET) < 0) {
+	cli_errmsg("cli_scanraw: lseek() failed\n");
+	return CL_EIO;
+    }
+
+    ret = cli_scandesc(desc, ctx, ftrec, type, 0, &ftoffset);
+
+    if(ret >= CL_TYPENO) {
+
+	if(type == CL_TYPE_UNKNOWN_TEXT) {
+	    lseek(desc, 0, SEEK_SET);
+
+	    nret = cli_scandesc(desc, ctx, 0, ret, 1, NULL);
+	    if(nret == CL_VIRUS)
+		cli_dbgmsg("%s found in descriptor %d when scanning file type %u\n", *ctx->virname, desc, ret);
+	}
+
+	if(nret != CL_VIRUS && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP)) {
+	    lastzip = lastrar = 0xdeadbeef;
+	    fpt = ftoffset;
+	    while(fpt) {
+		switch(fpt->type) {
+		    case CL_TYPE_RARSFX:
+#ifdef ENABLE_UNRAR
+			if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_RAR)) {
+			    cli_dbgmsg("RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
+			    nret = cli_scanrar(desc, ctx, fpt->offset, &lastrar);
+			}
+#endif
+			break;
+
+		    case CL_TYPE_ZIPSFX:
+			if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ZIP) && fpt->offset) {
+			    cli_dbgmsg("ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
+			    nret = cli_scanzip(desc, ctx, fpt->offset, &lastzip);
+			}
+			break;
+
+		    case CL_TYPE_CABSFX:
+			if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_CAB)) {
+			    cli_dbgmsg("CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
+			    nret = cli_scanmscab(desc, ctx, fpt->offset);
+			}
+			break;
+		    case CL_TYPE_ARJSFX:
+			if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ARJ)) {
+			    cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
+			    nret = cli_scanarj(desc, ctx, fpt->offset, &lastrar);
+			}
+			break;
+
+		    case CL_TYPE_NULSFT:
+		        if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) && fpt->offset > 4) {
+			    cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
+			    nret = cli_scannulsft(desc, ctx, fpt->offset - 4);
+			}
+			break;
+
+		    case CL_TYPE_AUTOIT:
+		        if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
+			    cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
+			    nret = cli_scanautoit(desc, ctx, fpt->offset + 23);
+			}
+			break;
+
+		    case CL_TYPE_MSEXE:
+			if(SCAN_PE && ctx->dconf->pe && fpt->offset) {
+			    cli_dbgmsg("PE signature found at %u\n", (unsigned int) fpt->offset);
+			    memset(&peinfo, 0, sizeof(struct cli_exe_info));
+			    peinfo.offset = fpt->offset;
+			    lseek(desc, fpt->offset, SEEK_SET);
+			    if(cli_peheader(desc, &peinfo) == 0) {
+				cli_dbgmsg("*** Detected embedded PE file ***\n");
+				if(peinfo.section)
+				    free(peinfo.section);
+
+				lseek(desc, fpt->offset, SEEK_SET);
+				nret = cli_scanembpe(desc, ctx);
+				break_loop = 1; /* we can stop here and other
+						 * embedded executables will
+						 * be found recursively
+						 * through the above call
+						 */
+			    }
+			}
+			break;
+
+		    default:
+			cli_warnmsg("cli_scanraw: Type %u not handled in fpt loop\n", fpt->type);
+		}
+
+		if(nret == CL_VIRUS || break_loop)
+		    break;
+
+		fpt = fpt->next;
+	    }
+	}
+
+	ret == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
+
+	if(nret != CL_VIRUS) switch(ret) {
+	    case CL_TYPE_HTML:
+		if(SCAN_HTML && type == CL_TYPE_UNKNOWN_TEXT && (DCONF_DOC & DOC_CONF_HTML))
+		    nret = cli_scanhtml(desc, ctx);
+		break;
+
+	    case CL_TYPE_MAIL:
+		if(SCAN_MAIL && type == CL_TYPE_UNKNOWN_TEXT && (DCONF_MAIL & MAIL_CONF_MBOX))
+		    nret = cli_scanmail(desc, ctx);
+		break;
+
+	    default:
+		break;
+	}
+	ret == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
+	ret = nret;
+    }
+
+    while(ftoffset) {
+	fpt = ftoffset;
+	ftoffset = ftoffset->next;
+	free(fpt);
+    }
+
+    if(ret == CL_VIRUS)
+	cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
+
+    return ret;
+}
+
+int cli_magic_scandesc(int desc, cli_ctx *ctx)
+{
+	int ret = CL_CLEAN;
+	cli_file_t type;
+	struct stat sb;
+	uint8_t typercg = 1;
+
+
+    if(fstat(desc, &sb) == -1) {
+	cli_errmsg("Can't fstat descriptor %d\n", desc);
+	return CL_EIO;
+    }
+
+    if(sb.st_size <= 5) {
+	cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) sb.st_size);
+	return CL_CLEAN;
+    }
+
+    if(!ctx->engine) {
+	cli_errmsg("CRITICAL: engine == NULL\n");
+	return CL_EMALFDB;
+    }
+
+    if(!ctx->options) { /* raw mode (stdin, etc.) */
+	cli_dbgmsg("Raw mode: No support for special files\n");
+	if((ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL)) == CL_VIRUS)
+	    cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
+	return ret;
+    }
+
+    if(SCAN_ARCHIVE && ctx->limits && ctx->limits->maxreclevel)
+	if(ctx->arec > ctx->limits->maxreclevel) {
+	    cli_dbgmsg("Archive recursion limit exceeded (arec == %u).\n", ctx->arec);
+	    if(BLOCKMAX) {
+		*ctx->virname = "Archive.ExceededRecursionLimit";
+		return CL_VIRUS;
+	    }
+	    return CL_CLEAN;
+	}
+
+    if(SCAN_MAIL)
+	if(ctx->mrec > MAX_MAIL_RECURSION) {
+	    cli_dbgmsg("Mail recursion level exceeded (mrec == %u).\n", ctx->mrec);
+	    /* return CL_EMAXREC; */
+	    return CL_CLEAN;
+	}
+
+    lseek(desc, 0, SEEK_SET);
+    type = cli_filetype2(desc, ctx->engine);
+    lseek(desc, 0, SEEK_SET);
+
+    if(type != CL_TYPE_DATA && ctx->engine->sdb) {
+	if((ret = cli_scanraw(desc, ctx, type, 0)) == CL_VIRUS)
+	    return CL_VIRUS;
+	lseek(desc, 0, SEEK_SET);
+    }
+
+    type == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
+
+    switch(type) {
+	case CL_TYPE_RAR:
+#ifdef ENABLE_UNRAR
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
+		ret = cli_scanrar(desc, ctx, 0, NULL);
+#else
+	    cli_warnmsg("RAR code not compiled-in\n");
+#endif
+	    break;
+
+	case CL_TYPE_ZIP:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
+		ret = cli_scanzip(desc, ctx, 0, NULL);
+	    break;
+
+	case CL_TYPE_GZ:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
+		ret = cli_scangzip(desc, ctx);
+	    break;
+
+	case CL_TYPE_BZ:
+#ifdef HAVE_BZLIB_H
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
+		ret = cli_scanbzip(desc, ctx);
+#endif
+	    break;
+	case CL_TYPE_ARJ:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
+		ret = cli_scanarj(desc, ctx, 0, NULL);
+	    break;
+
+        case CL_TYPE_NULSFT:
+	    if(SCAN_ARCHIVE)
+		ret = cli_scannulsft(desc, ctx, 0);
+	    break;
+
+        case CL_TYPE_AUTOIT:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
+		ret = cli_scanautoit(desc, ctx, 23);
+	    break;
+/*
+	case CL_TYPE_MSSZDD:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
+		ret = cli_scanszdd(desc, ctx);
+	    break;
+*/
+	case CL_TYPE_MSCAB:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
+		ret = cli_scanmscab(desc, ctx, 0);
+	    break;
+
+	case CL_TYPE_HTML:
+	    if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
+		ret = cli_scanhtml(desc, ctx);
+	    break;
+
+	case CL_TYPE_HTML_UTF16:
+	    if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
+		ret = cli_scanhtml_utf16(desc, ctx);
+	    break;
+
+	case CL_TYPE_RTF:
+	    if(DCONF_DOC & DOC_CONF_RTF)
+		ret = cli_scanrtf(desc, ctx);
+	    break;
+
+	case CL_TYPE_MAIL:
+	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
+		ret = cli_scanmail(desc, ctx);
+	    break;
+
+	case CL_TYPE_TNEF:
+	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
+		ret = cli_scantnef(desc, ctx);
+	    break;
+
+	case CL_TYPE_UUENCODED:
+	    if(DCONF_OTHER & OTHER_CONF_UUENC)
+		ret = cli_scanuuencoded(desc, ctx);
+	    break;
+
+	case CL_TYPE_PST:
+	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_PST))
+		ret = cli_scanpst(desc, ctx);
+	    break;
+
+	case CL_TYPE_MSCHM:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
+		ret = cli_scanmschm(desc, ctx);
+	    break;
+
+	case CL_TYPE_MSOLE2:
+	    if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
+		ret = cli_scanole2(desc, ctx);
+	    break;
+
+	case CL_TYPE_POSIX_TAR:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
+		ret = cli_scantar(desc, ctx, 1);
+	    break;
+
+	case CL_TYPE_OLD_TAR:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
+		ret = cli_scantar(desc, ctx, 0);
+	    break;
+
+	case CL_TYPE_BINHEX:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
+		ret = cli_scanbinhex(desc, ctx);
+	    break;
+
+	case CL_TYPE_SCRENC:
+	    if(DCONF_OTHER & OTHER_CONF_SCRENC)
+		ret = cli_scanscrenc(desc, ctx);
+	    break;
+
+	case CL_TYPE_RIFF:
+	    if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
+		ret = cli_scanriff(desc, ctx->virname);
+	    break;
+
+	case CL_TYPE_GRAPHICS:
+	    if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
+		ret = cli_scanjpeg(desc, ctx->virname);
+	    break;
+
+	case CL_TYPE_PDF:
+	    if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
+		ret = cli_scanpdf(desc, ctx);
+	    break;
+
+	case CL_TYPE_CRYPTFF:
+	    if(DCONF_OTHER & OTHER_CONF_CRYPTFF)
+		ret = cli_scancryptff(desc, ctx);
+	    break;
+
+	case CL_TYPE_ELF:
+	    if(SCAN_ELF && ctx->dconf->elf)
+		ret = cli_scanelf(desc, ctx);
+	    break;
+
+	case CL_TYPE_SIS:
+	    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
+		ret = cli_scansis(desc, ctx);
+	    break;
+
+	case CL_TYPE_DATA:
+	    /* it could be a false positive and a standard DOS .COM file */
+	    {
+		struct stat s;
+		if(fstat(desc, &s) == 0 && S_ISREG(s.st_mode) && s.st_size < 65536)
+		type = CL_TYPE_UNKNOWN_DATA;
+	    }
+
+	case CL_TYPE_UNKNOWN_DATA:
+	    ret = cli_check_mydoom_log(desc, ctx->virname);
+	    break;
+
+	default:
+	    break;
+    }
+
+    type == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
+
+    if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
+	if(sb.st_size > 1048576) {
+	    cli_dbgmsg("cli_magic_scandesc: Not checking for embedded PEs (zip file > 1 MB)\n");
+	    typercg = 0;
+	}
+    }
+
+    if(type != CL_TYPE_DATA && ret != CL_VIRUS && !ctx->engine->sdb) {
+	if(cli_scanraw(desc, ctx, type, typercg) == CL_VIRUS)
+	    return CL_VIRUS;
+    }
+
+    ctx->arec++;
+    lseek(desc, 0, SEEK_SET);
+    switch(type) {
+	/* Due to performance reasons all executables were first scanned
+	 * in raw mode. Now we will try to unpack them
+	 */
+	case CL_TYPE_MSEXE:
+	    if(SCAN_PE && ctx->dconf->pe)
+		ret = cli_scanpe(desc, ctx);
+	    break;
+
+	default:
+	    break;
+    }
+    ctx->arec--;
+
+    if(ret == CL_EFORMAT) {
+	cli_dbgmsg("Descriptor[%d]: %s\n", desc, cl_strerror(CL_EFORMAT));
+	return CL_CLEAN;
+    } else {
+	return ret;
+    }
+}
+
+int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options)
+{
+    cli_ctx ctx;
+    int rc;
+
+    memset(&ctx, '\0', sizeof(cli_ctx));
+    ctx.engine = engine;
+    ctx.virname = virname;
+    ctx.limits = limits;
+    ctx.scanned = scanned;
+    ctx.options = options;
+    ctx.found_possibly_unwanted = 0;
+    ctx.dconf = (struct cli_dconf *) engine->dconf;
+
+    rc = cli_magic_scandesc(desc, &ctx);
+    if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
+    	rc = CL_VIRUS;
+    return rc;
+}
+
+static int cli_scanfile(const char *filename, cli_ctx *ctx)
+{
+	int fd, ret;
+
+    /* internal version of cl_scanfile with arec/mrec preserved */
+    if((fd = open(filename, O_RDONLY|O_BINARY)) == -1)
+	return CL_EOPEN;
+
+    ret = cli_magic_scandesc(fd, ctx);
+
+    close(fd);
+    return ret;
+}
+
+int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options)
+{
+	int fd, ret;
+
+
+    if((fd = open(filename, O_RDONLY|O_BINARY)) == -1)
+	return CL_EOPEN;
+
+    ret = cl_scandesc(fd, virname, scanned, engine, limits, options);
+    close(fd);
+
+    return ret;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,691 @@
+/*
+ *  Copyright (C) 2006 Sensory Networks, Inc.
+ *	      Written by Tomasz Kojm
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#if HAVE_MMAP
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <zlib.h>
+
+#include "others.h"
+
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#else /* HAVE_SYS_MMAN_H */
+#undef HAVE_MMAP
+#endif
+
+#include "clamav.h"
+#include "scanners.h"
+#include "cltypes.h"
+#include "sis.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define EC16(x) le16_to_host(x) /* Convert little endian to host */
+
+static const char *langcodes[] = {
+    "",   "EN", "FR", "GE", "SP", "IT", "SW", "DA", "NO", "FI", "AM",
+    "SF", "SG", "PO", "TU", "IC", "RU", "HU", "DU", "BL", "AU", "BG",
+    "AS", "NZ", "IF", "CS", "SK", "PL", "SL", "TC", "HK", "ZH", "JA",
+    "TH", "AF", "SQ", "AH", "AR", "HY", "TL", "BE", "BN", "BG", "MY",
+    "CA", "HR", "CE", "IE", "SF", "ET", "FA", "CF", "GD", "KA", "EL",
+    "CG", "GU", "HE", "HI", "IN", "GA", "SZ", "KN", "KK", "KM", "KO",
+    "LO", "LV", "LT", "MK", "MS", "ML", "MR", "MO", "MN", "NN", "BP",
+    "PA", "RO", "SR", "SI", "SO", "OS", "LS", "SH", "FS", "TA", "TE",
+    "BO", "TI", "CT", "TK", "UK", "UR", "",   "VI", "CY", "ZU"
+};
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define SIS_MAX_NAME 512
+#define SIS_MAX_SIZE 134217728
+
+static char *sis_utf16_decode(const char *str, uint32_t length)
+{
+	char *decoded;
+	uint32_t i, j;
+
+
+    if(!length || length % 2) {
+	cli_dbgmsg("SIS: sis_utf16_decode: Broken filename (length == %d)\n", length);
+	return NULL;
+    }
+
+    if(!(decoded = cli_calloc(length / 2 + 1, sizeof(char))))
+	return NULL;
+
+    for(i = 0, j = 0; i < length; i += 2, j++) {
+       decoded[j] = str[i + 1] << 4;
+       decoded[j] += str[i];
+       if(decoded[j] == '%')
+	   decoded[j] = '_';
+    }
+
+    return decoded;
+}
+
+static int sis_extract_simple(int fd, char *mfile, uint32_t length, uint32_t offset, uint16_t nlangs, uint8_t compressed, uint8_t *ifile, const char *dir, cli_ctx *ctx)
+{
+	const char *typedir = NULL;
+	char *sname = NULL, *dname = NULL, *subdir, *fname, *buff;
+	int desc, i;
+	uint8_t get_dname = 1;
+	uint32_t namelen, nameoff, filelen, fileoff, val;
+	struct stat sb;
+	uLong osize = 0;
+	uLongf csize = 0;
+
+
+    if(offset + 24 + 8 * nlangs >= length) {
+	cli_errmsg("SIS: sis_extract_simple: Broken file record\n");
+	return CL_EFORMAT;
+    }
+
+    switch(cli_readint32(mfile + offset)) {
+	case 0x00:
+	    cli_dbgmsg("SIS: File type: Standard file\n");
+	    typedir = "standard";
+	    break;
+	case 0x01:
+	    cli_dbgmsg("SIS: File type: Text file\n");
+	    typedir = "text";
+	    get_dname = 0;
+	    break;
+	case 0x02:
+	    cli_dbgmsg("SIS: File type: Component file\n");
+	    typedir = "component";
+	    get_dname = 0;
+	    break;
+	case 0x03:
+	    cli_dbgmsg("SIS: File type: Run file\n");
+	    typedir = "run";
+	    val = cli_readint32(mfile + offset + 4);
+	    switch(val & 0xff) {
+		case 0x00:
+		    cli_dbgmsg("SIS:    * During installation only\n");
+		    break;
+		case 0x01:
+		    cli_dbgmsg("SIS:    * During removal only\n");
+		    break;
+		case 0x02:
+		    cli_dbgmsg("SIS:    * During installation and removal\n");
+		    break;
+		default:
+		    cli_warnmsg("SIS: sis_extract_simple: Unknown value in file details (0x%x)\n", cli_readint32(mfile + offset + 4));
+	    }
+	    switch(val & 0xff00) {
+		case 0x0000:
+		    break;
+		case 0x0100:
+		    cli_dbgmsg("SIS:    * Ends when installation finished\n");
+		    break;
+		case 0x0200:
+		    cli_dbgmsg("SIS:    * Waits until closed before continuing\n");
+		    break;
+		default:
+		    cli_warnmsg("SIS: sis_extract_simple: Unknown value in file details (0x%x)\n", cli_readint32(mfile + offset + 4));
+	    }
+	    break;
+	case 0x04:
+	    cli_dbgmsg("SIS: File type: Null file\n");
+	    return CL_CLEAN;
+	case 0x05:
+	    cli_dbgmsg("SIS: File type: MIME file\n");
+	    return CL_CLEAN;
+	default:
+	    cli_warnmsg("SIS: Unknown file type in file record\n");
+    }
+
+    /* Source name */
+    namelen = (uint32_t) cli_readint32(mfile + offset + 8);
+    if(namelen > SIS_MAX_NAME) {
+	cli_warnmsg("SIS: sis_extract_simple: Source name too long and will not be decoded\n");
+    } else {
+	nameoff = cli_readint32(mfile + offset + 12);
+	if(nameoff >= length || nameoff + namelen >= length) {
+	    cli_errmsg("SIS: sis_extract_simple: Broken source name data\n");
+	    return CL_EFORMAT;
+	}
+
+	if((sname = sis_utf16_decode(mfile + nameoff, namelen)))
+	    cli_dbgmsg("SIS: Source name: %s\n", sname);
+	else
+	    cli_warnmsg("SIS: Source name not decoded\n");
+    }
+
+    /* Destination name */
+    if(get_dname) {
+	namelen = (uint32_t) cli_readint32(mfile + offset + 16);
+	if(namelen > SIS_MAX_NAME) {
+	    cli_warnmsg("SIS: sis_extract_simple: Destination name too long and will not be decoded\n");
+	} else {
+	    nameoff = cli_readint32(mfile + offset + 20);
+	    if(nameoff >= length || nameoff + namelen >= length) {
+		cli_errmsg("SIS: sis_extract_simple: Broken destination name data\n");
+		if(sname)
+		    free(sname);
+		return CL_EFORMAT;
+	    }
+
+	    if((dname = sis_utf16_decode(mfile + nameoff, namelen)))
+		cli_dbgmsg("SIS: Destination name: %s\n", dname);
+	    else
+		cli_warnmsg("SIS: Destination name not decoded\n");
+	}
+    }
+
+    if(!cli_leavetemps_flag) {
+	if(sname)
+	    free(sname);
+	if(dname)
+	    free(dname);
+    }
+
+    /* Files */
+    if(typedir) {
+	if(!(subdir = cli_malloc(strlen(dir) + strlen(typedir) + 2)))
+	    return CL_EMEM;
+	sprintf(subdir, "%s/%s", dir, typedir);
+    } else {
+	if(!(subdir = cli_strdup(dir)))
+	    return CL_EMEM;
+    }
+
+    if(stat(subdir, &sb) == -1) {
+	if(mkdir(subdir, 0700) == -1) {
+	    free(subdir);
+	    return CL_EIO;
+	}
+    }
+
+    for(i = 0; i < nlangs; i++) {
+	filelen = cli_readint32(mfile + offset + 24 + 4 * i);
+	fileoff = cli_readint32(mfile + offset + 24 + 4 * i + 4 * nlangs);
+
+	if(fileoff == length) {
+	    cli_dbgmsg("SIS: Null file (installation record)\n");
+	    *ifile = 1;
+	    continue;
+	} else if (fileoff > length) {
+	    if(!*ifile) {
+		cli_errmsg("SIS: sis_extract_simple: Broken file data (fileoff)\n");
+		free(subdir);
+		return CL_EFORMAT;
+	    } else {
+		cli_dbgmsg("SIS: Null file (installation track)\n");
+		continue;
+	    }
+	}
+
+	if(filelen >= length || filelen + fileoff > length) {
+	    cli_errmsg("SIS: sis_extract_simple: Broken file data (filelen, fileoff)\n");
+	    free(subdir);
+	    return CL_EFORMAT;
+	}
+
+	if(!(fname = cli_gentemp(subdir))) {
+	    free(subdir);
+	    return CL_EMEM;
+	}
+
+	if(compressed) {
+	    csize = (uLong) filelen;
+	    filelen = cli_readint32(mfile + offset + 24 + 4 * i + 8 * nlangs);
+	    osize = (uLongf) filelen;
+
+	    if(!osize) {
+		cli_dbgmsg("SIS: Empty file, skipping\n");
+		free(fname);
+		continue;
+	    }
+
+	    cli_dbgmsg("SIS: Compressed size: %u\n", (unsigned int) csize);
+	    cli_dbgmsg("SIS: Original size: %u\n", (unsigned int) osize);
+
+	    if(ctx->limits && ctx->limits->maxfilesize && osize > ctx->limits->maxfilesize) {
+		cli_dbgmsg("SIS: Size exceeded (%u, max: %lu)\n", (unsigned int) osize, ctx->limits->maxfilesize);
+		if(BLOCKMAX) {
+		    *ctx->virname = "SIS.ExceededFileSize";
+		    free(subdir);
+		    free(fname);
+		    return CL_VIRUS;
+		}
+		/* osize is not reliable so continue */
+	    }
+
+	    if((osize <= 3 * csize) || (ctx->limits && ctx->limits->maxfilesize && osize > ctx->limits->maxfilesize))
+		osize = 3 * csize;
+
+	    if(!(buff = cli_malloc((size_t) osize))) {
+		cli_errmsg("SIS: sis_extract_simple: Can't allocate decompression buffer\n");
+		free(subdir);
+		free(fname);
+		return CL_EIO;
+	    } 
+
+	    if(uncompress((Bytef *) buff, &osize , (Bytef *) mfile + fileoff, csize) != Z_OK) {
+		cli_dbgmsg("SIS: sis_extract_simple: File decompression failed\n");
+		free(buff);
+		free(subdir);
+		free(fname);
+		return CL_EIO;
+	    }
+
+	    if(osize != (uLongf) filelen) {
+		cli_dbgmsg("SIS: WARNING: Real original size: %u\n", (unsigned int) osize);
+		filelen = (uint32_t) osize;
+	    }
+
+	} else {
+	    buff = mfile + fileoff;
+	}
+
+	if((desc = open(fname, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) == -1) {
+	    cli_errmsg("SIS: sis_extract_simple: Can't create new file %s\n", fname);
+	    free(subdir);
+	    free(fname);
+	    if(compressed)
+		free(buff);
+	    return CL_EIO;
+	} 
+
+	if((uint32_t) cli_writen(desc, buff, filelen) != filelen) {
+	    cli_errmsg("SIS: sis_extract_simple: Can't write %d bytes to %s\n", filelen, fname);
+	    free(subdir);
+	    free(fname);
+	    if(compressed)
+		free(buff);
+	    close(desc);
+	    return CL_EIO;
+	} else {
+	    if(compressed)
+		cli_dbgmsg("SIS: File decompressed into %s\n", fname);
+	    else
+		cli_dbgmsg("SIS: File saved into %s\n", fname);
+	}
+
+	if(close(desc) == -1) {
+	    cli_errmsg("SIS: sis_extract_simple: Can't close descriptor %d\n", desc);
+	    free(subdir);
+	    free(fname);
+	    if(compressed)
+		free(buff);
+	    return CL_EIO;
+	} 
+
+	free(fname);
+
+	if(compressed)
+	    free(buff);
+    }
+
+    free(subdir);
+    return CL_SUCCESS;
+}
+
+int cli_scansis(int desc, cli_ctx *ctx)
+{
+	struct sis_file_hdr file_hdr;
+	struct sis_file_hdr6 file_hdr6;
+	uint8_t release = 0, compressed, ifile = 0;
+	uint16_t opts, nlangs, *langrecs, nfiles;
+	uint32_t frecord, n;
+	size_t length;
+	char *mfile = NULL, *langs, *dir;
+	struct stat sb;
+	int i, ret;
+
+
+    if(fstat(desc, &sb) == -1) {
+	cli_errmsg("SIS: fstat() failed\n");
+	return CL_EIO;
+    }
+
+    if(sb.st_size < (off_t) sizeof(struct sis_file_hdr)) {
+	cli_dbgmsg("SIS: Broken or not a SIS file (too small)\n");
+	return CL_CLEAN;
+    }
+
+    length = sb.st_size;
+
+    if(length <= SIS_MAX_SIZE) {
+	mfile = (char *) mmap(NULL, length, PROT_READ, MAP_PRIVATE, desc, 0);
+	if(mfile == MAP_FAILED) {
+	    cli_errmsg("SIS: mmap() failed\n");
+	    return CL_EMEM;
+	} else {
+	    cli_dbgmsg("SIS: mmap'ed file\n");
+	    memcpy(&file_hdr, mfile, sizeof(struct sis_file_hdr));
+	}
+    } else {
+	cli_warnmsg("SIS: File too large (> %d)\n", SIS_MAX_SIZE);
+	return CL_CLEAN;
+    }
+
+    if(EC32(file_hdr.uid3) != 0x10000419) {
+	cli_dbgmsg("SIS: Not a SIS file\n");
+	munmap(mfile, length);
+	return CL_CLEAN;
+    }
+
+    switch(EC32(file_hdr.uid2)) {
+	case 0x1000006d:
+	    cli_dbgmsg("SIS: EPOC release 3, 4 or 5\n");
+	    release = 3;
+	    break;
+	case 0x10003a12:
+	    cli_dbgmsg("SIS: EPOC release 6\n");
+	    release = 6;
+	    break;
+	case 0x100039ce:
+	case 0x10003a38:
+	    cli_dbgmsg("SIS: Application(?)\n");
+	    return CL_CLEAN;
+	default:
+	    cli_warnmsg("SIS: Unknown value of UID 2 (EPOC release == 0x%x) -> not a real SIS file??\n", EC32(file_hdr.uid2));
+	    munmap(mfile, length);
+	    return CL_CLEAN;
+    }
+
+    /* TODO: Verify checksums (uid4 and checksum) */
+
+    /* Languages */
+    nlangs = EC16(file_hdr.nlangs);
+    cli_dbgmsg("SIS: Number of languages: %d\n", nlangs);
+
+    if(nlangs && nlangs < 100) {
+
+	if(EC32(file_hdr.plangs) >= length || EC32(file_hdr.plangs) + nlangs * 2 >= (uint32_t) sb.st_size) {
+	    cli_errmsg("SIS: Broken file structure (language records)\n");
+	    munmap(mfile, length);
+	    return CL_EFORMAT;
+	}
+
+	if(!(langrecs = (uint16_t *) cli_malloc(nlangs * 2))) {
+	    munmap(mfile, length);
+	    return CL_EMEM;
+	}
+
+	memcpy(langrecs, mfile + EC32(file_hdr.plangs), nlangs * 2);
+
+	if(!(langs = (char *) cli_calloc(nlangs * 3 + 1, sizeof(char)))) {
+	    munmap(mfile, length);
+	    free(langrecs);
+	    return CL_EMEM;
+	}
+
+	for(i = 0; i < nlangs; i++) {
+	    strncat(langs, langcodes[EC16(langrecs[i]) % 98], 2);
+	    if(i != nlangs - 1)
+		strncat(langs, " ", 1);
+	}
+	cli_dbgmsg("SIS: Supported languages: %s\n", langs);
+	free(langrecs);
+	free(langs);
+
+    } else  {
+	cli_errmsg("SIS: Incorrect number of languages (%d)\n", nlangs);
+	munmap(mfile, length);
+	return CL_EFORMAT;
+    }
+
+    cli_dbgmsg("SIS: Offset of languages records: %d\n", EC32(file_hdr.plangs));
+
+    if(EC16(file_hdr.ilang))
+	cli_dbgmsg("SIS: Installation language: %d\n", EC16(file_hdr.ilang));
+
+    /* Requisites */
+    cli_dbgmsg("SIS: Number of requisites: %d\n", EC16(file_hdr.nreqs));
+    cli_dbgmsg("SIS: Offset of requisites records: %d\n", EC32(file_hdr.preqs));
+
+    /* Options flags */
+    opts = EC16(file_hdr.options);
+    cli_dbgmsg("SIS: Options:\n");
+    if(opts & 0x0001)
+	cli_dbgmsg("SIS:    * File is in Unicode format\n");
+    if(opts & 0x0002)
+	cli_dbgmsg("SIS:    * File is distributable\n");
+    if(opts & 0x0008) {
+	cli_dbgmsg("SIS:    * Archived files are not compressed\n");
+	compressed = 0;
+    } else {
+	cli_dbgmsg("SIS:    * Archived files are compressed\n");
+	compressed = 1;
+    }
+    if(opts & 0x0010)
+	cli_dbgmsg("SIS:    * File installation shuts down all applications\n");
+
+    /* Type flags */
+    switch(EC16(file_hdr.type)) {
+	case 0x0000:
+	    cli_dbgmsg("SIS: Type: Contains an application\n");
+	    break;
+	case 0x0001:
+	    cli_dbgmsg("SIS: Type: Contains a shared/system component\n");
+	    break;
+	case 0x0002:
+	    cli_dbgmsg("SIS: Type: Contains an optional (selectable) component\n");
+	    break;
+	case 0x0003:
+	    cli_dbgmsg("SIS: Type: Configures an existing application or service\n");
+	    break;
+	case 0x0004:
+	    cli_dbgmsg("SIS: Type: Patches an existing component\n");
+	    break;
+	case 0x0005:
+	    cli_dbgmsg("SIS: Type: Upgrades an existing component\n");
+	    break;
+	default:
+	    cli_warnmsg("SIS: Unknown value of type\n");
+    } 
+
+    cli_dbgmsg("SIS: Major version: %d\n", EC16(file_hdr.majorver));
+    cli_dbgmsg("SIS: Minor version: %d\n", EC16(file_hdr.minorver));
+
+    if(release == 6) {
+
+	if(sizeof(struct sis_file_hdr) + sizeof(struct sis_file_hdr6) >= length) {
+	    cli_errmsg("SIS: Broken file structure (language records)\n");
+	    munmap(mfile, length);
+	    return CL_EFORMAT;
+	}
+
+	memcpy(&file_hdr6, mfile + sizeof(struct sis_file_hdr), sizeof(struct sis_file_hdr6));
+	cli_dbgmsg("SIS: Maximum space required: %d\n", EC32(file_hdr6.maxispace));
+    }
+
+    /* Files */
+    nfiles = EC16(file_hdr.nfiles);
+
+    if(ctx->limits && ctx->limits->maxfiles && nfiles > ctx->limits->maxfiles) {
+	cli_dbgmsg("SIS: Files limit reached (max: %d)\n", ctx->limits->maxfiles);
+	if(BLOCKMAX) {
+	    *ctx->virname = "SIS.ExceededFilesLimit";
+	    munmap(mfile, length);
+	    return CL_VIRUS;
+	}
+	return CL_CLEAN;
+    }
+
+    cli_dbgmsg("SIS: Number of files: %d\n", nfiles);
+    cli_dbgmsg("SIS: Offset of files records: %d\n", EC32(file_hdr.pfiles));
+
+    if((frecord = EC32(file_hdr.pfiles)) >= length) {
+	cli_errmsg("SIS: Broken file structure (frecord)\n");
+	munmap(mfile, length);
+	return CL_EFORMAT;
+    }
+
+    dir = cli_gentemp(NULL);
+    if(!dir || mkdir(dir, 0700) == -1) {
+	cli_errmsg("SIS: Can't create temporary directory %s\n", dir ? dir : "");
+	munmap(mfile, length);
+	return CL_ETMPDIR;
+    }
+
+    for(i = 0; i < nfiles; i++) {
+
+	cli_dbgmsg("SIS: -----\n");
+
+	if(frecord + 4 >= length) {
+	    cli_errmsg("SIS: Broken file structure (frecord)\n");
+	    munmap(mfile, length);
+	    if(!cli_leavetemps_flag)
+		cli_rmdirs(dir);
+	    free(dir);
+	    return CL_EFORMAT;
+	}
+
+	switch(cli_readint32(mfile + frecord)) {
+	    case 0x00000000:
+		cli_dbgmsg("SIS: Simple file record\n");
+		if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, 1, compressed, &ifile, dir, ctx))) {
+		    munmap(mfile, length);
+		    if(!cli_leavetemps_flag)
+			cli_rmdirs(dir);
+		    free(dir);
+		    return ret;
+		}
+
+		if(release == 6)
+		    frecord += 32 + 12 + 4;
+		else
+		    frecord += 28 + 4 + 4;
+
+		break;
+	    case 0x00000001:
+		cli_dbgmsg("SIS: Multiple languages file record\n");
+		/* TODO: Pass language strings into sis_extract */
+		if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, nlangs, compressed, &ifile, dir, ctx))) {
+		    munmap(mfile, length);
+		    if(!cli_leavetemps_flag)
+			cli_rmdirs(dir);
+		    free(dir);
+		    return ret;
+		}
+
+		if(release == 6)
+		    frecord += 32 + 12 * nlangs + 4;
+		else
+		    frecord += 28 + 4 * nlangs + 4;
+
+		break;
+	    case 0x00000002:
+		cli_dbgmsg("SIS: Options record\n");
+		if(frecord + 8 >= length) {
+		    munmap(mfile, length);
+		    if(!cli_leavetemps_flag)
+			cli_rmdirs(dir);
+		    free(dir);
+		    return CL_EFORMAT;
+		}
+
+		n = cli_readint32(mfile + frecord + 4);
+		cli_dbgmsg("SIS: Number of options: %d\n", n);
+
+		if(n > 128 || frecord + 8 * n * nlangs >= length) {
+		    cli_errmsg("SIS: Incorrect number of options\n");
+		    munmap(mfile, length);
+		    if(!cli_leavetemps_flag)
+			cli_rmdirs(dir);
+		    free(dir);
+		    return CL_EFORMAT;
+		}
+
+		frecord += 8 + 8 * n * nlangs + 16;
+
+		break;
+	    case 0x00000003:
+	    case 0x00000004:
+		cli_dbgmsg("SIS: If/ElseIf record\n");
+		if(frecord + 8 >= length) {
+		    munmap(mfile, length);
+		    if(!cli_leavetemps_flag)
+			cli_rmdirs(dir);
+		    free(dir);
+		    return CL_EFORMAT;
+		}
+
+		n = cli_readint32(mfile + frecord + 4);
+		cli_dbgmsg("SIS: Size of conditional expression: %d\n", n);
+
+		if(n >= length) {
+		    cli_errmsg("SIS: Incorrect size of conditional expression\n");
+		    munmap(mfile, length);
+		    if(!cli_leavetemps_flag)
+			cli_rmdirs(dir);
+		    free(dir);
+		    return CL_EFORMAT;
+		}
+
+		frecord += 8 + n;
+		break;
+	    case 0x00000005:
+		cli_dbgmsg("SIS: Else record\n");
+		frecord += 4;
+		break;
+	    case 0x00000006:
+		cli_dbgmsg("SIS: EndIf record\n");
+		frecord += 4;
+		break;
+	    default:
+		cli_warnmsg("SIS: Unknown file record type\n");
+	}
+    }
+
+    /* scan extracted files */
+    cli_dbgmsg("SIS:  ****** Scanning extracted files ******\n");
+    ret = cli_scandir(dir, ctx);
+
+    if(!cli_leavetemps_flag)
+	cli_rmdirs(dir);
+
+    free(dir);
+    munmap(mfile, length);
+
+    return ret;
+}
+
+#else /* HAVE_MMAP */
+
+#include "clamav.h"
+#include "others.h"
+#include "sis.h"
+
+int cli_scansis(int desc, cli_ctx *ctx)
+{
+    cli_warnmsg("Support for SIS files not compiled in!\n");
+    return CL_CLEAN;
+}
+
+#endif /* HAVE_MMAP */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,658 @@
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell at astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ * 
+ *  Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats. 
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Ben Lindstrom <mouring at eviladmin.org> 09/27/00 for OpenSSH
+ *    Welcome to the world of %lld and %qd support.  With other
+ *    long long support.  This is needed for sftp-server to work
+ *    right.
+ *
+ *  Ben Lindstrom <mouring at eviladmin.org> 02/12/01 for OpenSSH
+ *    Removed all hint of VARARGS stuff and banished it to the void,
+ *    and did a bit of KNF style work to make things a bit more
+ *    acceptable.  Consider stealing from mutt or enlightenment.
+ **************************************************************/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#if defined(BROKEN_SNPRINTF)		/* For those with broken snprintf() */
+# undef HAVE_SNPRINTF
+# undef HAVE_VSNPRINTF
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+#include <sys/types.h>
+#include <stdarg.h>
+
+static void
+dopr(char *buffer, size_t maxlen, const char *format, va_list args);
+
+static void 
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
+    int min, int max);
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
+    int min, int max, int flags);
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+    int min, int max, int flags);
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS 	(1 << 0)
+#define DP_F_PLUS  	(1 << 1)
+#define DP_F_SPACE 	(1 << 2)
+#define DP_F_NUM   	(1 << 3)
+#define DP_F_ZERO  	(1 << 4)
+#define DP_F_UP    	(1 << 5)
+#define DP_F_UNSIGNED 	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT     1
+#define DP_C_LONG      2
+#define DP_C_LDOUBLE   3
+#define DP_C_LONG_LONG 4
+
+#define char_to_int(p) (p - '0')
+#define abs_val(p) (p < 0 ? -p : p)
+
+#ifndef MAX
+#define MAX(a,b) ((a > b) ? a : b)
+#endif
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+	char *strvalue, ch;
+	long value;
+	long double fvalue;
+	int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
+	size_t currlen = 0;
+  
+	ch = *format++;
+
+	while (state != DP_S_DONE) {
+		if ((ch == '\0') || (currlen >= maxlen)) 
+			state = DP_S_DONE;
+
+		switch(state) {
+		case DP_S_DEFAULT:
+			if (ch == '%') 
+				state = DP_S_FLAGS;
+			else 
+				dopr_outch(buffer, &currlen, maxlen, ch);
+			ch = *format++;
+			break;
+		case DP_S_FLAGS:
+			switch (ch) {
+			case '-':
+				flags |= DP_F_MINUS;
+				ch = *format++;
+				break;
+			case '+':
+				flags |= DP_F_PLUS;
+				ch = *format++;
+				break;
+			case ' ':
+				flags |= DP_F_SPACE;
+				ch = *format++;
+				break;
+			case '#':
+				flags |= DP_F_NUM;
+				ch = *format++;
+				break;
+			case '0':
+				flags |= DP_F_ZERO;
+				ch = *format++;
+				break;
+			default:
+				state = DP_S_MIN;
+				break;
+			}
+			break;
+		case DP_S_MIN:
+			if (isdigit((unsigned char)ch)) {
+				min = 10 * min + char_to_int (ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				min = va_arg (args, int);
+				ch = *format++;
+				state = DP_S_DOT;
+			} else 
+				state = DP_S_DOT;
+			break;
+		case DP_S_DOT:
+			if (ch == '.') {
+				state = DP_S_MAX;
+				ch = *format++;
+			} else 
+				state = DP_S_MOD;
+			break;
+		case DP_S_MAX:
+			if (isdigit((unsigned char)ch)) {
+				if (max < 0)
+					max = 0;
+				max = 10 * max + char_to_int(ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				max = va_arg (args, int);
+				ch = *format++;
+				state = DP_S_MOD;
+			} else 
+				state = DP_S_MOD;
+			break;
+		case DP_S_MOD:
+			switch (ch) {
+			case 'h':
+				cflags = DP_C_SHORT;
+				ch = *format++;
+				break;
+			case 'l':
+				cflags = DP_C_LONG;
+				ch = *format++;
+				if (ch == 'l') {
+					cflags = DP_C_LONG_LONG;
+					ch = *format++;
+				}
+				break;
+			case 'q':
+				cflags = DP_C_LONG_LONG;
+				ch = *format++;
+				break;
+			case 'L':
+				cflags = DP_C_LDOUBLE;
+				ch = *format++;
+				break;
+			default:
+				break;
+			}
+			state = DP_S_CONV;
+			break;
+		case DP_S_CONV:
+			switch (ch) {
+			case 'd':
+			case 'i':
+				if (cflags == DP_C_SHORT) 
+					value = va_arg(args, int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg (args, long long);
+				else
+					value = va_arg (args, int);
+				fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
+				break;
+			case 'o':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
+				break;
+			case 'u':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+				break;
+			case 'X':
+				flags |= DP_F_UP;
+			case 'x':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
+				break;
+			case 'f':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				/* um, floating point? */
+				fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
+				break;
+			case 'E':
+				flags |= DP_F_UP;
+			case 'e':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'G':
+				flags |= DP_F_UP;
+			case 'g':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'c':
+				dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
+				break;
+			case 's':
+				strvalue = va_arg(args, char *);
+				if (max < 0) 
+					max = maxlen; /* ie, no max */
+				fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
+				break;
+			case 'p':
+				strvalue = va_arg(args, void *);
+				fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+				break;
+			case 'n':
+				if (cflags == DP_C_SHORT) {
+					short int *num;
+					num = va_arg(args, short int *);
+					*num = currlen;
+				} else if (cflags == DP_C_LONG) {
+					long int *num;
+					num = va_arg(args, long int *);
+					*num = currlen;
+				} else if (cflags == DP_C_LONG_LONG) {
+					long long *num;
+					num = va_arg(args, long long *);
+					*num = currlen;
+				} else {
+					int *num;
+					num = va_arg(args, int *);
+					*num = currlen;
+				}
+				break;
+			case '%':
+				dopr_outch(buffer, &currlen, maxlen, ch);
+				break;
+			case 'w': /* not supported yet, treat as next char */
+				ch = *format++;
+				break;
+			default: /* Unknown, skip */
+			break;
+			}
+			ch = *format++;
+			state = DP_S_DEFAULT;
+			flags = cflags = min = 0;
+			max = -1;
+			break;
+		case DP_S_DONE:
+			break;
+		default: /* hmm? */
+			break; /* some picky compilers need this */
+		}
+	}
+	if (currlen < maxlen - 1) 
+		buffer[currlen] = '\0';
+	else 
+		buffer[maxlen - 1] = '\0';
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+    char *value, int flags, int min, int max)
+{
+	int cnt = 0, padlen, strln;     /* amount to pad */
+  
+	if (value == 0) 
+		value = "<NULL>";
+
+	for (strln = 0; value[strln]; ++strln); /* strlen */
+	padlen = min - strln;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justify */
+
+	while ((padlen > 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+		++cnt;
+	}
+	while (*value && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, *value++);
+		++cnt;
+	}
+	while ((padlen < 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+		++cnt;
+	}
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+    long value, int base, int min, int max, int flags)
+{
+	unsigned long uvalue;
+	char convert[20];
+	int signvalue = 0, place = 0, caps = 0;
+	int spadlen = 0; /* amount to space pad */
+	int zpadlen = 0; /* amount to zero pad */
+  
+	if (max < 0)
+		max = 0;
+
+	uvalue = value;
+
+	if (!(flags & DP_F_UNSIGNED)) {
+		if (value < 0) {
+			signvalue = '-';
+			uvalue = -value;
+		} else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+			signvalue = '+';
+		else if (flags & DP_F_SPACE)
+			signvalue = ' ';
+	}
+  
+	if (flags & DP_F_UP) 
+		caps = 1; /* Should characters be upper case? */
+	do {
+		convert[place++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [uvalue % (unsigned)base];
+		uvalue = (uvalue / (unsigned)base );
+	} while (uvalue && (place < 20));
+	if (place == 20) 
+		place--;
+	convert[place] = 0;
+
+	zpadlen = max - place;
+	spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (spadlen < 0)
+		spadlen = 0;
+	if (flags & DP_F_ZERO) {
+		zpadlen = MAX(zpadlen, spadlen);
+		spadlen = 0;
+	}
+	if (flags & DP_F_MINUS) 
+		spadlen = -spadlen; /* Left Justifty */
+
+	/* Spaces */
+	while (spadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--spadlen;
+	}
+
+	/* Sign */
+	if (signvalue) 
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	/* Zeros */
+	if (zpadlen > 0) {
+		while (zpadlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+	}
+
+	/* Digits */
+	while (place > 0) 
+		dopr_outch(buffer, currlen, maxlen, convert[--place]);
+  
+	/* Left Justified spaces */
+	while (spadlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++spadlen;
+	}
+}
+
+static long double 
+pow10(int exp)
+{
+	long double result = 1;
+
+	while (exp) {
+		result *= 10;
+		exp--;
+	}
+  
+	return result;
+}
+
+static long 
+round(long double value)
+{
+	long intpart = value;
+
+	value -= intpart;
+	if (value >= 0.5)
+		intpart++;
+
+	return intpart;
+}
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+      int min, int max, int flags)
+{
+	char iconvert[20], fconvert[20];
+	int signvalue = 0, iplace = 0, fplace = 0;
+	int padlen = 0; /* amount to pad */
+	int zpadlen = 0, caps = 0;
+	long intpart, fracpart;
+	long double ufvalue;
+  
+	/* 
+	 * AIX manpage says the default is 0, but Solaris says the default
+	 * is 6, and sprintf on AIX defaults to 6
+	 */
+	if (max < 0)
+		max = 6;
+
+	ufvalue = abs_val(fvalue);
+
+	if (fvalue < 0)
+		signvalue = '-';
+	else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+		signvalue = '+';
+	else if (flags & DP_F_SPACE)
+		signvalue = ' ';
+
+	intpart = ufvalue;
+
+	/* 
+	 * Sorry, we only support 9 digits past the decimal because of our 
+	 * conversion method
+	 */
+	if (max > 9)
+		max = 9;
+
+	/* We "cheat" by converting the fractional part to integer by
+	 * multiplying by a factor of 10
+	 */
+	fracpart = round((pow10 (max)) * (ufvalue - intpart));
+
+	if (fracpart >= pow10 (max)) {
+		intpart++;
+		fracpart -= pow10 (max);
+	}
+
+	/* Convert integer part */
+	do {
+		iconvert[iplace++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [intpart % 10];
+		intpart = (intpart / 10);
+	} while(intpart && (iplace < 20));
+	if (iplace == 20) 
+		iplace--;
+	iconvert[iplace] = 0;
+
+	/* Convert fractional part */
+	do {
+		fconvert[fplace++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [fracpart % 10];
+		fracpart = (fracpart / 10);
+	} while(fracpart && (fplace < 20));
+	if (fplace == 20) 
+		fplace--;
+	fconvert[fplace] = 0;
+
+	/* -1 for decimal point, another -1 if we are printing a sign */
+	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+	zpadlen = max - fplace;
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justifty */
+
+	if ((flags & DP_F_ZERO) && (padlen > 0)) {
+		if (signvalue) {
+			dopr_outch(buffer, currlen, maxlen, signvalue);
+			--padlen;
+			signvalue = 0;
+		}
+		while (padlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--padlen;
+		}
+	}
+	while (padlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	if (signvalue) 
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	while (iplace > 0) 
+		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+	/*
+	 * Decimal point.  This should probably use locale to find the 
+	 * correct char to print out.
+	 */
+	dopr_outch(buffer, currlen, maxlen, '.');
+
+	while (fplace > 0) 
+		dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+
+	while (zpadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, '0');
+		--zpadlen;
+	}
+
+	while (padlen < 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+
+static void 
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+	if (*currlen < maxlen)
+		buffer[(*currlen)++] = c;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#ifndef HAVE_VSNPRINTF
+int 
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+	str[0] = 0;
+	dopr(str, count, fmt, args);
+
+	return(strlen(str));
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+int 
+snprintf(char *str,size_t count,const char *fmt,...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) vsnprintf(str, count, fmt, ap);
+	va_end(ap);
+
+	return(strlen(str));
+}
+
+#endif /* !HAVE_SNPRINTF */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,350 @@
+/*
+ *  Copyright (C) 2004-2005 trog at uncon.org
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifdef	_MSC_VER
+#include <windows.h>
+#endif
+
+#include "clamav-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef	C_WINDOWS
+#include <netinet/in.h>
+#endif
+#include <string.h>
+
+#include "clamav.h"
+#include "others.h"
+#include "cltypes.h"
+#include "special.h"
+
+/* NOTE: Photoshop stores data in BIG ENDIAN format, this is the opposite
+	to virtually everything else */
+
+#define special_endian_convert_16(v) be16_to_host(v)
+#define special_endian_convert_32(v) be32_to_host(v)
+
+int cli_check_mydoom_log(int desc, const char **virname)
+{
+	int32_t record[8], check;
+	int i, retval=CL_VIRUS, j;
+
+    cli_dbgmsg("in cli_check_mydoom_log()\n");
+
+    /* Check upto the first five records in the file */
+    for (j=0 ; j<5 ; j++) {
+	if (cli_readn(desc, &record, 32) != 32) {
+	    break;
+	}
+
+	/* Decode the key */
+	record[0] = ~ntohl(record[0]);
+	cli_dbgmsg("Mydoom: key: %d\n", record[0]);
+	check = 0;
+	for (i=1 ; i<8; i++) {
+	    record[i] = ntohl(record[i]) ^ record[0];
+	    check += record[i];
+	}
+	cli_dbgmsg("Mydoom: check: %d\n", ~check);
+	if ((~check) != record[0]) {
+	    return CL_CLEAN;
+	}
+    }
+
+    if (j < 2) {
+	retval = CL_CLEAN;
+    } else if (retval==CL_VIRUS) {
+	if(virname)
+	    *virname = "Worm.Mydoom.M.log";
+    }
+
+    return retval;
+}
+
+static int jpeg_check_photoshop_8bim(int fd)
+{
+	unsigned char bim[5];
+	uint16_t id, ntmp;
+	uint8_t nlength;
+	uint32_t size;
+	off_t offset;
+	int retval;
+
+	if (cli_readn(fd, bim, 4) != 4) {
+		cli_dbgmsg("read bim failed\n");
+		return -1;
+	}
+
+	if (memcmp(bim, "8BIM", 4) != 0) {
+		bim[4] = '\0';
+		cli_dbgmsg("missed 8bim: %s\n", bim);
+		return -1;
+	}
+
+	if (cli_readn(fd, &id, 2) != 2) {
+		return -1;
+	}
+	id = special_endian_convert_16(id);
+	cli_dbgmsg("ID: 0x%.4x\n", id);
+	if (cli_readn(fd, &nlength, 1) != 1) {
+		return -1;
+	}
+	ntmp = nlength + ((((uint16_t)nlength)+1) & 0x01);
+	lseek(fd, ntmp, SEEK_CUR);
+	
+	if (cli_readn(fd, &size, 4) != 4) {
+		return -1;
+	}
+	size = special_endian_convert_32(size);
+	if (size == 0) {
+		return -1;
+	}
+	if ((size & 0x01) == 1) {
+		size++;
+	}
+	/* Is it a thumbnail image */
+	if ((id != 0x0409) && (id != 0x040c)) {
+		/* No - Seek past record */
+		lseek(fd, size, SEEK_CUR);
+		return 0;
+	}
+
+	cli_dbgmsg("found thumbnail\n");
+	/* Check for thumbmail image */
+	offset = lseek(fd, 0, SEEK_CUR);
+
+	/* Jump past header */
+	lseek(fd, 28, SEEK_CUR);
+
+	retval = cli_check_jpeg_exploit(fd);
+	if (retval == 1) {
+		cli_dbgmsg("Exploit found in thumbnail\n");
+	}
+	lseek(fd, offset+size, SEEK_SET);
+
+	return retval;
+}
+
+static int jpeg_check_photoshop(int fd)
+{
+	int retval;
+	unsigned char buffer[14];
+	off_t old, new;
+
+	if (cli_readn(fd, buffer, 14) != 14) {
+		return 0;
+	}
+
+	if (memcmp(buffer, "Photoshop 3.0", 14) != 0) {
+		return 0;
+	}
+
+	cli_dbgmsg("Found Photoshop segment\n");
+	do {
+		old = lseek(fd, 0, SEEK_CUR);
+		retval = jpeg_check_photoshop_8bim(fd);
+		new = lseek(fd, 0, SEEK_CUR);
+		if(new <= old)
+			break;
+	} while (retval == 0);
+
+	if (retval == -1) {
+		retval = 0;
+	}
+	return retval;
+}
+
+int cli_check_jpeg_exploit(int fd)
+{
+	unsigned char buffer[4];
+	off_t offset;
+	int retval;
+
+
+	cli_dbgmsg("in cli_check_jpeg_exploit()\n");
+
+	if (cli_readn(fd, buffer, 2) != 2) {
+		return 0;
+	}
+
+	if ((buffer[0] != 0xff) || (buffer[1] != 0xd8)) {
+		return 0;
+	}
+
+	for (;;) {
+		if ((retval=cli_readn(fd, buffer, 4)) != 4) {
+			return 0;
+		}
+		/* Check for multiple 0xFF values, we need to skip them */
+		if ((buffer[0] == 0xff) && (buffer[1] == 0xff)) {
+			lseek(fd, -3, SEEK_CUR);
+			continue;
+		}
+
+		if ((buffer[0] == 0xff) && (buffer[1] == 0xfe)) {
+			if (buffer[2] == 0x00) {
+				if ((buffer[3] == 0x00) || (buffer[3] == 0x01)) {
+					return 1;
+				}
+			}
+		}
+		if (buffer[0] != 0xff) {
+			return -1;
+		}
+		if (buffer[1] == 0xda) {
+			/* End of Image marker */
+			return 0;
+		}
+
+		offset = ((unsigned int) buffer[2] << 8) + buffer[3];
+		if (offset < 2) {
+			return 1;
+		}
+		offset -= 2;
+		offset += lseek(fd, 0, SEEK_CUR);
+
+		if (buffer[1] == 0xed) {
+			/* Possible Photoshop file */
+			if ((retval=jpeg_check_photoshop(fd)) != 0) {
+				return retval;
+			}
+		}
+
+		if (lseek(fd, offset, SEEK_SET) != offset) {
+			return -1;
+		}
+	}
+}
+
+static uint32_t riff_endian_convert_32(uint32_t value, int big_endian)
+{
+	if (big_endian)
+		return be32_to_host(value);
+	else
+		return le32_to_host(value);
+}
+
+static int riff_read_chunk(int fd, int big_endian, int rec_level)
+{
+	uint32_t chunk_id;
+	uint32_t chunk_size;
+	int length;
+	uint32_t list_type;
+	off_t offset, cur_offset;
+
+	if (rec_level > 1000) {
+		cli_dbgmsg("riff_read_chunk: recursion level exceeded\n");
+		return 0;
+	}
+	
+	length = sizeof(uint32_t);
+	if (cli_readn(fd, &chunk_id, length) != length) {
+		return 0;
+	}
+	if (cli_readn(fd, &chunk_size, length) != length) {
+		return 0;
+	}
+	chunk_size = riff_endian_convert_32(chunk_size, big_endian);
+
+	if (memcmp(&chunk_id, "RIFF", 4) == 0) {
+		return 0;
+	} else if (memcmp(&chunk_id, "RIFX", 4) == 0) {
+		return 0;
+	}
+	
+	if ((memcmp(&chunk_id, "LIST", 4) == 0) ||
+		 (memcmp(&chunk_id, "PROP", 4) == 0) ||
+		 (memcmp(&chunk_id, "FORM", 4) == 0) ||
+		 (memcmp(&chunk_id, "CAT ", 4) == 0)) {
+		if (cli_readn(fd, &list_type, sizeof(list_type)) != sizeof(list_type)) {
+			cli_dbgmsg("riff_read_chunk: read list type failed\n");
+			return 0;
+		}
+		return riff_read_chunk(fd, big_endian, ++rec_level);	
+	}
+	
+	cur_offset = lseek(fd, 0, SEEK_CUR);
+	offset = cur_offset + chunk_size;
+	/* Check for odd alignment */
+	if ((offset & 0x01) == 1) {
+		offset++;
+	}
+	if (offset < cur_offset) {
+		return 0;
+	}
+	if (lseek(fd, offset, SEEK_SET) != offset) {
+		return 2;
+	}
+	return 1;
+}
+
+int cli_check_riff_exploit(int fd)
+{
+	uint32_t chunk_id;
+	uint32_t chunk_size;
+	uint32_t form_type;
+	int length, big_endian, retval;
+	off_t offset;
+	
+	cli_dbgmsg("in cli_check_riff_exploit()\n");
+
+	length = sizeof(uint32_t);
+	if (cli_readn(fd, &chunk_id, length) != length) {
+		return 0;
+	}
+	if (cli_readn(fd, &chunk_size, length) != length) {
+		return 0;
+	}
+	if (cli_readn(fd, &form_type, length) != length) {
+		return 0;
+	}
+	
+	if (memcmp(&chunk_id, "RIFF", 4) == 0) {
+		big_endian = FALSE;
+	} else if (memcmp(&chunk_id, "RIFX", 4) == 0) {
+		big_endian = TRUE;
+	} else {
+		/* Not a RIFF file */
+		return 0;
+	}
+
+	if (memcmp(&form_type, "ACON", 4) != 0) {
+		/* Only scan MS animated icon files */
+		/* There is a *lot* of broken software out there that produces bad RIFF files */
+		return 0;
+	}
+
+	chunk_size = riff_endian_convert_32(chunk_size, big_endian);
+
+	do {
+		retval = riff_read_chunk(fd, big_endian, 1);
+	} while (retval == 1);
+		
+	offset = lseek(fd, 0, SEEK_CUR);
+
+	if (offset < (int64_t)chunk_size) {
+		retval = 2;
+	}
+	return retval;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,492 @@
+/*
+ *  Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/*
+** spin.c
+** 
+** 19/07/2k5 - Finally started coding something
+** 21/07/2k5 - Works, started clearing the mess
+** 31/07/2k5 - Porting to libclamav
+*/
+
+/*
+** Unpacks pespin v1.1
+**
+** Funny thing to reverse
+**
+** [ A big fat thank to christoph for not letting me give up ]
+*/
+
+
+/*
+** TODO ( a fat one ):
+**
+** OEP restore and unhijacking
+** code redir handling (at least near OEP)
+** passwd protection (didn't really look at it)
+**
+** All this stuff really needs a way better emu and a hell of unlaming
+** ATM not worth the effort... and pespin v1.3 is out :@
+**
+*/
+
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "pe.h"
+#include "rebuildpe.h"
+#include "execs.h"
+#include "others.h"
+#include "packlibs.h"
+#include "spin.h"
+
+
+static char exec86(uint8_t aelle, uint8_t cielle, char *curremu, int *retval) {
+  int len = 0;
+  *retval=0;
+  while (len <0x24) {
+    uint8_t opcode = curremu[len], support;
+    len++;
+    switch (opcode) {
+      case 0xeb:
+        len++;
+      case 0x0a:
+        len++;
+      case 0x90:
+      case 0xf8:
+      case 0xf9:
+        break;
+
+      case 0x02: /* add al, cl */
+        aelle+=cielle;
+	len++;
+        break;
+      case 0x2a: /* sub al, cl */
+        aelle-=cielle;
+	len++;
+        break;
+      case 0x04: /* add al, ?? */
+        aelle+=curremu[len];
+	len++;
+        break;
+      case 0x2c: /* sub al, ?? */
+        aelle-=curremu[len];
+	len++;
+        break;
+      case 0x32: /* xor al, cl */
+        aelle^=cielle;
+	len++;
+        break;
+      case 0x34: /* xor al, ?? */
+        aelle^=curremu[len];
+	len++;
+        break;
+
+      case 0xfe: /* inc/dec al */
+        if ( curremu[len] == '\xc0' ) aelle++;
+	else aelle--;
+        len++;
+        break;
+
+      case 0xc0: /* ror/rol al, ?? */
+	support = curremu[len];
+        len++;
+        if ( support == 0xc0 ) CLI_ROL(aelle, curremu[len]);
+        else CLI_ROR(aelle, curremu[len]);
+        len++;
+        break;
+
+      default:
+        cli_dbgmsg("spin: bogus opcode %x\n", opcode);
+	*retval=1;
+	return aelle;
+    }
+  }
+  if ( len!=0x24 || curremu[len]!='\xaa' ) {
+    cli_dbgmsg("spin: bad emucode\n");
+    *retval=1;
+  }
+  return aelle;
+}
+
+
+static uint32_t summit (char *src, int size) 
+{
+  uint32_t eax=0xffffffff, ebx=0xffffffff;
+  int i;
+
+  while(size) {
+    eax ^= *src++<<8 & 0xff00;
+    eax = eax>>3 & 0x1fffffff;
+    for (i=0; i<4; i++) {
+      uint32_t swap;
+      eax ^= ebx>>8 & 0xff;
+      eax += 0x7801a108;
+      eax ^= ebx;
+      CLI_ROR(eax, ebx&0xff);
+      swap = eax;
+      eax = ebx;
+      ebx = swap;
+    }
+    size--; 
+  }
+  return ebx;
+}
+
+
+int unspin(char *src, int ssize, struct cli_exe_section *sections, int sectcnt, uint32_t nep, int desc, cli_ctx *ctx) {
+  char *curr, *emu, *ep, *spinned;
+  char **sects;
+  int blobsz=0, j;
+  uint32_t key32, bitmap, bitman;
+  uint32_t len;
+  uint8_t key8;
+
+  cli_dbgmsg("in unspin\n");
+
+  if ((spinned = (char *) cli_malloc(sections[sectcnt].rsz)) == NULL )
+    return 1;
+
+  memcpy(spinned, src + sections[sectcnt].raw, sections[sectcnt].rsz); 
+  ep = spinned + nep - sections[sectcnt].rva;
+
+  curr = ep+0xdb;
+  if ( *curr != '\xbb' ) {
+    free(spinned);
+    cli_dbgmsg("spin: Not spinned or bad version\n");
+    return 1;
+  }
+  
+  key8 = (uint8_t)*++curr;
+  curr+=4;
+  if ( *curr != '\xb9' ) {
+    free(spinned);
+    cli_dbgmsg("spin: Not spinned or bad version\n");
+    return 1;
+  }
+
+  if ( (len = cli_readint32(curr+1)) != 0x11fe ) {
+    free(spinned);
+    cli_dbgmsg("spin: Not spinned or bad version\n");
+    return 1;
+  }
+
+  cli_dbgmsg("spin: Key8 is %x, Len is %x\n", key8, len);
+
+  if (!CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep, len+0x1fe5-1) || !CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep+0x3217, 4)) {
+    free(spinned);
+    cli_dbgmsg("spin: len or key out of bounds, giving up\n");
+    return 1;
+  }
+
+  if ( ep[0x1e0]!='\xb8' )
+    cli_dbgmsg("spin: prolly not spinned, expect failure\n");
+  
+  if ( (cli_readint32(ep+0x1e1) & 0x00200000) )
+    cli_dbgmsg("spin: password protected, expect failure\n");
+
+  curr = ep+0x1fe5+len-1;
+  while ( len-- ) {
+    *curr=(*curr)^(key8--);
+    curr--;
+  }
+
+  curr = ep+0x26eb;
+  key32 = cli_readint32(curr);
+  if ( (len = cli_readint32(curr+5)) != 0x5a0) {
+    free(spinned);
+    cli_dbgmsg("spin: Not spinned or bad version\n");
+    return 1;
+  }
+
+  curr = ep+0x2d5;
+  cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len);
+
+  while ( len-- ) {
+    if ( key32 & 1 ) {
+      key32 = key32>>1;
+      key32 ^= 0x8c328834;
+    } else {
+      key32 = key32>>1;
+    }
+    *curr = *curr ^ (key32 & 0xff);
+    curr++;
+  }
+
+  len = ssize - cli_readint32(ep+0x429); /* sub size, value */
+  if ( len >= (uint32_t)ssize ) {
+    free(spinned);
+    cli_dbgmsg("spin: crc out of bounds, giving up\n");
+    return 1;
+  }
+  key32 = cli_readint32(ep+0x3217) - summit(src,len);
+
+  memcpy(src + sections[sectcnt].raw, spinned, sections[sectcnt].rsz); 
+  free(spinned); /* done CRC'ing - can have a dirty buffer now */
+  ep = src + nep + sections[sectcnt].raw - sections[sectcnt].rva; /* Fix the helper */
+
+  if (!CLI_ISCONTAINED(src, ssize, ep+0x3207, 4)) { /* this one holds all ep based checks */
+    cli_dbgmsg("spin: key out of bounds, giving up\n");
+    return 1;
+  }
+  bitmap = cli_readint32(ep+0x3207);
+  cli_dbgmsg("spin: Key32 is %x - XORbitmap is %x\n", key32, bitmap);
+  
+  cli_dbgmsg("spin: Decrypting sects (xor)\n");
+  for (j=0; j<sectcnt; j++) {
+
+    if (bitmap&1) {
+      uint32_t size = sections[j].rsz;
+      char *ptr = src + sections[j].raw;
+      uint32_t keydup = key32;
+      
+      if (!CLI_ISCONTAINED(src, (unsigned int)ssize, ptr, size)) {
+	cli_dbgmsg("spin: sect %d out of file, giving up\n", j);
+	return 1; /* FIXME: Already checked in pe.c? */
+      }
+
+      while (size--) {
+	if (! (keydup & 1)) {
+	  keydup = keydup>>1;
+	  keydup ^= 0xed43af31;
+	} else {
+	  keydup = keydup>>1;
+	}
+	*ptr = *ptr ^ (keydup & 0xff);
+	ptr++;
+      }
+    } 
+    bitmap = bitmap >>1;
+  }
+  
+  cli_dbgmsg("spin: done\n");
+
+  
+  curr = ep+0x644;
+  if ( (len = cli_readint32(curr)) != 0x180) {
+    cli_dbgmsg("spin: Not spinned or bad version\n");
+    return 1;
+  }
+
+  key32 = cli_readint32(curr+0x0c);
+  cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len);
+  curr = ep+0x28d3;
+
+  if (!CLI_ISCONTAINED(src, (unsigned int)ssize, curr, len)) { /* always true but i may decide to remove the previous check */
+    cli_dbgmsg("spin: key out of bounds, giving up\n");
+    return 1;
+  }
+  while ( len-- ) {
+    if ( key32 & 1 ) {
+      key32 = key32>>1;
+      key32 ^= 0xed43af32;
+    } else {
+      key32 = key32>>1;
+    }
+    *curr = *curr ^ (key32 & 0xff);
+    curr++;
+  }
+
+
+  curr = ep+0x28dd;
+  if ( (len = cli_readint32(curr)) != 0x1a1 ) {
+    cli_dbgmsg("spin: Not spinned or bad version\n");
+    return 1;
+  }
+
+  cli_dbgmsg("spin: POLY1 len is %x\n", len);
+  curr+=0xf; /* POLY1 */
+  emu = ep+0x6d4;
+  if (!CLI_ISCONTAINED(src, (unsigned int)ssize, emu, len)) {
+    cli_dbgmsg("spin: poly1 out of bounds\n");
+    return 1;
+  }
+  while (len) {
+    int xcfailure=0;
+    *emu=exec86(*emu, len-- & 0xff, curr, &xcfailure); /* unlame POLY1 */
+    if (xcfailure) {
+      cli_dbgmsg("spin: cannot exec poly1\n");
+      return 1;
+    }
+    emu++;
+  }
+
+
+  bitmap = cli_readint32(ep+0x6f1);
+  cli_dbgmsg("spin: POLYbitmap is %x - decrypting sects (poly)\n", bitmap);
+  curr = ep+0x755;
+
+  for (j=0; j<sectcnt; j++) {
+    if (bitmap&1) {
+      uint32_t notthesamelen = sections[j].rsz;
+
+      emu = src + sections[j].raw;
+
+      if (!CLI_ISCONTAINED(src,ssize,curr,0x24)) { /* section bounds already checked twice now */
+	cli_dbgmsg("spin: poly1 emucode is out of file?\n");
+	return 1;
+      }
+
+      while (notthesamelen) {
+	int xcfailure=0;
+        *emu=exec86(*emu, notthesamelen-- & 0xff, curr, &xcfailure);
+	if (xcfailure) {
+	  cli_dbgmsg("spin: cannot exec section\n");
+	  return 1;
+	}
+        emu++;
+      }
+    }
+      bitmap = bitmap >>1;
+  }
+  
+  cli_dbgmsg("spin: done\n");
+
+  bitmap = cli_readint32(ep+0x3061);
+  bitman = bitmap;
+
+  cli_dbgmsg("spin: Compression bitmap is %x\n", bitmap);
+  if ( (sects= (char **) cli_malloc(sectcnt*sizeof(char *))) == NULL )
+    return 1;
+
+  key8 = 0;
+  for (j=0; j<sectcnt; j++) {
+    uint32_t thissize = (bitmap&1) ? sections[j].vsz : sections[j].rsz;
+    if(ctx->limits && ctx->limits->maxfilesize && ((unsigned long int)thissize > ctx->limits->maxfilesize || (unsigned long int)blobsz > ctx->limits->maxfilesize - thissize)) {
+      key8++;
+      cli_dbgmsg("spin: section %d size exceeded (%u, %lu)\n", j, thissize, ctx->limits->maxfilesize);
+      break;
+    }
+    if (bitmap&1) {
+      if ( (sects[j] = (char *) cli_calloc(thissize, sizeof(char)) ) == NULL ) {
+	cli_dbgmsg("spin: malloc(%d) failed\n", thissize);
+	key8++;
+	break;
+      }
+      blobsz+=thissize;
+      cli_dbgmsg("spin: Growing sect%d: was %x will be %x\n", j, sections[j].rsz, thissize);
+      if ( cli_unfsg(src + sections[j].raw, sects[j], sections[j].rsz, thissize, NULL, NULL) == -1 ) {
+	key8++;
+	j++;
+	cli_dbgmsg("spin: Unpack failure\n");
+	break;
+      }
+    } else {
+      blobsz+=thissize;
+      sects[j] = src + sections[j].raw;
+      cli_dbgmsg("spin: Not growing sect%d\n", j);
+    }
+    bitmap>>=1;
+  }
+  
+  cli_dbgmsg("spin: decompression complete\n");
+ 
+  if ( key8 ) {
+    int t;
+    for (t=0 ; t<j ; t++) {
+      if (bitman&1)
+	free(sects[t]);
+      bitman = bitman >>1;
+    }
+    free(sects);
+    return 1;
+  }
+
+
+  key32 = cli_readint32(ep+0x2fee);
+  if (key32) {
+    /*    len = cli_readint32(ep+0x2fc8); -- Using vsizes instead */
+
+    for (j=0; j<sectcnt; j++) {
+      if (sections[j].rva <= key32 && sections[j].rva+sections[j].rsz > key32)
+	break;
+    }
+
+    if (j!=sectcnt && ((bitman & (1<<j)) == 0)) { /* FIXME: not really sure either the res sect is lamed or just compressed, but this'll save some major headakes */
+      cli_dbgmsg("spin: Resources (sect%d) appear to be compressed\n\tuncompressed offset %x, len %x\n\tcompressed offset %x, len %x\n", j, sections[j].rva, key32 - sections[j].rva, key32, sections[j].vsz - (key32 - sections[j].rva));
+
+      if ( (curr=(char *)cli_malloc(sections[j].vsz)) != NULL ) {
+	memcpy(curr, src + sections[j].raw, key32 - sections[j].rva); /* Uncompressed part */
+	memset(curr + key32 - sections[j].rva, 0, sections[j].vsz - (key32 - sections[j].rva)); /* bzero */
+	if ( cli_unfsg(src + sections[j].raw + key32 - sections[j].rva, curr + key32 - sections[j].rva, sections[j].rsz - (key32 - sections[j].rva), sections[j].vsz - (key32 - sections[j].rva), NULL, NULL) ) {
+      
+	  free(curr);
+	  cli_dbgmsg("spin: Failed to grow resources, continuing anyway\n");
+	  blobsz+=sections[j].rsz;
+	} else {
+	  sects[j]=curr;
+	  bitman|=1<<j;
+	  cli_dbgmsg("spin: Resources grown\n");
+	  blobsz+=sections[j].vsz;
+	}
+      } else {
+	/* malloc failed but i'm too deep into this crap to quit without leaking more :( */
+	blobsz+=sections[j].rsz;
+      }
+    } else {
+      cli_dbgmsg("spin: No res?!\n");
+    }
+  }
+  
+
+  bitmap=bitman; /* save as a free() bitmap */
+
+  if ( (ep = (char *) cli_malloc(blobsz)) != NULL ) {
+    struct cli_exe_section *rebhlp;
+    if ( (rebhlp = (struct cli_exe_section *) cli_malloc(sizeof(struct cli_exe_section)*(sectcnt))) != NULL ) {
+      char *to = ep;
+      int retval = 0;
+
+      for (j = 0; j < sectcnt; j++) {
+	rebhlp[j].raw = (j>0)?(rebhlp[j-1].raw + rebhlp[j-1].rsz):0;
+	rebhlp[j].rsz = (bitmap &1) ? sections[j].vsz : sections[j].rsz;
+	rebhlp[j].rva = sections[j].rva;
+	rebhlp[j].vsz = sections[j].vsz;
+
+	memcpy(to, sects[j], rebhlp[j].rsz);
+	to+=rebhlp[j].rsz;
+	if ( bitmap & 1 ) free(sects[j]);
+	bitmap = bitmap >>1;
+      }
+
+      if (! cli_rebuildpe(ep, rebhlp, sectcnt, 0x400000, 0x1000, 0, 0, desc)) { /* can't be bothered fixing those values: the rebuilt exe is completely broken anyway. */
+	cli_dbgmsg("spin: Cannot write unpacked file\n");
+	retval = 1;
+      }
+      free(rebhlp);
+      free(ep);
+      free(sects);
+      return retval;
+    }
+    free(ep);
+  }
+
+  cli_dbgmsg ("spin: free bitmap is %x\n", bitman);
+  for (j=0; j<sectcnt; j++) {
+    if (bitmap&1) free(sects[j]);
+    bitman = bitman >>1;
+  }
+  free(sects);
+  return 1; /* :( */
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,417 @@
+/*
+ *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *  cli_strrcpy(): Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *  cli_strtokenize(): Copyright (C) 2007 Edwin Torok <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "str.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "clamav.h"
+#include "others.h"
+#include "matcher.h"
+#include "cltypes.h"
+
+static int cli_hex2int(int c)
+{
+	int l;
+
+    if(!isascii(c))
+    	return -1;
+
+    if(isdigit(c))
+	return c - '0';
+
+    l = tolower(c);
+    if((l >= 'a') && (l <= 'f'))
+	return l + 10 - 'a';
+
+    cli_errmsg("hex2int() translation problem (%d)\n", l);
+    return -1;
+}
+
+uint16_t *cli_hex2ui(const char *hex)
+{
+	uint16_t *str, *ptr, val;
+	unsigned int i, len;
+	int c;
+
+
+    len = strlen(hex);
+
+    if(len % 2 != 0) {
+	cli_errmsg("cli_hex2si(): Malformed hexstring: %s (length: %u)\n", hex, len);
+	return NULL;
+    }
+
+    str = cli_calloc((len / 2) + 1, sizeof(uint16_t));
+    if(!str)
+	return NULL;
+
+    ptr = str;
+
+    for(i = 0; i < len; i += 2) {
+	val = 0;
+
+	if(hex[i] == '?' && hex[i + 1] == '?') {
+	    val |= CLI_MATCH_IGNORE;
+
+	} else if(hex[i + 1] == '?') {
+	    if((c = cli_hex2int(hex[i])) >= 0) {
+		val = c << 4;
+	    } else {
+		free(str);
+		return NULL;
+	    }
+	    val |= CLI_MATCH_NIBBLE_HIGH;
+
+	} else if(hex[i] == '?') {
+	    if((c = cli_hex2int(hex[i + 1])) >= 0) {
+		val = c;
+	    } else {
+		free(str);
+		return NULL;
+	    }
+	    val |= CLI_MATCH_NIBBLE_LOW;
+
+	} else if(hex[i] == '(') {
+	    val |= CLI_MATCH_ALTERNATIVE;
+
+	} else {
+	    if((c = cli_hex2int(hex[i])) >= 0) {
+		val = c;
+		if((c = cli_hex2int(hex[i+1])) >= 0) {
+		    val = (val << 4) + c;
+		} else {
+		    free(str);
+		    return NULL;
+		}
+	    } else {
+		free(str);
+		return NULL;
+	    }
+	}
+
+	*ptr++ = val;
+    }
+
+    return str;
+}
+
+char *cli_hex2str(const char *hex)
+{
+	char *str, *ptr, val, c;
+	int i, len;
+
+
+    len = strlen(hex);
+
+    if(len % 2 != 0) {
+	cli_errmsg("cli_hex2str(): Malformed hexstring: %s (length: %d)\n", hex, len);
+	return NULL;
+    }
+
+    str = cli_calloc((len / 2) + 1, sizeof(char));
+    if(!str)
+	return NULL;
+
+    ptr = str;
+
+    for(i = 0; i < len; i += 2) {
+	if((c = cli_hex2int(hex[i])) >= 0) {
+	    val = c;
+	    if((c = cli_hex2int(hex[i+1])) >= 0) {
+		val = (val << 4) + c;
+	    } else {
+		free(str);
+		return NULL;
+	    }
+	} else {
+	    free(str);
+	    return NULL;
+	}
+
+	*ptr++ = val;
+    }
+
+    return str;
+}
+
+int cli_hex2num(const char *hex)
+{
+	int hexval, ret = 0, len, i;
+
+
+    len = strlen(hex);
+
+    if(len % 2 != 0) {
+	cli_errmsg("cli_hex2num(): Malformed hexstring: %s (length: %d)\n", hex, len);
+	return -1;
+    }
+
+    for(i = 0; i < len; i++) {
+	if((hexval = cli_hex2int(hex[i])) < 0)
+	    break;
+	ret = (ret << 4) | hexval;
+    }
+
+    return ret;
+}
+
+char *cli_str2hex(const char *string, unsigned int len)
+{
+	char *hexstr;
+	char HEX[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+		       'a', 'b', 'c', 'd', 'e', 'f' };
+	unsigned int i, j;
+
+    if((hexstr = (char *) cli_calloc(2 * len + 1, sizeof(char))) == NULL)
+	return NULL;
+
+    for(i = 0, j = 0; i < len; i++, j += 2) {
+	hexstr[j] = HEX[(string[i] >> 4) & 0xf];
+	hexstr[j + 1] = HEX[string[i] & 0xf];
+    }
+
+    return hexstr;
+}
+
+char *cli_utf16toascii(const char *str, unsigned int length)
+{
+	char *decoded;
+	unsigned int i, j;
+
+
+    if(length < 2) {
+	cli_warnmsg("cli_utf16toascii: length < 2\n");
+	return NULL;
+    }
+
+    if(length % 2)
+	length--;
+
+    if(!(decoded = cli_calloc(length / 2 + 1, sizeof(char))))
+	return NULL;
+
+    for(i = 0, j = 0; i < length; i += 2, j++) {
+       decoded[j] = str[i + 1] << 4;
+       decoded[j] += str[i];
+    }
+
+    return decoded;
+}
+
+int cli_strbcasestr(const char *haystack, const char *needle)
+{
+	const char *pt =  haystack;
+	int i, j;
+
+    i = strlen(haystack);
+    j = strlen(needle);
+
+    if(i < j)
+	return 0;
+
+    pt += i - j;
+
+    return !strcasecmp(pt, needle);
+}
+
+/*
+ * Remove trailing NL and CR characters from the end of the given string.
+ * Return the new length of the string (ala strlen)
+ */
+int
+cli_chomp(char *string)
+{
+	int l;
+
+	if(string == NULL)
+		return -1;
+
+	l  = strlen(string);
+
+	if(l == 0)
+		return 0;
+
+	--l;
+
+	while((l >= 0) && ((string[l] == '\n') || (string[l] == '\r')))
+		string[l--] = '\0';
+
+	return l + 1;
+}
+
+/*
+ * char *cli_strok(const char *line, int fieldno, char *delim)
+ * Return a copy of field <fieldno> from the string <line>, where
+ * fields are delimited by any char from <delim>, or NULL if <line>
+ * doesn't have <fieldno> fields or not enough memory is available.
+ * The caller has to free() the result afterwards.
+ */
+char *cli_strtok(const char *line, int fieldno, const char *delim)
+{
+    int counter = 0, i, j;
+    char *buffer = NULL;
+
+
+    /* step to arg # <fieldno> */
+    for (i=0; line[i] && counter != fieldno; i++) {
+	if (strchr(delim, line[i])) {
+	    counter++;
+	    while(line[i+1] && strchr(delim, line[i+1])) {
+		i++;
+	    }
+	}
+    }
+    if (!line[i]) {
+	/* end of buffer before field reached */
+	return NULL;
+    }
+
+    for (j=i; line[j]; j++) {
+	if (strchr(delim, line[j])) {
+	    break;
+	}
+    }
+    if (i == j) {
+	return NULL;
+    }
+    buffer = cli_malloc(j-i+1);
+    if(!buffer)
+	return NULL;
+    strncpy(buffer, line+i, j-i);
+    buffer[j-i] = '\0';
+
+    return buffer;
+}
+
+/*
+ * Like cli_strtok, but this puts the output into a given argument, rather
+ * than allocating fresh memory
+ * Returns NULL for error, or a pointer to output
+ * njh at bandsman.co.uk
+ */
+char *cli_strtokbuf(const char *input, int fieldno, const char *delim, char *output)
+{
+    int counter = 0, i, j;
+
+    /* step to arg # <fieldno> */
+    for (i=0; input[i] && counter != fieldno; i++) {
+	if (strchr(delim, input[i])) {
+	    counter++;
+	    while(input[i+1] && strchr(delim, input[i+1])) {
+		i++;
+	    }
+	}
+    }
+    if (input[i] == '\0') {
+	/* end of buffer before field reached */
+	return NULL;
+    }
+
+    for (j=i; input[j]; j++) {
+	if (strchr(delim, input[j])) {
+	    break;
+	}
+    }
+    if (i == j) {
+	return NULL;
+    }
+    strncpy(output, input+i, j-i);
+    output[j-i] = '\0';
+
+    return output;
+}
+
+const char *cli_memstr(const char *haystack, int hs, const char *needle, int ns)
+{
+	const char *pt, *hay;
+	int n;
+
+
+    if(hs < ns)
+	return NULL;
+
+    if(haystack == needle)
+	return haystack;
+
+    if(!memcmp(haystack, needle, ns))
+	return haystack;
+
+    pt = hay = haystack;
+    n = hs;
+
+    while((pt = memchr(hay, needle[0], n)) != NULL) {
+	n -= (int) (pt - hay);
+	if(n < ns)
+	    break;
+
+	if(!memcmp(pt, needle, ns))
+	    return pt;
+
+	if(hay == pt) {
+	    n--;
+	    hay++;
+	} else {
+	    hay = pt;
+	}
+    }
+
+    return NULL;
+}
+
+char *cli_strrcpy(char *dest, const char *source) /* by NJH */
+{
+
+    if(!dest || !source) {
+	cli_errmsg("cli_strrcpy: NULL argument\n");
+	return NULL;
+    }
+
+    while((*dest++ = *source++));
+
+    return --dest;
+}
+
+void cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens)
+{
+	size_t tokens_found;
+
+
+    for(tokens_found = 0; tokens_found < token_count; ) {
+	tokens[tokens_found++] = buffer;
+	buffer = strchr(buffer, delim);
+	if(buffer) {
+	    *buffer++ = '\0';
+	} else {
+	    while(tokens_found < token_count)
+		tokens[tokens_found++] = NULL;
+
+	    return;
+	}
+    }
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,130 @@
+/*
+ *  Copyright (C) 2006 Sensory Networks, Inc.
+ *             Written by aCaB <acab at clamav.net>
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+
+/*
+** suecrypt.c
+**
+** 05/08/2k6 - Quick RCE, started coding.
+** 06/08/2k6 - There were large drops of black rain.
+** 07/08/2k6 - Found more versions, back to reversing.
+** 11/08/2k6 - Generic and special cases handler. Release. 
+**
+*/
+
+/*
+** Unpacks and rebuilds suecrypt(*)
+**
+** Not sure at all what this stuff is, couldn't find any reference to it
+** Seems to be popular in dialers, can't say more except...
+** Christoph asked for it and that's enough :)
+**
+** (*) some versions or maybe only some samples
+*/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "others.h"
+#include "pe.h"
+#include "suecrypt.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define EC16(x) le16_to_host(x)
+
+char *sudecrypt(int desc, size_t fsize, struct cli_exe_section *sections, uint16_t sects, char *buff, uint32_t bkey, uint32_t pkey, uint32_t e_lfanew) {
+  char *file, *hunk;
+  uint32_t va,sz,key;
+  int i, j;
+
+  cli_dbgmsg("in suecrypt\n");
+
+  if (!(file=cli_calloc(fsize, 1))) return 0;
+  lseek(desc, 0, SEEK_SET);
+  if((size_t) cli_readn(desc, file, fsize) != fsize) {
+    cli_dbgmsg("SUE: Can't read %d bytes\n", fsize);
+    free(file);
+    return 0;
+  }
+
+  va=(bkey>>16)|(bkey<<16);
+  key=((sz=cli_readint32(buff+0x3e))^va);
+  if (!key || key==0x208 || key==0x3bc) key=((sz=cli_readint32(buff+0x46))^va); /* FIXME: black magic */
+
+  if (key!=pkey) {
+    cli_dbgmsg("SUE: Key seems not (entirely) encrypted\n\tpossible key: 0%08x\n\tcrypted key:  0%08x\n\tplain key:    0%08x\n", pkey, key, sz);
+    va=0;
+    for (i=0; i<4; i++) {
+      va=(va<<8)|0xff;
+      if (((key&va)|(sz&(~va)))==pkey) {
+	key=pkey;
+	break;
+      }
+    }
+    if (i==4) cli_dbgmsg("SUE: let's roll the dice...\n");
+  }
+  cli_dbgmsg("SUE: Decrypting with 0%08x\n", key);
+
+  i=0;
+  while(1) {
+    if (!CLI_ISCONTAINED(buff-0x74, 0xbe, buff-0x58+i*8, 8)) {
+      free(file);
+      return 0;
+    }
+    va=(cli_readint32(buff-0x58+i*8)^bkey);
+    sz=(cli_readint32(buff-0x58+4+i*8)^bkey);
+    if (!va) break;
+    cli_dbgmsg("SUE: Hunk #%d RVA:%x size:%d\n", i, va, sz);
+    for (j=0; j<sects; j++) {
+      if(!CLI_ISCONTAINED(sections[j].rva, sections[j].rsz, va, sz)) continue;
+      hunk=file+sections[j].rva-va+sections[j].raw;
+      while(sz>=4) {
+	cli_writeint32(hunk, cli_readint32(hunk)^key);
+	hunk+=4;
+	sz-=4;
+      }
+      break;
+    }
+    if (j==sects) {
+      cli_dbgmsg("SUE: Hunk out of file or cross sections\n");
+      free(file);
+      return 0;
+    }
+    i++;
+  }
+  va=(cli_readint32(buff-0x74)^bkey);
+  cli_dbgmsg("SUE: found OEP: @%x\n", va);
+
+  hunk=file+e_lfanew;
+  hunk[6]=sects&0xff;
+  hunk[7]=sects>>8;
+  cli_writeint32(hunk+0x28, va);
+  hunk+=0x18+(cli_readint32(hunk+0x14)&0xffff); /* size of PE + size of OPT */
+  memset(hunk+0x28*sects, 0, 0x28);
+
+  return file;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,212 @@
+/*
+ *  Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * TODO: Allow individual items to be updated or removed
+ *
+ * It is up to the caller to create a mutex for the table if needed
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifndef	CL_DEBUG
+#define	NDEBUG	/* map CLAMAV debug onto standard */
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef	HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <assert.h>
+
+#include "table.h"
+#include "others.h"
+
+struct table *
+tableCreate(void)
+{
+	return (struct table *)cli_calloc(1, sizeof(struct table));
+}
+
+void
+tableDestroy(table_t *table)
+{
+	tableEntry *tableItem;
+
+	assert(table != NULL);
+
+	tableItem = table->tableHead;
+
+	while(tableItem) {
+		tableEntry *tableNext = tableItem->next;
+
+		if(tableItem->key)
+			free(tableItem->key);
+		free(tableItem);
+
+		tableItem = tableNext;
+	}
+
+	free(table);
+}
+
+/*
+ * Returns the value, or -1 for failure
+ */
+int
+tableInsert(table_t *table, const char *key, int value)
+{
+	const int v = tableFind(table, key);
+
+	if(v > 0)	/* duplicate key */
+		return (v == value) ? value : -1;	/* allow real dups */
+
+	assert(value != -1);	/* that would confuse us */
+
+	if(table->tableHead == NULL)
+		table->tableLast = table->tableHead = (tableEntry *)cli_malloc(sizeof(tableEntry));
+	else {
+		/*
+		 * Re-use deleted items
+		 */
+		if(table->flags&TABLE_HAS_DELETED_ENTRIES) {
+			tableEntry *tableItem;
+
+			assert(table->tableHead != NULL);
+
+			for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+				if(tableItem->key == NULL) {
+					/* This item has been deleted */
+					tableItem->key = cli_strdup(key);
+					tableItem->value = value;
+					return value;
+				}
+
+			table->flags &= ~TABLE_HAS_DELETED_ENTRIES;
+		}
+
+		table->tableLast = table->tableLast->next =
+			(tableEntry *)cli_malloc(sizeof(tableEntry));
+	}
+
+	if(table->tableLast == NULL)
+		return -1;
+
+	table->tableLast->next = NULL;
+	table->tableLast->key = cli_strdup(key);
+	table->tableLast->value = value;
+
+	return value;
+}
+
+/*
+ * Returns the value - -1 for not found. This means the value of a valid key
+ *	can't be -1 :-(
+ */
+int
+tableFind(const table_t *table, const char *key)
+{
+	const tableEntry *tableItem;
+#ifdef	CL_DEBUG
+	int cost;
+#endif
+
+	assert(table != NULL);
+
+	if(key == NULL)
+		return -1;	/* not treated as a fatal error */
+
+#ifdef	CL_DEBUG
+	cost = 0;
+#endif
+
+	for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) {
+#ifdef	CL_DEBUG
+		cost++;
+#endif
+		if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
+#ifdef	CL_DEBUG
+			cli_dbgmsg("tableFind: Cost of '%s' = %d\n", key, cost);
+#endif
+			return tableItem->value;
+		}
+	}
+
+	return -1;	/* not found */
+}
+
+/*
+ * Change a value in the table. If the key isn't in the table insert it
+ * Returns -1 for error, otherwise the new value
+ */
+int
+tableUpdate(table_t *table, const char *key, int new_value)
+{
+	tableEntry *tableItem;
+
+	assert(table != NULL);
+
+	if(key == NULL)
+		return -1;	/* not treated as a fatal error */
+
+	for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+		if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
+			tableItem->value = new_value;
+			return new_value;
+		}
+
+	/* not found */
+	return tableInsert(table, key, new_value);
+}
+
+/*
+ * Remove an item from the table
+ */
+void
+tableRemove(table_t *table, const char *key)
+{
+	tableEntry *tableItem;
+
+	assert(table != NULL);
+
+	if(key == NULL)
+		return;	/* not treated as a fatal error */
+
+	for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+		if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
+			free(tableItem->key);
+			tableItem->key = NULL;
+			table->flags |= TABLE_HAS_DELETED_ENTRIES;
+			/* don't break, duplicate keys are allowed */
+		}
+}
+
+void
+tableIterate(table_t *table, void(*callback)(char *key, int value, void *arg), void *arg)
+{
+	tableEntry *tableItem;
+
+	if(table == NULL)
+		return;
+
+	for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+		if(tableItem->key)	/* check node has not been deleted */
+			(*callback)(tableItem->key, tableItem->value, arg);
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,458 @@
+/*
+ *  Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * $Log: text.c,v $
+ * Revision 1.25  2007/02/12 20:46:09  njh
+ * Various tidy
+ *
+ * Revision 1.24  2006/09/13 20:53:50  njh
+ * Added debug
+ *
+ * Revision 1.23  2006/07/14 12:13:08  njh
+ * Typo
+ *
+ * Revision 1.22  2006/07/01 21:03:36  njh
+ * Better use of destroy mode
+ *
+ * Revision 1.21  2006/07/01 16:17:35  njh
+ * Added destroy flag
+ *
+ * Revision 1.20  2006/07/01 03:47:50  njh
+ * Don't loop if binhex runs out of memory
+ *
+ * Revision 1.19  2006/05/19 11:02:12  njh
+ * Just include mbox.h
+ *
+ * Revision 1.18  2006/05/04 10:37:03  nigelhorne
+ * Speed up scanning of clean files
+ *
+ * Revision 1.17  2006/05/03 09:36:40  nigelhorne
+ * Pass full ctx into the mbox code
+ *
+ * Revision 1.16  2006/04/09 19:59:28  kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.15  2005/03/10 08:50:49  nigelhorne
+ * Tidy
+ *
+ * Revision 1.14  2005/01/19 05:31:55  nigelhorne
+ * Added textIterate
+ *
+ * Revision 1.13  2004/12/08 19:03:41  nigelhorne
+ * Fix compilation error on Solaris
+ *
+ * Revision 1.12  2004/12/04 16:03:55  nigelhorne
+ * Text/plain now handled as no encoding
+ *
+ * Revision 1.11  2004/11/27 21:54:26  nigelhorne
+ * Tidy
+ *
+ * Revision 1.10  2004/08/22 10:34:24  nigelhorne
+ * Use fileblob
+ *
+ * Revision 1.9  2004/08/21 11:57:57  nigelhorne
+ * Use line.[ch]
+ *
+ * Revision 1.8  2004/07/20 14:35:29  nigelhorne
+ * Some MYDOOM.I were getting through
+ *
+ * Revision 1.7  2004/06/22 04:08:02  nigelhorne
+ * Optimise empty lines
+ *
+ * Revision 1.6  2004/05/05 09:37:52  nigelhorne
+ * Removed textClean - not needed in clamAV
+ *
+ * Revision 1.5  2004/03/25 22:40:46  nigelhorne
+ * Removed even more calls to realloc and some duplicated code
+ *
+ * Revision 1.4  2004/02/26 13:26:34  nigelhorne
+ * Handle spaces at the end of uuencoded lines
+ *
+ */
+
+static	char	const	rcsid[] = "$Id: text.c,v 1.25 2007/02/12 20:46:09 njh Exp $";
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifndef	CL_DEBUG
+#define	NDEBUG	/* map CLAMAV debug onto standard */
+#endif
+
+#include <stdlib.h>
+#ifdef	C_DARWIN
+#include <sys/types.h>
+#include <sys/malloc.h>
+#else
+#ifdef HAVE_MALLOC_H /* tk: FreeBSD-CURRENT doesn't support malloc.h */
+#ifndef	C_BSD	/* BSD now uses stdlib.h */
+#include <malloc.h>
+#endif
+#endif
+#endif
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "others.h"
+
+#include "mbox.h"
+
+static	text	*textCopy(const text *t_head);
+static	text	*textAdd(text *t_head, const text *t);
+static	void	addToFileblob(const line_t *line, void *arg);
+static	void	getLength(const line_t *line, void *arg);
+static	void	addToBlob(const line_t *line, void *arg);
+static	void	*textIterate(text *t_text, void (*cb)(const line_t *line, void *arg), void *arg, int destroy);
+
+void
+textDestroy(text *t_head)
+{
+	while(t_head) {
+		text *t_next = t_head->t_next;
+		if(t_head->t_line)
+			(void)lineUnlink(t_head->t_line);
+		free(t_head);
+		t_head = t_next;
+	}
+}
+
+/* Clone the current object */
+static text *
+textCopy(const text *t_head)
+{
+	text *first = NULL, *last = NULL;
+
+	while(t_head) {
+		if(first == NULL)
+			last = first = (text *)cli_malloc(sizeof(text));
+		else {
+			last->t_next = (text *)cli_malloc(sizeof(text));
+			last = last->t_next;
+		}
+
+		if(last == NULL) {
+			if(first)
+				textDestroy(first);
+			return NULL;
+		}
+
+		if(t_head->t_line)
+			last->t_line = lineLink(t_head->t_line);
+		else
+			last->t_line = NULL;
+
+		t_head = t_head->t_next;
+	}
+
+	if(first)
+		last->t_next = NULL;
+
+	return first;
+}
+
+/* Add a copy of a text to the end of the current object */
+static text *
+textAdd(text *t_head, const text *t)
+{
+	text *ret;
+	int count;
+
+	if(t_head == NULL) {
+		if(t == NULL) {
+			cli_errmsg("textAdd fails sanity check\n");
+			return NULL;
+		}
+		return textCopy(t);
+	}
+
+	if(t == NULL)
+		return t_head;
+
+	ret = t_head;
+
+	count = 0;
+	while(t_head->t_next) {
+		count++;
+		t_head = t_head->t_next;
+	}
+
+	cli_dbgmsg("textAdd: count = %d\n", count);
+
+	while(t) {
+		t_head->t_next = (text *)cli_malloc(sizeof(text));
+		t_head = t_head->t_next;
+
+		assert(t_head != NULL);
+
+		if(t->t_line)
+			t_head->t_line = lineLink(t->t_line);
+		else
+			t_head->t_line = NULL;
+
+		t = t->t_next;
+	}
+
+	t_head->t_next = NULL;
+
+	return ret;
+}
+
+/*
+ * Add a message's content to the end of the current object
+ */
+text *
+textAddMessage(text *aText, message *aMessage)
+{
+	assert(aMessage != NULL);
+
+	if(messageGetEncoding(aMessage) == NOENCODING)
+		return textAdd(aText, messageGetBody(aMessage));
+	else {
+		text *anotherText = messageToText(aMessage);
+
+		if(aText)
+			return textMove(aText, anotherText);
+		return anotherText;
+	}
+}
+
+/*
+ * Put the contents of the given text at the end of the current object.
+ * The given text emptied; it can be used again if needed, though be warned that
+ * it will have an empty line at the start.
+ */
+text *
+textMove(text *t_head, text *t)
+{
+	text *ret;
+
+	if(t_head == NULL) {
+		if(t == NULL) {
+			cli_errmsg("textMove fails sanity check\n");
+			return NULL;
+		}
+		t_head = (text *)cli_malloc(sizeof(text));
+		if(t_head == NULL)
+			return NULL;
+		t_head->t_line = t->t_line;
+		t_head->t_next = t->t_next;
+		t->t_line = NULL;
+		t->t_next = NULL;
+		return t_head;
+	}
+
+	if(t == NULL)
+		return t_head;
+
+	ret = t_head;
+
+	while(t_head->t_next)
+		t_head = t_head->t_next;
+
+	/*
+	 * Move the first line manually so that the caller is left clean but
+	 * empty, the rest is moved by a simple pointer reassignment
+	 */
+	t_head->t_next = (text *)cli_malloc(sizeof(text));
+	if(t_head->t_next == NULL)
+		return NULL;
+	t_head = t_head->t_next;
+
+	assert(t_head != NULL);
+
+	if(t->t_line) {
+		t_head->t_line = t->t_line;
+		t->t_line = NULL;
+	} else
+		t_head->t_line = NULL;
+
+	t_head->t_next = t->t_next;
+	t->t_next = NULL;
+
+	return ret;
+}
+
+/*
+ * Transfer the contents of the text into a blob
+ * The caller must free the returned blob if b is NULL
+ */
+blob *
+textToBlob(text *t, blob *b, int destroy)
+{
+	size_t s;
+	blob *bin;
+
+	if(t == NULL)
+		return NULL;
+
+	s = 0;
+
+	(void)textIterate(t, getLength, &s, 0);
+
+	if(s == 0)
+		return b;
+
+	/*
+	 * copy b. If b is NULL and an error occurs we know we need to free
+	 *	before returning
+	 */
+	bin = b;
+	if(b == NULL) {
+		b = blobCreate();
+
+		if(b == NULL)
+			return NULL;
+	}
+
+	if(blobGrow(b, s) != CL_SUCCESS) {
+		cli_warnmsg("Couldn't grow the blob: we may be low on memory\n");
+#if	0
+		if(!destroy) {
+			if(bin == NULL)
+				blobDestroy(b);
+			return NULL;
+		}
+		/*
+		 * We may be able to recover enough memory as we destroy to
+		 * create the blob
+		 */
+#else
+		if(bin == NULL)
+			blobDestroy(b);
+		return NULL;
+#endif
+	}
+
+	(void)textIterate(t, addToBlob, b, destroy);
+
+	if(destroy && t->t_next) {
+		textDestroy(t->t_next);
+		t->t_next = NULL;
+	}
+
+	blobClose(b);
+
+	return b;
+}
+
+fileblob *
+textToFileblob(text *t, fileblob *fb, int destroy)
+{
+	assert(fb != NULL);
+	assert(t != NULL);
+
+	if(fb == NULL) {
+		cli_dbgmsg("textToFileBlob, destroy = %d\n", destroy);
+		fb = fileblobCreate();
+
+		if(fb == NULL)
+			return NULL;
+	} else {
+		cli_dbgmsg("textToFileBlob to %s, destroy = %d\n",
+			fileblobGetFilename(fb), destroy);
+
+		fb->ctx = NULL;	/* no need to scan */
+	}
+
+	fb = textIterate(t, addToFileblob, fb, destroy);
+	if(destroy && t->t_next) {
+		textDestroy(t->t_next);
+		t->t_next = NULL;
+	}
+	return fb;
+}
+
+static void
+getLength(const line_t *line, void *arg)
+{
+	size_t *length = (size_t *)arg;
+
+	if(line)
+		*length += strlen(lineGetData(line)) + 1;
+	else
+		(*length)++;
+}
+
+static void
+addToBlob(const line_t *line, void *arg)
+{
+	blob *b = (blob *)arg;
+
+	if(line) {
+		const char *l = lineGetData(line);
+
+		blobAddData(b, (const unsigned char *)l, strlen(l));
+	}
+	blobAddData(b, (const unsigned char *)"\n", 1);
+}
+
+static void
+addToFileblob(const line_t *line, void *arg)
+{
+	fileblob *fb = (fileblob *)arg;
+
+	if(line) {
+		const char *l = lineGetData(line);
+
+		fileblobAddData(fb, (const unsigned char *)l, strlen(l));
+	}
+	fileblobAddData(fb, (const unsigned char *)"\n", 1);
+}
+
+static void *
+textIterate(text *t_text, void (*cb)(const line_t *item, void *arg), void *arg, int destroy)
+{
+	/*
+	 * Have two loops rather than one, so that we're not checking the
+	 * value of "destroy" lots and lots of times
+	 */
+#if	0
+	while(t_text) {
+		(*cb)(t_text->t_line, arg);
+
+		if(destroy && t_text->t_line) {
+			lineUnlink(t_text->t_line);
+			t_text->t_line = NULL;
+		}
+
+		t_text = t_text->t_next;
+	}
+#else
+	if(destroy)
+		while(t_text) {
+			(*cb)(t_text->t_line, arg);
+
+			if(t_text->t_line) {
+				lineUnlink(t_text->t_line);
+				t_text->t_line = NULL;
+			}
+
+			t_text = t_text->t_next;
+		}
+	else
+		while(t_text) {
+			(*cb)(t_text->t_line, arg);
+
+			t_text = t_text->t_next;
+		}
+#endif
+	return arg;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,409 @@
+/*
+ *  Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * The algorithm is based on kdepim/ktnef/lib/ktnefparser.cpp from
+ * KDE, rewritten in C by NJH. That algorithm is released under the GPL and is
+ *	Copyright (C) 2002 Michael Goffioul <kdeprint at swing.be>
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+static	char	const	rcsid[] = "$Id: tnef.c,v 1.41 2007/02/12 22:22:27 njh Exp $";
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "cltypes.h"
+#include "clamav.h"
+#include "others.h"
+
+#include "mbox.h"
+#include "tnef.h"
+
+static	int	tnef_message(FILE *fp, uint16_t type, uint16_t tag, int32_t length, off_t fsize);
+static	int	tnef_attachment(FILE *fp, uint16_t type, uint16_t tag, int32_t length, const char *dir, fileblob **fbref, off_t fsize);
+static	int	tnef_header(FILE *fp, uint8_t *part, uint16_t *type, uint16_t *tag, int32_t *length);
+
+#define	TNEF_SIGNATURE	0x223E9f78
+#define	LVL_MESSAGE	0x01
+#define	LVL_ATTACHMENT	0x02
+
+#define	attMSGCLASS	0x8008
+#define	attBODY		0x800c
+#define	attATTACHDATA	0x800f	/* Attachment Data */
+#define	attATTACHTITLE	0x8010	/* Attachment File Name */
+#define	attDATEMODIFIED	0x8020
+#define	attTNEFVERSION	0x9006
+#define	attOEMCODEPAGE	0x9007
+
+#define host16(v)	le16_to_host(v)
+#define host32(v)	le32_to_host(v)
+
+
+int
+cli_tnef(const char *dir, int desc)
+{
+	uint32_t i32;
+	uint16_t i16;
+	fileblob *fb;
+	int i, ret, alldone;
+	FILE *fp;
+	off_t fsize;
+	struct stat statb;
+
+	lseek(desc, 0L, SEEK_SET);
+
+	if(fstat(desc, &statb) < 0) {
+		cli_errmsg("Can't fstat descriptor %d\n", desc);
+		return CL_EIO;
+	}
+	fsize = statb.st_size;
+
+	i = dup(desc);
+	if((fp = fdopen(i, "rb")) == NULL) {
+		cli_errmsg("Can't open descriptor %d\n", desc);
+		close(i);
+		return CL_EOPEN;
+	}
+
+	if(fread(&i32, sizeof(uint32_t), 1, fp) != 1) {
+		fclose(fp);
+		return CL_EIO;
+	}
+	if(host32(i32) != TNEF_SIGNATURE) {
+		fclose(fp);
+		return CL_EFORMAT;
+	}
+
+	if(fread(&i16, sizeof(uint16_t), 1, fp) != 1) {
+		fclose(fp);
+		return CL_EIO;
+	}
+
+	fb = NULL;
+	ret = CL_CLEAN;	/* we don't know if it's clean or not :-) */
+	alldone = 0;
+
+	do {
+		uint8_t part = 0;
+		uint16_t type = 0, tag = 0;
+		int32_t length = 0;
+
+		switch(tnef_header(fp, &part, &type, &tag, &length)) {
+			case 0:
+				if(ferror(fp)) {
+					perror("read");
+					ret = CL_EIO;
+				}
+				alldone = 1;
+				break;
+			case 1:
+				break;
+			default:
+				ret = CL_EIO;
+				alldone = 1;
+				break;
+		}
+		if(length == 0)
+			continue;
+		if(length < 0) {
+			cli_warnmsg("Corrupt TNEF header detected - length %d\n",
+				(int)length);
+			ret = CL_EFORMAT;
+			break;
+		}
+		if(alldone)
+			break;
+		switch(part) {
+			case LVL_MESSAGE:
+				cli_dbgmsg("TNEF - found message\n");
+				if(fb != NULL) {
+					fileblobDestroy(fb);
+					fb = NULL;
+				}
+				fb = fileblobCreate();
+				if(tnef_message(fp, type, tag, length, fsize) != 0) {
+					cli_errmsg("Error reading TNEF message\n");
+					ret = CL_EFORMAT;
+					alldone = 1;
+				}
+				break;
+			case LVL_ATTACHMENT:
+				cli_dbgmsg("TNEF - found attachment\n");
+				if(tnef_attachment(fp, type, tag, length, dir, &fb, fsize) != 0) {
+					cli_errmsg("Error reading TNEF attachment\n");
+					ret = CL_EFORMAT;
+					alldone = 1;
+				}
+				break;
+			case 0:
+				break;
+			default:
+				cli_warnmsg("TNEF - unknown level %d tag 0x%x\n", (int)part, (int)tag);
+
+				/*
+				 * Dump the file incase it was part of an
+				 * email that's about to be deleted
+				 */
+				if(cli_debug_flag) {
+					int fout;
+					char *filename = cli_gentemp(NULL);
+					char buffer[BUFSIZ];
+
+#ifdef	O_BINARY
+					fout = open(filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
+#else
+					fout = open(filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
+#endif
+
+					if(fout >= 0) {
+						int count;
+
+						cli_warnmsg("Saving dump to %s:  refer to http://www.clamav.net/bugs\n", filename);
+
+						lseek(desc, 0L, SEEK_SET);
+						while((count = cli_readn(desc, buffer, sizeof(buffer))) > 0)
+							cli_writen(fout, buffer, count);
+						close(fout);
+					}
+					free(filename);
+				}
+				ret = CL_EFORMAT;
+				alldone = 1;
+				break;
+		}
+	} while(!alldone);
+
+	fclose(fp);
+
+	if(fb) {
+		cli_dbgmsg("cli_tnef: flushing final data\n");
+		if(fileblobGetFilename(fb) == NULL) {
+			cli_dbgmsg("Saving TNEF portion with an unknown name\n");
+			fileblobSetFilename(fb, dir, "tnef");
+		}
+		fileblobDestroy(fb);
+		fb = NULL;
+	}
+
+	cli_dbgmsg("cli_tnef: returning %d\n", ret);
+	return ret;
+}
+
+static int
+tnef_message(FILE *fp, uint16_t type, uint16_t tag, int32_t length, off_t fsize)
+{
+	uint16_t i16;
+	off_t offset;
+#ifdef	CL_DEBUG
+	uint32_t i32;
+	char *string;
+#endif
+
+	cli_dbgmsg("message tag 0x%x, type 0x%x, length %d\n", tag, type,
+		(int)length);
+
+	offset = ftell(fp);
+
+	/*
+	 * a lot of this stuff should be only discovered in debug mode...
+	 */
+	switch(tag) {
+		case attBODY:
+			cli_warnmsg("TNEF body not being scanned - if you believe this file contains a virus, submit it to www.clamav.net\n");
+			break;
+#ifdef	CL_DEBUG
+		case attTNEFVERSION:
+			/*assert(length == sizeof(uint32_t))*/
+			if(fread(&i32, sizeof(uint32_t), 1, fp) != 1)
+				return -1;
+			i32 = host32(i32);
+			cli_dbgmsg("TNEF version %d\n", i32);
+			break;
+		case attOEMCODEPAGE:
+			/* 8 bytes, but just print the first 4 */
+			/*assert(length == sizeof(uint32_t))*/
+			if(fread(&i32, sizeof(uint32_t), 1, fp) != 1)
+				return -1;
+			i32 = host32(i32);
+			cli_dbgmsg("TNEF codepage %d\n", i32);
+			break;
+		case attDATEMODIFIED:
+			/* 14 bytes, long */
+			break;
+		case attMSGCLASS:
+			if(length <= 0)
+				return -1;
+			string = cli_malloc(length + 1);
+			if(string == NULL)
+				return -1;
+			if(fread(string, 1, (uint32_t)length, fp) != (uint32_t)length) {
+				free(string);
+				return -1;
+			}
+			string[length] = '\0';
+			cli_dbgmsg("TNEF class %s\n", string);
+			free(string);
+			break;
+		default:
+			cli_dbgmsg("TNEF - unsupported message tag 0x%x type 0x%d length %d\n", tag, type, length);
+			break;
+#endif
+	}
+
+	/*cli_dbgmsg("%lu %lu\n", (long)(offset + length), ftell(fp));*/
+
+	if(!CLI_ISCONTAINED2(0, fsize, (off_t)offset, (off_t)length)) {
+		cli_errmsg("TNEF: Incorrect length field in tnef_message\n");
+		return -1;
+	}
+	if(fseek(fp, offset + length, SEEK_SET) < 0)
+		return -1;
+
+	/* Checksum - TODO, verify */
+	if(fread(&i16, sizeof(uint16_t), 1, fp) != 1)
+		return -1;
+
+	return 0;
+}
+
+static int
+tnef_attachment(FILE *fp, uint16_t type, uint16_t tag, int32_t length, const char *dir, fileblob **fbref, off_t fsize)
+{
+	uint32_t todo;
+	uint16_t i16;
+	off_t offset;
+	char *string;
+
+	cli_dbgmsg("attachment tag 0x%x, type 0x%x, length %d\n", tag, type,
+		(int)length);
+
+	offset = ftell(fp);
+
+	switch(tag) {
+		case attATTACHTITLE:
+			if(length <= 0)
+				return -1;
+			string = cli_malloc(length + 1);
+			if(string == NULL)
+				return -1;
+			if(fread(string, 1, (uint32_t)length, fp) != (uint32_t)length) {
+				free(string);
+				return -1;
+			}
+			string[length] = '\0';
+			cli_dbgmsg("TNEF filename %s\n", string);
+			if(*fbref == NULL) {
+				*fbref = fileblobCreate();
+				if(*fbref == NULL) {
+					free(string);
+					return -1;
+				}
+			}
+			fileblobSetFilename(*fbref, dir, string);
+			free(string);
+			break;
+		case attATTACHDATA:
+			if(*fbref == NULL) {
+				*fbref = fileblobCreate();
+				if(*fbref == NULL)
+					return -1;
+			}
+			for(todo = length; todo; todo--) {
+#if WORDS_BIGENDIAN == 1
+				int c;
+				unsigned char c2;
+
+				if((c = fgetc(fp)) == EOF)
+					break;
+				c2 = (unsigned char)c;
+				fileblobAddData(*fbref, (const unsigned char *)&c2, 1);
+#else
+				int c;
+
+				if((c = fgetc(fp)) == EOF)
+					break;
+				fileblobAddData(*fbref, (const unsigned char *)&c, 1);
+#endif
+			}
+			break;
+		default:
+			cli_dbgmsg("TNEF - unsupported attachment tag 0x%x type 0x%d length %d\n",
+				tag, type, (int)length);
+			break;
+	}
+
+	/*cli_dbgmsg("%lu %lu\n", (long)(offset + length), ftell(fp));*/
+
+	if(!CLI_ISCONTAINED2(0, fsize, (off_t)offset, (off_t)length)) {
+		cli_errmsg("TNEF: Incorrect length field in tnef_attachment\n");
+		return -1;
+	}
+	if(fseek(fp, (long)(offset + length), SEEK_SET) < 0)	/* shouldn't be needed */
+		return -1;
+
+	/* Checksum - TODO, verify */
+	if(fread(&i16, sizeof(uint16_t), 1, fp) != 1)
+		return -1;
+
+	return 0;
+}
+
+static int
+tnef_header(FILE *fp, uint8_t *part, uint16_t *type, uint16_t *tag, int32_t *length)
+{
+	uint32_t i32;
+
+	if(fread(part, sizeof(uint8_t), 1, fp) != 1)
+		return 0;
+
+	if(*part == (uint8_t)0)
+		return 0;
+
+	if(fread(&i32, sizeof(uint32_t), 1, fp) != 1) {
+		if((*part == '\n') && feof(fp)) {
+			/*
+			 * trailing newline in the file, could be caused by
+			 * broken quoted-printable encoding in the source
+			 * message missing a final '='
+			 */
+			cli_dbgmsg("tnef_header: ignoring trailing newline\n");
+			return 0;
+		}
+		return -1;
+	}
+
+	i32 = host32(i32);
+	*tag = (uint16_t)(i32 & 0xFFFF);
+	*type = (uint16_t)((i32 & 0xFFFF0000) >> 16);
+
+	if(fread(&i32, sizeof(uint32_t), 1, fp) != 1)
+		return -1;
+	*length = (int32_t)host32(i32);
+
+	cli_dbgmsg("message tag 0x%x, type 0x%x, length %d\n",
+		*tag, *type, (int)*length);
+
+	return 1;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,991 @@
+/*
+ *  Extract component parts of ARJ archives.
+ *
+ *  Copyright (C) 2007 trog at uncon.org
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <clamav.h>
+#include <ctype.h>
+
+#include "clamav.h"
+#include "cltypes.h"
+#include "others.h"
+#include "unarj.h"
+
+#define FIRST_HDR_SIZE		30
+#define COMMENT_MAX		2048
+#define FNAME_MAX		512
+#define HEADERSIZE_MAX		(FIRST_HDR_SIZE + 10 + FNAME_MAX + COMMENT_MAX)
+#define MAXDICBIT		16
+#define DDICSIZ			26624
+#define THRESHOLD		3
+#ifndef UCHAR_MAX
+#define UCHAR_MAX		(255)
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT		(8)
+#endif
+#define MAXMATCH		256
+#ifndef FALSE
+#define FALSE	(0)
+#define TRUE	(1)
+#endif
+
+#define CODE_BIT	16
+#define NT		(CODE_BIT + 3)
+#define PBIT		5
+#define TBIT		5
+#define NC		(UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
+#define NP		(MAXDICBIT + 1)
+#define CBIT		9
+#define CTABLESIZE	4096
+#define PTABLESIZE	256
+#define STRTP		9
+#define STOPP		13
+
+#define STRTL		0
+#define STOPL		7
+
+#if NT > NP
+#define NPT NT
+#else
+#define NPT NP
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a < b) ? a : b)
+#endif
+
+#define GARBLE_FLAG     0x01
+
+#ifndef HAVE_ATTRIB_PACKED
+#define __attribute__(x)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY        0
+#endif
+
+typedef struct arj_main_hdr_tag {
+	uint8_t first_hdr_size;		/* must be 30 bytes */
+	uint8_t version;
+	uint8_t min_version;
+	uint8_t host_os;
+	uint8_t flags;
+	uint8_t security_version;
+	uint8_t file_type;
+	uint8_t pad;
+	uint32_t time_created __attribute__ ((packed));
+	uint32_t time_modified __attribute__ ((packed));
+	uint32_t archive_size __attribute__ ((packed));
+	uint32_t sec_env_file_position __attribute__ ((packed));
+	uint16_t entryname_pos __attribute__ ((packed));
+	uint16_t sec_trail_size __attribute__ ((packed));
+	uint16_t host_data __attribute__ ((packed));
+} arj_main_hdr_t;
+
+typedef struct arj_file_hdr_tag {
+	uint8_t first_hdr_size;		/* must be 30 bytes */
+	uint8_t version;
+	uint8_t min_version;
+	uint8_t host_os;
+	uint8_t flags;
+	uint8_t method;
+	uint8_t file_type;
+	uint8_t password_mod;
+	uint32_t time_modified __attribute__ ((packed));
+	uint32_t comp_size __attribute__ ((packed));
+	uint32_t orig_size __attribute__ ((packed));
+	uint32_t orig_crc __attribute__ ((packed));
+	uint16_t entryname_pos __attribute__ ((packed));
+	uint16_t file_mode __attribute__ ((packed));
+	uint16_t host_data __attribute__ ((packed));
+} arj_file_hdr_t;
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack()
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack
+#endif
+
+typedef struct arj_decode_tag {
+	int fd;
+	unsigned char *text;
+	uint16_t blocksize;
+	uint16_t bit_buf;
+	unsigned char sub_bit_buf;
+	int bit_count;
+	uint32_t comp_size;
+	int16_t getlen, getbuf;
+	uint16_t left[2 * NC - 1];
+	uint16_t right[2 * NC - 1];
+	unsigned char c_len[NC];
+	uint16_t c_table[CTABLESIZE];
+	unsigned char pt_len[NPT];
+	uint16_t pt_table[PTABLESIZE];
+} arj_decode_t;
+
+static int fill_buf(arj_decode_t *decode_data, int n)
+{
+	decode_data->bit_buf = (decode_data->bit_buf << n) & 0xFFFF;
+	while (n > decode_data->bit_count) {
+		decode_data->bit_buf |= decode_data->sub_bit_buf << (n -= decode_data->bit_count);
+		if (decode_data->comp_size != 0) {
+			decode_data->comp_size--;
+			if (cli_readn(decode_data->fd, &decode_data->sub_bit_buf, 1) != 1) {
+				return CL_EIO;
+			}
+		} else {
+			decode_data->sub_bit_buf = 0;
+		}
+		decode_data->bit_count = CHAR_BIT;
+	}
+	decode_data->bit_buf |= decode_data->sub_bit_buf >> (decode_data->bit_count -= n);
+	return CL_SUCCESS;
+}
+
+static int init_getbits(arj_decode_t *decode_data)
+{
+	decode_data->bit_buf = 0;
+	decode_data->sub_bit_buf = 0;
+	decode_data->bit_count = 0;
+	return fill_buf(decode_data, 2 * CHAR_BIT);
+}
+
+static unsigned short arj_getbits(arj_decode_t *decode_data, int n)
+{
+	unsigned short x;
+	
+	x = decode_data->bit_buf >> (2 * CHAR_BIT - n);
+	fill_buf(decode_data, n);
+	return x;
+}
+
+static int decode_start(arj_decode_t *decode_data)
+{
+	decode_data->blocksize = 0;
+	return init_getbits(decode_data);
+}
+
+static int write_text(int ofd, unsigned char *data, int length)
+{
+	int count;
+	
+	count = cli_writen(ofd, data, length);
+	if (count != length) {
+		return CL_EIO;
+	} else {
+		return CL_SUCCESS;
+	}
+}
+
+static int make_table(arj_decode_t *decode_data, int nchar, unsigned char *bitlen, int tablebits,
+			unsigned short *table, int tablesize)
+{
+	unsigned short count[17], weight[17], start[18], *p;
+	unsigned int i, k, len, ch, jutbits, avail, nextcode, mask;
+	
+	for (i = 1; i <=16; i++) {
+		count[i] = 0;
+	}
+	for (i = 0; (int)i < nchar; i++) {
+		count[bitlen[i]]++;
+	}
+	
+	start[1] = 0;
+	for (i = 1; i <= 16; i++) {
+		start[i+1] = start[i] + (count[i] << (16 - i));
+	}
+	if (start[17] != (unsigned short) (1 << 16)) {
+		return CL_EARJ;
+	}
+	
+	jutbits = 16 - tablebits;
+	for (i = 1; (int)i <= tablebits; i++) {
+		start[i] >>= jutbits;
+		weight[i] = 1 << (tablebits - i);
+	}
+	while (i <= 16) {
+		weight[i] = 1 << (16 - i);
+		i++;
+	}
+	
+	i = start[tablebits + 1] >> jutbits;
+	if (i != (unsigned short) (1 << 16)) {
+		k = 1 << tablebits;
+		while (i != k) {
+			table[i++] = 0;
+		}
+	}
+	
+	avail = nchar;
+	mask = 1 << (15 - tablebits);
+	for (ch = 0; (int)ch < nchar; ch++) {
+		if ((len = bitlen[ch]) == 0) {
+			continue;
+		}
+		k = start[len];
+		nextcode = k + weight[len];
+		if ((int)len <= tablebits) {
+			if (nextcode > (unsigned int) tablesize) {
+				return CL_EARJ;
+			}
+			for (i = start[len]; i < nextcode; i++) {
+				table[i] = ch;
+			}
+		} else {
+			p = &table[k >> jutbits];
+			i = len - tablebits;
+			while (i != 0) {
+				if (*p == 0) {
+					decode_data->right[avail] = decode_data->left[avail] = 0;
+					*p = avail++;
+				}
+				if (k & mask) {
+					p = &decode_data->right[*p];
+				} else {
+					p = &decode_data->left[*p];
+				}
+				k <<= 1;
+				i--;
+			}
+			*p = ch;
+		}
+		start[len] = nextcode;
+	}
+	return CL_SUCCESS;
+}
+
+static void read_pt_len(arj_decode_t *decode_data, int nn, int nbit, int i_special)
+{
+	int i, n;
+	short c;
+	unsigned short mask;
+	
+	n = arj_getbits(decode_data, nbit);
+	if (n == 0) {
+		c = arj_getbits(decode_data, nbit);
+		for (i = 0; i < nn; i++) {
+			decode_data->pt_len[i] = 0;
+		}
+		for (i = 0; i < 256; i++) {
+			decode_data->pt_table[i] = c;
+		}
+	} else {
+		i = 0;
+		while ((i < n) && (i < NPT)) {
+			c = decode_data->bit_buf >> 13;
+			if (c == 7) {
+				mask = 1 << 12;
+				while (mask & decode_data->bit_buf) {
+					mask >>= 1;
+					c++;
+				}
+			}
+			fill_buf(decode_data, (c < 7) ? 3 : (int)(c - 3));
+			decode_data->pt_len[i++] = (unsigned char) c;
+			if (i == i_special) {
+				c = arj_getbits(decode_data, 2);
+				while ((--c >= 0) && (i < NPT)) {
+					decode_data->pt_len[i++] = 0;
+				}
+			}
+		}
+		while ((i < nn) && (i < NPT)) {
+			decode_data->pt_len[i++] = 0;
+		}
+		make_table(decode_data, nn, decode_data->pt_len, 8, decode_data->pt_table, PTABLESIZE);
+	}
+}
+
+static int read_c_len(arj_decode_t *decode_data)
+{
+	short i, c, n;
+	unsigned short mask;
+	
+	n = arj_getbits(decode_data, CBIT);
+	if (n == 0) {
+		c = arj_getbits(decode_data, CBIT);
+		for (i = 0; i < NC; i++) {
+			decode_data->c_len[i] = 0;
+		}
+		for (i = 0; i < CTABLESIZE; i++) {
+			decode_data->c_table[i] = c;
+		}
+	} else {
+		i = 0;
+		while (i < n) {
+			c = decode_data->pt_table[decode_data->bit_buf >> 8];
+			if (c >= NT) {
+				mask = 1 << 7;
+				do {
+					if (c >= (2 * NC - 1)) {
+						cli_warnmsg("ERROR: bounds exceeded\n");
+						return CL_EFORMAT;
+					}
+					if (decode_data->bit_buf & mask) {
+						c = decode_data->right[c];
+					} else {
+						c = decode_data->left[c];
+					}
+					mask >>= 1;
+				} while (c >= NT);
+			}
+			fill_buf(decode_data, (int)(decode_data->pt_len[c]));
+			if (c <= 2) {
+				if (c == 0) {
+					c = 1;
+				} else if (c == 1) {
+					c = arj_getbits(decode_data, 4) + 3;
+				} else {
+					c = arj_getbits(decode_data, CBIT) + 20;
+				}
+				while (--c >= 0) {
+					if (i >= NC) {
+						cli_warnmsg("ERROR: bounds exceeded\n");
+						return CL_EFORMAT;
+					}
+					decode_data->c_len[i++] = 0;
+				}
+			} else {
+				if (i >= NC) {
+					cli_warnmsg("ERROR: bounds exceeded\n");
+					return CL_EFORMAT;
+				}
+				decode_data->c_len[i++] = (unsigned char) (c - 2);
+			}
+		}
+		while (i < NC) {
+			decode_data->c_len[i++] = 0;
+		}
+		make_table(decode_data, NC, decode_data->c_len, 12, decode_data->c_table, CTABLESIZE);
+	}
+	return CL_SUCCESS;
+}
+
+
+static uint16_t decode_c(arj_decode_t *decode_data)
+{
+	uint16_t j, mask;
+	
+	if (decode_data->blocksize == 0) {
+		decode_data->blocksize = arj_getbits(decode_data, 16);
+		read_pt_len(decode_data, NT, TBIT, 3);
+		read_c_len(decode_data);
+		read_pt_len(decode_data, NT, PBIT, -1);
+	}
+	decode_data->blocksize--;
+	j = decode_data->c_table[decode_data->bit_buf >> 4];
+	if (j >= NC) {
+		mask = 1 << 3;
+		do {
+			if (j >= (2 * NC - 1)) {
+				cli_warnmsg("ERROR: bounds exceeded\n");
+				return 0;
+			}
+			if (decode_data->bit_buf & mask) {
+				j = decode_data->right[j];
+			} else {
+				j = decode_data->left[j];
+			}
+			mask >>= 1;
+		} while (j >= NC);
+	}
+	fill_buf(decode_data, (int)(decode_data->c_len[j]));
+	return j;
+}
+
+static uint16_t decode_p(arj_decode_t *decode_data)
+{
+	unsigned short j, mask;
+	
+	j = decode_data->pt_table[decode_data->bit_buf >> 8];
+	if (j >= NP) {
+		mask = 1 << 7;
+		do {
+			if (j >= (2 * NC - 1)) {
+				cli_warnmsg("ERROR: bounds exceeded\n");
+				return 0;
+			}
+			if (decode_data->bit_buf & mask) {
+				j = decode_data->right[j];
+			} else {
+				j = decode_data->left[j];
+			}
+			mask >>= 1;
+		} while (j >= NP);
+	}
+	fill_buf(decode_data, (int)(decode_data->pt_len[j]));
+	if (j != 0) {
+		j--;
+		j = (1 << j) + arj_getbits(decode_data, (int)j);
+	}
+	return j;
+}
+
+static int decode(int fd, arj_metadata_t *metadata)
+{
+	int ret;
+
+	arj_decode_t decode_data;
+	uint32_t count=0, out_ptr=0;
+	int16_t chr, i, j;
+
+	decode_data.text = (unsigned char *) cli_malloc(DDICSIZ);
+	if (!decode_data.text) {
+		return CL_EMEM;
+	}
+	decode_data.fd = fd;
+	decode_data.comp_size = metadata->comp_size;
+	ret = decode_start(&decode_data);
+	if (ret != CL_SUCCESS) {
+		return ret;
+	}
+
+	while (count < metadata->orig_size) {
+		if ((chr = decode_c(&decode_data)) <= UCHAR_MAX) {
+			decode_data.text[out_ptr] = (unsigned char) chr;
+			count++;
+			if (++out_ptr >= DDICSIZ) {
+				out_ptr = 0;
+				write_text(metadata->ofd, decode_data.text, DDICSIZ);
+			}
+		} else {
+			j = chr - (UCHAR_MAX + 1 - THRESHOLD);
+			count += j;
+			i = decode_p(&decode_data);
+			if ((i = out_ptr - i - 1) < 0) {
+				i += DDICSIZ;
+			}
+			if ((i >= DDICSIZ) || (i < 0)) {
+				cli_warnmsg("UNARJ: bounds exceeded - probably a corrupted file.\n");
+				break;
+			}
+			if (out_ptr > i && out_ptr < DDICSIZ - MAXMATCH - 1) {
+				while ((--j >= 0) && (i < DDICSIZ) && (out_ptr < DDICSIZ)) {
+					decode_data.text[out_ptr++] = decode_data.text[i++];
+				}
+			} else {
+				while (--j >= 0) {				
+					decode_data.text[out_ptr] = decode_data.text[i];
+					if (++out_ptr >= DDICSIZ) {
+						out_ptr = 0;
+						write_text(metadata->ofd, decode_data.text, DDICSIZ);
+					}
+					if (++i >= DDICSIZ) {
+						i = 0;
+					}
+				}
+			}
+		}
+	}
+	if (out_ptr != 0) {
+		write_text(metadata->ofd, decode_data.text, out_ptr);
+	}
+	
+	free(decode_data.text);
+	return CL_SUCCESS;
+}
+
+#define ARJ_BFIL(dd) {dd->getbuf|=dd->bit_buf>>dd->getlen;fill_buf(dd,CODE_BIT-dd->getlen);dd->getlen=CODE_BIT;}
+#define ARJ_GETBIT(dd,c) {if(dd->getlen<=0)ARJ_BFIL(dd) c=(dd->getbuf&0x8000)!=0;dd->getbuf<<=1;dd->getlen--;}
+#define ARJ_BPUL(dd,l) {dd->getbuf<<=l;dd->getlen-=l;}
+#define ARJ_GETBITS(dd,c,l) {if(dd->getlen<l)ARJ_BFIL(dd) c=(uint16_t)dd->getbuf>>(CODE_BIT-l);ARJ_BPUL(dd,l)}
+
+static uint16_t decode_ptr(arj_decode_t *decode_data)
+{
+	uint16_t c, width, plus, pwr;
+	
+	plus = 0;
+	pwr = 1 << STRTP;
+	for (width = STRTP; width < STOPP; width++) {
+		ARJ_GETBIT(decode_data, c);
+		if (c == 0) {
+			break;
+		}
+		plus += pwr;
+		pwr <<= 1;
+	}
+	if (width != 0) {
+		ARJ_GETBITS(decode_data, c, width);
+	}
+	c += plus;
+	return c;
+}
+
+static uint16_t decode_len(arj_decode_t *decode_data)
+{
+	uint16_t c, width, plus, pwr;
+
+	plus = 0;
+	pwr = 1 << STRTL;
+	for (width = STRTL; width < STOPL; width++) {
+		ARJ_GETBIT(decode_data, c);
+		if (c == 0) {
+			break;
+		}
+		plus += pwr;
+		pwr <<= 1;
+	}
+	if (width != 0) {
+		ARJ_GETBITS(decode_data, c, width);
+	}
+	c += plus;
+	return c;
+}
+
+static int decode_f(int fd, arj_metadata_t *metadata)
+{
+	int ret;
+
+	arj_decode_t decode_data, *dd;
+	uint32_t count=0, out_ptr=0;
+	int16_t chr, i, j, pos;
+
+	dd = &decode_data;
+	decode_data.text = (unsigned char *) cli_malloc(DDICSIZ);
+	if (!decode_data.text) {
+		return CL_EMEM;
+	}
+	decode_data.fd = fd;
+	decode_data.comp_size = metadata->comp_size;
+	ret = init_getbits(&decode_data);
+	if (ret != CL_SUCCESS) {
+		return ret;
+	}
+    	decode_data.getlen = decode_data.getbuf = 0;
+
+	while (count < metadata->orig_size) {
+		chr = decode_len(&decode_data);
+		if (chr == 0) {
+			ARJ_GETBITS(dd, chr, CHAR_BIT);
+			decode_data.text[out_ptr] = (unsigned char) chr;
+			count++;
+			if (++out_ptr >= DDICSIZ) {
+				out_ptr = 0;
+				write_text(metadata->ofd, decode_data.text, DDICSIZ);
+			}
+		} else {
+			j = chr - 1 + THRESHOLD;
+			count += j;
+			pos = decode_ptr(&decode_data);
+			if ((i = out_ptr - pos - 1) < 0) {
+				i += DDICSIZ;
+			}
+			if ((i >= DDICSIZ) || (i < 0)) {
+				cli_warnmsg("UNARJ: bounds exceeded - probably a corrupted file.\n");
+				break;
+			}
+			while (j-- > 0) {
+				decode_data.text[out_ptr] = decode_data.text[i];
+				if (++out_ptr >= DDICSIZ) {
+					out_ptr = 0;
+					write_text(metadata->ofd, decode_data.text, DDICSIZ);
+				}
+				if (++i >= DDICSIZ) {
+					i = 0;
+				}
+			}
+		}
+	}
+	if (out_ptr != 0) {
+		write_text(metadata->ofd, decode_data.text, out_ptr);
+	}
+	
+	free(decode_data.text);
+	return CL_SUCCESS;
+}	
+
+static uint32_t arj_unstore(int ifd, int ofd, uint32_t len)
+{
+	unsigned char data[8192];
+	uint32_t count, rem;
+	unsigned int todo;
+
+	cli_dbgmsg("in arj_unstore\n");
+	rem = len;
+
+	while (rem > 0) {
+		todo = (unsigned int) MIN(8192, rem);
+		count = cli_readn(ifd, data, todo);
+		if (count != todo) {
+			return len-rem;
+		}
+		if (cli_writen(ofd, data, count) != count) {
+			return len-rem-count;
+		}
+		rem -= count;
+	}
+	return len;
+}
+
+static int is_arj_archive(int fd)
+{
+	const char header_id[2] = {0x60, 0xea};
+	char mark[2];
+	
+	if (cli_readn(fd, &mark[0], 2) != 2) {
+		return FALSE;
+	}
+	if (memcmp(&mark[0], &header_id[0], 2) == 0) {
+		return TRUE;
+	}
+	cli_dbgmsg("Not an ARJ archive\n");
+	return FALSE;
+}
+
+static int arj_read_main_header(int fd)
+{
+	uint16_t header_size, count;
+	uint32_t crc;
+	arj_main_hdr_t main_hdr;
+	char *filename, *comment;
+	off_t header_offset;
+
+	if (cli_readn(fd, &header_size, 2) != 2) {
+		return FALSE;
+	}
+	header_offset = lseek(fd, 0, SEEK_CUR);
+	header_size = le16_to_host(header_size);
+	cli_dbgmsg("Header Size: %d\n", header_size);
+	if (header_size == 0) {
+		/* End of archive */
+		return FALSE;
+	}
+	if (header_size > HEADERSIZE_MAX) {
+		cli_dbgmsg("arj_read_header: invalid header_size: %u\n ", header_size);
+		return FALSE;
+	}
+	
+	if (cli_readn(fd, &main_hdr, 30) != 30) {
+		return FALSE;
+	}
+	
+	cli_dbgmsg("ARJ Main File Header\n");
+	cli_dbgmsg("First Header Size: %d\n", main_hdr.first_hdr_size);
+	cli_dbgmsg("Version: %d\n", main_hdr.version);
+	cli_dbgmsg("Min version: %d\n", main_hdr.min_version);
+	cli_dbgmsg("Host OS: %d\n", main_hdr.host_os);
+	cli_dbgmsg("Flags: 0x%x\n", main_hdr.flags);
+	cli_dbgmsg("Security version: %d\n", main_hdr.security_version);
+	cli_dbgmsg("File type: %d\n", main_hdr.file_type);
+
+	if (main_hdr.first_hdr_size < 30) {
+		cli_dbgmsg("Format error. First Header Size < 30\n");
+		return FALSE;
+	}
+	if (main_hdr.first_hdr_size > 30) {
+		if (lseek(fd, main_hdr.first_hdr_size - 30, SEEK_CUR) == -1) {
+			return FALSE;
+		}
+	}
+
+	filename = (char *) cli_malloc(header_size);
+	if (!filename) {
+		return FALSE;
+	}
+	for (count=0 ; count < header_size ; count++) {
+		if (cli_readn(fd, &filename[count], 1) != 1) {
+			free(filename);
+			return FALSE;
+		}
+		if (filename[count] == '\0') {
+			break;
+		}
+	}
+	if (count == header_size) {
+		free(filename);
+		return FALSE;
+	}
+	comment = (char *) cli_malloc(header_size);
+	if (!comment) {
+		free(filename);
+		return FALSE;
+	}
+	for (count=0 ; count < header_size ; count++) {
+		if (cli_readn(fd, &comment[count], 1) != 1) {
+			free(filename);
+			free(comment);
+			return FALSE;
+		}
+		if (comment[count] == '\0') {
+			break;
+		}
+	}
+	if (count == header_size) {
+		free(filename);
+		free(comment);
+		return FALSE;
+	}
+	cli_dbgmsg("Filename: %s\n", filename);
+	cli_dbgmsg("Comment: %s\n", comment);
+	
+	free(filename);
+	free(comment);
+	
+	if (cli_readn(fd, &crc, 4) != 4) {
+		return FALSE;
+	}
+	
+	/* Skip past any extended header data */
+	for (;;) {
+		if (cli_readn(fd, &count, 2) != 2) {
+			return FALSE;
+		}
+		count = le16_to_host(count);
+		cli_dbgmsg("Extended header size: %d\n", count);
+		if (count == 0) {
+			break;
+		}
+		/* Skip extended header + 4byte CRC */
+		if (lseek(fd, (off_t) (count + 4), SEEK_CUR) == -1) {
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+static int arj_read_file_header(int fd, arj_metadata_t *metadata)
+{
+	uint16_t header_size, count;
+	char *filename, *comment;
+	arj_file_hdr_t file_hdr;
+	
+	if (cli_readn(fd, &header_size, 2) != 2) {
+		return CL_EFORMAT;
+	}
+	header_size = le16_to_host(header_size);
+	cli_dbgmsg("Header Size: %d\n", header_size);
+	if (header_size == 0) {
+		/* End of archive */
+		return CL_BREAK;
+	}
+	if (header_size > HEADERSIZE_MAX) {
+		cli_dbgmsg("arj_read_file_header: invalid header_size: %u\n ", header_size);
+		return CL_EFORMAT;
+	}
+	
+	if (cli_readn(fd, &file_hdr, 30) != 30) {
+		return CL_EFORMAT;
+	}
+	file_hdr.comp_size = le32_to_host(file_hdr.comp_size);
+	file_hdr.orig_size = le32_to_host(file_hdr.orig_size);
+	
+	cli_dbgmsg("ARJ File Header\n");
+	cli_dbgmsg("First Header Size: %d\n", file_hdr.first_hdr_size);
+	cli_dbgmsg("Version: %d\n", file_hdr.version);
+	cli_dbgmsg("Min version: %d\n", file_hdr.min_version);
+	cli_dbgmsg("Host OS: %d\n", file_hdr.host_os);
+	cli_dbgmsg("Flags: 0x%x\n", file_hdr.flags);
+	cli_dbgmsg("Method: %d\n", file_hdr.method);
+	cli_dbgmsg("File type: %d\n", file_hdr.file_type);
+	cli_dbgmsg("File type: %d\n", file_hdr.password_mod);
+	cli_dbgmsg("Compressed size: %u\n", file_hdr.comp_size);
+	cli_dbgmsg("Original size: %u\n", file_hdr.orig_size);	
+
+	if (file_hdr.first_hdr_size < 30) {
+		cli_dbgmsg("Format error. First Header Size < 30\n");
+		return CL_EFORMAT;
+	}
+
+	/* Note: this skips past any extended file start position data (multi-volume) */
+	if (file_hdr.first_hdr_size > 30) {
+		if (lseek(fd, file_hdr.first_hdr_size - 30, SEEK_CUR) == -1) {
+			return CL_EFORMAT;
+		}
+	}
+
+	filename = (char *) cli_malloc(header_size);
+	if (!filename) {
+		return CL_EMEM;
+	}
+	for (count=0 ; count < header_size ; count++) {
+		if (cli_readn(fd, &filename[count], 1) != 1) {
+			free(filename);
+			return CL_EFORMAT;
+		}
+		if (filename[count] == '\0') {
+			break;
+		}
+	}
+	if (count == header_size) {
+		free(filename);
+		return CL_EFORMAT;
+	}
+
+	comment = (char *) cli_malloc(header_size);
+	if (!comment) {
+		free(filename);
+		return CL_EFORMAT;
+	}
+	for (count=0 ; count < header_size ; count++) {
+		if (cli_readn(fd, &comment[count], 1) != 1) {
+			free(filename);
+			free(comment);
+			return CL_EFORMAT;
+		}
+		if (comment[count] == '\0') {
+			break;
+		}
+	}
+	if (count == header_size) {
+		free(filename);
+		free(comment);
+		return CL_EFORMAT;
+	}
+	cli_dbgmsg("Filename: %s\n", filename);
+	cli_dbgmsg("Comment: %s\n", comment);
+	metadata->filename = cli_strdup(filename);
+
+	free(filename);
+	free(comment);
+
+	/* Skip CRC */
+	if (lseek(fd, (off_t) 4, SEEK_CUR) == -1) {
+		return CL_EFORMAT;
+	}
+	
+	/* Skip past any extended header data */
+	for (;;) {
+		if (cli_readn(fd, &count, 2) != 2) {
+			return CL_EFORMAT;
+		}
+		count = le16_to_host(count);
+		cli_dbgmsg("Extended header size: %d\n", count);
+		if (count == 0) {
+			break;
+		}
+		/* Skip extended header + 4byte CRC */
+		if (lseek(fd, (off_t) (count + 4), SEEK_CUR) == -1) {
+			return CL_EFORMAT;
+		}
+	}
+	metadata->comp_size = file_hdr.comp_size;
+	metadata->orig_size = file_hdr.orig_size;
+	metadata->method = file_hdr.method;
+	metadata->encrypted = ((file_hdr.flags & GARBLE_FLAG) != 0) ? TRUE : FALSE;
+	metadata->ofd = -1;
+	if (!metadata->filename) {
+		return CL_EMEM;
+	}
+	
+	return CL_SUCCESS;
+}
+
+int cli_unarj_open(int fd, const char *dirname)
+{
+
+	cli_dbgmsg("in cli_unarj_open\n");
+
+	if (!is_arj_archive(fd)) {
+		cli_dbgmsg("Not in ARJ format\n");
+		return CL_EFORMAT;
+	}
+	if (!arj_read_main_header(fd)) {
+		cli_dbgmsg("Failed to read main header\n");
+		return CL_EFORMAT;
+	}
+	return CL_SUCCESS;
+}
+
+int cli_unarj_prepare_file(int fd, const char *dirname, arj_metadata_t *metadata)
+{
+	cli_dbgmsg("in cli_unarj_prepare_file\n");
+	if (!metadata || !dirname || (fd < 0)) {
+		return CL_ENULLARG;
+	}
+	/* Each file is preceeded by the ARJ file marker */
+	if (!is_arj_archive(fd)) {
+		cli_dbgmsg("Not in ARJ format\n");
+		return CL_EFORMAT;
+	}
+	return arj_read_file_header(fd, metadata);
+}
+
+int cli_unarj_extract_file(int fd, const char *dirname, arj_metadata_t *metadata)
+{
+	off_t offset;
+	int ret = CL_SUCCESS;
+	char filename[1024];
+	
+	cli_dbgmsg("in cli_unarj_extract_file\n");
+	if (!metadata || !dirname || (fd < 0)) {
+		return CL_ENULLARG;
+	}
+
+	if (metadata->encrypted) {
+		cli_dbgmsg("PASSWORDed file (skipping)\n");
+		offset = lseek(fd, 0, SEEK_CUR) + metadata->comp_size;
+		cli_dbgmsg("Target offset: %ld\n", offset);
+		if (lseek(fd, offset, SEEK_SET) != offset) {
+			return CL_EARJ;
+		}
+		return CL_SUCCESS;
+	}
+	
+	snprintf(filename, 1024, "%s/file.uar", dirname);
+	cli_dbgmsg("Filename: %s\n", filename);
+	metadata->ofd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
+	if (metadata->ofd < 0) {
+		return CL_EOPEN;
+	}
+	switch (metadata->method) {
+		case 0:
+			ret = arj_unstore(fd, metadata->ofd, metadata->comp_size);
+			if (ret != metadata->comp_size) {
+				ret = CL_EIO;
+			} else {
+				ret = CL_SUCCESS;
+			}
+			break;
+		case 1:
+		case 2:
+		case 3:
+			decode(fd, metadata);
+			break;
+		case 4:
+			decode_f(fd, metadata);
+			break;
+		default:
+			ret = CL_EFORMAT;
+			break;
+	}
+	return ret;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,523 @@
+/*
+ *  Copyright (C) 2006 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/*
+** unsp.c
+**
+** 11/10/2k6 - Merge started.
+**
+*/
+
+/*
+** Plays around with NsPack compressed executables
+**
+** This piece of code is dedicated to Damian Put
+** who I made a successful and wealthy man.
+**
+** Damian, you owe me a pint!
+*/
+
+/*
+** TODO:
+**
+** - Investigate the "unused" code in NsPack
+** - Fetch all the nspacked samples from the zoo and run extensive testing
+** - Add bound checks
+** - Test against the zoo again
+** - Perform regression testing against the full zoo 
+** - check nested
+** - look at the 64bit version (one of these days)
+**
+*/
+
+/* 
+
+   FIXME: clean this rubbish
+
+
+init_and_check_dll_loadflags();
+
+nsp1:004359FE                 add     edi, [ebp-28Dh]
+nsp1:00435A04                 mov     ebx, edi
+nsp1:00435A06                 cmp     dword ptr [edi], 0
+nsp1:00435A09                 jnz     short loc_435A15
+nsp1:00435A0B                 add     edi, 4
+nsp1:00435A0E                 mov     ecx, 0
+nsp1:00435A13                 jmp     short loc_435A2B
+nsp1:00435A15 ; ---------------------------------------------------------------------------
+nsp1:00435A15
+nsp1:00435A15 loc_435A15:                             ; CODE XREF: start+349EEj
+nsp1:00435A15                 mov     ecx, 1
+nsp1:00435A1A                 add     edi, [ebx]
+nsp1:00435A1C                 add     ebx, 4
+nsp1:00435A1F
+nsp1:00435A1F loc_435A1F:                             ; CODE XREF: start+34A3Dj
+nsp1:00435A1F                 cmp     dword ptr [ebx], 0
+nsp1:00435A22                 jz      short loc_435A5A
+nsp1:00435A24                 add     [ebx], edx
+nsp1:00435A26                 mov     esi, [ebx]
+nsp1:00435A28                 add     edi, [ebx+4]
+nsp1:00435A2B
+nsp1:00435A2B loc_435A2B:                             ; CODE XREF: start+349F8j
+nsp1:00435A2B                 push    edi
+nsp1:00435A2C                 push    ecx
+nsp1:00435A2D                 push    edx
+nsp1:00435A2E                 push    ebx
+nsp1:00435A2F                 push    dword ptr [ebp-1D1h] ; VirtualFree
+nsp1:00435A35                 push    dword ptr [ebp-1D5h] ; alloc
+nsp1:00435A3B                 mov     edx, esi
+nsp1:00435A3D                 mov     ecx, edi
+nsp1:00435A3F                 mov     eax, offset get_byte
+nsp1:00435A44                 int     3               ; Trap to Debugger
+nsp1:00435A45                 add     eax, 5A9h
+nsp1:00435A4A                 call    eax ; real_unpack ; edx=401000
+nsp1:00435A4A                                         ; ecx=436282
+nsp1:00435A4C                 pop     ebx
+nsp1:00435A4D                 pop     edx
+nsp1:00435A4E                 pop     ecx
+nsp1:00435A4F                 pop     edi
+nsp1:00435A50                 cmp     ecx, 0
+nsp1:00435A53                 jz      short loc_435A5A
+nsp1:00435A55                 add     ebx, 8
+nsp1:00435A58                 jmp     short loc_435A1F
+nsp1:00435A5A ; ---------------------------------------------------------------------------
+nsp1:00435A5A
+nsp1:00435A5A loc_435A5A:                             ; CODE XREF: start+34A07j
+nsp1:00435A5A                                         ; start+34A38j
+nsp1:00435A5A                 push    8000h
+
+*/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "cltypes.h"
+#include "clamav.h"
+#include "others.h"
+#include "rebuildpe.h"
+#include "execs.h"
+#include "unsp.h"
+
+
+/* real_unpack(start_of_stuff, dest, malloc, free); */
+uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, uint32_t base, uint32_t ep, int file) {
+  uint8_t c = *start_of_stuff;
+  uint32_t i,firstbyte,tre,allocsz,tablesz,dsize,ssize;
+  uint16_t *table;
+  char *dst = dest;
+  char *src = start_of_stuff+0xd;
+  struct cli_exe_section section;
+  
+  if (c>=0xe1) return 1;
+
+  if (c>=0x2d) {
+    firstbyte = i = c/0x2d;
+    do {c+=0xd3;} while (--i);
+  } else firstbyte = 0;
+
+  if (c>=9) {
+    allocsz = i = c/9;
+    do {c+=0xf7;} while (--i);
+  } else allocsz = 0;
+  
+  tre = c;
+  i = allocsz;
+  c = (tre+i)&0xff;
+  tablesz = ((0x300<<c)+0x736)*sizeof(uint16_t);
+  if(ctx->limits && ctx->limits->maxfilesize && tablesz > ctx->limits->maxfilesize) {
+    return 1; /* Should be ~15KB, if it's so big it's prolly just not nspacked */
+  }
+    
+  cli_dbgmsg("unsp: table size = %d\n", tablesz);
+  if (!(table = cli_malloc(tablesz))) return 1;
+  
+  dsize = cli_readint32(start_of_stuff+9);
+  ssize = cli_readint32(start_of_stuff+5);
+  if (ssize <= 13) {
+  	free(table);
+  	return 1;
+  }
+
+  tre = very_real_unpack(table,tablesz,tre,allocsz,firstbyte,src,ssize,dst,dsize);
+  free(table);
+  if (tre) return 1;
+
+  section.raw=0;
+  section.rsz = dsize;
+  section.vsz = dsize;
+  section.rva = rva;
+  return !cli_rebuildpe(dest, &section, 1, base, ep, 0, 0, file);
+}
+
+
+uint32_t very_real_unpack(uint16_t *table, uint32_t tablesz, uint32_t tre, uint32_t allocsz, uint32_t firstbyte, char *src, uint32_t ssize, char *dst, uint32_t dsize) {
+  struct UNSP read_struct;
+  uint32_t i = (0x300<<((allocsz+tre)&0xff)) + 0x736;
+
+  uint32_t previous_bit = 0;
+  uint32_t unpacked_so_far = 0;
+  uint32_t backbytes = 1;
+  uint32_t oldbackbytes = 1;
+  uint32_t old_oldbackbytes = 1;
+  uint32_t old_old_oldbackbytes = 1;
+
+  uint32_t damian = 0;
+  uint32_t put = (1<<(allocsz&0xff))-1;
+
+  uint32_t bielle = 0;
+
+  firstbyte = (1<<(firstbyte&0xff))-1;
+
+  if (tablesz < i*sizeof(uint16_t)) return 2;
+
+  /* init table */
+  while (i) table[--i]=0x400;
+
+  /* table noinit */
+
+  /* get_five - inlined */
+  read_struct.error = 0;
+  read_struct.oldval = 0;
+  read_struct.src_curr = src;
+  read_struct.bitmap = 0xffffffff;
+  read_struct.src_end = src + ssize - 13;
+  read_struct.table = (char *)table;
+  read_struct.tablesz = tablesz;
+
+  for ( i = 0; i<5 ; i++) read_struct.oldval = (read_struct.oldval<<8) | get_byte(&read_struct);
+  if (read_struct.error) return 1;
+  /* if (!dsize) return 0; - checked in pe.c */
+
+
+  /* very_unpacking_loop */
+
+  while (1) {
+    uint32_t backsize = firstbyte&unpacked_so_far;
+    uint32_t tpos;
+    uint32_t temp = damian;
+
+    if (read_struct.error) return 1; /* checked once per mainloop, keeps the code readable and it's still safe */
+    
+    if (!getbit_from_table(&table[(damian<<4) + backsize], &read_struct)) { /* no_mainbit */
+
+      uint32_t shft = 8 - (tre&0xff);
+      shft &= 0xff;
+      tpos = (bielle>>shft) + ((put&unpacked_so_far)<<(tre&0xff));
+      tpos *=3;
+      tpos<<=8;
+
+      if ((int32_t)damian>=4) { /* signed */
+	if ((int32_t)damian>=0xa) { /* signed */
+	  damian -= 6;
+	} else {
+	  damian -= 3;
+	}
+      } else {
+	damian=0;
+      }
+
+      /* 44847E */
+      if (previous_bit) {
+	if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1;
+	ssize = (ssize&0xffffff00) | (uint8_t)dst[unpacked_so_far - backbytes]; /* FIXME! ssize is not static */
+	bielle = get_100_bits_from_tablesize(&table[tpos+0x736], &read_struct, ssize);
+	previous_bit=0;
+      } else {
+	bielle = get_100_bits_from_table(&table[tpos+0x736], &read_struct);
+      }
+
+      /* unpack_one_byte - duplicated */
+      if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], 1)) return 1;
+      dst[unpacked_so_far] = bielle;
+      unpacked_so_far++;
+      if (unpacked_so_far>=dsize) return 0;
+      continue;
+
+    } else { /* got_mainbit */
+
+      bielle = previous_bit = 1;
+
+      if (getbit_from_table(&table[damian+0xc0], &read_struct)) {
+	if (!getbit_from_table(&table[damian+0xcc], &read_struct)) {
+	  tpos = damian+0xf;
+	  tpos <<=4;
+	  tpos += backsize;
+	  if (!getbit_from_table(&table[tpos], &read_struct)) {
+	    if (!unpacked_so_far) return bielle; /* FIXME: WTF?! */
+	    
+	    damian = 2*((int32_t)damian>=7)+9; /* signed */
+	    if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1;
+	    bielle = (uint8_t)dst[unpacked_so_far - backbytes];
+	    /* unpack_one_byte - real */
+	    dst[unpacked_so_far] = bielle;
+	    unpacked_so_far++;
+	    if (unpacked_so_far>=dsize) return 0;
+	    continue;
+	    
+	  } else { /* gotbit_tre */
+	    backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize);
+	    damian = ((int32_t)damian>=7); /* signed */
+	    damian = ((damian-1) & 0xfffffffd)+0xb;
+	    /* jmp checkloop_and_backcopy (uses edx) */
+	  } /* gotbit_uno ends */
+	} else { /* gotbit_due */
+	  if (!getbit_from_table(&table[damian+0xd8], &read_struct)) {
+	    tpos = oldbackbytes;
+	  } else {
+	    if (!getbit_from_table(&table[damian+0xe4], &read_struct)) {
+	      tpos = old_oldbackbytes;
+	    } else {
+	      /* set_old_old_oldback */
+	      tpos = old_old_oldbackbytes;
+	      old_old_oldbackbytes = old_oldbackbytes;
+	    }
+	    /* set_old_oldback */
+	    old_oldbackbytes = oldbackbytes;
+	  }
+	  /* set_oldback */
+	  oldbackbytes = backbytes;
+	  backbytes = tpos;
+	  
+	  backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize);
+	  damian = ((int32_t)damian>=7); /* signed */
+	  damian = ((damian-1) & 0xfffffffd)+0xb;
+	  /* jmp checkloop_and_backcopy (uses edx) */
+	} /* gotbit_due ends */
+      } else { /* gotbit_uno */
+	
+	old_old_oldbackbytes = old_oldbackbytes;
+	old_oldbackbytes = oldbackbytes;
+	oldbackbytes = backbytes;
+	
+	damian = ((int32_t)damian>=7); /* signed */
+	damian = ((damian-1) & 0xfffffffd)+0xa;
+
+	backsize = get_n_bits_from_tablesize(&table[0x332], &read_struct, backsize);
+
+	tpos = ((int32_t)backsize>=4)?3:backsize; /* signed */
+	tpos<<=6;
+	tpos = get_n_bits_from_table(&table[0x1b0+tpos], 6, &read_struct);
+
+	if (tpos>=4) { /* signed */
+
+	  uint32_t s = tpos;
+	  s>>=1;
+	  s--;
+
+	  temp = (tpos & bielle) | 2;
+	  temp<<=(s&0xff);
+
+
+	  if ((int32_t)tpos<0xe) {
+	    temp += get_bb(&table[(temp-tpos)+0x2af], s, &read_struct);
+	  } else {
+	    s += 0xfffffffc;
+	    tpos = get_bitmap(&read_struct, s);
+	    tpos <<=4;
+	    temp += tpos;
+	    temp += get_bb(&table[0x322], 4, &read_struct);
+	  }
+	} else {
+	  /* gotbit_uno_out1 */
+	  backbytes = temp = tpos;
+	}
+	/* gotbit_uno_out2 */
+	backbytes = temp+1;
+	/* jmp checkloop_and_backcopy (uses edx) */
+      } /* gotbit_uno ends */
+
+      /* checkloop_and_backcopy */
+      if (!backbytes) return 0; /* very_real_unpack_end */
+      if (backbytes > unpacked_so_far) return bielle; /* FIXME: WTF?! */
+
+      backsize +=2;
+
+      if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], backsize) ||
+	  !CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], backsize)
+	  ) {
+	cli_dbgmsg("%x %x %x %x\n", dst, dsize, &dst[unpacked_so_far], backsize);
+	return 1;
+      }
+      
+      do {
+	dst[unpacked_so_far] = dst[unpacked_so_far - backbytes];
+	unpacked_so_far++;
+      } while (--backsize && unpacked_so_far<dsize);
+      bielle = (uint8_t)dst[unpacked_so_far - 1];
+
+      if (unpacked_so_far>=dsize) return 0;
+
+    } /* got_mainbit ends */
+
+  } /* while true ends */
+}
+
+
+
+uint32_t get_byte(struct UNSP *read_struct) {
+
+  uint32_t ret;
+
+  if (read_struct->src_curr >= read_struct->src_end) {
+    read_struct->error = 1;
+    return 0xff;
+  }
+  ret = *(read_struct->src_curr);
+  read_struct->src_curr++;
+  return ret&0xff;
+}
+
+
+int getbit_from_table(uint16_t *intable, struct UNSP *read_struct) {
+  
+  uint32_t nval;
+  if (!CLI_ISCONTAINED((char *)read_struct->table, read_struct->tablesz, (char *)intable, sizeof(uint16_t))) {
+    read_struct->error = 1;
+    return 0xff;
+  }
+  nval = *intable * (read_struct->bitmap>>0xb);
+
+  if (read_struct->oldval<nval) { /* unsigned */
+    uint32_t sval;
+    read_struct->bitmap = nval;
+    nval = *intable;
+    sval = 0x800 - nval;
+    sval = CLI_SRS((int32_t)sval,5); /* signed */
+    sval += nval;
+    *intable=sval;
+    if (read_struct->bitmap<0x1000000) { /* unsigned */
+      read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
+      read_struct->bitmap<<=8;
+    }
+    return 0;
+  }
+
+  read_struct->bitmap -= nval;
+  read_struct->oldval -= nval;
+
+  nval = *intable;
+  nval -= (nval>>5); /* word, unsigned */
+  *intable=nval;
+
+  if (read_struct->bitmap<0x1000000) { /* unsigned */
+    read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
+    read_struct->bitmap<<=8;
+  }
+
+  return 1;
+}
+
+
+uint32_t get_100_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t ssize) {
+  
+  uint32_t count = 1;
+  
+  while (count<0x100) {
+    uint32_t lpos, tpos;
+    lpos = ssize&0xff;
+    ssize=(ssize&0xffffff00)|((lpos<<1)&0xff);
+    lpos>>=7;
+    tpos = lpos+1;
+    tpos<<=8;
+    tpos+=count;
+    tpos = getbit_from_table(&intable[tpos], read_struct);
+    count=(count*2)|tpos;
+    if (lpos!=tpos) {
+      /* second loop */
+      while (count<0x100)
+	count = (count*2)|getbit_from_table(&intable[count], read_struct);
+    }
+  } 
+  return count&0xff;
+}
+
+
+uint32_t get_100_bits_from_table(uint16_t *intable, struct UNSP *read_struct) {
+  uint32_t count = 1;
+  
+  while (count<0x100)
+    count = (count*2)|getbit_from_table(&intable[count], read_struct);
+  return count&0xff;
+}
+
+
+uint32_t get_n_bits_from_table(uint16_t *intable, uint32_t bits, struct UNSP *read_struct) {
+  uint32_t count = 1;
+  uint32_t bitcounter;
+
+  /*  if (bits) { always set! */
+  bitcounter = bits;
+  while (bitcounter--)
+    count = count*2 + getbit_from_table(&intable[count], read_struct);
+  /*  } */
+  
+  return count-(1<<(bits&0xff));
+}
+
+
+uint32_t get_n_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t backsize) {
+  
+  if (!getbit_from_table(intable, read_struct))
+    return get_n_bits_from_table(&intable[(backsize<<3)+2], 3, read_struct);
+  
+  if (!getbit_from_table(&intable[1], read_struct))
+    return 8+get_n_bits_from_table(&intable[(backsize<<3)+0x82], 3, read_struct);
+
+  return 0x10+get_n_bits_from_table(&intable[0x102], 8, read_struct);
+}
+
+
+uint32_t get_bb(uint16_t *intable, uint32_t back, struct UNSP *read_struct) {
+  uint32_t pos = 1;
+  uint32_t bb = 0;
+  uint32_t i;
+
+  if ((int32_t)back<=0) /* signed */
+    return 0;
+  
+  for (i=0;i<back;i++) {
+    uint32_t bit = getbit_from_table(&intable[pos], read_struct);
+    pos=(pos*2) + bit;
+    bb|=(bit<<i);
+  }
+  return bb;
+}
+
+
+uint32_t get_bitmap(struct UNSP *read_struct, uint32_t bits) {
+  uint32_t retv = 0;
+
+  if ((int32_t)bits<=0) return 0; /* signed */
+
+  while (bits--) {
+    read_struct->bitmap>>=1; /* unsigned */
+    retv<<=1;
+    if (read_struct->oldval>=read_struct->bitmap) { /* unsigned */
+      read_struct->oldval-=read_struct->bitmap;
+      retv|=1;
+    }
+    if (read_struct->bitmap<0x1000000) {
+      read_struct->bitmap<<=8;
+      read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
+    }
+  }
+  return retv;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,258 @@
+/*
+ *  Copyright (C) 2000-2007 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * Much of this code is based on minitar.c which is in the public domain.
+ * Author: Charles G. Waldman (cgw at pgt.com),  Aug 4 1998
+ * There are many tar files that this code cannot decode.
+ */
+static	char	const	rcsid[] = "$Id: untar.c,v 1.35 2007/02/12 20:46:09 njh Exp $";
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef	HAVE_SYS_PARAM_H
+#include <sys/param.h>	/* for NAME_MAX */
+#endif
+
+#include "clamav.h"
+#include "others.h"
+#include "untar.h"
+#include "mbox.h"
+#include "blob.h"
+
+#define BLOCKSIZE 512
+
+#ifndef	O_BINARY
+#define	O_BINARY	0
+#endif
+
+static int
+octal(const char *str)
+{
+	int ret;
+
+	if(sscanf(str, "%o", (unsigned int *)&ret) != 1)
+		return -1;
+	return ret;
+}
+
+int
+cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits *limits)
+{
+	int size = 0;
+	int in_block = 0;
+	unsigned int files = 0;
+	char fullname[NAME_MAX + 1];
+	FILE *outfile = NULL;
+
+	cli_dbgmsg("In untar(%s, %d)\n", dir ? dir : "", desc);
+
+	for(;;) {
+		char block[BLOCKSIZE];
+		const int nread = cli_readn(desc, block, (unsigned int)sizeof(block));
+
+		if(!in_block && nread == 0)
+			break;
+
+		if(nread < 0) {
+			if(outfile)
+				fclose(outfile);
+			cli_errmsg("cli_untar: block read error\n");
+			return CL_EIO;
+		}
+
+		if(!in_block) {
+			char type;
+			const char *suffix;
+			size_t suffixLen = 0;
+			int fd, directory, skipEntry = 0;
+			char magic[7], name[101], osize[13];
+
+			if(outfile) {
+				if(fclose(outfile)) {
+					cli_errmsg("cli_untar: cannot close file %s\n",
+						fullname);
+					return CL_EIO;
+				}
+				outfile = (FILE*)0;
+			}
+
+			if(block[0] == '\0')	/* We're done */
+				break;
+
+			if(limits && limits->maxfiles && (files >= limits->maxfiles)) {
+				cli_dbgmsg("cli_untar: number of files exceeded %u\n", limits->maxfiles);
+				return CL_CLEAN;
+			}
+
+			/* Notice assumption that BLOCKSIZE > 262 */
+			if(posix) {
+				strncpy(magic, block+257, 5);
+				magic[5] = '\0';
+				if(strcmp(magic, "ustar") != 0) {
+					cli_dbgmsg("Incorrect magic string '%s' in tar header\n", magic);
+					return CL_EFORMAT;
+				}
+			}
+
+			type = block[156];
+
+			/*
+			 * Extra types from djgardner at users.sourceforge.net
+			 */
+			switch(type) {
+				default:
+					cli_warnmsg("cli_untar: unknown type flag %c\n", type);
+				case '0':	/* plain file */
+				case '\0':	/* plain file */
+				case '7':	/* contiguous file */
+				case 'M':	/* continuation of a file from another volume; might as well scan it. */
+					files++;
+					directory = 0;
+					break;
+				case '1':	/* Link to already archived file */
+				case '5':	/* directory */
+				case '2':	/* sym link */
+				case '3':	/* char device */
+				case '4':	/* block device */
+				case '6':	/* fifo special */
+				case 'V':	/* Volume header */
+					directory = 1;
+					break;
+				case 'K':
+				case 'L':
+					/* GNU extension - ././@LongLink
+					 * Discard the blocks with the extended filename,
+					 * the last header will contain parts of it anyway
+					 */
+				case 'N': 	/* Old GNU format way of storing long filenames. */
+				case 'A':	/* Solaris ACL */
+				case 'E':	/* Solaris Extended attribute s*/
+				case 'I':	/* Inode only */
+				case 'g':	/* Global extended header */
+				case 'x': 	/* Extended attributes */
+				case 'X':	/* Extended attributes (POSIX) */
+					directory = 0;
+					skipEntry = 1;
+					break;
+			}
+
+			if(directory) {
+				in_block = 0;
+				continue;
+			}
+
+			strncpy(osize, block+124, 12);
+			osize[12] = '\0';
+			size = octal(osize);
+			if(size < 0) {
+				cli_errmsg("Invalid size in tar header\n");
+				if(outfile)
+					fclose(outfile);
+				return CL_EFORMAT;
+			}
+			cli_dbgmsg("cli_untar: size = %d\n", size);
+			if(limits && limits->maxfilesize && ((unsigned int)size > limits->maxfilesize)) {
+				cli_dbgmsg("cli_untar: size exceeded %d bytes\n", size);
+				skipEntry++;
+			}
+
+			if(skipEntry) {
+				const int nskip = (size % BLOCKSIZE || !size) ? size + BLOCKSIZE - (size % BLOCKSIZE) : size;
+
+				cli_dbgmsg("cli_untar: skipping entry\n");
+				lseek(desc, nskip, SEEK_CUR);
+				continue;
+			}
+
+			strncpy(name, block, 100);
+			name[100] = '\0';
+
+			/*
+			 * see also fileblobSetFilename()
+			 * TODO: check if the suffix needs to be put back
+			 */
+			sanitiseName(name);
+			suffix = strrchr(name, '.');
+			if(suffix == NULL)
+				suffix = "";
+			else {
+				suffixLen = strlen(suffix);
+				if(suffixLen > 4) {
+					/* Found a full stop which isn't a suffix */
+					suffix = "";
+					suffixLen = 0;
+				}
+			}
+			snprintf(fullname, sizeof(fullname) - 1 - suffixLen, "%s/%.*sXXXXXX", dir,
+				(int)(sizeof(fullname) - 9 - suffixLen - strlen(dir)), name);
+#if	defined(C_LINUX) || defined(C_BSD) || defined(HAVE_MKSTEMP) || defined(C_SOLARIS) || defined(C_CYGWIN)
+			fd = mkstemp(fullname);
+#else
+			(void)mktemp(fullname);
+			fd = open(fullname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
+#endif
+
+			if(fd < 0) {
+				cli_errmsg("Can't create temporary file %s: %s\n", fullname, strerror(errno));
+				cli_dbgmsg("%lu %lu %lu\n",
+					(unsigned long)suffixLen,
+					(unsigned long)sizeof(fullname),
+					(unsigned long)strlen(fullname));
+				return CL_ETMPFILE;
+			}
+
+			cli_dbgmsg("cli_untar: extracting %s\n", fullname);
+
+			in_block = 1;
+			if((outfile = fdopen(fd, "wb")) == NULL) {
+				cli_errmsg("cli_untar: cannot create file %s\n",
+					fullname);
+				close(fd);
+				return CL_ETMPFILE;
+			}
+		} else { /* write or continue writing file contents */
+			const int nbytes = size>512? 512:size;
+			const int nwritten = (int)fwrite(block, 1, (size_t)nbytes, outfile);
+
+			if(nwritten != nbytes) {
+				cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disc space?)\n",
+					nwritten, fullname);
+				if(outfile)
+					fclose(outfile);
+				return CL_EIO;
+			}
+			size -= nbytes;
+		}
+		if (size == 0)
+			in_block = 0;
+	}
+	if(outfile)
+		return fclose(outfile);
+
+	return 0;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,665 @@
+/*
+ *  Copyright (C) 2003 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *	      (C) 2006 Sensory Networks, Inc.
+ *
+ *  The code of this module was based on zziplib 0.12.83:
+ *  (c) 1999 - 2002 Guido Draheim <guidod at gmx.de>, published under
+ *  the Lesser GNU General Public License
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <zlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#include "clamav.h"
+#include "others.h"
+#include "unzip.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define EC16(x) le16_to_host(x)
+
+#define __sizeof(X) ((ssize_t)(sizeof(X)))
+
+#define ZIPBUFSIZ   1024
+#define ZIP32K	    32768
+
+inline static void __fixup_rootseek(off_t offset_of_trailer, struct zip_disk_trailer *trailer)
+{
+    if((off_t) EC32(trailer->z_rootseek) >
+	offset_of_trailer - (off_t) EC32(trailer->z_rootsize) &&
+	offset_of_trailer > (off_t) EC32(trailer->z_rootsize))
+	    trailer->z_rootseek = (uint32_t) (offset_of_trailer -  EC32(trailer->z_rootsize)); 
+}
+
+static int __zip_find_disk_trailer(int fd, off_t filesize, struct zip_disk_trailer *trailer, off_t *start)
+{
+	char *buf, *end, *tail;
+	off_t offset = 0, bufsize;
+	struct zip_root_dirent dirent;
+	uint32_t u_rootseek, shift = 0;
+	int i;
+
+
+    if(!trailer) {
+	cli_errmsg("Unzip: __zip_find_disk_trailer: trailer == NULL\n");
+	return CL_ENULLARG;
+    }
+
+    if(filesize < __sizeof(struct zip_disk_trailer)) {
+	cli_errmsg("Unzip: __zip_find_disk_trailer: File too short\n");
+	return CL_EFORMAT;
+    }
+
+    if(!(buf = cli_malloc(ZIPBUFSIZ)))
+	return CL_EMEM;
+
+    offset = filesize;
+    while(1) {
+
+	if(offset <= 0) {
+	     cli_dbgmsg("Unzip: __zip_find_disk_trailer: Central directory not found\n");
+	     free(buf);
+	     return CL_EFORMAT;
+	}
+
+	if(offset >= ZIPBUFSIZ) {
+	    if(offset == filesize)
+		offset -= ZIPBUFSIZ;
+	    else
+		offset -= ZIPBUFSIZ - sizeof(struct zip_disk_trailer);
+
+	    bufsize = ZIPBUFSIZ;
+	} else {
+	    if(filesize < ZIPBUFSIZ)
+		bufsize = offset;
+	    else
+		bufsize = ZIPBUFSIZ;
+
+	    offset = 0;
+	}
+
+        if(lseek(fd, offset, SEEK_SET) < 0) {
+	    cli_errmsg("Unzip: __zip_find_disk_trailer: Can't lseek descriptor %d\n", fd);
+	    free(buf);
+	    return CL_EIO;
+	}
+
+        if(cli_readn(fd, buf, (size_t) bufsize) < (ssize_t) bufsize) {
+	    cli_errmsg("Unzip: __zip_find_disk_trailer: Can't read %u bytes\n", (unsigned int) bufsize);
+	    free(buf);
+	    return CL_EIO;
+	}
+
+	end = buf + bufsize;
+	for(tail = end - 1; tail >= buf; tail--) {
+	    if((*tail == 'P') && (end - tail >= __sizeof(struct zip_disk_trailer) - 2) && cli_readint32(tail) == ZIP_DISK_TRAILER_MAGIC) {
+		if(end - tail >= __sizeof(struct zip_disk_trailer)) {
+		    memcpy(trailer, tail, sizeof(struct zip_disk_trailer)); 
+		} else {
+		    memcpy(trailer, tail, sizeof(struct zip_disk_trailer) - 2);
+		    trailer->z_comment = 0; 
+		}
+		__fixup_rootseek(offset + tail - buf, trailer);
+
+		u_rootseek = EC32(trailer->z_rootseek);
+		if(u_rootseek > (uint32_t) filesize) {
+		    cli_dbgmsg("Unzip: __zip_find_disk_trailer: u_rootseek > filesize, continue search\n");
+		    continue;
+		}
+
+		for(i = 0; i < 2; i++) {
+		    if(u_rootseek + shift + sizeof(dirent) < (uint32_t) filesize) {
+			if(lseek(fd, u_rootseek + shift, SEEK_SET) < 0) {
+			    cli_errmsg("Unzip: __zip_find_disk_trailer: Can't lseek descriptor %d\n", fd);
+			    free(buf);
+			    return CL_EIO;
+			}
+
+			if(cli_readn(fd, &dirent, sizeof(dirent)) < __sizeof(dirent)) {
+			    cli_errmsg("Unzip: __zip_find_disk_trailer: Can't read %u bytes\n", (unsigned int) bufsize);
+			    free(buf);
+			    return CL_EIO;
+			}
+
+			if(EC32(dirent.z_magic) == ZIP_ROOT_DIRENT_MAGIC) {
+			    cli_dbgmsg("Unzip: __zip_find_disk_trailer: found file header at %u, shift %u\n", u_rootseek + shift, shift);
+			    free(buf);
+			    *start = shift;
+			    return CL_SUCCESS;
+			}
+
+			shift = *start;
+		    }
+		}
+	    }
+	}
+    }
+
+    /* this should never be reached */
+    free(buf);
+    return CL_EFORMAT;
+}
+
+static int __zip_parse_root_directory(int fd, struct zip_disk_trailer *trailer, zip_dir_hdr **hdr_return, off_t start)
+{
+	struct zip_root_dirent dirent, *d;
+	zip_dir_hdr *hdr, *hdr0, *prev_hdr;
+	uint16_t *p_reclen = NULL, entries;
+	uint32_t offset;
+	struct stat sb;
+	uint16_t u_entries  = EC16(trailer->z_entries);   
+	uint32_t u_rootsize = EC32(trailer->z_rootsize);  
+	uint32_t u_rootseek = EC32(trailer->z_rootseek) + start;
+	uint16_t u_extras, u_comment, u_namlen, u_flags;
+	unsigned int bfcnt;
+	char *pt;
+
+
+    if(fstat(fd, &sb) == -1) {
+	cli_errmsg("Unzip: __zip_parse_root_directory: Can't fstat file descriptor %d\n", fd);
+	return CL_EIO;
+    }
+
+    if(!u_entries) {
+	cli_errmsg("Unzip: __zip_parse_root_directory: File contains no entries\n");
+	return CL_EFORMAT;
+    }
+
+    if(u_rootsize > (uint32_t) sb.st_size) {
+	cli_errmsg("Unzip: __zip_parse_root_directory: Incorrect root size\n");
+	return CL_EFORMAT;
+    }
+
+    hdr0 = (zip_dir_hdr*) cli_malloc(u_rootsize);
+    if (!hdr0) 
+        return CL_EMEM;
+
+    hdr = hdr0;
+
+    for(entries = u_entries, offset = 0; entries > 0; entries--) {
+
+	if(lseek(fd, u_rootseek + offset, SEEK_SET) < 0) {
+	    free(hdr0);
+	    cli_errmsg("Unzip: __zip_parse_root_directory: Can't lseek descriptor %d\n", fd);
+            return CL_EIO;
+	}
+
+        if(cli_readn(fd, &dirent, sizeof(dirent)) < __sizeof(dirent)) {
+	    if(entries != u_entries) {
+		entries = 0;
+		break;
+	    } else {
+		free(hdr0);
+		cli_dbgmsg("Unzip: __zip_parse_root_directory: Can't read %d bytes\n", sizeof(dirent));
+		return CL_EIO;
+	    }
+	}
+        d = &dirent;
+
+	if(offset + sizeof(struct zip_root_dirent) > u_rootsize) {
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: Entry %d outside of root directory\n", entries);
+	    break;
+	}
+
+        u_extras  = EC16(d->z_extras); 
+        u_comment = EC16(d->z_comment); 
+
+        u_namlen  = EC16(d->z_namlen); 
+	if(u_namlen > 1024) {
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: Entry %d name too long\n", entries);
+	    break;
+	}
+
+	u_flags   = EC16(d->z_flags);
+
+        hdr->d_crc32 = EC32(d->z_crc32);
+        hdr->d_csize = EC32(d->z_csize); 
+        hdr->d_usize = EC32(d->z_usize); 
+        hdr->d_off   = EC32(d->z_off) + start;
+
+        hdr->d_compr = EC16(d->z_compr);
+
+	bfcnt = 0;
+	if(!hdr->d_compr && hdr->d_csize != hdr->d_usize) {
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: File claims to be stored but csize != usize\n");
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: Also checking for method 'deflated'\n");
+	    hdr->d_bf[bfcnt] = ZIP_METHOD_DEFLATED;
+	    bfcnt++;
+	} else if(hdr->d_compr && hdr->d_csize == hdr->d_usize) {
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: File claims to be deflated but csize == usize\n");
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: Also checking for method 'stored'\n");
+	    hdr->d_bf[bfcnt] = ZIP_METHOD_STORED;
+	    bfcnt++;
+	}
+	hdr->d_bf[bfcnt] = -1;
+
+	hdr->d_flags = u_flags;
+
+	if(offset + sizeof(struct zip_root_dirent) + u_namlen > u_rootsize) {
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: Name of entry %d outside of root directory\n", entries);
+	    break;
+	}
+
+	if(cli_readn(fd, hdr->d_name, u_namlen) != u_namlen) {
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: Can't read name of entry %d\n", entries);
+	    break;
+	}
+
+        hdr->d_name[u_namlen] = '\0'; 
+        hdr->d_namlen = u_namlen;
+
+        offset += sizeof(struct zip_root_dirent) + u_namlen + u_extras + u_comment;
+
+        if(offset > u_rootsize) {
+	    cli_dbgmsg("Unzip: __zip_parse_root_directory: End of entry %d outside of root directory\n", entries);
+	    break;
+	}
+
+	pt = (char *) hdr + sizeof(zip_dir_hdr) + u_namlen + 1;
+	pt += ((long) pt) & 1;
+	pt += ((long) pt) & 2;
+	hdr->d_reclen = (uint16_t) (pt - (char *) hdr);
+	p_reclen = &hdr->d_reclen;
+
+	prev_hdr = hdr;
+	hdr = (zip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
+    }
+
+    if(p_reclen) {
+	*p_reclen = 0;
+	if(hdr_return) 
+	    *hdr_return = hdr0;
+    } else {
+	free(hdr0);
+    }
+
+    return entries ? CL_EFORMAT : CL_SUCCESS;
+}
+
+int zip_dir_close(zip_dir *dir)
+{
+    if(dir->hdr0)
+	free(dir->hdr0);
+
+    if(dir->cache.fp)
+	free(dir->cache.fp);
+
+    if(dir->cache.buf32k)
+	free(dir->cache.buf32k);
+
+    free(dir);
+    return CL_SUCCESS;
+}
+
+static int __zip_dir_parse(zip_dir *dir, off_t start)
+{
+	int ret;
+	struct zip_disk_trailer trailer;
+	struct stat sb;
+
+
+    if(fstat(dir->fd, &sb) == -1) {
+	cli_errmsg("Unzip: __zip_dir_parse: Can't fstat file descriptor %d\n", dir->fd);
+	return CL_EIO;
+    }
+
+    if((ret = __zip_find_disk_trailer(dir->fd, sb.st_size, &trailer, &start)))
+	return ret;
+
+    if((ret = __zip_parse_root_directory(dir->fd, &trailer, &dir->hdr0, start)))
+	return ret;
+
+    return CL_SUCCESS;
+}
+
+zip_dir *zip_dir_open(int fd, off_t start, int *errcode_p)
+{
+	int ret;
+	zip_dir * dir;
+
+
+    dir = (zip_dir *) cli_calloc(1, sizeof(zip_dir));
+    if(!dir) {
+	if(errcode_p)
+	    *errcode_p = CL_EMEM;
+	return NULL;
+    }
+
+    if(start) {
+	if(lseek(fd, start, SEEK_SET) == -1) {
+	    cli_errmsg("Unzip: zip_dir_open: Can't lseek descriptor %d\n", fd);
+	    if(errcode_p)
+		*errcode_p = CL_EIO;
+	    return NULL;
+	}
+    }
+
+    dir->fd = fd;
+
+    if((ret = __zip_dir_parse(dir, start))) {
+	zip_dir_close(dir);
+	if(errcode_p)
+	    *errcode_p = CL_EMEM;
+	return NULL;
+    }
+
+    dir->hdr = dir->hdr0;
+
+    if(errcode_p)
+	*errcode_p = CL_SUCCESS;
+
+    return dir;
+}
+
+int zip_dir_read(zip_dir *dir, zip_dirent *d)
+{
+
+    if(!dir || !dir->hdr || !d)
+	return 0;
+
+    d->d_compr = dir->hdr->d_compr;
+    d->d_csize = dir->hdr->d_csize;
+    d->st_size = dir->hdr->d_usize;
+    d->d_name  = dir->hdr->d_name;
+    d->d_flags = dir->hdr->d_flags;
+    d->d_off   = dir->hdr->d_off;
+    d->d_crc32 = dir->hdr->d_crc32;
+
+    if(!dir->hdr->d_reclen)
+	dir->hdr = NULL;
+    else
+	dir->hdr = (zip_dir_hdr *) ((char *) dir->hdr + dir->hdr->d_reclen);
+
+    return 1;
+}
+
+int zip_file_close(zip_file *fp)
+{
+	zip_dir *dir;
+
+
+    if(!fp) {
+	cli_errmsg("Unzip: zip_file_close: fp == NULL\n");
+	return CL_ENULLARG;
+    }
+
+    inflateEnd(&fp->d_stream);
+
+    dir = fp->dir;
+    if(fp->buf32k) {
+        if(!dir->cache.buf32k)
+	    dir->cache.buf32k = fp->buf32k;
+        else
+	    free(fp->buf32k);
+    }
+
+    memset(fp, 0, sizeof(zip_file)); 
+
+    if(!dir->cache.fp)
+	dir->cache.fp = fp;
+    else
+	free(fp);
+
+    return CL_SUCCESS;
+}
+
+static int __zip_inflate_init(zip_file *fp, zip_dir_hdr *hdr)
+{
+	int ret;
+	fp->method = hdr->d_compr;
+	fp->restlen = hdr->d_usize;
+
+
+    if(fp->method) {
+        memset(&fp->d_stream, 0, sizeof(fp->d_stream));
+
+        ret = inflateInit2(&fp->d_stream, -MAX_WBITS);
+
+        if(ret != Z_OK) {
+	    cli_errmsg("Unzip: __zip_inflate_init: inflateInit2 failed\n");
+	    return CL_EZIP;
+	}
+
+        fp->crestlen = hdr->d_csize;
+    }
+
+    return CL_SUCCESS;
+}
+
+zip_file *zip_file_open(zip_dir *dir, const char *name, int d_off)
+{
+	int ret;
+	zip_file *fp = NULL;
+	zip_dir_hdr *hdr = dir->hdr0;
+        const char *hdr_name;
+        ssize_t dataoff;
+        struct zip_file_header *hp;
+ 
+
+    if(!dir || dir->fd < 0) {
+	cli_errmsg("Unzip: zip_file_open: dir == NULL || dir->fd <= 0\n");
+	return NULL;
+    }
+
+    if(!hdr) {
+	cli_errmsg("Unzip: zip_file_open: hdr == NULL\n");
+	dir->errcode = CL_ENULLARG;
+	return NULL;
+    }
+
+    while(1) {
+	hdr_name = hdr->d_name;
+
+        if(!strcmp(hdr_name, name) && (d_off == -1 || (uint32_t) d_off == hdr->d_off)) {
+	    switch (hdr->d_compr) {
+		case ZIP_METHOD_STORED:
+		case ZIP_METHOD_DEFLATED:
+		case ZIP_METHOD_DEFLATED64:
+		    break;
+
+		case ZIP_METHOD_SHRUNK:
+		case ZIP_METHOD_REDUCEDx1:
+		case ZIP_METHOD_REDUCEDx2:
+		case ZIP_METHOD_REDUCEDx3:
+		case ZIP_METHOD_REDUCEDx4:
+		case ZIP_METHOD_IMPLODED:
+		case ZIP_METHOD_TOKENIZED:
+		case ZIP_METHOD_IMPLODED_DCL:
+		case ZIP_METHOD_BZIP2:
+		case ZIP_METHOD_AES:
+		    cli_dbgmsg("Unzip: zip_file_open: Not supported compression method (%d)\n", hdr->d_compr);
+		    dir->errcode = CL_ESUPPORT;
+		    return NULL;
+
+		default:
+		    cli_errmsg("Unzip: zip_file_read: Unknown compression method (%d)\n", hdr->d_compr);
+		    dir->errcode = CL_EFORMAT;
+		    return NULL;
+            }
+
+            if(dir->cache.fp) {
+                fp = dir->cache.fp;
+		dir->cache.fp = NULL;
+            } else {
+                fp = (zip_file *) cli_calloc(1, sizeof(zip_file));
+                if(!fp) {
+		    dir->errcode = CL_EMEM;
+		    return NULL;
+		}
+            }
+
+            fp->dir = dir;
+
+            if(dir->cache.buf32k) {
+		fp->buf32k = dir->cache.buf32k;
+		dir->cache.buf32k = NULL;
+	    } else {
+                fp->buf32k = (char *) cli_malloc(ZIP32K);
+                if(!fp->buf32k) {
+		    dir->errcode = CL_EMEM;
+		    zip_file_close(fp);
+		    return NULL;
+		}
+            }
+
+            if(lseek(dir->fd, hdr->d_off, SEEK_SET) < 0) {
+		cli_errmsg("Unzip: zip_file_open: Can't lseek descriptor %d\n", dir->fd);
+		dir->errcode = CL_EIO;
+		zip_file_close(fp);
+		return NULL;
+	    }
+
+	    hp = (void *) fp->buf32k;
+	    dataoff = cli_readn(dir->fd, (void *) hp, sizeof(struct zip_file_header));
+
+	    if(dataoff < __sizeof(struct zip_file_header)) {
+		cli_errmsg("Unzip: zip_file_open: Can't read zip header (only read %d bytes)\n", dataoff);
+		dir->errcode = CL_EIO;
+		zip_file_close(fp);
+		return NULL;
+	    }
+
+	    dataoff = EC16(hp->z_namlen) + EC16(hp->z_extras);
+
+            if(lseek(dir->fd, dataoff, SEEK_CUR) < 0) {
+		cli_errmsg("Unzip: zip_file_open: Can't lseek descriptor %d\n", dir->fd);
+		dir->errcode = CL_EIO;
+		zip_file_close(fp);
+		return NULL;
+	    }
+
+            fp->usize = hdr->d_usize;
+            fp->csize = hdr->d_csize;
+
+	    fp->bf = hdr->d_bf;
+
+            ret = __zip_inflate_init(fp, hdr);
+
+	    if(ret) {
+		dir->errcode = CL_EIO;
+		zip_file_close(fp);
+		return NULL;
+	    }
+
+            return fp;
+
+        } else {
+            if(!hdr->d_reclen)
+                break;
+
+            hdr = (zip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
+        }
+    }
+
+    dir->errcode = CL_EOPEN;
+    if(fp)
+	zip_file_close(fp);
+    return NULL;
+}
+
+ssize_t zip_file_read(zip_file *fp, char *buf, size_t len)
+{
+	zip_dir *dir; 
+	size_t l;
+	ssize_t bread;
+
+
+    if(!fp || !fp->dir) {
+	cli_errmsg("Unzip: zip_file_read: fp == NULL || fp->dir == NULL\n");
+	return -1;
+    }
+
+    dir = fp->dir;
+    l = fp->restlen > len ? len : fp->restlen;
+    if(!fp->restlen)
+        return 0;
+
+    switch(fp->method) {
+
+	case ZIP_METHOD_STORED:
+	    bread = cli_readn(dir->fd, buf, l);
+	    if(bread > 0) {
+		fp->restlen -= bread;
+	    } else if(bread < 0) {
+		cli_errmsg("Unzip: zip_file_read: Can't read %d bytes\n", l);
+		dir->errcode = CL_EIO;
+	    }
+	    return bread;
+
+	case ZIP_METHOD_DEFLATED:
+	case ZIP_METHOD_DEFLATED64:
+	    fp->d_stream.avail_out = l;
+	    fp->d_stream.next_out = (unsigned char *) buf;
+	    do {
+		int ret;
+		size_t startlen;
+
+		if(fp->crestlen > 0 && fp->d_stream.avail_in == 0) {
+		    size_t cl = (fp->crestlen < ZIP32K ? fp->crestlen : ZIP32K);
+		    ssize_t i = cli_readn(dir->fd, fp->buf32k, cl);
+		    if(i <= 0) {
+			dir->errcode = CL_EIO;
+			cli_errmsg("Unzip: zip_file_read: Can't read %d bytes (read %d)\n", cl, i);
+			return -1;
+		    }
+		    fp->crestlen -= i;
+		    fp->d_stream.avail_in = i;
+		    fp->d_stream.next_in = (unsigned char *) fp->buf32k;
+		}
+
+		startlen = fp->d_stream.total_out;
+		ret = inflate(&fp->d_stream, Z_NO_FLUSH);
+
+		if(ret == Z_STREAM_END) {
+		    fp->restlen = 0;
+		} else {
+		    if(ret == Z_OK) {
+			fp->restlen -= (fp->d_stream.total_out - startlen);
+		    } else {
+			if(fp->method == ZIP_METHOD_DEFLATED64) {
+			    cli_dbgmsg("Unzip: zip_file_read: Not supported compression method (%u)\n", fp->method);
+			    dir->errcode = CL_ESUPPORT;
+			} else {
+			    dir->errcode = CL_EZIP;
+			}
+			return -1;
+		    }
+		}
+	    } while(fp->restlen && fp->d_stream.avail_out);
+
+	    return l - fp->d_stream.avail_out;
+
+	default:
+	    /* this should not be reached because of the previous check in
+	     * zip_file_open
+	     */
+	    cli_errmsg("Unzip: zip_file_read: Unknown compression method (%d)\n", fp->method);
+	    dir->errcode = CL_EZIP;
+	    return -1;
+    }
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,689 @@
+/*
+ *  Copyright (C) 2006 Michal 'GiM' Spadlinski http://gim.org.pl/
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/*
+ * upack.c
+ *
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#ifdef        HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef        HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef        HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef        HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef        HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "cltypes.h"
+#include "pe.h"
+#include "rebuildpe.h"
+#include "others.h"
+#include "upack.h"
+#include "mew.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define CE32(x) be32_to_host(x) /* Convert big endian to host */
+
+int unupack399(char *, uint32_t, uint32_t, char *, uint32_t, char *, char *, uint32_t, char *);
+
+enum { UPACK_399, UPACK_11_12, UPACK_0151477, UPACK_0297729 };
+
+int unupack(int upack, char *dest, uint32_t dsize, char *buff, uint32_t vma, uint32_t ep, uint32_t base, uint32_t va, int file)
+{
+	int j, searchval;
+	char *loc_esi, *loc_edi, *loc_ebx, *end_edi, *save_edi, *rpeb, *alvalue;
+	char *paddr, *pushed_esi, *save2;
+	uint32_t save1, save3, loc_ecx, count, shlsize, original_ep, ret, loc_ebx_u;
+	struct cli_exe_section section;
+	int upack_version = UPACK_399;
+
+	/* buff [168 bytes] doesn't have to be checked, since it was checked in pe.c */
+	if (upack)
+	{
+		uint32_t aljump, shroff, lngjmpoff;
+
+		/* dummy characteristics ;/ */
+		if (buff[5] == '\xff' && buff[6] == '\x36')
+			upack_version = UPACK_0297729;
+		loc_esi = dest + (cli_readint32(buff + 1) -  vma);
+
+		if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12))
+			return -1;
+		original_ep = cli_readint32(loc_esi);
+		loc_esi += 4;
+		/*cli_readint32(loc_esi);*/
+		loc_esi += 4;
+
+		original_ep -= vma;
+		cli_dbgmsg("Upack: EP: %08x original:  %08X || %08x\n", ep, original_ep, cli_readint32(loc_esi-8));
+
+		if (upack_version == UPACK_399)
+		{
+			/* jmp 1 */
+			loc_edi = dest + (cli_readint32(loc_esi) -  vma);
+			if (!CLI_ISCONTAINED(dest, dsize, dest+ep+0xa, 2) || dest[ep+0xa] != '\xeb')
+				return -1;
+			loc_esi = dest + *(dest + ep + 0xb) + ep + 0xc;
+
+			/* use this as a temp var */
+			/* jmp 2 + 0xa */
+			alvalue = loc_esi+0x1a;
+			if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xeb')
+				return -1;
+			alvalue++;
+			alvalue += (*alvalue&0xff) + 1 + 0xa;
+			lngjmpoff = 8;
+		} else {
+			if (!CLI_ISCONTAINED(dest, dsize, dest+ep+7, 5) || dest[ep+7] != '\xe9')
+				return -1;
+			loc_esi = dest + cli_readint32(dest + ep + 8) + ep + 0xc;
+			alvalue = loc_esi + 0x25;
+			lngjmpoff = 10;
+		}
+
+		if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xb5')
+			return -1;
+		alvalue++;
+		count = *alvalue&0xff;
+
+		if (!CLI_ISCONTAINED(dest, dsize, alvalue, lngjmpoff+5) || *(alvalue+lngjmpoff) != '\xe9')
+			return -1;
+		/* use this as a temp to make a long jmp to head of unpacking proc */
+		shlsize = cli_readint32(alvalue + lngjmpoff+1);
+		/* upack_399 + upack_0151477 */
+		if (upack_version == UPACK_399)
+			shlsize = shlsize + (loc_esi - dest) + *(loc_esi+0x1b) + 0x1c + 0x018; /* read checked above */
+		else
+			/* there is no additional jump in upack_0297729 */
+			shlsize = shlsize + (loc_esi - dest) + 0x035;
+		/* do the jump, 43 - point to jecxz */
+		alvalue = dest+shlsize+43;
+
+		/* 0.39 */
+		aljump = 8;
+		shroff = 24;
+		if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3')
+		{
+			/* in upack_0297729 and upack_0151477 jecxz is at offset: 46 */
+			alvalue = dest+shlsize+46;
+			if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3')
+				return -1;
+			else {
+				if (upack_version != UPACK_0297729)
+					upack_version = UPACK_0151477;
+				aljump = 7;
+				shroff = 26;
+			}
+			
+		}
+		/* do jecxz */
+		alvalue += (*alvalue&0xff) + 1;
+		/* is there a long jump ? */
+		if (!CLI_ISCONTAINED(dest, dsize, alvalue, aljump+5) || *(alvalue+aljump) != '\xe9')
+			return -1;
+		/* do jmp, 1+4 - size of jmp instruction, aljump - instruction offset, 27 offset to cmp al,xx*/
+		ret = cli_readint32(alvalue+aljump+1);
+		alvalue += ret + aljump+1+4 + 27;
+		if (upack_version == UPACK_0297729)
+			alvalue += 2;
+		/* shr ebp */
+		if (!CLI_ISCONTAINED(dest, dsize, dest+shlsize+shroff, 3) || *(dest+shlsize+shroff) != '\xc1' || *(dest+shlsize+shroff+1) != '\xed')
+			return -1;
+		shlsize = (*(dest + shlsize + shroff+2))&0xff;
+		count *= 0x100;
+		if (shlsize < 2 || shlsize > 8)
+		{
+			cli_dbgmsg ("Upack: context bits out of bounds\n");
+			return -1;
+		}
+		cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count);
+		/* check if loc_esi + .. == 0xbe -> mov esi */
+		/* upack_0297729 has mov esi, .. + mov edi, .., in upack_0151477 and upack_399 EDI has been already set before */
+		if (upack_version == UPACK_0297729)
+		{
+			if (!CLI_ISCONTAINED(dest, dsize, loc_esi+6, 10) || *(loc_esi+6) != '\xbe' || *(loc_esi+11) != '\xbf')
+				return -1;
+			if ((uint32_t)cli_readint32(loc_esi + 7) < base || (uint32_t)cli_readint32(loc_esi+7) > vma)
+				return -1;
+			loc_edi = dest + (cli_readint32(loc_esi + 12) - vma);
+			loc_esi = dest + (cli_readint32(loc_esi + 7) - base);
+		} else {
+			if (!CLI_ISCONTAINED(dest, dsize, loc_esi+7, 5) || *(loc_esi+7) != '\xbe')
+				return -1;
+			loc_esi = dest + (cli_readint32(loc_esi + 8) - vma);
+		}
+
+		if (upack_version == UPACK_0297729)
+		{
+			/* 0x16*4=0x58, 6longs*4 = 24, 0x64-last loc_esi read location */
+			if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x58 + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x58 + 0x64 + 4)))
+				return -1;
+
+			/* XXX I don't know if this [0x16] is constant number, not enough samples provided */
+			for (j=0; j<0x16; j++, loc_esi+=4, loc_edi+=4)
+				cli_writeint32(loc_edi, cli_readint32(loc_esi)); 
+		} else {
+			/* 0x27*4=0x9c, 6longs*4 = 24, 0x34-last loc_esi read location */
+			if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x9c + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x9c + 0x34 + 4)))
+				return -1;
+			for (j=0; j<0x27; j++, loc_esi+=4, loc_edi+=4)
+				cli_writeint32(loc_edi, cli_readint32(loc_esi)); 
+		}
+		save3 = cli_readint32(loc_esi + 4);
+		paddr = dest + ((uint32_t)cli_readint32(loc_edi - 4)) - vma;
+		loc_ebx = loc_edi;
+		cli_writeint32(loc_edi, 0xffffffff);
+		loc_edi+=4;
+		cli_writeint32(loc_edi, 0);
+		loc_edi+=4;
+		for (j=0; j<4; j++, loc_edi+=4)
+		    cli_writeint32(loc_edi, (1));
+
+		for (j=0; (unsigned int)j<count; j++, loc_edi+=4)
+		    cli_writeint32(loc_edi, 0x400);
+		
+		loc_edi = dest + cli_readint32(loc_esi + 0xc) - vma;
+		if (upack_version == UPACK_0297729)
+			loc_edi = dest+vma-base; /* XXX not enough samples provided to be sure of it! */
+
+		pushed_esi = loc_edi;
+		end_edi = dest + cli_readint32(loc_esi + 0x34) - vma;
+		if (upack_version == UPACK_0297729)
+		{
+			end_edi = dest + cli_readint32(loc_esi + 0x64) - vma;
+			save3 = cli_readint32(loc_esi + 0x40);
+		}
+		/* begin end */
+		cli_dbgmsg("Upack: data initialized, before upack lzma call!\n");
+		if ((ret = (uint32_t)unupack399(dest, dsize, 0, loc_ebx, 0, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff)
+			return -1;
+	/* alternative begin */
+	} else {
+		int ep_jmp_offs, rep_stosd_count_offs, context_bits_offs;
+		loc_esi = dest + vma + ep;
+		/* yet another dummy characteristics ;/ */
+		if (buff[0] == '\xbe' && buff[5] == '\xad' && buff[6] == '\x8b' && buff[7] == '\xf8')
+			upack_version = UPACK_11_12;
+
+		if (upack_version == UPACK_11_12)
+		{
+			ep_jmp_offs = 0x1a4;
+			rep_stosd_count_offs = 0x1b;
+			context_bits_offs = 0x41;
+			alvalue = loc_esi + 0x184;
+		} else {
+			ep_jmp_offs = 0x217;
+			rep_stosd_count_offs = 0x3a;
+			context_bits_offs = 0x5f;
+			alvalue = loc_esi + 0x1c1;
+		}
+
+		if (!CLI_ISCONTAINED(dest, dsize, loc_esi, ep_jmp_offs+4))
+			return -1;
+		save1 = cli_readint32(loc_esi + ep_jmp_offs);
+		original_ep = (loc_esi - dest) + ep_jmp_offs + 4;
+		original_ep += (int32_t)save1;
+		cli_dbgmsg("Upack: EP: %08x original %08x\n", ep, original_ep);
+
+		/* this are really ugly hacks,
+		 * rep_stosd_count_offs & context_bits_offs are < ep_jmp_offs,
+		 * so checked in CLI_ISCONTAINED above */
+		count = (*(loc_esi + rep_stosd_count_offs))&0xff;
+		shlsize = (*(loc_esi + context_bits_offs))&0xff;
+		shlsize = 8 - shlsize;
+		if (shlsize < 2 || shlsize > 8)
+		{
+			cli_dbgmsg ("Upack: context bits out of bounds\n");
+			return -1;
+		}
+		count *= 0x100;
+		cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count);
+		if (upack_version == UPACK_399)
+		{
+			loc_esi += 4;
+			loc_ecx = cli_readint32(loc_esi+2);
+			cli_writeint32(loc_esi+2,0);
+			if (!loc_ecx)
+			{
+				cli_dbgmsg("Upack: something's wrong, report back\n");
+				return -1;/* XXX XXX XXX XXX */
+			}
+			loc_esi -= (loc_ecx - 2);
+			if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12))
+				return -1;
+
+			cli_dbgmsg("Upack: %08x %08x %08x %08x\n", loc_esi, dest, cli_readint32(loc_esi), base);
+			loc_ebx_u = loc_esi - (dest + cli_readint32(loc_esi) - base);
+			cli_dbgmsg("Upack: EBX: %08x\n", loc_ebx_u);
+			loc_esi += 4;
+			save2 = loc_edi = dest + cli_readint32(loc_esi) - base;
+			cli_dbgmsg("Upack: DEST: %08x, %08x\n", cli_readint32(loc_esi), cli_readint32(loc_esi) - base);
+			loc_esi += 4;
+			/* 2vGiM: j is signed. Is that really what you want? Will it cause problems with the following checks?
+			 * yes! this is wrong! how did you notice that?!
+			 */
+			j = cli_readint32(loc_esi);
+			if (j<0)
+			{
+				cli_dbgmsg("Upack: probably hand-crafted data, report back\n");
+				return -1;
+			}
+			loc_esi += 4;
+			cli_dbgmsg("Upack: ecx counter: %08x\n", j);
+
+			if (!CLI_ISCONTAINED(dest, dsize, loc_esi, (j*4)) || !CLI_ISCONTAINED(dest, dsize, loc_edi, ((j+count)*4)))
+				return -1;
+			for (;j--; loc_edi+=4, loc_esi+=4)
+				cli_writeint32(loc_edi, cli_readint32(loc_esi));
+			if (!CLI_ISCONTAINED(dest, dsize, save2, 8))
+				return -1;
+			loc_ecx = cli_readint32(save2);
+			save2 += 4;
+			loc_esi = save2;
+			/* I could probably do simple loc_esi+= (0xe<<2),
+			 *  but I'm not sure if there is always 0xe and is always ebx =0
+			 */
+			do {
+				loc_esi += loc_ebx_u;
+				loc_esi += 4;
+			} while (--loc_ecx);
+			if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 4))
+				return -1;
+			save1 = cli_readint32(loc_esi); /* loc_eax = 0x400 */
+			loc_esi += 4;
+
+			for (j=0; j<count; j++, loc_edi+=4) /* checked above */
+				cli_writeint32(loc_edi, (save1));
+
+			if (!CLI_ISCONTAINED(dest, dsize, (loc_esi+0x10), 4))
+				return -1;
+			cli_writeint32(loc_esi+0x10, (uint32_t)cli_readint32(loc_esi+0x10)+loc_ebx_u);
+			loc_ebx = loc_esi+0x14;
+			loc_esi = save2;
+			/* loc_ebx_u gets saved */
+			/* checked above, (...save2, 8) */
+			save_edi = loc_edi = dest + ((uint32_t)cli_readint32(loc_esi) - base);
+			loc_esi +=4;
+			cli_dbgmsg("Upack: before_fixing\n");
+			/* fix values */
+			if (!CLI_ISCONTAINED(dest, dsize, loc_ebx-4, (12 + 4*4)) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x24, 4) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x40, 4))
+				return -1;
+			for (j=2; j<6; j++)
+			      cli_writeint32(loc_ebx+(j<<2), cli_readint32(loc_ebx+(j<<2)));
+			paddr = dest + cli_readint32(loc_ebx - 4) - base;
+			save1 = loc_ecx;
+			pushed_esi = loc_edi;
+			end_edi = dest + cli_readint32(loc_esi+0x24) - base;
+			vma = cli_readint32(loc_ebx); cli_writeint32(loc_ebx, cli_readint32(loc_ebx + 4)); cli_writeint32((loc_ebx + 4), vma);
+		/* Upack 1.1/1.2 is something between 0.39 2-section and 0.39 3-section */
+		} else if (upack_version == UPACK_11_12) {
+			cli_dbgmsg("Upack v 1.1/1.2\n");
+			loc_esi = dest + 0x148; /* always constant? */
+			loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */
+			loc_esi += 4;
+			save_edi = loc_edi;
+			/* movsd */
+			paddr = dest + ((uint32_t)cli_readint32(loc_esi)) - base;
+			loc_esi += 4;
+			loc_edi += 4;
+			loc_ebx = loc_edi;
+		
+			if (!CLI_ISCONTAINED(dest, dsize, loc_edi, ((6+count)*4)))
+				return -1;
+			cli_writeint32(loc_edi, 0xffffffff);
+			loc_edi += 4;
+			cli_writeint32(loc_edi, 0);
+			loc_edi += 4;
+			for (j=0; j<4; j++, loc_edi+=4)
+				cli_writeint32(loc_edi, (1));
+
+			for (j=0; j<count; j++, loc_edi+=4)
+				cli_writeint32(loc_edi, 0x400);
+			
+			loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */
+			pushed_esi = loc_edi;
+			loc_esi += 4;
+			loc_ecx = 0;
+
+			loc_esi += 4;
+
+			end_edi = dest + cli_readint32(loc_esi-0x28) - base; /* read checked above */
+			loc_esi = save_edi;
+		}
+		cli_dbgmsg("Upack: data initialized, before upack lzma call!\n");
+		if ((ret = (uint32_t)unupack399(dest, dsize, loc_ecx, loc_ebx, loc_ecx, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff)
+			return -1;
+		if (upack_version == UPACK_399)
+			save3 = cli_readint32(loc_esi + 0x40);
+		else if (upack_version == UPACK_11_12)
+			save3 = cli_readint32(dest + vma + ep + 0x174);
+	}
+
+	/* let's fix calls */
+	loc_ecx = 0;
+	if (!CLI_ISCONTAINED(dest, dsize, alvalue, 1)) {
+		cli_dbgmsg("Upack: alvalue out of bounds\n");
+		return -1;
+	}
+
+	searchval = *alvalue&0xff;
+	cli_dbgmsg("Upack: loops: %08x search value: %02x\n", save3, searchval);
+	while(save3) {
+		if (!CLI_ISCONTAINED(dest, dsize, pushed_esi + loc_ecx, 1))
+		{
+			cli_dbgmsg("Upack: callfixerr %08x %08x = %08x, %08x\n", dest, dsize, dest+dsize, pushed_esi+loc_ecx);
+			return -1;
+		}
+		if (pushed_esi[loc_ecx] == '\xe8' || pushed_esi[loc_ecx] == '\xe9')
+		{
+			char *adr = (pushed_esi + loc_ecx + 1);
+			loc_ecx++;
+			if (!CLI_ISCONTAINED(dest, dsize, adr, 4))
+			{
+				cli_dbgmsg("Upack: callfixerr\n");
+				return -1;
+			}
+			if ((cli_readint32(adr)&0xff) != searchval)
+				continue;
+			cli_writeint32(adr, EC32(CE32((uint32_t)(cli_readint32(adr)&0xffffff00)))-loc_ecx-4);
+			loc_ecx += 4;
+			save3--;
+		} else 
+			loc_ecx++;
+	}
+
+	section.raw = 0;
+	section.rva = va;
+	section.rsz = end_edi-loc_edi;
+	section.vsz = end_edi-loc_edi;
+
+	if (!cli_rebuildpe(dest + (upack?0:va), &section, 1, base, original_ep, 0, 0, file)) {
+		cli_dbgmsg("Upack: Rebuilding failed\n");
+		return 0;
+	}
+	return 1;
+}
+
+
+int unupack399(char *bs, uint32_t bl, uint32_t init_eax, char *init_ebx, uint32_t init_ecx, char *init_edi, char *end_edi, uint32_t shlsize, char *paddr)
+{
+	struct lzmastate p;
+	uint32_t loc_eax, ret, loc_al, loc_ecx = init_ecx, loc_ebp, eax_copy = init_eax, temp, i, jakas_kopia;
+	uint32_t state[6], temp_ebp;
+	char *loc_edx, *loc_ebx = init_ebx, *loc_edi = init_edi, *loc_ebp8, *edi_copy;
+	p.p0 = paddr;
+	p.p1 = cli_readint32(init_ebx);
+	p.p2 = cli_readint32(init_ebx + 4);
+
+	cli_dbgmsg("\n\tp0: %08x\n\tp1: %08x\n\tp2: %08x\n", p.p0, p.p1, p.p2);
+	for (i = 0; i<6; i++)
+		state[i] = cli_readint32(loc_ebx + (i<<2)),
+		cli_dbgmsg("state[%d] = %08x\n", i, state[i]);
+	do {
+		loc_eax = eax_copy;
+		loc_edx = loc_ebx + (loc_eax<<2) + 0x58;
+
+		if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl)))
+		{
+			/* loc_483927 */
+			loc_al = loc_eax&0xff;
+			loc_al = ((loc_al + 0xf9) > 0xff)?(3+8):8;
+			loc_eax = (loc_eax&0xffffff00)|(loc_al&0xff);
+			loc_ebp = state[2];
+			loc_ecx = (loc_ecx&0xffffff00)|0x30;
+			loc_edx += loc_ecx;
+			/* *(uint32_t *)(loc_ebx + 14) = loc_ebp; ???? */
+			if (!(ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+				/* loc_48397c */
+				loc_eax--;
+				/*
+				temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x0c); cli_writeint32(loc_ebx+0x0c, temp_ebp);
+				temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x10); cli_writeint32(loc_ebx+0x10, temp_ebp);
+				*/
+				temp_ebp = loc_ebp;
+				loc_ebp = state[4];
+				state[4] = state[3];
+				state[3] = temp_ebp;
+				eax_copy = loc_eax;
+				loc_edx = loc_ebx + 0xbc0;
+				state[5] = loc_ebp;
+				if (lzma_upack_esi_54(&p, loc_eax, &loc_ecx, &loc_edx, &temp, bs, bl) == 0xffffffff)
+					return -1;
+				loc_ecx = 3;
+				jakas_kopia = temp;
+				loc_eax = temp-1;
+				if (loc_eax >= loc_ecx)
+					loc_eax = loc_ecx;
+				loc_ecx = 0x40;
+				loc_eax <<= 6; /* ecx=0x40, mul cl */
+				loc_ebp8 = loc_ebx + ((loc_eax<<2) + 0x378);
+				if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+					return -1;
+				loc_ebp = loc_eax;
+				if ((loc_eax&0xff) >= 4)
+				{
+					/* loc_4839af */
+					loc_ebp = 2 + (loc_eax&1);
+					loc_eax >>= 1;
+					loc_eax--;
+					temp_ebp = loc_eax; loc_eax = loc_ecx; loc_ecx = temp_ebp;
+					loc_ebp <<= (loc_ecx&0xff);
+					loc_edx = loc_ebx + (loc_ebp<<2) + 0x178;
+					if ((loc_ecx&0xff) > 5)
+					{
+						/* loc_4839c6 */
+						loc_ecx = (loc_ecx&0xffffff00)|(((loc_ecx&0xff)-4)&0xff);
+						loc_eax = 0;
+						do {
+							uint32_t temp_edx;
+							/* compare with lzma_upack_esi_00 */
+							/* do not put in one statment because of difference in signedness */
+							if (!CLI_ISCONTAINED(bs, bl, p.p0, 4))
+								return -1;
+							temp_edx = cli_readint32((char *)p.p0);
+							temp_edx = EC32(CE32(temp_edx));
+							p.p1 >>= 1;
+							temp_edx -= p.p2;
+							loc_eax <<= 1;
+							if (temp_edx >= p.p1)
+							{
+								temp_edx = p.p1;
+								loc_eax++;
+								p.p2 += temp_edx;
+							}
+							if(((p.p1)&0xff000000) == 0)
+							{
+								p.p2 <<= 8;
+								p.p1 <<= 8;
+								p.p0++;
+							}
+						} while (--loc_ecx);
+						/* loc_4839e8 */
+						loc_ecx = (loc_ecx&0xffffff00)|4;
+						loc_eax <<= 4;
+						loc_ebp += loc_eax;
+						loc_edx = loc_ebx + 0x18;
+					}
+					/* loc4839f1 */
+					loc_eax = 1;
+					loc_eax <<= (loc_ecx&0xff);
+					loc_ebp8 = loc_edx;
+					temp_ebp = loc_ecx; loc_ecx = loc_eax; loc_eax = temp_ebp;
+					if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+						return -1;
+					/* cdq, loc_edx = (loc_eax&0x80000000)?0xffffffff:0; */
+					loc_ecx = temp_ebp;
+					temp_ebp = CLI_SRS((int32_t)loc_eax, 31); /* thx, desp */
+					/* loc_483a00 */
+					do {
+						temp_ebp += temp_ebp;
+						temp_ebp += (loc_eax&1);
+						loc_eax >>= 1;
+					} while (--loc_ecx);
+					loc_ebp += temp_ebp;
+					/* loc_483a06 */
+				}
+				/* loc_483a09 */
+				loc_ebp++;
+				loc_ecx = jakas_kopia;
+			} else {
+				/* loc_48393a */
+				loc_edx += loc_ecx;
+				if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+					/* loc_483954 */
+					loc_edx += 0x60;
+					if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+						/* loc_48395e */
+						loc_edx += loc_ecx;
+						ret = lzma_upack_esi_00(&p, loc_edx, bs, bl);
+						temp_ebp = loc_ebp;
+						loc_ebp = state[4];
+						state[4] = state[3];
+						state[3] = temp_ebp;
+						if (ret)
+						{
+							temp_ebp = loc_ebp; loc_ebp = state[5]; state[5] = temp_ebp;
+						}
+					} else {
+						temp_ebp = loc_ebp; loc_ebp = state[3]; state[3] = temp_ebp;
+					}
+				} else {
+					/* loc_483940 */
+					loc_edx += loc_ecx;
+					if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+					} else {
+						/* loc_483946 */
+						loc_eax |= 1;
+						eax_copy = loc_eax;
+						edi_copy = loc_edi;
+						edi_copy -= state[2];
+						loc_ecx = (loc_ecx&0xffffff00)|0x80;
+						if (!CLI_ISCONTAINED(bs, bl, edi_copy, 1) || !CLI_ISCONTAINED(bs, bl, loc_edi, 1))
+							return -1;
+						loc_al = (*(uint8_t *)edi_copy)&0xff;
+						/* loc_483922 */
+						/* ok jmp to 483a19 */
+						/* loc_483a19 */
+						*loc_edi++ = loc_al;
+						continue;
+					}
+				}
+				/* loc_48396a */
+				eax_copy = loc_eax;
+				loc_edx = loc_ebx + 0x778;
+				if (lzma_upack_esi_54(&p, loc_eax, &loc_ecx, &loc_edx, &temp, bs, bl) == 0xffffffff)
+					return -1;
+				loc_eax = loc_ecx;
+				loc_ecx = temp;
+			}
+			/* loc_483a0b */
+			if (!CLI_ISCONTAINED(bs, bl, loc_edi, loc_ecx) || !CLI_ISCONTAINED(bs, bl, loc_edi-loc_ebp, loc_ecx+1))
+				return -1;
+			state[2] = loc_ebp;
+			for (i=0; i<loc_ecx; i++, loc_edi++)
+				*loc_edi = *(loc_edi - loc_ebp);
+			loc_eax = (loc_eax&0xffffff00)|*(uint8_t *)(loc_edi - loc_ebp);
+			loc_ecx = 0x80;
+		} else {
+			/* loc_4838d8 */
+			do {
+				if ( (loc_al = (loc_eax&0xff)) + 0xfd > 0xff)
+					loc_al -= 3; /* 0x100 - 0xfd = 3 */
+				else
+					loc_al = 0;
+				loc_eax = (loc_eax&0xffffff00)|loc_al;
+			} while (loc_al >= 7);
+			/* loc_4838e2 */
+			eax_copy = loc_eax;
+			if (loc_edi > init_edi && loc_edi < bl+bs)
+			{
+				loc_ebp = (*(uint8_t *)(loc_edi - 1)) >> shlsize;
+			} else {
+				loc_ebp = 0;
+			}
+			loc_ebp *= (int)0x300; /* XXX */
+			loc_ebp8 = loc_ebx + ((loc_ebp<<2) + 0x1008);
+			/* XXX save edi */
+			edi_copy = loc_edi;
+
+			loc_eax = (loc_eax&0xffffff00)|1;
+			if (loc_ecx) {
+				uint8_t loc_cl = loc_ecx&0xff;
+				loc_edi -= state[2];
+				if (!CLI_ISCONTAINED(bs, bl, loc_edi, 1))
+					return -1;
+				do {
+					loc_eax = (loc_eax&0xffff00ff)|((*loc_edi & loc_cl)?0x200:0x100);
+
+					loc_edx = loc_ebp8 + (loc_eax<<2);
+					ret = lzma_upack_esi_00(&p, loc_edx, bs, bl);
+					loc_al = loc_eax&0xff;
+					loc_al += loc_al;
+					loc_al += ret;
+					loc_al &= 0xff;
+					loc_eax = (loc_eax&0xffffff00)|loc_al;
+					loc_cl >>= 1;
+					if (loc_cl) {
+						uint8_t loc_ah = (loc_eax>>8)&0xff;
+						loc_ah -= loc_al;
+						loc_ah &= 1;
+						if (!loc_ah)
+						{
+							loc_eax = (loc_eax&0xffff0000)|(loc_ah<<8)|loc_al;
+							/* loc_483918, loc_48391a */
+							if (lzma_upack_esi_50(&p, loc_eax, 0x100, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+								return -1;
+							break;
+						}
+					} else
+						break;
+				} while(1);
+			} else {
+				/* loc_48391a */
+				loc_ecx = (loc_ecx&0xffff00ff)|0x100;
+				if (lzma_upack_esi_50(&p, loc_eax, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+					return -1;
+			}
+			/* loc_48391f */
+			loc_ecx = 0;
+			loc_edi = edi_copy;
+		}
+		/* loc_483a19 */
+		/* 2GiM: i think this one is not properly checked, 2aCaB: true */
+		if (!CLI_ISCONTAINED(bs, bl, loc_edi, 1))
+			return -1;
+		*loc_edi++ = (loc_eax&0xff);
+	} while (loc_edi < end_edi);
+
+	return 1;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,520 @@
+/*
+ *  Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/*
+** upxdec.c
+**
+** 05/05/2k4 - 1st attempt
+** 08/05/2k4 - Now works as a charm :D
+** 09/05/2k4 - Moved code outta main(), got rid of globals for thread safety, added bound checking, minor cleaning
+** 04/06/2k4 - Now we handle 2B, 2D and 2E :D
+** 28/08/2k4 - PE rebuild for nested packers
+** 12/12/2k4 - Improved PE rebuild code and added some debug info on failure
+** 23/03/2k7 - New approach for rebuilding:
+               o Get imports via magic
+               o Get imports via leascan
+               o if (!pe) pe=scan4pe();
+	       o if (!pe) forgepe();
+*/
+
+/*
+** This code unpacks a dumped UPX1 section to a file.
+** It was written reversing the loader found on some Win32 UPX compressed trojans; while porting
+** it to C i've kinda followed the asm flow so it will probably be a bit hard to read.
+** This code DOES NOT revert the uncompressed section to its original state as no E8/E9 fixup and
+** of cause no IAT rebuild are performed.
+**
+** The Win32 asm unpacker is really a little programming jewel, pretty damn rare in these days of
+** bloatness. My gratitude to whoever wrote it.
+*/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "others.h"
+#include "upx.h"
+#include "str.h"
+
+#define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
+#define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
+
+#define HEADERS "\
+\x4D\x5A\x90\x00\x02\x00\x00\x00\x04\x00\x0F\x00\xFF\xFF\x00\x00\
+\xB0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x1A\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00\
+\x0E\x1F\xB4\x09\xBA\x0D\x00\xCD\x21\xB4\x4C\xCD\x21\x54\x68\x69\
+\x73\x20\x66\x69\x6C\x65\x20\x77\x61\x73\x20\x63\x72\x65\x61\x74\
+\x65\x64\x20\x62\x79\x20\x43\x6C\x61\x6D\x41\x56\x20\x66\x6F\x72\
+\x20\x69\x6E\x74\x65\x72\x6E\x61\x6C\x20\x75\x73\x65\x20\x61\x6E\
+\x64\x20\x73\x68\x6F\x75\x6C\x64\x20\x6E\x6F\x74\x20\x62\x65\x20\
+\x72\x75\x6E\x2E\x0D\x0A\x43\x6C\x61\x6D\x41\x56\x20\x2D\x20\x41\
+\x20\x47\x50\x4C\x20\x76\x69\x72\x75\x73\x20\x73\x63\x61\x6E\x6E\
+\x65\x72\x20\x2D\x20\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\
+\x63\x6C\x61\x6D\x61\x76\x2E\x6E\x65\x74\x0D\x0A\x24\x00\x00\x00\
+"
+#define FAKEPE "\
+\x50\x45\x00\x00\x4C\x01\x01\x00\x43\x4C\x41\x4D\x00\x00\x00\x00\
+\x00\x00\x00\x00\xE0\x00\x83\x8F\x0B\x01\x00\x00\x00\x10\x00\x00\
+\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\
+\x00\x10\x00\x00\x00\x00\x40\x00\x00\x10\x00\x00\x00\x02\x00\x00\
+\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x0A\x00\x00\x00\x00\x00\
+\xFF\xFF\xFF\xFF\x00\x02\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\
+\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x10\x00\x00\x10\x00\x00\
+\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x2e\x63\x6c\x61\x6d\x30\x31\x00\
+\xFF\xFF\xFF\xFF\x00\x10\x00\x00\xFF\xFF\xFF\xFF\x00\x02\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\
+"
+
+static char *checkpe(char *dst, uint32_t dsize, char *pehdr, uint32_t *valign, unsigned int *sectcnt)
+{
+  char *sections;
+  if (!CLI_ISCONTAINED(dst, dsize,  pehdr, 0xf8)) return NULL;
+
+  if (cli_readint32(pehdr) != 0x4550 ) return NULL;
+  
+  if (!(*valign=cli_readint32(pehdr+0x38))) return NULL;
+  
+  sections = pehdr+0xf8;
+  if (!(*sectcnt = (unsigned char)pehdr[6] + (unsigned char)pehdr[7]*256)) return NULL;
+  
+  if (!CLI_ISCONTAINED(dst, dsize, sections, *sectcnt*0x28)) return NULL;
+
+  return sections;
+}
+
+/* PE from UPX */
+
+static int pefromupx (char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic, uint32_t dend)
+{
+  char *imports, *sections, *pehdr=NULL, *newbuf;
+  unsigned int sectcnt=0, upd=1;
+  uint32_t realstuffsz=0, valign=0;
+  uint32_t foffset=0xd0+0xf8;
+
+  if((dst == NULL) || (src == NULL))
+    return 0;
+
+  while ((valign=magic[sectcnt++])) {
+    if ( ep - upx1 + valign <= ssize-5  &&    /* Wondering how we got so far?! */
+	 src[ep - upx1 + valign - 2] == '\x8d' && /* lea edi, ...                  */
+	 src[ep - upx1 + valign - 1] == '\xbe' )  /* ... [esi + offset]          */
+      break;
+  }
+
+  if (!valign && ep - upx1 + 0x80 < ssize-8) {
+    char *pt = &src[ep - upx1 + 0x80];
+    cli_dbgmsg("UPX: bad magic - scanning for imports\n");
+    
+    while ((pt=(char *)cli_memstr(pt, ssize - (pt-src) - 8, "\x8d\xbe", 2))) {
+      if (pt[6] == '\x8b' && pt[7] == '\x07') { /* lea edi, [esi+imports] / mov eax, [edi] */
+	valign=pt-src+2-ep+upx1;
+	break;
+      }
+      pt++;
+    }
+  }
+
+  if (valign && CLI_ISCONTAINED(src, ssize, src + ep - upx1 + valign, 4)) {
+    imports = dst + cli_readint32(src + ep - upx1 + valign);
+    
+    realstuffsz = imports-dst;
+    
+    if (realstuffsz >= *dsize ) {
+      cli_dbgmsg("UPX: wrong realstuff size\n");
+      /* fallback and eventually craft */
+    } else {
+      pehdr = imports;
+      while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && cli_readint32(pehdr)) {
+	pehdr+=8;
+	while(CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr) {
+	  pehdr++;
+	  while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr)
+	    pehdr++;
+	  pehdr++;
+	}
+	pehdr++;
+      }
+      
+      pehdr+=4;
+      if (!(sections=checkpe(dst, *dsize, pehdr, &valign, &sectcnt))) pehdr=NULL;
+    }
+  }
+
+  if (!pehdr && dend>0xf8+0x28) {
+    cli_dbgmsg("UPX: no luck - scanning for PE\n");
+    pehdr = &dst[dend-0xf8-0x28];
+    while (pehdr>dst) {
+      if ((sections=checkpe(dst, *dsize, pehdr, &valign, &sectcnt)))
+	break;
+      pehdr--;
+    }
+    if (!(realstuffsz = pehdr-dst)) pehdr=NULL;
+  }
+
+  if (!pehdr) {
+    uint32_t rebsz = PESALIGN(dend, 0x1000);
+    cli_dbgmsg("UPX: no luck - brutally crafing a reasonable PE\n");
+    if (!(newbuf = (char *)cli_calloc(rebsz+0x200, sizeof(char)))) {
+      cli_dbgmsg("UPX: malloc failed - giving up rebuild\n");
+      return 0;
+    }
+    memcpy(newbuf, HEADERS, 0xd0);
+    memcpy(newbuf+0xd0, FAKEPE, 0x120);
+    memcpy(newbuf+0x200, dst, dend);
+    memcpy(dst, newbuf, dend+0x200);
+    free(newbuf);
+    cli_writeint32(dst+0xd0+0x50, rebsz+0x1000);
+    cli_writeint32(dst+0xd0+0x100, rebsz);
+    cli_writeint32(dst+0xd0+0x108, rebsz);
+    *dsize=rebsz+0x200;
+    cli_dbgmsg("UPX: PE structure added to uncompressed data\n");
+    return 1;
+  }
+  
+  foffset = PESALIGN(foffset+0x28*sectcnt, valign);
+  
+  for (upd = 0; upd <sectcnt ; upd++) {
+    uint32_t vsize=PESALIGN((uint32_t)cli_readint32(sections+8), valign);
+    uint32_t urva=PEALIGN((uint32_t)cli_readint32(sections+12), valign);
+    
+    /* Within bounds ? */
+    if (!CLI_ISCONTAINED(upx0, realstuffsz, urva, vsize)) {
+      cli_dbgmsg("UPX: Sect %d out of bounds - giving up rebuild\n", upd);
+      return 0;
+    }
+    
+    cli_writeint32(sections+8, vsize);
+    cli_writeint32(sections+12, urva);
+    cli_writeint32(sections+16, vsize);
+    cli_writeint32(sections+20, foffset);
+    foffset+=vsize;
+    
+    sections+=0x28;
+  }
+
+  cli_writeint32(pehdr+8, 0x4d414c43);
+  cli_writeint32(pehdr+0x3c, valign);
+
+  if (!(newbuf = (char *) cli_calloc(foffset, sizeof(char)))) {
+    cli_dbgmsg("UPX: malloc failed - giving up rebuild\n");
+    return 0;
+  }
+  
+  memcpy(newbuf, HEADERS, 0xd0);
+  memcpy(newbuf+0xd0, pehdr,0xf8+0x28*sectcnt);
+  sections = pehdr+0xf8;
+  for (upd = 0; upd <sectcnt ; upd++) {
+    memcpy(newbuf+cli_readint32(sections+20), dst+cli_readint32(sections+12)-upx0, cli_readint32(sections+16));
+    sections+=0x28;
+  }
+
+  /* CBA restoring the imports they'll look different from the originals anyway... */
+  /* ...and yeap i miss the icon too :P */
+
+  if (foffset > *dsize + 8192) {
+    cli_dbgmsg("UPX: wrong raw size - giving up rebuild\n");
+    free(newbuf);
+    return 0;
+  }
+  memcpy(dst, newbuf, foffset);
+  *dsize = foffset;
+  free(newbuf);
+
+  cli_dbgmsg("UPX: PE structure rebuilt from compressed file\n");
+  return 1;
+}
+
+
+/* [doubleebx] */
+
+static int doubleebx(char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize)
+{
+  uint32_t oldebx = *myebx;
+
+  *myebx*=2;
+  if ( !(oldebx & 0x7fffffff)) {
+    if (! CLI_ISCONTAINED(src, ssize, src+*scur, 4))
+      return -1;
+    oldebx = cli_readint32(src+*scur);
+    *myebx = oldebx*2+1;
+    *scur+=4;
+  }
+  return (oldebx>>31);
+}
+
+/* [inflate] */
+
+int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
+{
+  int32_t backbytes, unp_offset = -1;
+  uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x108,0x110,0xd5,0};
+  int oob;
+  
+  while (1) {
+    while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 1) {
+      if (scur>=ssize || dcur>=*dsize)
+	return -1;
+      dst[dcur++] = src[scur++];
+    }
+
+    if ( oob == -1 )
+      return -1;
+    
+    backbytes = 1;
+
+    while (1) {
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+        return -1;
+      backbytes = backbytes*2+oob;
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+	return -1;
+      if (oob)
+        break;
+    }
+
+    backbytes-=3;
+  
+    if ( backbytes >= 0 ) {
+
+      if (scur>=ssize)
+	return -1;
+      backbytes<<=8;
+      backbytes+=(unsigned char)(src[scur++]);
+      backbytes^=0xffffffff;
+
+      if (!backbytes)
+	break;
+      unp_offset = backbytes;
+    }
+
+    if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff)
+      return -1;
+    if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+      return -1;
+    backsize = backsize*2 + oob;
+    if (!backsize) {
+      backsize++;
+      do {
+        if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+          return -1;
+	backsize = backsize*2 + oob;
+      } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
+      if ( oob == -1 )
+        return -1;
+      backsize+=2;
+    }
+
+    if ( (uint32_t)unp_offset < 0xfffff300 )
+      backsize++;
+
+    backsize++;
+
+    if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0)
+      return -1;
+    for (i = 0; i < backsize; i++)
+      dst[dcur + i] = dst[dcur + unp_offset + i];
+    dcur+=backsize;
+  }
+
+  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
+}
+
+int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
+{
+  int32_t backbytes, unp_offset = -1;
+  uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x11c,0x124,0};
+  int oob;
+
+  while (1) {
+    while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 1) {
+      if (scur>=ssize || dcur>=*dsize)
+	return -1;
+      dst[dcur++] = src[scur++];
+    }
+
+    if ( oob == -1 )
+      return -1;
+
+    backbytes = 1;
+
+    while (1) {
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+        return -1;
+      backbytes = backbytes*2+oob;
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+        return -1;
+      if (oob)
+	break;
+      backbytes--;
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+        return -1;
+      backbytes=backbytes*2+oob;
+    }
+
+    backsize = 0;
+    backbytes-=3;
+  
+    if ( backbytes >= 0 ) {
+
+      if (scur>=ssize)
+	return -1;
+      backbytes<<=8;
+      backbytes+=(unsigned char)(src[scur++]);
+      backbytes^=0xffffffff;
+
+      if (!backbytes)
+	break;
+      backsize = backbytes & 1;
+      CLI_SAR(backbytes,1);
+      unp_offset = backbytes;
+    } else {
+      if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
+        return -1;
+    }
+ 
+    if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+      return -1;
+    backsize = backsize*2 + oob;
+    if (!backsize) {
+      backsize++;
+      do {
+        if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+          return -1;
+	backsize = backsize*2 + oob;
+      } while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
+      if ( oob == -1 )
+        return -1;
+      backsize+=2;
+    }
+
+    if ( (uint32_t)unp_offset < 0xfffffb00 ) 
+      backsize++;
+
+    backsize++;
+    if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
+      return -1;
+    for (i = 0; i < backsize; i++)
+      dst[dcur + i] = dst[dcur + unp_offset + i];
+    dcur+=backsize;
+  }
+
+  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
+}
+
+int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
+{
+  int32_t backbytes, unp_offset = -1;
+  uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x128,0x130,0};
+  int oob;
+
+  for(;;) {
+    while ( (oob = doubleebx(src, &myebx, &scur, ssize)) ) {
+      if (oob == -1)
+        return -1;
+      if (scur>=ssize || dcur>=*dsize)
+	return -1;
+      dst[dcur++] = src[scur++];
+    }
+
+    backbytes = 1;
+
+    for(;;) {
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+        return -1;
+      backbytes = backbytes*2+oob;
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+        return -1;
+      if ( oob )
+	break;
+      backbytes--;
+      if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+        return -1;
+      backbytes=backbytes*2+oob;
+    }
+
+    backbytes-=3;
+  
+    if ( backbytes >= 0 ) {
+
+      if (scur>=ssize)
+	return -1;
+      backbytes<<=8;
+      backbytes+=(unsigned char)(src[scur++]);
+      backbytes^=0xffffffff;
+
+      if (!backbytes)
+	break;
+      backsize = backbytes & 1; /* Using backsize to carry on the shifted out bit (UPX uses CF) */
+      CLI_SAR(backbytes,1);
+      unp_offset = backbytes;
+    } else {
+      if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
+        return -1;
+    } /* Using backsize to carry on the doubleebx result (UPX uses CF) */
+
+    if (backsize) { /* i.e. IF ( last sar shifted out 1 bit || last doubleebx()==1 ) */
+      if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
+        return -1;
+    } else {
+      backsize = 1;
+      if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+        return -1;
+      if (oob) {
+	if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+	  return -1;
+	  backsize = 2 + oob;
+	} else {
+	  do {
+	    if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+	      return -1;
+	    backsize = backsize * 2 + oob;
+	  } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
+	  if (oob == -1)
+	    return -1;
+	  backsize+=2;
+	}
+    }
+ 
+    if ( (uint32_t)unp_offset < 0xfffffb00 ) 
+      backsize++;
+
+    backsize+=2;
+
+    if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
+      return -1;
+    for (i = 0; i < backsize; i++)
+      dst[dcur + i] = dst[dcur + unp_offset + i];
+    dcur+=backsize;
+  }
+
+  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,147 @@
+/*
+ *  Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+static	char	const	rcsid[] = "$Id: uuencode.c,v 1.8 2006/12/11 11:55:11 njh Exp $";
+
+#include "clamav.h"
+
+#if	HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <memory.h>
+#include <sys/stat.h>
+#ifdef	HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include "others.h"
+#include "str.h"
+
+#ifdef	C_WINDOWS
+#include <io.h>
+#endif
+
+#include "mbox.h"
+#include "uuencode.h"
+
+/* Maximum line length according to RFC821 */
+#define	RFC2821LENGTH	1000
+
+int
+cli_uuencode(const char *dir, int desc)
+{
+	FILE *fin;
+	int i;
+	message *m;
+	char buffer[RFC2821LENGTH + 1];
+
+	i = dup(desc);
+	if((fin = fdopen(i, "rb")) == NULL) {
+		cli_errmsg("Can't open descriptor %d\n", desc);
+		close(i);
+		return CL_EOPEN;
+	}
+	if(fgets(buffer, sizeof(buffer) - 1, fin) == NULL) {
+		/* empty message */
+		fclose(fin);
+		return CL_CLEAN;
+	}
+	if(!isuuencodebegin(buffer)) {
+		fclose(fin);
+		cli_errmsg("Message is not in uuencoded format\n");
+		return CL_EFORMAT;
+	}
+
+	m = messageCreate();
+	if(m == NULL) {
+		fclose(fin);
+		return CL_EMEM;
+	}
+
+	cli_dbgmsg("found uuencode file\n");
+
+	if(uudecodeFile(m, buffer, dir, fin) < 0) {
+		messageDestroy(m);
+		fclose(fin);
+		cli_errmsg("Message is not in uuencoded format\n");
+		return CL_EFORMAT;
+	}
+	messageDestroy(m);
+
+	fclose(fin);
+
+	return CL_CLEAN;	/* a lie - but it gets things going */
+}
+
+/*
+ * Save the uuencoded part of the file as it is read in since there's no need
+ * to include it in the parse tree. Saves memory and parse time.
+ * Return < 0 for failure
+ */
+int
+uudecodeFile(message *m, const char *firstline, const char *dir, FILE *fin)
+{
+	fileblob *fb;
+	char buffer[RFC2821LENGTH + 1];
+	char *filename = cli_strtok(firstline, 2, " ");
+
+	if(filename == NULL)
+		return -1;
+
+	fb = fileblobCreate();
+	if(fb == NULL) {
+		free(filename);
+		return -1;
+	}
+
+	fileblobSetFilename(fb, dir, filename);
+	cli_dbgmsg("uudecode %s\n", filename);
+	free(filename);
+
+	while(fgets(buffer, sizeof(buffer) - 1, fin) != NULL) {
+		unsigned char data[1024];
+		const unsigned char *uptr;
+		size_t len;
+
+		cli_chomp(buffer);
+		if(strcasecmp(buffer, "end") == 0)
+			break;
+		if(buffer[0] == '\0')
+			break;
+
+		uptr = decodeLine(m, UUENCODE, buffer, data, sizeof(data));
+		if(uptr == NULL)
+			break;
+
+		len = (size_t)(uptr - data);
+		if((len > 62) || (len == 0))
+			break;
+
+		if(fileblobAddData(fb, data, len) < 0)
+			break;
+	}
+
+	fileblobDestroy(fb);
+
+	return 1;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1344 @@
+/*
+ *  Extract VBA source code for component MS Office Documents
+ *
+ *  Copyright (C) 2004-2005 trog at uncon.org
+ *
+ *  This code is based on the OpenOffice and libgsf sources.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <zlib.h>
+
+#include "clamav.h"
+
+#include "vba_extract.h"
+#include "others.h"
+#ifdef  CL_DEBUG
+#include "mbox.h"
+#endif
+#include "blob.h"
+
+#ifndef	O_BINARY
+#define	O_BINARY	0
+#endif
+
+#ifndef HAVE_ATTRIB_PACKED
+#define __attribute__(x)
+#endif
+
+#define PPT_LZW_BUFFSIZE 8192
+#define NUM_VBA_VERSIONS 14
+#define VBA_COMPRESSION_WINDOW 4096
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+
+struct vba56_header {
+	unsigned char magic[2];
+	unsigned char version[4];
+	uint16_t ooff __attribute__ ((packed));	/* 0x00FF */
+	uint32_t LidA __attribute__ ((packed));  /* Language identifiers */
+	uint32_t LidB __attribute__ ((packed));
+	uint16_t CharSet __attribute__ ((packed));
+	uint16_t LenA __attribute__ ((packed));
+	uint32_t UnknownB __attribute__ ((packed));
+	uint32_t UnknownC __attribute__ ((packed));
+	uint16_t LenB __attribute__ ((packed));
+	uint16_t LenC __attribute__ ((packed));
+	uint16_t LenD __attribute__ ((packed));
+};
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack()
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack
+#endif
+
+typedef struct vba_version_tag {
+	unsigned char signature[4];
+	const char *name;
+	int is_mac;
+} vba_version_t;
+
+static uint16_t vba_endian_convert_16(uint16_t value, int is_mac)
+{
+	if (is_mac)
+		return (uint16_t)be16_to_host(value);
+	else
+		return le16_to_host(value);
+}
+
+static uint32_t vba_endian_convert_32(uint32_t value, int is_mac)
+{
+	if (is_mac)
+		return be32_to_host(value);
+	else
+		return le32_to_host(value);
+}
+
+static const vba_version_t vba_version[NUM_VBA_VERSIONS] = {
+	{ { 0x5e, 0x00, 0x00, 0x01 }, "Office 97",              FALSE},
+	{ { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1",          FALSE },
+	{ { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?",     FALSE },
+	{ { 0x6b, 0x00, 0x00, 0x01 }, "Office 2000 beta?",      FALSE },
+	{ { 0x6d, 0x00, 0x00, 0x01 }, "Office 2000",            FALSE },
+	{ { 0x6f, 0x00, 0x00, 0x01 }, "Office 2000",            FALSE },
+	{ { 0x70, 0x00, 0x00, 0x01 }, "Office XP beta 1/2",     FALSE },
+	{ { 0x73, 0x00, 0x00, 0x01 }, "Office XP",              FALSE },
+	{ { 0x76, 0x00, 0x00, 0x01 }, "Office 2003",            FALSE },
+	{ { 0x79, 0x00, 0x00, 0x01 }, "Office 2003",            FALSE },
+	{ { 0x60, 0x00, 0x00, 0x0e }, "MacOffice 98",           TRUE },
+	{ { 0x62, 0x00, 0x00, 0x0e }, "MacOffice 2001",         TRUE },
+	{ { 0x63, 0x00, 0x00, 0x0e }, "MacOffice X",		TRUE },
+	{ { 0x64, 0x00, 0x00, 0x0e }, "MacOffice 2004",         TRUE },
+};
+
+static char *
+get_unicode_name(const char *name, int size, int is_mac)
+{
+        int i, increment;
+        char *newname, *ret;
+
+	if((name == NULL) || (*name == '\0') || (size <= 0))
+                return NULL;
+
+        newname = (char *)cli_malloc(size * 7);
+        if(newname == NULL)
+                return NULL;
+
+	if((!is_mac) && (size & 0x1)) {
+		cli_dbgmsg("get_unicode_name: odd number of bytes %d\n", size);
+		--size;
+	}
+
+	increment = (is_mac) ? 1 : 2;
+	ret = newname;
+
+        for(i = 0; i < size; i += increment) {
+                if(isprint(name[i]))
+                        *ret++ = name[i];
+                else {
+			if(name[i] < 10 && name[i] >= 0) {
+				*ret++ = '_';
+				*ret++ = (char)(name[i] + '0');
+			} else {
+				const uint16_t x = (uint16_t)(((name[i]) << 8) | name[i + 1]);
+
+				*ret++ = '_';
+				*ret++ = (char)('a'+((x&0xF)));
+				*ret++ = (char)('a'+((x>>4)&0xF));
+				*ret++ = (char)('a'+((x>>8)&0xF));
+#if	0
+				*ret++ = (char)('a'+((x>>16)&0xF));	/* FIXME: x>>16 MUST == 0 */
+				*ret++ = (char)('a'+((x>>24)&0xF));	/* FIXME: x>>24 MUST == 0 */
+#endif
+			}
+			*ret++ = '_';
+		}
+	}
+
+        *ret = '\0';
+        return newname;
+}
+
+static void vba56_test_middle(int fd)
+{
+	char test_middle[20];
+
+	/* MacOffice middle */
+	static const uint8_t middle1_str[20] = {
+		0x00, 0x01, 0x0d, 0x45, 0x2e, 0xe1, 0xe0, 0x8f, 0x10, 0x1a,
+		0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
+	};
+	/* MS Office middle */
+	static const uint8_t middle2_str[20] = {
+		0x00, 0x00, 0xe1, 0x2e, 0x45, 0x0d, 0x8f, 0xe0, 0x1a, 0x10,
+		0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
+	};
+
+	if(cli_readn(fd, &test_middle, 20) != 20) {
+		return;
+	}
+
+	if ((memcmp(test_middle, middle1_str, 20) != 0) &&
+		(memcmp(test_middle, middle2_str, 20) != 0)) {
+		cli_dbgmsg("middle not found\n");
+		lseek(fd, -20, SEEK_CUR);
+	} else {
+		cli_dbgmsg("middle found\n");
+	}
+	return;
+}
+
+static int
+vba_read_project_strings(int fd, int is_mac)
+{
+	for (;;) {
+		uint32_t offset;
+		uint16_t length;
+		unsigned char *buff;
+		char *name;
+
+		if (cli_readn(fd, &length, 2) != 2) {
+			return FALSE;
+		}
+		length = vba_endian_convert_16(length, is_mac);
+		if (length < 6) {
+			lseek(fd, -2, SEEK_CUR);
+			break;
+		}
+		buff = (unsigned char *) cli_malloc(length);
+		if (!buff) {
+			cli_errmsg("cli_malloc failed\n");
+			return FALSE;
+		}
+		offset = lseek(fd, 0, SEEK_CUR);
+
+		if (cli_readn(fd, buff, length) != (int)length) {
+			cli_dbgmsg("read name failed - rewinding\n");
+			lseek(fd, offset, SEEK_SET);
+			free(buff);
+			break;
+		}
+		name = get_unicode_name((const char *)buff, length, is_mac);
+		if (name)
+			cli_dbgmsg("length: %d, name: %s\n", length, name);
+		else
+			cli_dbgmsg("length: %d, name: [null]\n", length);
+		free(buff);
+
+		/* Ignore twelve bytes from entries of type 'G'.
+		   Type 'C' entries come in pairs, the second also
+		   having a 12 byte trailer */
+		/* TODO: Need to check if types H(same as G) and D(same as C) exist */
+		if((name == NULL) || (memcmp("*\\", name, 2) != 0) ||
+		   (strchr("GCHD", name[2]) == NULL)) {
+			/* Unknown type - probably ran out of strings - rewind */
+			lseek(fd, -(length+2), SEEK_CUR);
+			if(name)
+				free(name);
+			break;
+		}
+		free(name);
+
+		if (cli_readn(fd, &length, 2) != 2)
+			return FALSE;
+
+		length = vba_endian_convert_16(length, is_mac);
+		if ((length != 0) && (length != 65535)) {
+			lseek(fd, -2, SEEK_CUR);
+			continue;
+		}
+		offset = lseek(fd, 10, SEEK_CUR);
+		cli_dbgmsg("offset: %u\n", offset);
+		vba56_test_middle(fd);
+	}
+	return TRUE;
+}
+
+vba_project_t *vba56_dir_read(const char *dir)
+{
+	unsigned char *buff;
+	const unsigned char vba56_signature[] = { 0xcc, 0x61 };
+	uint16_t record_count, length;
+	uint16_t ffff;
+	uint16_t byte_count;
+	uint32_t offset;
+	int i, fd, is_mac;
+	vba_project_t *vba_project;
+	struct vba56_header v56h;
+	char fullname[NAME_MAX + 1];
+
+	cli_dbgmsg("in vba56_dir_read()\n");
+
+	snprintf(fullname, sizeof(fullname) - 1, "%s/_VBA_PROJECT", dir);
+        fd = open(fullname, O_RDONLY|O_BINARY);
+
+        if (fd == -1) {
+                cli_dbgmsg("Can't open %s\n", fullname);
+		/* vba56_old_dir_read(dir); */
+                return NULL;
+        }
+
+	if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) {
+		close(fd);
+		return NULL;
+	}
+	if (memcmp(v56h.magic, vba56_signature, sizeof(v56h.magic)) != 0) {
+		close(fd);
+		return NULL;
+	}
+
+	for(i = 0; i < NUM_VBA_VERSIONS; i++)
+		if(memcmp(v56h.version, vba_version[i].signature, sizeof(vba_version[i].signature)) == 0)
+			break;
+
+	if (i == NUM_VBA_VERSIONS) {
+		cli_warnmsg("Unknown VBA version signature %x %x %x %x\n",
+			v56h.version[0], v56h.version[1],
+			v56h.version[2], v56h.version[3]);
+		switch(v56h.version[3]) {
+			case 0x01:
+				cli_warnmsg("Guessing little-endian\n");
+				is_mac = FALSE;
+				break;
+			case 0x0E:
+				cli_warnmsg("Guessing big-endian\n");
+				is_mac = TRUE;
+				break;
+			default:
+				cli_warnmsg("Unable to guess VBA type\n");
+				close(fd);
+				return NULL;
+		}
+	} else {
+		cli_dbgmsg("VBA Project: %s\n", vba_version[i].name);
+		is_mac = vba_version[i].is_mac;
+	}
+
+	if (!vba_read_project_strings(fd, is_mac)) {
+		close(fd);
+		return NULL;
+	}
+
+	/* junk some more stuff */
+	do {
+		if (cli_readn(fd, &ffff, 2) != 2) {
+			close(fd);
+			return NULL;
+		}
+	} while(ffff != 0xFFFF);
+
+	/* check for alignment error */
+	lseek(fd, -3, SEEK_CUR);
+	if (cli_readn(fd, &ffff, 2) != 2) {
+		close(fd);
+		return NULL;
+	}
+	if (ffff != 0xFFFF) {
+		lseek(fd, 1, SEEK_CUR);
+	}
+
+	if (cli_readn(fd, &ffff, 2) != 2) {
+		close(fd);
+		return NULL;
+	}
+
+	/* no idea what this stuff is */
+	if (ffff != 0xFFFF) {
+		ffff = vba_endian_convert_16(ffff, is_mac);
+		lseek(fd, ffff, SEEK_CUR);
+	}
+	if (cli_readn(fd, &ffff, 2) != 2) {
+		close(fd);
+		return NULL;
+	}
+	if (ffff != 0xFFFF) {
+		ffff = vba_endian_convert_16(ffff, is_mac);
+		lseek(fd, ffff, SEEK_CUR);
+	}
+	lseek(fd, 100, SEEK_CUR);
+
+	if (cli_readn(fd, &record_count, 2) != 2) {
+		close(fd);
+		return NULL;
+	}
+	record_count = vba_endian_convert_16(record_count, is_mac);
+	cli_dbgmsg("\nVBA Record count: %d\n", record_count);
+	if (record_count == 0) {
+		close(fd);
+		return NULL;
+	}
+	if (record_count > 1000) {
+		/* Almost certainly an error */
+		cli_dbgmsg("\nVBA Record count too big");
+		close(fd);
+		return NULL;
+	}
+
+	vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
+	if (!vba_project) {
+		close(fd);
+		return NULL;
+	}
+	vba_project->name = (char **) cli_malloc(sizeof(char *) * record_count);
+	if (!vba_project->name) {
+		free(vba_project);
+		close(fd);
+		return NULL;
+	}
+	vba_project->dir = cli_strdup(dir);
+	vba_project->offset = (uint32_t *) cli_malloc (sizeof(uint32_t) *
+					record_count);
+	if (!vba_project->offset) {
+		free(vba_project->dir);
+		free(vba_project->name);
+		free(vba_project);
+		close(fd);
+		return NULL;
+	}
+	vba_project->count = record_count;
+	for(i = 0; i < record_count; i++) {
+		if(cli_readn(fd, &length, 2) != 2)
+			break;
+
+		length = vba_endian_convert_16(length, is_mac);
+		if (length == 0) {
+			cli_dbgmsg("zero name length\n");
+			break;
+		}
+		buff = (unsigned char *) cli_malloc(length);
+		if (!buff) {
+			cli_dbgmsg("cli_malloc failed\n");
+			break;
+		}
+		if (cli_readn(fd, buff, length) != length) {
+			cli_dbgmsg("read name failed\n");
+			free(buff);
+			break;
+		}
+		vba_project->name[i] = get_unicode_name((const char *)buff, length, is_mac);
+		free(buff);
+		if (!vba_project->name[i]) {
+			offset = lseek(fd, 0, SEEK_CUR);
+			vba_project->name[i] = (char *) cli_malloc(18);
+			if(vba_project->name[i] == NULL) {
+				break;
+			}
+			snprintf(vba_project->name[i], 18, "clamav-%.10d", (int)offset);
+		}
+		cli_dbgmsg("project name: %s, ", vba_project->name[i]);
+
+		/* some kind of string identifier ?? */
+		if (cli_readn(fd, &length, 2) != 2) {
+			free(vba_project->name[i]);
+			break;
+		}
+		length = vba_endian_convert_16(length, is_mac);
+		lseek(fd, length, SEEK_CUR);
+
+		/* unknown stuff */
+		if (cli_readn(fd, &ffff, 2) != 2) {
+			free(vba_project->name[i]);
+			break;
+		}
+		ffff = vba_endian_convert_16(ffff, is_mac);
+		if (ffff == 0xFFFF) {
+			lseek(fd, 2, SEEK_CUR);
+			if (cli_readn(fd, &ffff, 2) != 2) {
+				free(vba_project->name[i]);
+				break;
+			}
+			ffff = vba_endian_convert_16(ffff, is_mac);
+			lseek(fd, ffff, SEEK_CUR);
+		} else {
+			lseek(fd, 2 + ffff, SEEK_CUR);
+		}
+
+		lseek(fd, 8, SEEK_CUR);
+		if (cli_readn(fd, &byte_count, 2) != 2) {
+			free(vba_project->name[i]);
+			break;
+		}
+		byte_count = vba_endian_convert_16(byte_count, is_mac);
+		lseek(fd, (8 * byte_count) + 5, SEEK_CUR);
+		if (cli_readn(fd, &offset, 4) != 4) {
+			free(vba_project->name[i]);
+			break;
+		}
+		offset = vba_endian_convert_32(offset, is_mac);
+		vba_project->offset[i] = offset;
+		cli_dbgmsg("offset:%u\n", offset);
+		lseek(fd, 2, SEEK_CUR);
+	}
+
+	close(fd);
+
+	if(i < record_count) {
+		/* above loop failed */
+		while(--i >= 0)
+			free(vba_project->name[i]);
+
+		free(vba_project->name);
+		free(vba_project->dir);
+		free(vba_project->offset);
+		free(vba_project);
+		return NULL;
+	}
+
+	return vba_project;
+}
+
+unsigned char *vba_decompress(int fd, uint32_t offset, int *size)
+{
+	unsigned int i, pos=0, shift, win_pos, clean=TRUE, mask, distance;
+	uint8_t flag;
+	uint16_t token, len;
+	size_t s;
+	blob *b;
+	unsigned char *ret;
+	unsigned char buffer[VBA_COMPRESSION_WINDOW];
+
+	b = blobCreate();
+
+	if(b == NULL)
+		return NULL;
+
+	lseek(fd, offset+3, SEEK_SET); /* 1byte ?? , 2byte length ?? */
+
+	while (cli_readn(fd, &flag, 1) == 1) {
+		for (mask = 1; mask < 0x100; mask<<=1) {
+			if (flag & mask) {
+				if (cli_readn(fd, &token, 2) != 2) {
+					blobDestroy(b);
+					if (size) {
+						*size = 0;
+					}
+					return NULL;
+				}
+				token = vba_endian_convert_16(token, FALSE);
+				win_pos = pos % VBA_COMPRESSION_WINDOW;
+				if (win_pos <= 0x80) {
+					if (win_pos <= 0x20) {
+						shift = (win_pos <= 0x10) ? 12:11;
+					} else {
+						shift = (win_pos <= 0x40) ? 10:9;
+					}
+				} else {
+					if (win_pos <= 0x200) {
+						shift = (win_pos <= 0x100) ? 8:7;
+					} else if (win_pos <= 0x800) {
+						shift = (win_pos <= 0x400) ? 6:5;
+					} else {
+						shift = 4;
+					}
+				}
+				len = (uint16_t)((token & ((1 << shift) -1)) + 3);
+				distance = token >> shift;
+				clean = TRUE;
+
+				for (i=0 ; i < len; i++) {
+					unsigned int srcpos;
+					unsigned char c;
+
+					srcpos = (pos - distance - 1) % VBA_COMPRESSION_WINDOW;
+					c = buffer[srcpos];
+					buffer[pos++ % VBA_COMPRESSION_WINDOW]= c;
+				}
+			} else {
+				if ((pos != 0) &&
+					((pos % VBA_COMPRESSION_WINDOW) == 0) && clean) {
+
+					if (cli_readn(fd, &token, 2) != 2) {
+						blobDestroy(b);
+						if(size)
+						       *size = 0;
+						return NULL;
+					}
+					clean = FALSE;
+					(void)blobAddData(b, buffer, VBA_COMPRESSION_WINDOW);
+					break;
+				}
+				if (cli_readn(fd, buffer+(pos%VBA_COMPRESSION_WINDOW), 1) == 1){
+					pos++;
+				}
+				clean = TRUE;
+			}
+		}
+	}
+
+	if (pos % VBA_COMPRESSION_WINDOW)
+		if(blobAddData(b, buffer, pos%VBA_COMPRESSION_WINDOW) < 0) {
+			if(size)
+			       *size = 0;
+			blobDestroy(b);
+			return NULL;
+		}
+	s = blobGetDataSize(b);
+	ret = cli_malloc(s);
+	if(ret == NULL) {
+		blobDestroy(b);
+		if(size)
+		       *size = 0;
+		return NULL;
+	}
+	if(size)
+		*size = (int)s;
+	memcpy(ret, blobGetData(b), s);
+	blobDestroy(b);
+	return ret;
+}
+
+static uint32_t ole_copy_file_data(int ifd, int ofd, uint32_t len)
+{
+        unsigned int count, rem;
+        unsigned char data[FILEBUFF];
+
+        rem = len;
+
+        while (rem > 0) {
+                unsigned int todo = MIN(sizeof(data), rem);
+
+                count = cli_readn(ifd, data, todo);
+                if (count != todo) {
+                        return len-rem;
+                }
+                if((unsigned int)cli_writen(ofd, data, count) != count)
+                        return len-rem-count;
+                rem -= count;
+        }
+        return len;
+}
+
+int cli_decode_ole_object(int fd, const char *dir)
+{
+	int ofd;
+	struct stat statbuf;
+	char ch;
+	uint32_t object_size;
+	char fullname[NAME_MAX + 1];
+
+	if (fstat(fd, &statbuf) == -1) {
+		return -1;
+	}
+
+	if (cli_readn(fd, &object_size, 4) != 4) {
+		return -1;
+	}
+	object_size = vba_endian_convert_32(object_size, FALSE);
+
+	if ((statbuf.st_size -  object_size) >= 4) {
+		/* Probably the OLE type id */
+		if (lseek(fd, 2, SEEK_CUR) == -1) {
+			return -1;
+		}
+
+		/* Skip attachment name */
+		do {
+			if (cli_readn(fd, &ch, 1) != 1) {
+				return -1;
+			}
+		} while (ch);
+
+		/* Skip attachment full path */
+		do {
+			if (cli_readn(fd, &ch, 1) != 1) {
+				return -1;
+			}
+		} while (ch);
+
+		/* Skip unknown data */
+		if (lseek(fd, 8, SEEK_CUR) == -1) {
+			return -1;
+		}
+
+		/* Skip attachment full path */
+		do {
+			if (cli_readn(fd, &ch, 1) != 1) {
+				return -1;
+			}
+		} while (ch);
+
+		if (cli_readn(fd, &object_size, 4) != 4) {
+			return -1;
+		}
+		object_size = vba_endian_convert_32(object_size, FALSE);
+	}
+	snprintf(fullname, sizeof(fullname) - 1, "%s/_clam_ole_object", dir);
+	ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
+	if (ofd < 0) {
+		return -1;
+	}
+	ole_copy_file_data(fd, ofd, object_size);
+	lseek(ofd, 0, SEEK_SET);
+	return ofd;
+}
+
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+/* Code to extract Power Point Embedded OLE2 Objects		     */
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+
+typedef struct atom_header_tag {
+	off_t foffset;
+	uint16_t ver_inst;
+	uint8_t version;
+	uint16_t instance;
+	uint16_t type;
+	uint32_t length;
+} atom_header_t;
+
+static int ppt_read_atom_header(int fd, atom_header_t *atom_header)
+{
+	atom_header->foffset = lseek(fd, 0, SEEK_CUR);
+	if (cli_readn(fd, &atom_header->ver_inst, 2) != 2) {
+		cli_dbgmsg("read ppt_current_user failed\n");
+		return FALSE;
+	}
+	atom_header->ver_inst = vba_endian_convert_16(atom_header->ver_inst, FALSE);
+	atom_header->version = (uint8_t)(atom_header->ver_inst & 0x000f);
+	atom_header->instance = (uint16_t)(atom_header->ver_inst >> 4);
+	if(cli_readn(fd, &atom_header->type, sizeof(uint16_t)) != sizeof(uint16_t)) {
+		cli_dbgmsg("read ppt_current_user failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &atom_header->length, 4) != 4) {
+		cli_dbgmsg("read ppt_current_user failed\n");
+		return FALSE;
+	}
+	atom_header->type = vba_endian_convert_16(atom_header->type, FALSE);
+	atom_header->length = vba_endian_convert_32(atom_header->length, FALSE);
+	return TRUE;
+}
+
+static void ppt_print_atom_header(atom_header_t *atom_header)
+{
+	cli_dbgmsg("Atom Hdr:\n");
+	cli_dbgmsg("  Version: 0x%.2x\n", atom_header->version);
+	cli_dbgmsg("  Instance: 0x%.4x\n", atom_header->instance);
+	cli_dbgmsg("  Type: 0x%.4x\n", atom_header->type);
+	cli_dbgmsg("  Length: 0x%.8x\n", atom_header->length);
+}
+
+static int ppt_unlzw(const char *dir, int fd, uint32_t length)
+{
+	int ofd, retval;
+	unsigned char inbuff[PPT_LZW_BUFFSIZE], outbuff[PPT_LZW_BUFFSIZE];
+	uint32_t bufflen;
+	z_stream stream;
+	char fullname[NAME_MAX + 1];
+
+	snprintf(fullname, sizeof(fullname) - 1, "%s/ppt%.8lx.doc",
+		dir, (long)lseek(fd, 0L, SEEK_CUR));
+
+	ofd = open(fullname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600);
+	if (ofd == -1) {
+		cli_dbgmsg("ppt_unlzw Open outfile failed\n");
+		return FALSE;
+	}
+
+	stream.zalloc = Z_NULL;
+	stream.zfree = Z_NULL;
+	stream.opaque = (void *)0;
+
+	stream.next_in = inbuff;
+	bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
+
+	if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
+		close(ofd);
+		unlink(fullname);
+		return FALSE;
+	}
+	length -= stream.avail_in;
+
+	retval = inflateInit(&stream);
+	if (retval != Z_OK) {
+		cli_dbgmsg(" ppt_unlzw !Z_OK: %d\n", retval);
+	}
+
+	stream.next_out = outbuff;
+	stream.avail_out = PPT_LZW_BUFFSIZE;
+
+	do {
+		if (stream.avail_out == 0) {
+			if (cli_writen(ofd, outbuff, PPT_LZW_BUFFSIZE)
+						!= PPT_LZW_BUFFSIZE) {
+				close(ofd);
+				inflateEnd(&stream);
+				return FALSE;
+			}
+			stream.next_out = outbuff;
+			stream.avail_out = PPT_LZW_BUFFSIZE;
+		}
+		if (stream.avail_in == 0) {
+			stream.next_in = inbuff;
+			bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
+			if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
+				close(ofd);
+				inflateEnd(&stream);
+				return FALSE;
+			}
+			length -= stream.avail_in;
+		}
+		retval = inflate(&stream, Z_NO_FLUSH);
+	} while (retval == Z_OK);
+
+	if (cli_writen(ofd, outbuff, bufflen) != (int64_t)bufflen) {
+		close(ofd);
+		inflateEnd(&stream);
+		return FALSE;
+	}
+	inflateEnd(&stream);
+	return close(ofd);
+}
+
+static char *ppt_stream_iter(int fd)
+{
+	uint32_t ole_id;
+	char *out_dir;
+	off_t offset;
+	atom_header_t atom_header;
+
+	/* Create a directory to store the extracted OLE2 objects */
+	out_dir = cli_gentemp(NULL);
+	if(mkdir(out_dir, 0700)) {
+		cli_errmsg("ScanOLE2 -> Can't create temporary directory %s\n", out_dir);
+		free(out_dir);
+		return NULL;
+	}
+
+	while(ppt_read_atom_header(fd, &atom_header)) {
+		ppt_print_atom_header(&atom_header);
+
+		if (atom_header.length == 0) {
+			cli_rmdirs(out_dir);
+			free(out_dir);
+			return NULL;
+		}
+
+		if (atom_header.type == 0x1011) {
+			if (cli_readn(fd, &ole_id, 4) != 4) {
+				cli_dbgmsg("read ole_id failed\n");
+				cli_rmdirs(out_dir);
+				free(out_dir);
+				return NULL;
+			}
+			ole_id = vba_endian_convert_32(ole_id, FALSE);
+			cli_dbgmsg("OleID: %d, length: %d\n",
+					(int)ole_id, (int)atom_header.length-4);
+			if (!ppt_unlzw(out_dir, fd, atom_header.length-4)) {
+				cli_dbgmsg("ppt_unlzw failed\n");
+				cli_rmdirs(out_dir);
+				free(out_dir);
+				return NULL;
+			}
+
+		} else {
+			offset = lseek(fd, 0, SEEK_CUR);
+			/* Check we don't wrap */
+			if ((offset + (off_t)atom_header.length) < offset) {
+				break;
+			}
+			offset += atom_header.length;
+			if (lseek(fd, offset, SEEK_SET) != offset ) {
+				break;
+			}
+		}
+	}
+	return out_dir;
+}
+
+char *ppt_vba_read(const char *dir)
+{
+	char *out_dir;
+	int fd;
+	char fullname[NAME_MAX + 1];
+
+	snprintf(fullname, sizeof(fullname) - 1, "%s/PowerPoint Document", dir);
+	fd = open(fullname, O_RDONLY|O_BINARY);
+	if (fd == -1) {
+		cli_dbgmsg("Open PowerPoint Document failed\n");
+		return NULL;
+	}
+
+	out_dir = ppt_stream_iter(fd);
+	close(fd);
+	return out_dir;
+}
+
+
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+/* Code to extract Word6 macros					     */
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+
+typedef struct mso_fib_tag {
+	char ununsed[sizeof(uint16_t) + sizeof(uint16_t) +
+		sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) +
+		sizeof(uint16_t)];
+	uint32_t macro_offset;
+	uint32_t macro_len;
+} mso_fib_t;
+
+typedef struct macro_entry_tag {
+	unsigned char version;
+	unsigned char key;
+	uint16_t intname_i;
+	uint16_t extname_i;
+	uint16_t xname_i;
+	uint32_t unknown;
+	uint32_t len;
+	uint32_t state;
+	uint32_t offset;
+} macro_entry_t;
+
+typedef struct macro_info_tag {
+	uint16_t count;
+	struct macro_entry_tag *macro_entry;
+} macro_info_t;
+
+static	void	wm_free_macro_info(macro_info_t *macro_info);
+
+static void wm_print_fib(mso_fib_t *fib)
+{
+	cli_dbgmsg("macro offset: 0x%.4x\n", fib->macro_offset);
+	cli_dbgmsg("macro len: 0x%.4x\n\n", fib->macro_len);
+}
+
+static int wm_read_fib(int fd, mso_fib_t *fib)
+{
+	/* don't need the information is this block, so seek forward */
+	if (lseek(fd, 0x118, SEEK_SET) != 0x118) {
+		cli_dbgmsg("lseek wm_fib failed\n");
+		return FALSE;
+	}
+
+	if (cli_readn(fd, &fib->macro_offset, 4) != 4) {
+		cli_dbgmsg("read wm_fib failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &fib->macro_len, 4) != 4) {
+		cli_dbgmsg("read wm_fib failed\n");
+		return FALSE;
+	}
+	fib->macro_offset = vba_endian_convert_32(fib->macro_offset, FALSE);
+	fib->macro_len = vba_endian_convert_32(fib->macro_len, FALSE);
+
+	return TRUE;
+}
+
+static int wm_read_macro_entry(int fd, macro_entry_t *macro_entry)
+{
+	if (cli_readn(fd, &macro_entry->version, 1) != 1) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->key, 1) != 1) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->intname_i, 2) != 2) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->extname_i, 2) != 2) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->xname_i, 2) != 2) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->unknown, 4) != 4) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->len, 4) != 4) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->state, 4) != 4) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+	if (cli_readn(fd, &macro_entry->offset, 4) != 4) {
+		cli_dbgmsg("read macro_entry failed\n");
+		return FALSE;
+	}
+
+	macro_entry->intname_i = vba_endian_convert_16(macro_entry->intname_i, FALSE);
+	macro_entry->extname_i = vba_endian_convert_16(macro_entry->extname_i, FALSE);
+	macro_entry->xname_i = vba_endian_convert_16(macro_entry->xname_i, FALSE);
+	macro_entry->len = vba_endian_convert_32(macro_entry->len, FALSE);
+	macro_entry->state = vba_endian_convert_32(macro_entry->state, FALSE);
+	macro_entry->offset = vba_endian_convert_32(macro_entry->offset, FALSE);
+	return TRUE;
+}
+
+static macro_info_t *wm_read_macro_info(int fd)
+{
+	int i;
+	macro_info_t *macro_info;
+
+	macro_info = (macro_info_t *) cli_malloc(sizeof(macro_info_t));
+	if (!macro_info) {
+		return NULL;
+	}
+	if (cli_readn(fd, &macro_info->count, 2) != 2) {
+		cli_dbgmsg("read macro_info failed\n");
+		free(macro_info);
+		return NULL;
+	}
+	macro_info->count = vba_endian_convert_16(macro_info->count, FALSE);
+	cli_dbgmsg("macro count: %d\n", macro_info->count);
+	macro_info->macro_entry = (macro_entry_t *)
+			cli_malloc(sizeof(macro_entry_t) * macro_info->count);
+	if (!macro_info->macro_entry) {
+		free(macro_info);
+		return NULL;
+	}
+	for (i=0 ; i < macro_info->count ; i++) {
+		if (!wm_read_macro_entry(fd,
+				&macro_info->macro_entry[i])) {
+			wm_free_macro_info(macro_info);
+			return NULL;
+		}
+	}
+	return macro_info;
+}
+
+static	void
+wm_free_macro_info(macro_info_t *macro_info)
+{
+	if (macro_info) {
+		free(macro_info->macro_entry);
+		free(macro_info);
+	}
+}
+
+static int wm_read_oxo3(int fd)
+{
+	uint8_t count;
+
+	if (cli_readn(fd, &count, 1) != 1) {
+		cli_dbgmsg("read oxo3 record1 failed\n");
+		return FALSE;
+	}
+	if (lseek(fd, count*14, SEEK_CUR) == -1) {
+		cli_dbgmsg("lseek oxo3 record1 failed\n");
+		return FALSE;
+	}
+	cli_dbgmsg("oxo3 records1: %d\n", count);
+
+	if (cli_readn(fd, &count, 1) != 1) {
+		cli_dbgmsg("read oxo3 record2 failed\n");
+		return FALSE;
+	}
+	if (count == 0) {
+		if (cli_readn(fd, &count, 1) != 1) {
+			cli_dbgmsg("read oxo3 failed\n");
+			return FALSE;
+		}
+		if (count != 2) {
+			lseek(fd, -1, SEEK_CUR);
+			return TRUE;
+		}
+		if (cli_readn(fd, &count, 1) != 1) {
+			cli_dbgmsg("read oxo3 failed\n");
+			return FALSE;
+		}
+	}
+	if (count > 0) {
+		if (lseek(fd, (count*4)+1, SEEK_CUR) == -1) {
+			cli_dbgmsg("lseek oxo3 failed\n");
+			return FALSE;
+		}
+	}
+	cli_dbgmsg("oxo3 records2: %d\n", count);
+	return TRUE;
+}
+
+static int
+wm_skip_menu_info(int fd)
+{
+	uint16_t count;
+
+	if (cli_readn(fd, &count, sizeof(uint16_t)) != sizeof(uint16_t)) {
+		cli_dbgmsg("read menu_info failed\n");
+		return FALSE;
+	}
+	count = vba_endian_convert_16(count, FALSE);
+	cli_dbgmsg("menu_info count: %d\n", count);
+
+	if(count)
+		if(lseek(fd, count * 12, SEEK_CUR) == -1)
+			return FALSE;
+	return TRUE;
+}
+
+static int
+wm_skip_macro_extnames(int fd)
+{
+	int is_unicode;
+	int16_t size;
+	off_t offset_end = lseek(fd, 0, SEEK_CUR);
+
+	if(cli_readn(fd, &size, sizeof(int16_t)) != sizeof(int16_t)) {
+		cli_dbgmsg("read macro_extnames failed\n");
+		return FALSE;
+	}
+	size = vba_endian_convert_16(size, FALSE);
+	if (size == -1) { /* Unicode flag */
+		if(cli_readn(fd, &size, sizeof(int16_t)) != sizeof(int16_t)) {
+			cli_dbgmsg("read macro_extnames failed\n");
+			return FALSE;
+		}
+		size = vba_endian_convert_16(size, FALSE);
+		is_unicode = 1;
+	} else
+		is_unicode = 0;
+
+	cli_dbgmsg("ext names size: 0x%x\n", size);
+
+	offset_end += size;
+	while(lseek(fd, 0, SEEK_CUR) < offset_end) {
+		uint8_t length;
+		off_t offset;
+
+		if (cli_readn(fd, &length, 1) != 1) {
+			cli_dbgmsg("read macro_extnames failed\n");
+			return FALSE;
+		}
+
+		if(is_unicode)
+			offset = (off_t)length * 2 + 1;
+		else
+			offset = (off_t)length;
+
+		offset += sizeof(uint16_t);	/* numref */
+		if(lseek(fd, offset, SEEK_CUR) == -1) {
+			cli_dbgmsg("read macro_extnames failed to seek\n");
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+static int
+wm_skip_macro_intnames(int fd)
+{
+	uint16_t i, count;
+
+	if (cli_readn(fd, &count, sizeof(uint16_t)) != sizeof(uint16_t)) {
+		cli_dbgmsg("read macro_intnames failed\n");
+		return FALSE;
+	}
+	count = vba_endian_convert_16(count, FALSE);
+	cli_dbgmsg("int names count: %u\n", count);
+
+	for(i = 0; i < count; i++) {
+		uint8_t length;
+
+		/* id */
+		if(lseek(fd, sizeof(uint16_t), SEEK_CUR) == -1) {
+			cli_dbgmsg("skip_macro_intnames failed\n");
+			return FALSE;
+		}
+
+		if(cli_readn(fd, &length, sizeof(uint8_t)) != sizeof(uint8_t)) {
+			cli_dbgmsg("skip_macro_intnames failed\n");
+			return FALSE;
+		}
+
+		/* Internal name, plus one byte of unknown data */
+		if(lseek(fd, length + 1, SEEK_CUR) == -1) {
+			cli_dbgmsg("skip_macro_intnames failed\n");
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+vba_project_t *wm_dir_read(const char *dir)
+{
+	int fd, done;
+	off_t end_offset;
+	unsigned char info_id;
+	macro_info_t *macro_info=NULL;
+	vba_project_t *vba_project;
+	mso_fib_t fib;
+	char fullname[NAME_MAX + 1];
+
+	snprintf(fullname, sizeof(fullname) - 1, "%s/WordDocument", dir);
+	fd = open(fullname, O_RDONLY|O_BINARY);
+	if (fd == -1) {
+		cli_dbgmsg("Open WordDocument failed\n");
+		return NULL;
+	}
+
+	if (!wm_read_fib(fd, &fib)) {
+		close(fd);
+		return NULL;
+	}
+	if(fib.macro_len == 0) {
+		cli_dbgmsg("No macros detected\n");
+		/* Must be clean */
+		close(fd);
+		return NULL;
+	}
+	wm_print_fib(&fib);
+
+	/* Go one past the start to ignore start_id */
+	if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) {
+		cli_dbgmsg("lseek macro_offset failed\n");
+		close(fd);
+		return NULL;
+	}
+
+	end_offset = fib.macro_offset + fib.macro_len;
+	done = FALSE;
+
+	while ((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
+		if (cli_readn(fd, &info_id, 1) != 1) {
+			cli_dbgmsg("read macro_info failed\n");
+			close(fd);
+			return NULL;
+		}
+		switch (info_id) {
+			case 0x01:
+				if(macro_info)
+					wm_free_macro_info(macro_info);
+				macro_info = wm_read_macro_info(fd);
+				if(macro_info == NULL)
+					done = TRUE;
+				break;
+			case 0x03:
+				if(!wm_read_oxo3(fd))
+					done = TRUE;
+				break;
+			case 0x05:
+				if(!wm_skip_menu_info(fd))
+					done = TRUE;
+				break;
+			case 0x10:
+				if(!wm_skip_macro_extnames(fd))
+					done = TRUE;
+				break;
+			case 0x11:
+				if(!wm_skip_macro_intnames(fd))
+					done = TRUE;
+				break;
+			case 0x12:
+				/* No sure about these, always seems to
+				come after the macros though, so finish
+				*/
+				done = TRUE;
+				break;
+			case 0x40:
+				/* end marker */
+				done = TRUE;
+				break;
+			default:
+				cli_dbgmsg("unknown type: 0x%x\n", info_id);
+				done = TRUE;
+		}
+	}
+
+	close(fd);
+
+	if (macro_info) {
+		vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
+		if (!vba_project) {
+			goto abort;
+		}
+		vba_project->name = (char **) cli_malloc(sizeof(char *) *macro_info->count);
+		if (!vba_project->name) {
+			free(vba_project);
+			vba_project = NULL;
+			goto abort;
+		}
+		vba_project->dir = cli_strdup(dir);
+		vba_project->offset = (uint32_t *) cli_malloc(sizeof(uint32_t) *
+					macro_info->count);
+		if (!vba_project->offset) {
+			free(vba_project->name);
+			if(vba_project->dir)
+				free(vba_project->dir);
+			free(vba_project);
+			vba_project = NULL;
+			goto abort;
+		}
+		vba_project->length = (uint32_t *) cli_malloc(sizeof(uint32_t) *
+					macro_info->count);
+		if (!vba_project->length) {
+			free(vba_project->offset);
+			free(vba_project->name);
+			free(vba_project->dir);
+			free(vba_project);
+			vba_project = NULL;
+			goto abort;
+		}
+		vba_project->key = (unsigned char *) cli_malloc(sizeof(unsigned char) *
+					macro_info->count);
+		if (!vba_project->key) {
+			free(vba_project->length);
+			free(vba_project->offset);
+			free(vba_project->name);
+			free(vba_project->dir);
+			free(vba_project);
+			vba_project = NULL;
+		} else {
+			int i;
+
+			vba_project->count = macro_info->count;
+			for(i = 0; i < macro_info->count; i++) {
+				vba_project->name[i] = cli_strdup("WordDocument");
+				vba_project->offset[i] = macro_info->macro_entry[i].offset;
+				vba_project->length[i] = macro_info->macro_entry[i].len;
+				vba_project->key[i] = macro_info->macro_entry[i].key;
+			}
+		}
+abort:
+		wm_free_macro_info(macro_info);
+		/* Fall through */
+	} else
+		vba_project = NULL;
+
+	return vba_project;
+}
+
+unsigned char *wm_decrypt_macro(int fd, uint32_t offset, uint32_t len,
+					unsigned char key)
+{
+	unsigned char *buff;
+	uint32_t i;
+
+	if (lseek(fd, offset, SEEK_SET) != (int64_t)offset) {
+		return NULL;
+	}
+	buff = (unsigned char *) cli_malloc(len);
+	if (!buff) {
+		return NULL;
+	}
+
+	if (cli_readn(fd, buff, len) != (int)len) {
+		free(buff);
+		return NULL;
+	}
+	if (key != 0)
+		for (i=0 ; i < len; i++)
+			buff[i] ^= key;
+	return buff;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,361 @@
+/*
+ *  Copyright (C) 2006 Sensory Networks, Inc.
+ *             Written by aCaB <acab at clamav.net>
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/*
+** wwunpack.c
+**
+** 09/07/2k6 - Campioni del mondo!!!
+** 14/07/2k6 - RCE'ed + standalone sect unpacker
+** 15/07/2k6 - Merge started
+** 17/07/2k6 - Rebuild
+** 18/07/2k6 - Secured (well, hopefully...)
+**
+*/
+
+/*
+** Unpacks+rebuilds WWPack32 1.20
+**
+** Just boooooring stuff, blah.
+**
+*/
+
+
+/*
+** TODO:
+**
+** review
+** check eax vs al
+** (check for dll's)
+** (have a look at older versions)
+**
+*/
+
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "others.h"
+#include "wwunpack.h"
+
+#define VAALIGN(s) (((s)/0x1000+((s)%0x1000!=0))*0x1000)
+#define FIXVS(v, r) (VAALIGN((r>v)?r:v))
+
+
+static int getbitmap(uint32_t *bitmap, char **src, uint8_t *bits, char *buf, unsigned int size) {
+  if (! CLI_ISCONTAINED(buf, size, *src, 4)) return 1;
+  *bitmap=cli_readint32(*src);
+  *src+=4;
+  *bits=32;
+  return 0;
+}
+
+static int getbits(uint8_t X, uint32_t *eax, uint32_t *bitmap, uint8_t *bits, char **src, char *buf, unsigned int size) {
+  *eax=*bitmap>>(32-X);
+  if (*bits>X) {
+    *bitmap<<=X;
+    *bits-=X;
+  } else if (*bits<X) {
+    X-=*bits;
+    *eax>>=X;
+    if (getbitmap(bitmap, src, bits, buf, size)) return 1;
+    *eax<<=X;
+    *eax|=*bitmap>>(32-X);
+    *bitmap<<=X;
+    *bits-=X;
+  } else {
+    if (getbitmap(bitmap, src, bits, buf, size)) return 1;
+  }
+  return 0;
+}
+
+static int wunpsect(char *packed, char *unpacked, unsigned int psize, unsigned int usize) {
+  char *src=packed, *dst=unpacked;
+  uint32_t bitmap, eax;
+  uint8_t bits;
+  unsigned int lostbit, getmorestuff;
+  uint16_t backbytes;
+  uint16_t backsize;
+  uint8_t oal;
+
+  if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+  eax=bitmap;
+
+  while (1) {
+    lostbit=bitmap>>31;
+    bitmap<<=1;
+    bits--;
+    if (!lostbit && bits) {
+      if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
+      *dst++=*src++;
+      continue;
+    }
+    
+    if (!bits) {
+      if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+      eax=bitmap;
+      if (!lostbit) {
+	if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
+	*dst++=*src++;
+	continue;
+      }
+    }
+    
+    if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+    
+    if ((eax&0xff)>=3) {
+      /* 50ff - two_bytes */
+      uint8_t fetchbits;
+      
+      if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+      fetchbits=(eax&0xff)+5;
+      eax--;
+      if ((int16_t)(eax&0xffff)<=0) {
+	/* 5113 */
+	backbytes=1<<fetchbits;
+	backbytes=(backbytes&0xff00)|((backbytes-31)&0xff);
+      } else {
+	/* 511b */
+	fetchbits++;
+	backbytes=1<<fetchbits;
+	backbytes-=0x9f;
+      }
+      /* 5125 */
+      if (getbits(fetchbits, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+      if ((eax&0xffff)==0x1ff) break;
+      eax&=0xffff;
+      backbytes+=eax;
+      if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, 2) && CLI_ISCONTAINED(unpacked, usize, dst, 2))) return 1;
+      *dst=*(dst-backbytes);
+      dst++;
+      *dst=*(dst-backbytes);
+      dst++;
+      continue;
+    }
+
+    /* 5143 - more_backbytes */      
+    oal=eax&0xff;
+    getmorestuff=1;
+
+    
+    if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+    if ((eax&0xff)<=3) {
+      lostbit=0;
+      if ((eax&0xff)==3) {
+	/* next_bit_or_reseed */
+	lostbit=bitmap>>31;
+	bitmap<<=1;
+	bits--;
+	if (!bits) {
+	  if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1; 
+	}
+      }
+      eax=eax+lostbit+5;
+      /* jmp more_bb_commondock */
+    } else { /* >3 */
+      /* 5160 - more_bb_morethan3 */
+      if ((eax&0xff)==4) {
+	/* next_bit_or_reseed */
+	lostbit=bitmap>>31;
+	bitmap<<=1;
+	bits--;
+	if (!bits) {
+	  if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;  
+	}
+	eax=eax+lostbit+6;
+	/* jmp more_bb_commondock */
+      } else { /* !=4 */
+	eax+=7;
+	if ((eax&0xff)>=0x0d) {
+	  getmorestuff=0; /* jmp more_bb_PASTcommondock */
+	  if ((eax&0xff)==0x0d) {
+	    /* 5179  */
+	    if (getbits(0x0e, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+	    eax+=0x1fe1;
+	  } else {
+	    /* 516c */
+	    if (getbits(0x0f, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+	    eax+=0x5fe1;
+	  }
+	  /* jmp more_bb_PASTcommondock */
+	} /* al >= 0d */
+      } /* al != 4 */
+    } /* >3 */
+    
+    if (getmorestuff) {
+      /* 5192 - more_bb_commondock */
+      uint16_t bk=(1<<(eax&0xff))-0x1f;
+      if (getbits((eax&0xff), &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+      eax+=bk;
+    }
+    
+    /* 51a7 - more_bb_pastcommondock */
+    eax&=0xffff;
+    backbytes=eax;
+    backsize=3+(oal!=1);
+    
+    if (oal<1) { /* overrides backsize */
+      /* 51bb - more_bb_again */
+      
+      /* next_bit_or_reseed */
+      lostbit=bitmap>>31;
+      bitmap<<=1;
+      bits--;
+      if (!bits) {
+	if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;  
+      }
+      if (!lostbit) {
+	/* 51c2 */
+	/* next_bit_or_reseed */
+	lostbit=bitmap>>31;
+	bitmap<<=1;
+	bits--;
+	if (!bits) {
+	  if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;   
+	}
+	eax=5+lostbit;
+	/* jmp setsize_and_backcopy */
+      } else {
+	/* 51ce - more_bb_again_and_again */
+	if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+	if (eax&0xff) {
+	  /* 51e6 */
+	  eax+=6;
+	  /* jmp setsize_and_backcopy */
+	} else {
+	  if (getbits(4, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+	  if (eax&0xff) {
+	    /* 51e4 */
+	    eax+=7+6;
+	    /* jmp setsize_and_backcopy */
+	  } else {
+	    /* 51ea - OMGWTF */
+	    uint8_t c=4;
+	    uint16_t d=0x0d;
+	    
+	    while ( 1 ) {
+	      if (c!=7){
+		d+=2;
+		d<<=1;
+		d--;
+		
+		/* next_bit_or_reseed */
+		lostbit=bitmap>>31;
+		bitmap<<=1;
+		bits--;
+		if (!bits) {
+		  if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;    
+		}
+		c++;
+		if (!lostbit) continue;
+		if (getbits(c, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+		d+=eax&0xff;
+		eax&=0xffffff00;
+		eax|=d&0xff;
+	      } else {
+		if (getbits(14, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+	      }
+	      break;
+	    } /* while */
+	  } /* OMGWTF */
+	} /* eax&0xff */
+      } /* lostbit */
+	/* 521b - setsize_and_backcopy */
+      backsize=eax&0xffff;
+    }
+
+    /* 521e - backcopy */
+    if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, backsize) && CLI_ISCONTAINED(unpacked, usize, dst, backsize))) return 1;
+    while(backsize--){
+      *dst=*(dst-backbytes);
+      dst++;
+    }
+
+  } /* while true */
+
+  return 0;
+}
+
+int wwunpack(char *exe, uint32_t exesz, uint32_t headsize, uint32_t min, uint32_t wwprva, uint32_t e_lfanew, char *wwp, uint32_t wwpsz, uint16_t sects) {
+  char *stuff=wwp+0x2a1, *packed, *unpacked;
+  uint32_t rva, csize;
+
+  cli_dbgmsg("in wwunpack\n");
+
+
+  while(1) {
+    if (!CLI_ISCONTAINED(wwp, wwpsz, stuff, 17)) {
+      cli_dbgmsg("WWPack: next chunk out ouf file, giving up.\n");
+      return 1;
+    }
+    if ((csize=cli_readint32(stuff+8)*4)!=(uint32_t)cli_readint32(stuff+12)+4) {
+      cli_dbgmsg("WWPack: inconsistent/hacked data, go figure!\n");
+      return 1;
+    }
+    rva = wwprva-cli_readint32(stuff);
+    if((packed = (char *) cli_calloc(csize, sizeof(char))) == NULL) {
+      cli_dbgmsg("WWPack: Can't allocate %d bytes\n", csize);
+      return 1;
+    }
+    unpacked=exe+headsize+rva-min;
+    if (!CLI_ISCONTAINED(exe, exesz, unpacked, csize)) {
+      free(packed);
+      cli_dbgmsg("WWPack: packed data out of bounds, giving up.\n");
+      return 1;
+    }
+    memcpy(packed, unpacked, csize);
+    if (wunpsect(packed, unpacked, csize, exesz-(unpacked-exe))) {
+      free(packed);
+      cli_dbgmsg("WWPack: unpacking failed.\n");
+      return 1;
+    }
+    free(packed);
+    if (!stuff[16]) break;
+    stuff+=17;
+  }
+
+  stuff=exe+e_lfanew;
+  stuff[6]=sects&0xff;
+  stuff[7]=sects>>8;
+
+  csize=cli_readint32(wwp+0x295)+wwprva+0x299;
+  cli_dbgmsg("WWPack: found OEP @%x\n", csize);
+  cli_writeint32(stuff+0x28, csize);
+
+  csize=cli_readint32(stuff+0x50)-VAALIGN(wwpsz);
+  cli_writeint32(stuff+0x50, csize);
+
+
+  stuff+=0x18+(cli_readint32(stuff+0x14)&0xffff);
+  while (sects--) {
+    uint32_t v=cli_readint32(stuff+8);
+    uint32_t r=cli_readint32(stuff+16);
+    csize=FIXVS(v, r);
+    cli_writeint32(stuff+8, csize);
+    cli_writeint32(stuff+16, csize);
+    cli_writeint32(stuff+20, cli_readint32(stuff+12)-min+headsize);
+    stuff+=0x28;
+  }
+  memset(stuff, 0, 0x28);
+
+  return 0;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,238 @@
+/*
+ *  Copyright (C) 2005 Ivan Zlatev <pumqara at gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/* Decrypts files, protected by Y0da Cryptor 1.3 */
+
+/* aCaB:
+ * 13/01/2006 - merged standalone unpacker into libclamav
+ * 14/01/2006 - major rewrite and bugfix
+ */
+ 
+
+#include <string.h>
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+#include "pe.h"
+#include "others.h"
+#include "yc.h"
+
+#define EC16(x) le16_to_host(x) /* Convert little endian to host */
+
+/* ========================================================================== */
+/* "Emulates" the poly decryptors */
+
+static int yc_poly_emulator(char* decryptor_offset, char* code, unsigned int ecx)
+{
+
+  /* 
+     This is the instruction set of the poly code.
+     Numbers stand for example only.
+
+     2C 05            SUB AL,5
+     2AC1             SUB AL,CL
+     34 10            XOR AL,10
+     32C1             XOR AL,CL
+     FEC8             DEC AL
+     04 10            ADD AL,10
+     02C1             ADD AL,CL
+     C0C0 06          ROL AL,6
+     C0C8 05          ROR AL,5
+     D2C8             ROR AL,CL
+     D2C0             ROL AL,CL
+
+  */
+  unsigned char al;
+  unsigned char cl = ecx & 0xff;
+  unsigned int j,i;
+
+  for(i=0;i<ecx;i++) /* Byte looper - Decrypts every byte and write it back */
+    {
+      al = code[i];
+
+      for(j=0;j<0x30;j++)   /* Poly Decryptor "Emulator" */
+	{
+	  switch(decryptor_offset[j])
+	    {
+
+	    case '\xEB':	/* JMP short */
+	      j++;
+	      j = j + decryptor_offset[j];
+	      break;
+
+	    case '\xFE':	/* DEC  AL */
+	      al--;
+	      j++;
+	      break;
+
+	    case '\x2A':	/* SUB AL,CL */
+	      al = al - cl;
+	      j++;
+	      break;
+
+	    case '\x02':	/* ADD AL,CL */
+	      al = al + cl;
+	      j++;
+	      break
+		;
+	    case '\x32':	/* XOR AL,CL */
+	      al = al ^ cl;
+	      j++;
+	      break;
+	      ;
+	    case '\x04':	/* ADD AL,num */
+	      j++;
+	      al = al + decryptor_offset[j];
+	      break;
+	      ;
+	    case '\x34':	/* XOR AL,num */
+	      j++;
+	      al = al ^ decryptor_offset[j];
+	      break;
+
+	    case '\x2C':	/* SUB AL,num */
+	      j++;
+	      al = al - decryptor_offset[j];
+	      break;
+
+			
+	    case '\xC0':
+	      j++;
+	      if(decryptor_offset[j]=='\xC0') /* ROL AL,num */
+		{
+		  j++;
+		  CLI_ROL(al,decryptor_offset[j]);
+		}
+	      else			/* ROR AL,num */
+		{
+		  j++;
+		  CLI_ROR(al,decryptor_offset[j]);
+		}
+	      break;
+
+	    case '\xD2':
+	      j++;
+	      if(decryptor_offset[j]=='\xC8') /* ROR AL,CL */
+		{
+		  j++;
+		  CLI_ROR(al,cl);
+		}
+	      else			/* ROL AL,CL */
+		{
+		  j++;
+		  CLI_ROL(al,cl);
+		}
+	      break;
+
+	    case '\x90':
+	    case '\xf8':
+	    case '\xf9':
+	      break;
+
+	    default:
+	      cli_dbgmsg("yC: Unhandled opcode %x\n", (unsigned char)decryptor_offset[j]);
+	      return 1;
+	    }
+	}
+      cl--;
+      code[i] = al;
+    }
+  return 0;
+
+}
+
+
+/* ========================================================================== */
+/* Main routine which calls all others */
+
+int yc_decrypt(char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc)
+{
+  uint32_t ycsect = sections[sectcount].raw;
+  unsigned int i;
+  struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset);
+  char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18;
+
+  /* 
+
+  First layer (decryptor of the section decryptor) in last section 
+
+  Start offset for analyze: Start of yC Section + 0x93
+  End offset for analyze: Start of yC Section + 0xC3
+  Lenght to decrypt - ECX = 0xB97
+
+  */
+  cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount); 
+  if (yc_poly_emulator(fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6 ,0xB97))
+    return 1;
+  filesize-=sections[sectcount].ursz;
+
+  /* 
+
+  Second layer (decryptor of the sections) in last section 
+
+  Start offset for analyze: Start of yC Section + 0x457
+  End offset for analyze: Start of yC Section + 0x487
+  Lenght to decrypt - ECX = Raw Size of Section
+
+  */
+
+
+  /* Loop through all sections and decrypt them... */
+  for(i=0;i<sectcount;i++)
+    {
+      uint32_t name = (uint32_t) cli_readint32(sname+i*0x28);
+      if ( !sections[i].raw ||
+	   !sections[i].rsz ||
+	   name == 0x63727372 || /* rsrc */
+	   name == 0x7273722E || /* .rsr */
+	   name == 0x6F6C6572 || /* relo */
+	   name == 0x6C65722E || /* .rel */
+	   name == 0x6164652E || /* .eda */
+	   name == 0x6164722E || /* .rda */
+	   name == 0x6164692E || /* .ida */
+	   name == 0x736C742E || /* .tls */
+	   (name&0xffff) == 0x4379  /* yC */
+	) continue;
+      cli_dbgmsg("yC: decrypting sect%d\n",i); 
+      if (yc_poly_emulator(fbuf + ycsect + 0x457, fbuf + sections[i].raw, sections[i].ursz))
+	return 1;
+    }
+
+  /* Remove yC section */
+  pe->NumberOfSections=EC16(sectcount);
+
+  /* Remove IMPORT_DIRECTORY information */
+  memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8);
+
+  /* OEP resolving */
+  /* OEP = DWORD PTR [ Start of yC section+ A0F] */
+  cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f));
+
+  /* Fix SizeOfImage */
+  cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz);
+
+  if (cli_writen(desc, fbuf, filesize)==-1) {
+    cli_dbgmsg("yC: Cannot write unpacked file\n");
+    return 1;
+  }
+  return 0;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/line.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/line.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/line.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/line.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (C) 2004 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * $Log: line.h,v $
+ * Revision 1.5  2006/04/09 19:59:27  kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.4  2004/10/14 17:45:55  nigelhorne
+ * Try to reclaim some memory if it becomes low when decoding
+ *
+ * Revision 1.3  2004/08/21 11:57:57  nigelhorne
+ * Use line.[ch]
+ *
+ * Revision 1.2  2004/08/20 19:06:45  kojm
+ * add line.[ch]
+ *
+ * Revision 1.1  2004/08/20 11:58:20  nigelhorne
+ * First draft
+ *
+ */
+
+#ifndef __LINE_H
+#define __LINE_H
+
+typedef	char	line_t;	/* first byte is the ref count */
+
+line_t	*lineCreate(const char *data);
+line_t	*lineLink(line_t *line);
+line_t	*lineUnlink(line_t *line);
+const	char	*lineGetData(const line_t *line);
+
+#define	lineGetRefCount(line)	((unsigned char)line[0])
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (C) 2006 Mark Pizzolato <clamav-devel at subscriptions.pizzolato.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __LOCKDB_H
+#define __LOCKDB_H
+
+int cli_writelockdb(const char *dbdirpath, int wait);
+int cli_readlockdb(const char *dbdirpath, int wait);
+int cli_unlockdb(const char *dbdirpath);
+int cli_freelocks(void);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/manager.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/manager.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/manager.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/manager.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (C) 2002, 2003 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __MANAGER_H
+#define __MANAGER_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include "clamav.h"
+#include "options.h"
+
+int scanmanager(const struct optstruct *opt);
+
+int scanfile(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,75 @@
+/*
+ *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __MATCHER_AC_H
+#define __MATCHER_AC_H
+
+#include <sys/types.h>
+
+#include "filetypes.h"
+#include "cltypes.h"
+
+#define AC_DEFAULT_MIN_DEPTH 2
+#define AC_DEFAULT_MAX_DEPTH 3
+#define AC_DEFAULT_TRACKLEN 8
+extern uint8_t cli_ac_mindepth, cli_ac_maxdepth;
+
+struct cli_ac_data {
+    uint32_t partsigs;
+    int32_t ***offmatrix;
+};
+
+struct cli_ac_alt {
+    uint8_t chmode;
+    unsigned char *str;
+    uint16_t len, num;
+    struct cli_ac_alt *next;
+};
+
+struct cli_ac_patt {
+    uint16_t *pattern, *prefix, length, prefix_length;
+    uint8_t depth;
+    uint32_t mindist, maxdist;
+    char *virname, *offset;
+    uint32_t sigid;
+    uint16_t parts, partno, alt, alt_pattern;
+    struct cli_ac_alt **alttable;
+    uint8_t target;
+    uint16_t type;
+    struct cli_ac_patt *next, *next_same;
+};
+
+struct cli_ac_node {
+    uint8_t leaf, final;
+    struct cli_ac_patt *list;
+    struct cli_ac_node **trans, *fail;
+};
+
+#include "matcher.h"
+
+int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern);
+int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint8_t tracklen);
+void cli_ac_freedata(struct cli_ac_data *data);
+int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, struct cli_ac_data *mdata, uint8_t otfrec, uint32_t offset, cli_file_t ftype, int fd, struct cli_matched_type **ftoffset);
+int cli_ac_buildtrie(struct cli_matcher *root);
+int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth);
+void cli_ac_free(struct cli_matcher *root);
+int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target);
+void cli_ac_setdepth(uint8_t mindepth, uint8_t maxdepth);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __MATCHER_BM_H
+#define __MATCHER_BM_H
+
+#include "matcher.h"
+#include "filetypes.h"
+#include "cltypes.h"
+
+struct cli_bm_patt {
+    unsigned char *pattern, *prefix;
+    uint16_t length, prefix_length;
+    char *virname, *offset;
+    uint8_t target;
+    struct cli_bm_patt *next;
+    uint16_t cnt;
+};
+
+int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern);
+int cli_bm_init(struct cli_matcher *root);
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, cli_file_t ftype, int fd);
+void cli_bm_free(struct cli_matcher *root);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __MATCHER_H
+#define __MATCHER_H
+
+#include <sys/types.h>
+
+#include "clamav.h"
+#include "filetypes.h"
+#include "others.h"
+#include "execs.h"
+#include "cltypes.h"
+#include "md5.h"
+
+#include "matcher-ac.h"
+#include "matcher-bm.h"
+
+#define CLI_MATCH_WILDCARD	0xff00
+#define CLI_MATCH_CHAR		0x0000
+#define CLI_MATCH_IGNORE	0x0100
+#define CLI_MATCH_ALTERNATIVE	0x0200
+#define CLI_MATCH_NIBBLE_HIGH	0x0300
+#define CLI_MATCH_NIBBLE_LOW	0x0400
+
+struct cli_matcher {
+    uint16_t maxpatlen;
+    uint8_t ac_only;
+
+    /* Extended Boyer-Moore */
+    uint8_t *bm_shift;
+    struct cli_bm_patt **bm_suffix;
+    uint32_t *soff, soff_len; /* for PE section sigs */
+
+    /* Extended Aho-Corasick */
+    uint8_t ac_mindepth, ac_maxdepth;
+    struct cli_ac_node *ac_root, **ac_nodetable;
+    struct cli_ac_patt **ac_pattable;
+    uint32_t ac_partsigs, ac_nodes, ac_patterns;
+};
+
+struct cli_md5_node {
+    char *virname;
+    unsigned char *md5;
+    unsigned int size;
+    unsigned short fp;
+    struct cli_md5_node *next;
+};
+
+struct cli_meta_node {
+    int csize, size, method;
+    unsigned int crc32, fileno, encrypted, maxdepth;
+    char *filename, *virname;
+    struct cli_meta_node *next;
+};
+
+#define CL_TARGET_TABLE_SIZE 7
+
+struct cli_target_info {
+    off_t fsize;
+    struct cli_exe_info exeinfo;
+    int8_t status; /* 0 == not initialised, 1 == initialised OK, -1 == error */
+};
+
+int cli_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cl_engine *engine, cli_file_t ftype);
+
+int cli_scandesc(int desc, cli_ctx *ctx, uint8_t otfrec, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset);
+
+int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname);
+
+struct cli_md5_node *cli_vermd5(const unsigned char *md5, const struct cl_engine *engine);
+
+off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret, unsigned int *maxshift);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/* See RFC1521 */
+typedef	enum {
+	NOMIME, APPLICATION, AUDIO, IMAGE, MESSAGE, MULTIPART, TEXT, VIDEO, MEXTENSION
+} mime_type;
+
+typedef enum {
+	NOENCODING, QUOTEDPRINTABLE, BASE64, EIGHTBIT, BINARY, UUENCODE, YENCODE, EEXTENSION, BINHEX
+} encoding_type;
+
+/* tk: shut up manager.c warning */
+#include "clamav.h"
+
+/* classes supported by this system */
+typedef enum {
+	INVALIDCLASS, BLOBCLASS
+} object_type;
+
+#ifdef C_BSD
+#define UNIX
+#endif
+
+#include "table.h"
+#include "blob.h"
+#include "line.h"
+#include "text.h"
+#include "message.h"
+#include "uuencode.h"
+
+size_t	strstrip(char *s);	/* remove trailing white space */
+int	cli_mbox(const char *dir, int desc, cli_ctx *ctx);

Added: test-suite/trunk/MultiSource/Applications/ClamAV/md5.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/md5.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/md5.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/md5.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security,
+ * Inc. MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Written by Solar Designer <solar at openwall.com> in 2001, and placed
+ * in the public domain.  There's absolutely no warranty.
+ *
+ * See md5.c for more information.
+ */
+
+#ifndef __MD5_H
+#define __MD5_H
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
+
+typedef struct {
+	MD5_u32plus lo, hi;
+	MD5_u32plus a, b, c, d;
+	unsigned char buffer[64];
+	MD5_u32plus block[16];
+} cli_md5_ctx;
+
+extern void cli_md5_init(cli_md5_ctx *ctx);
+extern void cli_md5_update(cli_md5_ctx *ctx, void *data, unsigned long size);
+extern void cli_md5_final(unsigned char *result, cli_md5_ctx *ctx);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/message.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/message.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/message.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/message.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef	_MESSAGE_H
+#define	_MESSAGE_H
+
+/* The contents could change, ONLY access in message.c */
+typedef struct message {
+	mime_type	mimeType;
+	encoding_type	*encodingTypes;
+	int	numberOfEncTypes;	/* size of encodingTypes */
+	char	*mimeSubtype;
+	int	numberOfArguments;	/* count of mimeArguments */
+	char	**mimeArguments;
+	char	*mimeDispositionType;	/* probably attachment */
+	text	*body_first, *body_last;
+	cli_ctx	*ctx;
+
+	char	base64_1, base64_2, base64_3;
+	int	base64chars;
+	unsigned	int	isInfected : 1;
+
+	/*
+	 * Markers for the start of various non MIME messages that could
+	 * be included within this message
+	 */
+	text	*bounce;	/* start of a bounced message */
+	text	*binhex;	/* start of a binhex message */
+	text	*yenc;		/* start of a yEnc message */
+	text	*encoding;	/* is the non MIME message encoded? */
+	const text	*dedupedThisFar;
+} message;
+
+message	*messageCreate(void);
+void	messageDestroy(message *m);
+void	messageReset(message *m);
+int	messageSetMimeType(message *m, const char *type);
+mime_type	messageGetMimeType(const message *m);
+void	messageSetMimeSubtype(message *m, const char *subtype);
+const	char	*messageGetMimeSubtype(const message *m);
+void	messageSetDispositionType(message *m, const char *disptype);
+const	char	*messageGetDispositionType(const message *m);
+void	messageAddArgument(message *m, const char *arg);
+void	messageAddArguments(message *m, const char *arg);
+char	*messageFindArgument(const message *m, const char *variable);
+char	*messageGetFilename(const message *m);
+int	messageHasFilename(const message *m);
+void	messageSetEncoding(message *m, const char *enctype);
+encoding_type	messageGetEncoding(const message *m);
+int	messageAddLine(message *m, line_t *line);
+int	messageAddStr(message *m, const char *data);
+int	messageAddStrAtTop(message *m, const char *data);
+int	messageMoveText(message *m, text *t, message *old_message);
+text	*messageGetBody(message *m);
+unsigned	char	*base64Flush(message *m, unsigned char *buf);
+fileblob	*messageToFileblob(message *m, const char *dir, int destroy);
+blob	*messageToBlob(message *m, int destroy);
+text	*messageToText(message *m);
+text	*binhexBegin(message *m);
+text	*yEncBegin(message *m);
+text	*bounceBegin(message *m);
+text	*encodingLine(message *m);
+void	messageClearMarkers(message *m);
+unsigned char	*decodeLine(message *m, encoding_type enctype, const char *line, unsigned char *buf, size_t buflen);
+int	isuuencodebegin(const char *line);
+void	messageSetCTX(message *m, cli_ctx *ctx);
+int	messageContainsVirus(const message *m);
+
+#endif	/*_MESSAGE_H*/

Added: test-suite/trunk/MultiSource/Applications/ClamAV/mew.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/mew.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/mew.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/mew.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (C) 2006 Michal 'GiM' Spadlinski http://gim.org.pl/
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __MEW_H
+#define __MEW_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+
+struct lzmastate {
+	char *p0;
+	uint32_t p1, p2;
+};
+
+int mew_lzma(char *, char *, uint32_t, uint32_t, uint32_t);
+
+uint32_t lzma_upack_esi_00(struct lzmastate *, char *, char *, uint32_t);
+uint32_t lzma_upack_esi_50(struct lzmastate *, uint32_t, uint32_t, char **, char *, uint32_t *, char *, uint32_t);
+uint32_t lzma_upack_esi_54(struct lzmastate *, uint32_t, uint32_t *, char **, uint32_t *, char *, uint32_t);
+int unmew11(int, char *, int, int, int, uint32_t, uint32_t, int, char **, char **, int);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/misc.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/misc.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/misc.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/misc.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __MISC_H
+#define __MISC_H
+
+/* Maximum filenames under various systems - njh */
+#ifndef	NAME_MAX	/* e.g. Linux */
+# ifdef	MAXNAMELEN	/* e.g. Solaris */
+#   define	NAME_MAX	MAXNAMELEN
+# else
+#   ifdef	FILENAME_MAX	/* e.g. SCO */
+#     define	NAME_MAX	FILENAME_MAX
+#   endif
+# endif
+#endif
+
+#include "cfgparser.h"
+
+char *freshdbdir(void);
+void print_version(void);
+int filecopy(const char *src, const char *dest);
+int isnumb(const char *str);
+int dircopy(const char *src, const char *dest);
+int cvd_unpack(const char *cvd, const char *destdir);
+void daemonize(void);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2004 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __MSEXPAND_H
+#define __MSEXPAND_H
+
+#include <stdio.h>
+
+int cli_msexpand(FILE *in, FILE *out);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,292 @@
+/*
+ * This file includes code from libmspack adapted for libclamav by
+ * tkojm at clamav.net
+ *
+ * Copyright (C) 2003-2004 Stuart Caie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __MSPACK_H
+#define __MSPACK_H
+
+#include <sys/types.h>
+#include "cab.h"
+
+
+/***************************************************************************
+ *			 MS-ZIP decompression definitions                  *
+ ***************************************************************************/
+
+#define MSZIP_FRAME_SIZE          (32768) /* size of LZ history window */
+#define MSZIP_MAX_HUFFBITS        (16)    /* maximum huffman code length */
+#define MSZIP_LITERAL_MAXSYMBOLS  (288)   /* literal/length huffman tree */
+#define MSZIP_LITERAL_TABLEBITS   (9)
+#define MSZIP_DISTANCE_MAXSYMBOLS (32)    /* distance huffman tree */
+#define MSZIP_DISTANCE_TABLEBITS  (6)
+
+/* if there are less direct lookup entries than symbols, the longer
+ * code pointers will be <= maxsymbols. This must not happen, or we
+ * will decode entries badly */
+#if (1 << MSZIP_LITERAL_TABLEBITS) < (MSZIP_LITERAL_MAXSYMBOLS * 2)
+# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
+#else
+# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
+				  (MSZIP_LITERAL_MAXSYMBOLS * 2))
+#endif
+
+#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
+# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
+#else
+# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
+				  (MSZIP_DISTANCE_MAXSYMBOLS * 2))
+#endif
+
+struct mszip_stream {
+  int fd;		    /* input file descriptor */
+  int ofd;                  /* output file descriptor */
+  unsigned char wflag;	    /* write flag */
+
+  unsigned int window_posn;             /* offset within window  */
+
+  /* inflate() will call this whenever the window should be emptied. */
+  int (*flush_window)(struct mszip_stream *, unsigned int);
+
+  int error, repair_mode, bytes_output, input_end;
+
+  /* I/O buffering */
+  unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
+  unsigned int bit_buffer, bits_left, inbuf_size;
+
+  /* huffman code lengths */
+  unsigned char  LITERAL_len[MSZIP_LITERAL_MAXSYMBOLS];
+  unsigned char  DISTANCE_len[MSZIP_DISTANCE_MAXSYMBOLS];
+
+  /* huffman decoding tables */
+  unsigned short LITERAL_table [MSZIP_LITERAL_TABLESIZE];
+  unsigned short DISTANCE_table[MSZIP_DISTANCE_TABLESIZE];
+
+  /* 32kb history window */
+  unsigned char window[MSZIP_FRAME_SIZE];
+
+  /* cabinet related stuff */
+  struct cab_file *file;
+  int (*read)(struct cab_file *, unsigned char *, int);
+};
+
+struct mszip_stream *mszip_init(int fd,
+				  int ofd,
+				  int input_buffer_size,
+				  int repair_mode,
+				  struct cab_file *file,
+			          int (*read)(struct cab_file *, unsigned char *, int));
+
+extern int mszip_decompress(struct mszip_stream *zip, off_t out_bytes);
+
+void mszip_free(struct mszip_stream *zip);
+
+
+/***************************************************************************
+ *			 Quantum decompression definitions                 *
+ ***************************************************************************/
+
+/* Quantum compression / decompression definitions */
+
+#define QTM_FRAME_SIZE (32768)
+
+struct qtm_modelsym {
+  unsigned short sym, cumfreq;
+};
+
+struct qtm_model {
+  int shiftsleft, entries;
+  struct qtm_modelsym *syms;
+};
+
+struct qtm_stream {
+  int fd;                   /* input file descriptor */
+  int ofd;                  /* output file descriptor */
+  unsigned char wflag;	    /* write flag */
+
+  unsigned char *window;          /* decoding window                         */
+  unsigned int window_size;       /* window size                             */
+  unsigned int window_posn;       /* decompression offset within window      */
+  unsigned int frame_start;       /* start of current frame within window    */
+
+  unsigned short H, L, C;         /* high/low/current: arith coding state    */
+  unsigned char header_read;      /* have we started decoding a new frame?   */
+
+  int error;
+
+  /* I/O buffers */
+  unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
+  unsigned int  bit_buffer, inbuf_size;
+  unsigned char bits_left;
+
+  /* data tables */
+  unsigned int  position_base[42];
+  unsigned char extra_bits[42], length_base[27], length_extra[27];
+
+  /* four literal models, each representing 64 symbols
+   * model0 for literals from   0 to  63 (selector = 0)
+   * model1 for literals from  64 to 127 (selector = 1)
+   * model2 for literals from 128 to 191 (selector = 2)
+   * model3 for literals from 129 to 255 (selector = 3) */
+  struct qtm_model model0, model1, model2, model3;
+
+  /* three match models.
+   * model4 for match with fixed length of 3 bytes
+   * model5 for match with fixed length of 4 bytes
+   * model6 for variable length match, encoded with model6len model */
+  struct qtm_model model4, model5, model6, model6len;
+
+  /* selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6) */
+  struct qtm_model model7;
+
+  /* symbol arrays for all models */
+  struct qtm_modelsym m0sym[64 + 1];
+  struct qtm_modelsym m1sym[64 + 1];
+  struct qtm_modelsym m2sym[64 + 1];
+  struct qtm_modelsym m3sym[64 + 1];
+  struct qtm_modelsym m4sym[24 + 1];
+  struct qtm_modelsym m5sym[36 + 1];
+  struct qtm_modelsym m6sym[42 + 1], m6lsym[27 + 1];
+  struct qtm_modelsym m7sym[7 + 1];
+
+  /* cabinet related stuff */
+  struct cab_file *file;
+  int (*read)(struct cab_file *, unsigned char *, int);
+
+};
+
+extern struct qtm_stream *qtm_init(int fd,
+				     int ofd,
+				     int window_bits,
+				     int input_buffer_size,
+				     struct cab_file *file,
+				     int (*read)(struct cab_file *, unsigned char *, int));
+
+extern int qtm_decompress(struct qtm_stream *qtm, off_t out_bytes);
+
+void qtm_free(struct qtm_stream *qtm);
+
+/***************************************************************************
+ *			 LZX decompression definitions                     *
+ ***************************************************************************/
+
+/* some constants defined by the LZX specification */
+#define LZX_MIN_MATCH                (2)
+#define LZX_MAX_MATCH                (257)
+#define LZX_NUM_CHARS                (256)
+#define LZX_BLOCKTYPE_INVALID        (0)   /* also blocktypes 4-7 invalid */
+#define LZX_BLOCKTYPE_VERBATIM       (1)
+#define LZX_BLOCKTYPE_ALIGNED        (2)
+#define LZX_BLOCKTYPE_UNCOMPRESSED   (3)
+#define LZX_PRETREE_NUM_ELEMENTS     (20)
+#define LZX_ALIGNED_NUM_ELEMENTS     (8)   /* aligned offset tree #elements */
+#define LZX_NUM_PRIMARY_LENGTHS      (7)   /* this one missing from spec! */
+#define LZX_NUM_SECONDARY_LENGTHS    (249) /* length tree #elements */
+
+/* LZX huffman defines: tweak tablebits as desired */
+#define LZX_PRETREE_MAXSYMBOLS  (LZX_PRETREE_NUM_ELEMENTS)
+#define LZX_PRETREE_TABLEBITS   (6)
+#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
+#define LZX_MAINTREE_TABLEBITS  (12)
+#define LZX_LENGTH_MAXSYMBOLS   (LZX_NUM_SECONDARY_LENGTHS+1)
+#define LZX_LENGTH_TABLEBITS    (12)
+#define LZX_ALIGNED_MAXSYMBOLS  (LZX_ALIGNED_NUM_ELEMENTS)
+#define LZX_ALIGNED_TABLEBITS   (7)
+#define LZX_LENTABLE_SAFETY (64)  /* table decoding overruns are allowed */
+
+#define LZX_FRAME_SIZE (32768) /* the size of a frame in LZX */
+
+struct lzx_stream {
+  int fd;			  /* input file descriptor                   */
+  int ofd;			  /* output file descriptor                  */
+  unsigned char wflag;		  /* write flag */
+
+  off_t   offset;                 /* number of bytes actually output         */
+  off_t   length;                 /* overall decompressed length of stream   */
+
+  unsigned char *window;          /* decoding window                         */
+  unsigned int   window_size;     /* window size                             */
+  unsigned int   window_posn;     /* decompression offset within window      */
+  unsigned int   frame_posn;      /* current frame offset within in window   */
+  unsigned int   frame;           /* the number of 32kb frames processed     */
+  unsigned int   reset_interval;  /* which frame do we reset the compressor? */
+
+  unsigned int   R0, R1, R2;      /* for the LRU offset system               */
+  unsigned int   block_length;    /* uncompressed length of this LZX block   */
+  unsigned int   block_remaining; /* uncompressed bytes still left to decode */
+
+  signed int     intel_filesize;  /* magic header value used for transform   */
+  signed int     intel_curpos;    /* current offset in transform space       */
+
+  unsigned char  intel_started;   /* has intel E8 decoding started?          */
+  unsigned char  block_type;      /* type of the current block               */
+  unsigned char  header_read;     /* have we started decoding at all yet?    */
+  unsigned char  posn_slots;      /* how many posn slots in stream?          */
+  unsigned char  input_end;       /* have we reached the end of input?       */
+
+  int error;
+
+  /* I/O buffering */
+  unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
+  unsigned int  bit_buffer, bits_left, inbuf_size;
+
+  /* huffman code lengths */
+  unsigned char PRETREE_len  [LZX_PRETREE_MAXSYMBOLS  + LZX_LENTABLE_SAFETY];
+  unsigned char MAINTREE_len [LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
+  unsigned char LENGTH_len   [LZX_LENGTH_MAXSYMBOLS   + LZX_LENTABLE_SAFETY];
+  unsigned char ALIGNED_len  [LZX_ALIGNED_MAXSYMBOLS  + LZX_LENTABLE_SAFETY];
+
+  /* huffman decoding tables */
+  unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
+				(LZX_PRETREE_MAXSYMBOLS * 2)];
+  unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
+				(LZX_MAINTREE_MAXSYMBOLS * 2)];
+  unsigned short LENGTH_table  [(1 << LZX_LENGTH_TABLEBITS) +
+				(LZX_LENGTH_MAXSYMBOLS * 2)];
+  unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
+				(LZX_ALIGNED_MAXSYMBOLS * 2)];
+
+  unsigned int  position_base[51];
+  unsigned char extra_bits[51];
+
+  /* this is used purely for doing the intel E8 transform */
+  unsigned char  e8_buf[LZX_FRAME_SIZE];
+
+  /* cabinet related stuff */
+  struct cab_file *file;
+  int (*read)(struct cab_file *, unsigned char *, int);
+};
+
+struct lzx_stream *lzx_init(int fd,
+			      int ofd,
+			      int window_bits,
+			      int reset_interval,
+			      int input_buffer_size,
+			      off_t output_length,
+			      struct cab_file *file,
+			      int (*read)(struct cab_file *, unsigned char *, int));
+
+extern void lzx_set_output_length(struct lzx_stream *lzx,
+				   off_t output_length);
+
+extern int lzx_decompress(struct lzx_stream *lzx, off_t out_bytes);
+
+void lzx_free(struct lzx_stream *lzx);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/network.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/network.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/network.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/network.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __NETWORK_H
+#define __NETWORK_H
+
+#ifdef	HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef	C_WINDOWS
+#include <netdb.h>
+#endif
+
+int r_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,264 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library.                   ---*/
+/*---                                               bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.4 of 20 December 2006
+   Copyright (C) 1996-2006 Julian Seward <jseward at bzip.org>
+   This file was modified for ClamAV by aCaB <acab at clamav.net>
+
+   This program is released under the terms of the license contained
+   in the file COPYING.nsis.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _NSIS_BZLIB_H
+#define _NSIS_BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BZ_RUN               0
+#define BZ_FLUSH             1
+#define BZ_FINISH            2
+
+#define BZ_OK                0
+#define BZ_RUN_OK            1
+#define BZ_FLUSH_OK          2
+#define BZ_FINISH_OK         3
+#define BZ_STREAM_END        4
+#define BZ_SEQUENCE_ERROR    (-1)
+#define BZ_PARAM_ERROR       (-2)
+#define BZ_MEM_ERROR         (-3)
+#define BZ_DATA_ERROR        (-4)
+#define BZ_DATA_ERROR_MAGIC  (-5)
+#define BZ_IO_ERROR          (-6)
+#define BZ_UNEXPECTED_EOF    (-7)
+#define BZ_OUTBUFF_FULL      (-8)
+#define BZ_CONFIG_ERROR      (-9)
+
+typedef 
+   struct {
+      unsigned char *next_in;
+      unsigned int avail_in;
+      unsigned int total_in_lo32;
+      unsigned int total_in_hi32;
+
+      unsigned char *next_out;
+      unsigned int avail_out;
+      unsigned int total_out_lo32;
+      unsigned int total_out_hi32;
+
+      void *state;
+
+      void *(*bzalloc)(void *,int,int);
+      void (*bzfree)(void *,void *);
+      void *opaque;
+   } 
+   nsis_bzstream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include <stdio.h>
+#endif
+
+
+#define BZ_API(func) func
+#define BZ_EXTERN extern
+
+
+/*-- Core (low-level) library functions --*/
+/* aCaB
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( 
+      nsis_bzstream* strm, 
+      int        blockSize100k, 
+      int        verbosity, 
+      int        workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) ( 
+      nsis_bzstream* strm, 
+      int action 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( 
+      nsis_bzstream* strm 
+   );
+*/
+BZ_EXTERN int BZ_API(nsis_BZ2_bzDecompressInit) ( 
+      nsis_bzstream *strm, 
+      int       verbosity, 
+      int       small
+   );
+
+BZ_EXTERN int BZ_API(nsis_BZ2_bzDecompress) ( 
+      nsis_bzstream* strm 
+   );
+
+BZ_EXTERN int BZ_API(nsis_BZ2_bzDecompressEnd) ( 
+      nsis_bzstream *strm 
+   );
+
+
+
+/*-- High(er) level library functions --*/
+/* aCaB
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( 
+      int*  bzerror,   
+      FILE* f, 
+      int   verbosity, 
+      int   small,
+      void* unused,    
+      int   nUnused 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( 
+      int*    bzerror, 
+      BZFILE* b 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void**  unused,  
+      int*    nUnused 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( 
+      int*  bzerror,      
+      FILE* f, 
+      int   blockSize100k, 
+      int   verbosity, 
+      int   workFactor 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in, 
+      unsigned int* nbytes_out 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in_lo32, 
+      unsigned int* nbytes_in_hi32, 
+      unsigned int* nbytes_out_lo32, 
+      unsigned int* nbytes_out_hi32
+   );
+#endif
+*/
+/*-- Utility functions --*/
+/* aCaB
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           blockSize100k, 
+      int           verbosity, 
+      int           workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           small, 
+      int           verbosity 
+   );
+*/
+
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo at rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+/* aCaB
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+      void
+   );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+      const char *path,
+      const char *mode
+   );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+      int        fd,
+      const char *mode
+   );
+         
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+      BZFILE* b, 
+      void* buf, 
+      int len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+      BZFILE* b
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+      BZFILE* b
+   );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+      BZFILE *b, 
+      int    *errnum
+   );
+#endif
+*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.h ---*/
+/*-------------------------------------------------------------*/

Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,58 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in COPYING.nsis.
+ */
+
+/* @(#) $Id: ZCONF.H,v 1.3 2007/01/13 17:28:23 kichik Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+
+#define MAX_MEM_LEVEL 9
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+#define OF(args)  args
+
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte  FAR Bytef;
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+typedef void FAR *voidpf;
+typedef void     *voidp;
+
+#ifndef z_off_t
+#  define  z_off_t long
+#endif
+
+
+#endif /* _ZCONF_H */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,220 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.3, July 9th, 1998
+
+  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup at gzip.org          madler at alumni.caltech.edu
+
+
+*/
+
+#ifndef _NSIS_ZLIB_H
+#define _NSIS_ZLIB_H
+
+#include "nsis_zconf.h"
+#include "nsis_zutil.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+
+
+typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      CODES_START,    /* x: set up for LEN */
+      CODES_LEN,      /* i: get length/literal/eob next */
+      CODES_LENEXT,   /* i: getting length extra (have base) */
+      CODES_DIST,     /* i: get distance next */
+      CODES_DISTEXT,  /* i: getting distance extra */
+      CODES_COPY,     /* o: copying bytes in window, waiting for space */
+      CODES_LIT,      /* o: got literal, waiting for output space */
+      CODES_WASH,     /* o: got eob, possibly still output waiting */
+      /* CODES_END,      x: got eob and all data flushed */
+      /* CODES_BADCODE,  x: got error */
+
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONE,     /* finished last block, done */
+      NZ_BAD       /* got a data error--stuck here */
+} inflate_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  /* inflate_mode mode;      current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+  } word;
+  unsigned short base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+#define MANY 1440
+
+typedef struct inflate_codes_state inflate_codes_statef;
+
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_mode  mode;    /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf t_blens[258+31+31];             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_codes_statef t_codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+
+  uInt last;            /* DRY if this block is the last block, TYPE otherwise */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  inflate_huft hufts[MANY];  /* single malloc for tree space */
+  Bytef window[1 << MAX_WBITS];        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  uLong check;          /* check on output */
+
+};
+
+typedef struct nsis_z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+
+    /* char     *msg;      last error message, NULL if no error */
+    /* struct internal_state FAR *state; not visible by applications */
+    struct inflate_blocks_state blocks;
+
+} nsis_z_stream;
+
+typedef nsis_z_stream FAR *nsis_z_streamp;
+
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+
+/* EXEHEAD doesn't need a specific return code, just < 0 */
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+
+#define nsis_inflateInit(x) inflateReset(x)
+int ZEXPORT nsis_inflate(nsis_z_streamp z);
+#define inflateReset(z) \
+{ \
+  (z)->blocks.mode = TYPE; \
+  (z)->blocks.bitk = (z)->blocks.bitb = 0; \
+  (z)->blocks.read = (z)->blocks.write = (z)->blocks.window; \
+  (z)->blocks.end = (z)->blocks.window + (1 << DEF_WBITS); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,74 @@
+/*
+ * This file is a part of the zlib compression module for NSIS.
+ * 
+ * Copyright and license information can be found below.
+ * Modifications Copyright (C) 1999-2007 Nullsoft and Contributors
+ * 
+ * The original zlib source code is available at
+ * http://www.zlib.net/
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty.
+ */
+
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in COPYING.nsis.
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: ZUTIL.H,v 1.6 2007/01/25 18:07:40 kichik Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "nsis_zlib.h"
+
+#ifndef local
+#  define local static
+#endif
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+
+#define zmemcpy memcpy
+
+#define Assert(cond,msg)
+#define Trace(x)
+#define Tracev(x)
+#define Tracevv(x)
+#define Tracec(c,x)
+#define Tracecv(c,x)
+
+#define ZALLOC(strm, items, size) malloc((items)*(size))
+#define ZFREE(strm, addr)  { if (addr) free(addr); }
+#define TRY_FREE(s, p) { ZFREE(s, p); }
+#define ERR_RETURN(strm,err) return (err)
+
+#endif /* _Z_UTIL_H */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (C) 2007 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __NSIS_H
+#define __NSIS_H
+
+#include "others.h"
+int cli_scannulsft(int desc, cli_ctx *ctx, off_t offset);
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,31 @@
+/*
+ *  Extract component parts of OLE2 files (e.g. MS Office Documents)
+ *
+ *  Copyright (C) 2004 trog at uncon.org
+ *
+ *  This code is based on the OpenOffice and libgsf sources.
+ *                  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __OLE2_EXTRACT_H
+#define __OLE2_EXTRACT_H
+
+#include "clamav.h"
+
+int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/options.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/options.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/options.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/options.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __OPTIONS_H
+#define __OPTIONS_H
+
+#define _GNU_SOURCE
+#include "getopt.h"
+
+struct optnode {
+    char optshort;
+    char *optlong;
+    char *optarg;
+    struct optnode *next;
+};
+
+struct optstruct {
+    struct optnode *optlist;
+    char *filename;
+};
+
+void opt_free(struct optstruct *opt);
+
+struct optstruct *opt_parse(int argc, char * const *argv, const char *getopt_short, const struct option *options_long, const char * const *accepted_long);
+
+int opt_check(const struct optstruct *opt, const char *optlong);
+
+char *opt_arg(const struct optstruct *opt, const char *optlong);
+
+char *opt_firstarg(const struct optstruct *opt, const char *optlong, const struct optnode **optnode);
+
+char *opt_nextarg(const struct optnode **optnode, const char *optlong);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/others.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/others.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/others.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/others.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,227 @@
+/*
+ *  Copyright (C) 1999 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __OTHERS_H_LC
+#define __OTHERS_H_LC
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "cltypes.h"
+
+#include "clamav.h"
+#include "dconf.h"
+
+extern uint8_t cli_debug_flag, cli_leavetemps_flag;
+
+/*
+ * CLI_ISCONTAINED(buf1, size1, buf2, size2) checks if buf2 is contained
+ * within buf1.
+ *
+ * buf1 and buf2 are pointers (or offsets) for the main buffer and the
+ * sub-buffer respectively, and size1/2 are their sizes
+ *
+ * The macro can be used to protect against wraps.
+ */
+#define CLI_ISCONTAINED(bb, bb_size, sb, sb_size)	\
+    (bb_size > 0 && sb_size > 0 && sb_size <= bb_size	\
+     && sb >= bb && sb + sb_size <= bb + bb_size && sb + sb_size > bb)
+
+#define CLI_ISCONTAINED2(bb, bb_size, sb, sb_size)	\
+    (bb_size > 0 && sb_size >= 0 && sb_size <= bb_size	\
+     && sb >= bb && sb + sb_size <= bb + bb_size && sb + sb_size >= bb)
+
+#define CLI_MAX_ALLOCATION 184549376
+
+#ifdef	HAVE_SYS_PARAM_H
+#include <sys/param.h>	/* for NAME_MAX */
+#endif
+
+/* Maximum filenames under various systems - njh */
+#ifndef	NAME_MAX	/* e.g. Linux */
+# ifdef	MAXNAMELEN	/* e.g. Solaris */
+#   define	NAME_MAX	MAXNAMELEN
+# else
+#   ifdef	FILENAME_MAX	/* e.g. SCO */
+#     define	NAME_MAX	FILENAME_MAX
+#   else
+#     define    NAME_MAX        256
+#   endif
+# endif
+#endif
+
+#if NAME_MAX < 256
+#undef NAME_MAX
+#define NAME_MAX 256
+#endif
+
+/* internal clamav context */
+typedef struct {
+    const char **virname;
+    unsigned long int *scanned;
+    const struct cli_matcher *root;
+    const struct cl_engine *engine;
+    const struct cl_limits *limits;
+    unsigned int options;
+    unsigned int arec;
+    unsigned int mrec;
+    unsigned int found_possibly_unwanted;
+    struct cli_dconf *dconf;
+} cli_ctx;
+
+#define SCAN_ARCHIVE	    (ctx->options & CL_SCAN_ARCHIVE)
+#define SCAN_MAIL	    (ctx->options & CL_SCAN_MAIL)
+#define SCAN_OLE2	    (ctx->options & CL_SCAN_OLE2)
+#define SCAN_PDF	    (ctx->options & CL_SCAN_PDF)
+#define SCAN_HTML	    (ctx->options & CL_SCAN_HTML)
+#define SCAN_PE		    (ctx->options & CL_SCAN_PE)
+#define SCAN_ELF	    (ctx->options & CL_SCAN_ELF)
+#define SCAN_ALGO 	    (ctx->options & CL_SCAN_ALGORITHMIC)
+#define DETECT_ENCRYPTED    (ctx->options & CL_SCAN_BLOCKENCRYPTED)
+#define BLOCKMAX	    (ctx->options & CL_SCAN_BLOCKMAX)
+#define DETECT_BROKEN	    (ctx->options & CL_SCAN_BLOCKBROKEN)
+
+#if WORDS_BIGENDIAN == 0
+/* new macros from A. Melnikoff */
+#define le16_to_host(v)	(v)
+#define le32_to_host(v)	(v)
+#define le64_to_host(v)	(v)
+#define	be16_to_host(v)	((v >> 8) | ((v & 0xFF) << 8))
+#define	be32_to_host(v)	((v >> 24) | ((v & 0x00FF0000) >> 8) | \
+				((v & 0x0000FF00) << 8) | (v << 24))
+#define be64_to_host(v)	((v >> 56) | ((v & 0x00FF000000000000LL) >> 40) | \
+				((v & 0x0000FF0000000000LL) >> 24) | \
+				((v & 0x000000FF00000000LL) >> 8) |  \
+				((v & 0x00000000FF000000LL) << 8) |  \
+				((v & 0x0000000000FF0000LL) << 24) | \
+				((v & 0x000000000000FF00LL) << 40) | \
+				(v << 56))
+#else
+#define	le16_to_host(v)	((v >> 8) | ((v & 0xFF) << 8))
+#define	le32_to_host(v)	((v >> 24) | ((v & 0x00FF0000) >> 8) | \
+				((v & 0x0000FF00) << 8) | (v << 24))
+#define le64_to_host(v)	((v >> 56) | ((v & 0x00FF000000000000LL) >> 40) | \
+				((v & 0x0000FF0000000000LL) >> 24) | \
+				((v & 0x000000FF00000000LL) >> 8) |  \
+				((v & 0x00000000FF000000LL) << 8) |  \
+				((v & 0x0000000000FF0000LL) << 24) | \
+				((v & 0x000000000000FF00LL) << 40) | \
+				(v << 56))
+#define be16_to_host(v)	(v)
+#define be32_to_host(v)	(v)
+#define be64_to_host(v)	(v)
+#endif
+
+/* used by: spin, yc (C) aCaB */
+#define CLI_ROL(a,b) a = ( a << (b % (sizeof(a)<<3) ))  |  (a >> (  (sizeof(a)<<3)  -  (b % (sizeof(a)<<3 )) ) )
+#define CLI_ROR(a,b) a = ( a >> (b % (sizeof(a)<<3) ))  |  (a << (  (sizeof(a)<<3)  -  (b % (sizeof(a)<<3 )) ) )
+
+/* Implementation independent sign-extended signed right shift */
+#ifdef HAVE_SAR
+#define CLI_SRS(n,s) ((n)>>(s))
+#else
+#define CLI_SRS(n,s) (((n)>>(s)) ^ (1<<(sizeof(n)*8-1-s)) - (1<<(sizeof(n)*8-1-s)))
+#endif
+#define CLI_SAR(n,s) n = CLI_SRS(n,s)
+
+#ifndef	FALSE
+#define FALSE (0)
+#endif
+
+#ifndef	TRUE
+#define TRUE (1)
+#endif
+
+#ifndef MIN
+#define MIN(a, b)	(((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b)	(((a) > (b)) ? (a) : (b))
+#endif
+
+typedef struct bitset_tag
+{
+        unsigned char *bitset;
+        unsigned long length;
+} bitset_t;
+
+#ifdef __GNUC__
+void cli_warnmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void cli_warnmsg(const char *str, ...);
+#endif
+
+#ifdef __GNUC__
+void cli_errmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void cli_errmsg(const char *str, ...);
+#endif
+
+#ifdef __GNUC__
+void cli_dbgmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void cli_dbgmsg(const char *str, ...);
+#endif
+
+void *cli_malloc(size_t nmemb);
+void *cli_calloc(size_t nmemb, size_t size);
+void *cli_realloc(void *ptr, size_t size);
+void *cli_realloc2(void *ptr, size_t size);
+char *cli_strdup(const char *s);
+int cli_rmdirs(const char *dirname);
+unsigned char *cli_md5digest(int desc);
+char *cli_md5stream(FILE *fs, unsigned char *digcpy);
+char *cli_md5file(const char *filename);
+int cli_readn(int fd, void *buff, unsigned int count);
+int cli_writen(int fd, const void *buff, unsigned int count);
+char *cli_gentemp(const char *dir);
+int cli_gentempfd(const char *dir, char **name, int *fd);
+unsigned int cli_rndnum(unsigned int max);
+int cli_filecopy(const char *src, const char *dest);
+bitset_t *cli_bitset_init(void);
+void cli_bitset_free(bitset_t *bs);
+int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
+int cli_bitset_test(bitset_t *bs, unsigned long bit_offset);
+
+#if WORDS_BIGENDIAN == 0
+#define cli_readint32(buff) (*(const int32_t *)(buff))
+#define cli_writeint32(offset, value) (*(uint32_t *)(offset)=(uint32_t)(value))
+#else
+static inline int32_t cli_readint32(const char *buff)
+{
+	int32_t ret;
+    ret = buff[0] & 0xff;
+    ret |= (buff[1] & 0xff) << 8;
+    ret |= (buff[2] & 0xff) << 16;
+    ret |= (buff[3] & 0xff) << 24;
+    return ret;
+}
+
+static inline void cli_writeint32(char *offset, uint32_t value)
+{
+    offset[0] = value & 0xff;
+    offset[1] = (value & 0xff00) >> 8;
+    offset[2] = (value & 0xff0000) >> 16;
+    offset[3] = (value & 0xff000000) >> 24;
+}
+#endif /* WORDS_BIGENDIAN == 0 */
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/output.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/output.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/output.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/output.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __OUTPUT_H
+#define __OUTPUT_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include "cfgparser.h"
+
+int mdprintf(int desc, const char *str, ...);
+
+#ifdef __GNUC__
+int logg(const char *str, ...)      __attribute__((format(printf, 1, 2)));
+#else
+int logg(const char *str, ...);
+#endif
+
+void logg_close(void);
+extern short int logg_verbose, logg_lock, logg_time;
+extern unsigned int logg_size;
+extern const char *logg_file;
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+extern short logg_syslog;
+int logg_facility(const char *name);
+#endif
+
+#ifdef __GNUC__
+void mprintf(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void mprintf(const char *str, ...);
+#endif
+
+extern short int mprintf_disabled, mprintf_verbose, mprintf_quiet, mprintf_stdout;
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,33 @@
+/*
+ *  Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __PACKLIBS_H
+#define __PACKLIBS_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+#include "rebuildpe.h"
+
+int cli_unfsg(char *, char *, int, int, char **, char **);
+
+int unmew(char *, char *, int, int, char **, char **);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,25 @@
+/*
+ *  Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __PDF_H
+#define __PDF_H
+
+int cli_pdf(const char *dir, int desc, const cli_ctx *ctx);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/pe.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/pe.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/pe.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/pe.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,137 @@
+/*
+ *  Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  Implementation (header structures) based on the PE format description
+ *  by B. Luevelsmeyer
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __PE_H
+#define __PE_H
+
+#include "clamav.h"
+#include "execs.h"
+#include "others.h"
+#include "cltypes.h"
+
+struct pe_image_file_hdr {
+    uint32_t Magic;
+    uint16_t Machine;
+    uint16_t NumberOfSections;
+    uint32_t TimeDateStamp;		    /* unreliable */
+    uint32_t PointerToSymbolTable;	    /* debug */
+    uint32_t NumberOfSymbols;		    /* debug */
+    uint16_t SizeOfOptionalHeader;	    /* == 224 */
+    uint16_t Characteristics;
+};
+
+struct pe_image_data_dir {
+    uint32_t VirtualAddress;
+    uint32_t Size;
+};
+
+struct pe_image_optional_hdr32 {
+    uint16_t Magic;
+    uint8_t  MajorLinkerVersion;		    /* unreliable */
+    uint8_t  MinorLinkerVersion;		    /* unreliable */
+    uint32_t SizeOfCode;			    /* unreliable */
+    uint32_t SizeOfInitializedData;		    /* unreliable */
+    uint32_t SizeOfUninitializedData;		    /* unreliable */
+    uint32_t AddressOfEntryPoint;
+    uint32_t BaseOfCode;
+    uint32_t BaseOfData;
+    uint32_t ImageBase;				    /* multiple of 64 KB */
+    uint32_t SectionAlignment;			    /* usually 32 or 4096 */
+    uint32_t FileAlignment;			    /* usually 32 or 512 */
+    uint16_t MajorOperatingSystemVersion;	    /* not used */
+    uint16_t MinorOperatingSystemVersion;	    /* not used */
+    uint16_t MajorImageVersion;			    /* unreliable */
+    uint16_t MinorImageVersion;			    /* unreliable */
+    uint16_t MajorSubsystemVersion;
+    uint16_t MinorSubsystemVersion;
+    uint32_t Win32VersionValue;			    /* ? */
+    uint32_t SizeOfImage;
+    uint32_t SizeOfHeaders;
+    uint32_t CheckSum;				    /* NT drivers only */
+    uint16_t Subsystem;
+    uint16_t DllCharacteristics;
+    uint32_t SizeOfStackReserve;
+    uint32_t SizeOfStackCommit;
+    uint32_t SizeOfHeapReserve;
+    uint32_t SizeOfHeapCommit;
+    uint32_t LoaderFlags;			    /* ? */
+    uint32_t NumberOfRvaAndSizes;		    /* unreliable */
+    struct pe_image_data_dir DataDirectory[16];
+};
+
+struct pe_image_optional_hdr64 {
+    uint16_t Magic;
+    uint8_t  MajorLinkerVersion;		    /* unreliable */
+    uint8_t  MinorLinkerVersion;		    /* unreliable */
+    uint32_t SizeOfCode;			    /* unreliable */
+    uint32_t SizeOfInitializedData;		    /* unreliable */
+    uint32_t SizeOfUninitializedData;		    /* unreliable */
+    uint32_t AddressOfEntryPoint;
+    uint32_t BaseOfCode;
+    uint64_t ImageBase;				    /* multiple of 64 KB */
+    uint32_t SectionAlignment;			    /* usually 32 or 4096 */
+    uint32_t FileAlignment;			    /* usually 32 or 512 */
+    uint16_t MajorOperatingSystemVersion;	    /* not used */
+    uint16_t MinorOperatingSystemVersion;	    /* not used */
+    uint16_t MajorImageVersion;			    /* unreliable */
+    uint16_t MinorImageVersion;			    /* unreliable */
+    uint16_t MajorSubsystemVersion;
+    uint16_t MinorSubsystemVersion;
+    uint32_t Win32VersionValue;			    /* ? */
+    uint32_t SizeOfImage;
+    uint32_t SizeOfHeaders;
+    uint32_t CheckSum;				    /* NT drivers only */
+    uint16_t Subsystem;
+    uint16_t DllCharacteristics;
+    uint64_t SizeOfStackReserve;
+    uint64_t SizeOfStackCommit;
+    uint64_t SizeOfHeapReserve;
+    uint64_t SizeOfHeapCommit;
+    uint32_t LoaderFlags;			    /* ? */
+    uint32_t NumberOfRvaAndSizes;		    /* unreliable */
+    struct pe_image_data_dir DataDirectory[16];
+};
+
+struct pe_image_section_hdr {
+    uint8_t Name[8];			    /* may not end with NULL */
+    /*
+    union {
+	uint32_t PhysicalAddress;
+	uint32_t VirtualSize;
+    } AddrSize;
+    */
+    uint32_t VirtualSize;
+    uint32_t VirtualAddress;
+    uint32_t SizeOfRawData;		    /* multiple of FileAlignment */
+    uint32_t PointerToRawData;		    /* offset to the section's data */
+    uint32_t PointerToRelocations;	    /* object files only */
+    uint32_t PointerToLinenumbers;	    /* object files only */
+    uint16_t NumberOfRelocations;	    /* object files only */
+    uint16_t NumberOfLinenumbers;	    /* object files only */
+    uint32_t Characteristics;
+};
+
+int cli_scanpe(int desc, cli_ctx *ctx);
+
+int cli_peheader(int desc, struct cli_exe_info *peinfo);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/petite.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/petite.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/petite.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/petite.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __PETITE_H
+#define __PETITE_H
+
+#include "cltypes.h"
+#include "pe.h"
+
+int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct cli_exe_section *sections, unsigned int sectcount, uint32_t Imagebase, uint32_t pep, int desc, int version, uint32_t ResRva, uint32_t ResSize);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,34 @@
+/*
+ *  Phishing module: domain list implementation.
+ *
+ *  Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef _PHISH_DOMAINCHECK_DB_H
+#define _PHISH_DOMAINCHECK_DB_H
+#include "clamav.h"
+
+int init_domainlist(struct cl_engine* engine);
+void domainlist_done(struct cl_engine* engine);
+void domainlist_cleanup(const struct cl_engine* engine);
+int is_domainlist_ok(const struct cl_engine* engine);
+int domainlist_match(const struct cl_engine* engine,char* real_url,const char* display_url,const struct pre_fixup_info* pre_fixup, int hostOnly,unsigned short* flags);
+
+#endif
+

Added: test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,35 @@
+/*
+ *  Phishing module: whitelist implementation.
+ *
+ *  Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef _PHISH_WHITELIST_H
+#define _PHISH_WHITELIST_H
+
+#include "clamav.h"
+
+int init_whitelist(struct cl_engine* engine);
+void whitelist_done(struct cl_engine* engine);
+void whitelist_cleanup(const struct cl_engine* engine);
+int is_whitelist_ok(const struct cl_engine* engine);
+int whitelist_match(const struct cl_engine* engine, char* real_url,const char* display_url,int hostOnly);
+
+#endif
+

Added: test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+
+#ifndef _PHISH_CHECK_H
+#define _PHISH_CHECK_H
+
+#include "regex.h"
+
+#define CL_PHISH_BASE 100
+enum phish_status {CL_PHISH_NODECISION=0,CL_PHISH_CLEAN=CL_PHISH_BASE, CL_PHISH_CLEANUP_OK,CL_PHISH_HOST_OK, CL_PHISH_DOMAIN_OK,
+	CL_PHISH_HOST_NOT_LISTED,
+	CL_PHISH_REDIR_OK, CL_PHISH_HOST_REDIR_OK, CL_PHISH_DOMAIN_REDIR_OK,
+	CL_PHISH_HOST_REVERSE_OK,CL_PHISH_DOMAIN_REVERSE_OK,
+	CL_PHISH_WHITELISTED,CL_PHISH_HOST_WHITELISTED,
+	CL_PHISH_CLEAN_CID,
+	CL_PHISH_TEXTURL, CL_PHISH_MAILTO_OK,
+	CL_PHISH_CLOAKED_UIU, CL_PHISH_NUMERIC_IP,CL_PHISH_HEX_URL,CL_PHISH_CLOAKED_NULL,CL_PHISH_SSL_SPOOF, CL_PHISH_NOMATCH};
+
+#define HOST_SUFFICIENT   1
+#define DOMAIN_SUFFICIENT (HOST_SUFFICIENT | 2)
+#define DO_REVERSE_LOOKUP 4
+#define CHECK_REDIR       8
+#define CHECK_SSL         16
+#define CHECK_CLOAKING    32
+#define CLEANUP_URL       64
+#define CHECK_DOMAIN_REVERSE 128
+#define CHECK_IMG_URL        256
+#define DOMAINLIST_REQUIRED  512
+/* img checking disabled by default */
+
+#define LINKTYPE_IMAGE     1
+
+#define CL_PHISH_ALL_CHECKS (CLEANUP_URL|DOMAIN_SUFFICIENT|CHECK_SSL|CHECK_CLOAKING|CHECK_IMG_URL)
+
+struct string {
+	int refcount;
+	struct string* ref;
+	char* data;
+};
+
+struct phishcheck {
+	regex_t preg;
+	regex_t preg_realurl;
+	regex_t preg_tld;
+	regex_t preg_cctld;
+	regex_t preg_numeric;
+	regex_t preg_hexurl;
+	int      is_disabled;
+};
+
+struct pre_fixup_info {
+	/* pre_* url before fixup_spaces */
+	struct string pre_displayLink;
+	size_t host_start;
+	size_t host_end;
+};
+
+struct url_check {
+	struct string realLink;
+	struct string displayLink;
+	struct pre_fixup_info pre_fixup;
+	unsigned short       flags;
+	unsigned short always_check_flags;
+	unsigned short       link_type;
+};
+
+#ifdef _MESSAGE_H
+int phishingScan(message* m,const char* dir,cli_ctx* ctx,tag_arguments_t* hrefs);
+#endif
+
+void phish_disable(struct cl_engine* engine,const char* reason);
+/* Global, non-thread-safe functions, call only once! */
+int phishing_init(struct cl_engine* engine);
+void phishing_done(struct cl_engine* engine);
+/* end of non-thread-safe functions */
+
+
+#endif
+

Added: test-suite/trunk/MultiSource/Applications/ClamAV/pst.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/pst.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/pst.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/pst.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * Based on libpst version 0.5.1, written by Dave Smith, dave.s at earthcorp.com
+ *	http://alioth.debian.org/projects/libpst/
+ */
+
+#ifndef __PST_H
+#define __PST_H
+
+int	cli_pst(const char *dir, int desc);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __READDB_H
+#define __READDB_H
+
+#include "clamav.h"
+#include "matcher.h"
+
+int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, unsigned short type, const char *offset, unsigned short target);
+
+int cli_initengine(struct cl_engine **engine, unsigned int options);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __REBUILDPE_H
+#define __REBUILDPE_H
+
+#include "cltypes.h"
+#include "execs.h"
+
+int cli_rebuildpe(char *, struct cli_exe_section *, int, uint32_t, uint32_t, uint32_t, uint32_t, int);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/regex.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/regex.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/regex.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/regex.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,102 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992 Henry Spencer.
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regex.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _REGEX_H_
+#define	_REGEX_H_
+
+#include <sys/types.h>
+
+/* types */
+typedef off_t regoff_t;
+
+typedef struct {
+	int re_magic;
+	size_t re_nsub;		/* number of parenthesized subexpressions */
+	const char *re_endp;	/* end pointer for REG_PEND */
+	struct re_guts *re_g;	/* none of your business :-) */
+} regex_t;
+
+typedef struct {
+	regoff_t rm_so;		/* start of match */
+	regoff_t rm_eo;		/* end of match */
+} regmatch_t;
+
+/* cli_regcomp() flags */
+#define	REG_BASIC	0000
+#define	REG_EXTENDED	0001
+#define	REG_ICASE	0002
+#define	REG_NOSUB	0004
+#define	REG_NEWLINE	0010
+#define	REG_NOSPEC	0020
+#define	REG_PEND	0040
+#define	REG_DUMP	0200
+
+/* cli_regerror() flags */
+#define	REG_NOMATCH	 1
+#define	REG_BADPAT	 2
+#define	REG_ECOLLATE	 3
+#define	REG_ECTYPE	 4
+#define	REG_EESCAPE	 5
+#define	REG_ESUBREG	 6
+#define	REG_EBRACK	 7
+#define	REG_EPAREN	 8
+#define	REG_EBRACE	 9
+#define	REG_BADBR	10
+#define	REG_ERANGE	11
+#define	REG_ESPACE	12
+#define	REG_BADRPT	13
+#define	REG_EMPTY	14
+#define	REG_ASSERT	15
+#define	REG_INVARG	16
+#define	REG_ATOI	255	/* convert name to number (!) */
+#define	REG_ITOA	0400	/* convert number to name (!) */
+
+/* cli_regexec() flags */
+#define	REG_NOTBOL	00001
+#define	REG_NOTEOL	00002
+#define	REG_STARTEND	00004
+#define	REG_TRACE	00400	/* tracing of execution */
+#define	REG_LARGE	01000	/* force large representation */
+#define	REG_BACKR	02000	/* force use of backref code */
+
+int	cli_regcomp(regex_t *, const char *, int);
+size_t	cli_regerror(int, const regex_t *, char *, size_t);
+int	cli_regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+void	cli_regfree(regex_t *);
+size_t  cli_strlcpy(char *dst, const char *src, size_t siz);
+
+#endif /* !_REGEX_H_ */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,157 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)regex2.h	8.4 (Berkeley) 3/20/94
+ */
+
+/*
+ * internals of regex_t
+ */
+#define	MAGIC1	((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker.  (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination.  Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ *   OOR1 and OOR2 are respectively the end and the beginning of one of
+ *   the branches.  Note that there is an implicit OOR2 following OCH_
+ *   and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef unsigned long sop;	/* strip operator */
+typedef long sopno;
+#define	OPRMASK	0xf8000000LU
+#define	OPDMASK	0x07ffffffLU
+#define	OPSHIFT	((unsigned)27)
+#define	OP(n)	((n)&OPRMASK)
+#define	OPND(n)	((n)&OPDMASK)
+#define	SOP(op, opnd)	((op)|(opnd))
+/* operators			   meaning	operand			*/
+/*						(back, fwd are offsets)	*/
+#define	OEND	(1LU<<OPSHIFT)	/* endmarker	-			*/
+#define	OCHAR	(2LU<<OPSHIFT)	/* character	unsigned char		*/
+#define	OBOL	(3LU<<OPSHIFT)	/* left anchor	-			*/
+#define	OEOL	(4LU<<OPSHIFT)	/* right anchor	-			*/
+#define	OANY	(5LU<<OPSHIFT)	/* .		-			*/
+#define	OANYOF	(6LU<<OPSHIFT)	/* [...]	set number		*/
+#define	OBACK_	(7LU<<OPSHIFT)	/* begin \d	paren number		*/
+#define	O_BACK	(8LU<<OPSHIFT)	/* end \d	paren number		*/
+#define	OPLUS_	(9LU<<OPSHIFT)	/* + prefix	fwd to suffix		*/
+#define	O_PLUS	(10LU<<OPSHIFT)	/* + suffix	back to prefix		*/
+#define	OQUEST_	(11LU<<OPSHIFT)	/* ? prefix	fwd to suffix		*/
+#define	O_QUEST	(12LU<<OPSHIFT)	/* ? suffix	back to prefix		*/
+#define	OLPAREN	(13LU<<OPSHIFT)	/* (		fwd to )		*/
+#define	ORPAREN	(14LU<<OPSHIFT)	/* )		back to (		*/
+#define	OCH_	(15LU<<OPSHIFT)	/* begin choice	fwd to OOR2		*/
+#define	OOR1	(16LU<<OPSHIFT)	/* | pt. 1	back to OOR1 or OCH_	*/
+#define	OOR2	(17LU<<OPSHIFT)	/* | pt. 2	fwd to OOR2 or O_CH	*/
+#define	O_CH	(18LU<<OPSHIFT)	/* end choice	back to OOR1		*/
+#define	OBOW	(19LU<<OPSHIFT)	/* begin word	-			*/
+#define	OEOW	(20LU<<OPSHIFT)	/* end word	-			*/
+
+/*
+ * Structure for [] character-set representation.  Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte.  A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements.  As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+typedef struct {
+	uch *ptr;		/* -> uch [csetsize] */
+	uch mask;		/* bit within array */
+	uch hash;		/* hash code */
+	size_t smultis;
+	char *multis;		/* -> char[smulti]  ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define	CHadd(cs, c)	((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define	CHsub(cs, c)	((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define	CHIN(cs, c)	((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define	MCadd(p, cs, cp)	mcadd(p, cs, cp)	/* cli_regcomp() internal fns */
+#define	MCsub(p, cs, cp)	mcsub(p, cs, cp)
+#define	MCin(p, cs, cp)	mcin(p, cs, cp)
+
+/* stuff for character categories */
+typedef unsigned char cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+	int magic;
+#		define	MAGIC2	((('R'^0200)<<8)|'E')
+	sop *strip;		/* malloced area for strip */
+	int csetsize;		/* number of bits in a cset vector */
+	int ncsets;		/* number of csets in use */
+	cset *sets;		/* -> cset [ncsets] */
+	uch *setbits;		/* -> uch[csetsize][ncsets/CHAR_BIT] */
+	int cflags;		/* copy of cli_regcomp() cflags argument */
+	sopno nstates;		/* = number of sops */
+	sopno firststate;	/* the initial OEND (normally 0) */
+	sopno laststate;	/* the final OEND */
+	int iflags;		/* internal flags */
+#		define	USEBOL	01	/* used ^ */
+#		define	USEEOL	02	/* used $ */
+#		define	BAD	04	/* something wrong */
+	int nbol;		/* number of ^ used */
+	int neol;		/* number of $ used */
+	int ncategories;	/* how many character categories */
+	cat_t *categories;	/* ->catspace[-CHAR_MIN] */
+	char *must;		/* match must contain this string */
+	int mlen;		/* length of must */
+	size_t nsub;		/* copy of re_nsub */
+	int backrefs;		/* does it use back references? */
+	sopno nplus;		/* how deep does it nest +s? */
+	/* catspace must be last */
+	cat_t catspace[1];	/* actually [NC] */
+};
+
+/* misc utilities */
+#define	OUT	(CHAR_MAX+1)	/* a non-character value */
+#define	ISWORD(c)	(isalnum(c) || (c) == '_')

Added: test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,63 @@
+/*
+ *  Match a string against a list of patterns/regexes.
+ *
+ *  Copyright (C) 2006 Török Edvin <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef _REGEX_LIST_H
+#define _REGEX_LIST_H
+
+#ifdef NDEBUG
+#define massert(x) (void)(0)
+#else
+/*debug version, massert enabled*/
+
+#define __massert_fail(expr,file,line) (void)cli_errmsg("Assertion failed at %s:%d\n %s\n",file,line,expr)
+
+#define massert(expr) ((void) ((expr) ? (void)0 : (__massert_fail (#expr,__FILE__,__LINE__))))
+#endif
+
+#include "phishcheck.h"
+struct node_stack {
+	struct tree_node** data;
+	size_t capacity;
+	size_t cnt;
+};
+
+struct regex_matcher {
+	struct cli_matcher* root_hosts;
+	struct tree_node* root_regex;
+	struct tree_node* root_regex_hostonly; 
+	size_t root_hosts_cnt;
+	int list_inited;
+	int list_loaded;
+	int list_built;
+	struct node_stack node_stack;
+	struct node_stack node_stack_alt;
+};
+
+int regex_list_match(struct regex_matcher* matcher, char* real_url,const char* display_url,const struct pre_fixup_info* pre_fixup, int hostOnly,const char** info,int is_whitelist);
+int init_regex_list(struct regex_matcher* matcher);
+int load_regex_matcher(struct regex_matcher* matcher,FILE* fd,unsigned int options,int is_whitelist);
+void regex_list_cleanup(struct regex_matcher* matcher);
+void regex_list_done(struct regex_matcher* matcher);
+int is_regex_ok(struct regex_matcher* matcher);
+
+#endif
+

Added: test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (C) 2006 Török Edwin <edwin at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef _RTF_H
+#define _RTF_H
+
+#include "others.h"
+
+int cli_scanrtf(int desc, cli_ctx *ctx);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __SCANNERS_H
+#define __SCANNERS_H
+
+#include "clamav.h"
+#include "others.h"
+
+int cli_magic_scandesc(int desc, cli_ctx *ctx);
+
+int cli_scandir(const char *dirname, cli_ctx *ctx);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,4 @@
+#!/bin/sh
+# usage: find svn -name \*.h -exec sh header_rename.sh {} include/ \;
+FILE=`basename "$1"`
+cp $1 $FILE

Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,46 @@
+#!/bin/sh
+BASEURL=http://svn.clamav.net/svn/clamav-devel/tags/clamav-0.92/
+if test $# != 1; then
+	echo "Usage: $0 <checkout|update|copy>"
+	exit 1
+fi
+if [ $1 = "checkout" ]; then
+	mkdir svn &&
+	echo "Checking out ClamAV from $BASEURL ... to directory svn" &&
+	cd svn && svn co $BASEURL/clamscan $BASEURL/libclamav $BASEURL/shared $BASEURL/test . &&
+	svn cat $BASEURL/COPYING >./COPYING &&
+	cd .. &&
+	echo "Checkout complete" &&
+	sh remove.sh &&
+	echo "done"
+elif [ $1 = "update" ]; then
+	echo "svn up" &&
+	svn up svn/clamscan svn/libclamav svn/shared svn/test &&
+	sh remove.sh &&
+	echo "done"
+elif [ $1 = "getdb" ]; then
+    	wget http://database.clamav.net/main.cvd http://database.clamav.net/daily.cvd -P dbdir/ 
+elif [ $1 = "copy" ]; then
+	echo "Copying&renaming files ..." &&
+# special handling for clamscan/others.h, because we also have a libclamav/others.h
+	mv svn/clamscan/others.h clamscan_others.h &&
+	find svn -name '*.c' -exec sh rename.sh {} . \; &&
+	find svn -name '*.h' -exec sh header_rename.sh {} . \; &&
+	for i in clamscan_*.c; do
+		sed -ie "s/\"others.h\"/\"clamscan_others.h\"/" $i;
+	done &&
+#flatten hierarchy	
+	for i in *.[ch]; do
+		sed -re 's/^(#include *")[^/]+\/([^"]+")/\1\2/g' -i $i;
+	done &&
+	cp svn/COPYING . &&
+	#special case, regexec.c #includes a .c file directly, preserve name 
+	mv libclamav_regex_engine.c engine.c &&
+	sed -re 's/MSGCODE\("LibClamAV debug: "\)/puts\(str\)/g' -i libclamav_others.c &&
+	touch target.h &&
+	mkdir -p inputs &&
+	cp svn/test/* inputs/ 
+	echo "All files copied, you can now safely remove the directory svn" 
+	#    clamscan/ files must include others.h from clamscan/ and not from libclamav unless explicitly specified in #include!	
+fi
+

Propchange: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh

------------------------------------------------------------------------------
    svn:executable = *

Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,15 @@
+#!/bin/sh
+echo "Removing unnecessary files" &&
+	pwd &&
+	rm -rf svn/libclamav/js svn/libclamav/pst.c &&
+	cat >svn/libclamav/pst.c <<EOF
+#include "clamav-config.h"
+#include "clamav.h"
+int
+cli_pst(const char *dir, int desc)
+{
+        cli_warnmsg("PST files not yet supported\n");
+        return CL_EFORMAT;
+}
+EOF
+# pst.c is huge, and is experimental, don't compile it

Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,4 @@
+#!/bin/sh
+#usage: find svn -name *.c -exec sh rename.sh {} . \;
+FILE=`echo "$1" | sed -e 's/svn\///' | sed -e 's/\//_/g'`
+cp $1 $FILE

Added: test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2001 Niels Moller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+ 
+#ifndef __SHA256_H
+#define __SHA256_H
+
+#include "cltypes.h"
+
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_DATA_SIZE 64
+
+/* Digest is kept internally as 8 32-bit words. */
+#define _SHA256_DIGEST_LENGTH 8
+
+typedef struct sha256_ctx
+{
+  uint32_t state[_SHA256_DIGEST_LENGTH];    /* State variables */
+  uint32_t count_low, count_high;           /* 64-bit block count */
+  unsigned char block[SHA256_DATA_SIZE];          /* SHA256 data buffer */
+  uint32_t index;                       /* index into buffer */
+} SHA256_CTX;
+
+void
+sha256_init(struct sha256_ctx *ctx);
+
+void
+sha256_update(struct sha256_ctx *ctx, const unsigned char *data, uint32_t length);
+
+void
+sha256_final(struct sha256_ctx *ctx);
+
+void
+sha256_digest(const struct sha256_ctx *ctx, unsigned char *digest);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1054 @@
+/*
+ *  Copyright (C) 2006 Sensory Networks, Inc.
+ *	      (C) 2007 Tomasz Kojm <tkojm at clamav.net>
+ *	      Written by Tomasz Kojm
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "misc.h"
+#include "output.h"
+#include "cdiff.h"
+#include "sha256.h"
+
+#include "str.h"
+#include "others.h"
+#include "cvd.h"
+
+#include "zlib.h"
+
+#ifdef HAVE_GMP
+#include "dsig.h"
+
+#define PSS_NSTR "14783905874077467090262228516557917570254599638376203532031989214105552847269687489771975792123442185817287694951949800908791527542017115600501303394778618535864845235700041590056318230102449612217458549016089313306591388590790796515819654102320725712300822356348724011232654837503241736177907784198700834440681124727060540035754699658105895050096576226753008596881698828185652424901921668758326578462003247906470982092298106789657211905488986281078346361469524484829559560886227198091995498440676639639830463593211386055065360288422394053998134458623712540683294034953818412458362198117811990006021989844180721010947"
+#define PSS_ESTR "100002053"
+#define PSS_NBITS 2048
+#define PSS_DIGEST_LENGTH 32
+#endif /* HAVE_GMP */
+
+struct cdiff_node {
+    unsigned int lineno;
+    char *str, *str2;
+    struct cdiff_node *next;
+};
+
+struct cdiff_ctx {
+    char *open_db;
+    struct cdiff_node *add_start, *add_last;
+    struct cdiff_node *del_start;
+    struct cdiff_node *xchg_start;
+};
+
+struct cdiff_cmd {
+    const char *name;
+    unsigned short argc;
+    int (*handler)(const char *, struct cdiff_ctx *);
+};
+
+static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_move(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_unlink(const char *cmdstr, struct cdiff_ctx *ctx);
+
+static struct cdiff_cmd commands[] = {
+    /* OPEN db_name */
+    { "OPEN", 1, &cdiff_cmd_open },
+
+    /* ADD newsig */
+    { "ADD", 1, &cdiff_cmd_add },
+
+    /* DEL line_no some_first_bytes */
+    { "DEL", 2, &cdiff_cmd_del },
+
+    /* XCHG line_no some_first_bytes_of_old_line new_line */
+    { "XCHG", 3, &cdiff_cmd_xchg },
+
+    /* CLOSE */
+    { "CLOSE", 0, &cdiff_cmd_close },
+
+    /* MOVE src_db dst_db start_line first_16b end_line first_16b */
+    { "MOVE", 6, &cdiff_cmd_move },
+
+    /* UNLINK db_name */
+    { "UNLINK", 1, &cdiff_cmd_unlink },
+
+    { NULL, 0, NULL }
+};
+
+static void cdiff_ctx_free(struct cdiff_ctx *ctx)
+{
+	struct cdiff_node *pt;
+
+
+    if(ctx->open_db) {
+	free(ctx->open_db);
+	ctx->open_db = NULL;
+    }
+
+    while(ctx->add_start) {
+	free(ctx->add_start->str);
+	pt = ctx->add_start;
+	ctx->add_start = ctx->add_start->next;
+	free(pt);
+    }
+    ctx->add_last = NULL;
+
+    while(ctx->del_start) {
+	free(ctx->del_start->str);
+	pt = ctx->del_start;
+	ctx->del_start = ctx->del_start->next;
+	free(pt);
+    }
+
+    while(ctx->xchg_start) {
+	free(ctx->xchg_start->str);
+	free(ctx->xchg_start->str2);
+	pt = ctx->xchg_start;
+	ctx->xchg_start = ctx->xchg_start->next;
+	free(pt);
+    }
+}
+
+static char *cdiff_token(const char *line, unsigned int token, unsigned int last)
+{
+	unsigned int counter = 0, i, j;
+	char *buffer;
+
+
+    for(i = 0; line[i] && counter != token; i++)
+	if(line[i] == ' ')
+	    counter++;
+
+    if(!line[i])
+	return NULL;
+
+    if(last)
+	return strdup(&line[i]);
+
+    for(j = i; line[j]; j++)
+	if(line[j] == ' ')
+	    break;
+
+    if(i == j)
+	return NULL;
+
+    buffer = malloc(j - i + 1);
+    if(!buffer)
+	return NULL;
+
+    strncpy(buffer, line + i, j - i);
+    buffer[j - i] = '\0';
+
+    return buffer;
+}
+
+static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	char *db;
+	unsigned int i;
+
+
+    if(!(db = cdiff_token(cmdstr, 1, 1))) {
+	logg("!cdiff_cmd_open: Can't get first argument\n");
+	return -1;
+    }
+
+    if(ctx->open_db) {
+	logg("!cdiff_cmd_open: %s not closed before opening %s\n", ctx->open_db, db);
+	free(db);
+	return -1;
+    }
+
+    for(i = 0; i < strlen(db); i++) {
+	if((db[i] != '.' && !isalnum(db[i])) || strchr("/\\", db[i])) {
+	    logg("!cdiff_cmd_open: Forbidden characters found in database name\n");
+	    free(db);
+	    return -1;
+	}
+    }
+
+    ctx->open_db = db;
+    return 0;
+}
+
+static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	char *sig;
+	struct cdiff_node *new;
+
+
+    if(!(sig = cdiff_token(cmdstr, 1, 1))) {
+	logg("!cdiff_cmd_add: Can't get first argument\n");
+	return -1;
+    }
+
+    new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
+    if(!new) {
+	logg("!cdiff_cmd_add: Can't allocate memory for cdiff_node\n");
+	free(sig);
+	return -1;
+    }
+    new->str = sig;
+
+    if(!ctx->add_last) {
+	ctx->add_start = ctx->add_last = new;
+    } else { 
+	ctx->add_last->next = new;
+	ctx->add_last = new;
+    }
+
+    return 0;
+}
+
+static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	char *arg;
+	struct cdiff_node *pt, *last, *new;
+	unsigned int lineno;
+
+
+    if(!(arg = cdiff_token(cmdstr, 1, 0))) {
+	logg("!cdiff_cmd_del: Can't get first argument\n");
+	return -1;
+    }
+    lineno = (unsigned int) atoi(arg);
+    free(arg);
+
+    if(!(arg = cdiff_token(cmdstr, 2, 1))) {
+	logg("!cdiff_cmd_del: Can't get second argument\n");
+	return -1;
+    }
+
+    new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
+    if(!new) {
+	logg("!cdiff_cmd_del: Can't allocate memory for cdiff_node\n");
+	free(arg);
+	return -1;
+    }
+    new->str = arg;
+    new->lineno = lineno;
+
+    if(!ctx->del_start) {
+
+	ctx->del_start = new;
+
+    } else { 
+
+	if(lineno < ctx->del_start->lineno) {
+	    new->next = ctx->del_start;
+	    ctx->del_start = new;
+
+	} else {
+	    pt = ctx->del_start;
+
+	    while(pt) {
+		last = pt;
+		if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
+		    break;
+
+		pt = pt->next;
+	    }
+
+	    new->next = last->next;
+	    last->next = new;
+	}
+    }
+
+    return 0;
+}
+
+static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	char *arg, *arg2;
+	struct cdiff_node *pt, *last, *new;
+	unsigned int lineno;
+
+
+    if(!(arg = cdiff_token(cmdstr, 1, 0))) {
+	logg("!cdiff_cmd_xchg: Can't get first argument\n");
+	return -1;
+    }
+    lineno = (unsigned int) atoi(arg);
+    free(arg);
+
+    if(!(arg = cdiff_token(cmdstr, 2, 0))) {
+	logg("!cdiff_cmd_xchg: Can't get second argument\n");
+	return -1;
+    }
+
+    if(!(arg2 = cdiff_token(cmdstr, 3, 1))) {
+	free(arg);
+	logg("!cdiff_cmd_xchg: Can't get second argument\n");
+	return -1;
+    }
+
+    new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
+    if(!new) {
+	logg("!cdiff_cmd_xchg: Can't allocate memory for cdiff_node\n");
+	free(arg);
+	free(arg2);
+	return -1;
+    }
+    new->str = arg;
+    new->str2 = arg2;
+    new->lineno = lineno;
+
+    if(!ctx->xchg_start) {
+
+	ctx->xchg_start = new;
+
+    } else { 
+
+	if(lineno < ctx->xchg_start->lineno) {
+	    new->next = ctx->xchg_start;
+	    ctx->xchg_start = new;
+
+	} else {
+	    pt = ctx->xchg_start;
+
+	    while(pt) {
+		last = pt;
+		if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
+		    break;
+
+		pt = pt->next;
+	    }
+
+	    new->next = last->next;
+	    last->next = new;
+	}
+    }
+
+    return 0;
+}
+
+static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	struct cdiff_node *add, *del, *xchg;
+	unsigned int lines = 0;
+	char *tmp, line[1024];
+	FILE *fh, *tmpfh;
+
+
+    if(!ctx->open_db) {
+	logg("!cdiff_cmd_close: No database to close\n");
+	return -1;
+    }
+
+    add = ctx->add_start;
+    del = ctx->del_start;
+    xchg = ctx->xchg_start;
+
+    if(del || xchg) {
+
+	if(!(fh = fopen(ctx->open_db, "r"))) {
+	    logg("!cdiff_cmd_close: Can't open file %s for reading\n", ctx->open_db);
+	    return -1;
+	}
+
+	if(!(tmp = cli_gentemp("."))) {
+	    logg("!cdiff_cmd_close: Can't generate temporary name\n");
+	    fclose(fh);
+	    return -1;
+	}
+
+	if(!(tmpfh = fopen(tmp, "w"))) {
+	    logg("!cdiff_cmd_close: Can't open file %s for writing\n", tmp);
+	    fclose(fh);
+	    free(tmp);
+	    return -1;
+	}
+
+	while(fgets(line, sizeof(line), fh)) {
+	    lines++;
+
+	    if(del && del->lineno == lines) {
+		if(strncmp(line, del->str, strlen(del->str))) {
+		    fclose(fh);
+		    fclose(tmpfh);
+		    unlink(tmp);
+		    free(tmp);
+		    logg("!cdiff_cmd_close: Can't apply DEL at line %d of %s\n", lines, ctx->open_db);
+		    return -1;
+		}
+
+		del = del->next;
+		continue;
+	    }
+
+	    if(xchg && xchg->lineno == lines) {
+		if(strncmp(line, xchg->str, strlen(xchg->str))) {
+		    fclose(fh);
+		    fclose(tmpfh);
+		    unlink(tmp);
+		    free(tmp);
+		    logg("!cdiff_cmd_close: Can't apply XCHG at line %d of %s\n", lines, ctx->open_db);
+		    return -1;
+		}
+
+		if(fputs(xchg->str2, tmpfh) == EOF || fputc('\n', tmpfh) == EOF) {
+		    fclose(fh);
+		    fclose(tmpfh);
+		    unlink(tmp);
+		    logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
+		    free(tmp);
+		    return -1;
+		}
+		xchg = xchg->next;
+		continue;
+	    }
+
+	    if(fputs(line, tmpfh) == EOF) {
+		fclose(fh);
+		fclose(tmpfh);
+		unlink(tmp);
+		logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
+		free(tmp);
+		return -1;
+	    }
+	}
+
+	fclose(fh);
+	fclose(tmpfh);
+
+	if(del || xchg) {
+	    logg("!cdiff_cmd_close: Not all DEL/XCHG have been executed\n");
+	    unlink(tmp);
+	    free(tmp);
+	    return -1;
+	}
+
+	if(unlink(ctx->open_db) == -1) {
+	    logg("!cdiff_cmd_close: Can't unlink %s\n", ctx->open_db);
+	    unlink(tmp);
+	    free(tmp);
+	    return -1;
+	}
+
+	if(rename(tmp, ctx->open_db) == -1) {
+	    logg("!cdiff_cmd_close: Can't rename %s to %s\n", tmp, ctx->open_db);
+	    unlink(tmp);
+	    free(tmp);
+	    return -1;
+	}
+
+	free(tmp);
+    }
+
+    if(add) {
+
+	if(!(fh = fopen(ctx->open_db, "a"))) {
+	    logg("!cdiff_cmd_close: Can't open file %s for appending\n", ctx->open_db);
+	    return -1;
+	}
+
+	while(add) {
+	    if(fputs(add->str, fh) == EOF || fputc('\n', fh) == EOF) {
+		fclose(fh);
+		logg("!cdiff_cmd_close: Can't write to %s\n", ctx->open_db);
+		return -1;
+	    }
+	    add = add->next;
+	}
+
+	fclose(fh);
+    }
+
+    cdiff_ctx_free(ctx);
+
+    return 0;
+}
+
+static int cdiff_cmd_move(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	unsigned int lines = 0, start_line, end_line;
+	char *arg, *srcdb, *dstdb, *tmpdb, line[1024], *start_str, *end_str;
+	FILE *src, *dst, *tmp;
+
+
+    if(ctx->open_db) {
+	logg("!cdiff_cmd_move: Database %s is still open\n", ctx->open_db);
+	return -1;
+    }
+
+    if(!(arg = cdiff_token(cmdstr, 3, 0))) {
+	logg("!cdiff_cmd_move: Can't get third argument\n");
+	return -1;
+    }
+    start_line = atoi(arg);
+    free(arg);
+
+    if(!(arg = cdiff_token(cmdstr, 5, 0))) {
+	logg("!cdiff_cmd_move: Can't get fifth argument\n");
+	return -1;
+    }
+    end_line = atoi(arg);
+    free(arg);
+
+    if(end_line < start_line) {
+	logg("!cdiff_cmd_move: end_line < start_line\n");
+	return -1;
+    }
+
+    if(!(start_str = cdiff_token(cmdstr, 4, 0))) {
+	logg("!cdiff_cmd_move: Can't get fourth argument\n");
+	return -1;
+    }
+
+    if(!(end_str = cdiff_token(cmdstr, 6, 0))) {
+	logg("!cdiff_cmd_move: Can't get sixth argument\n");
+	free(start_str);
+	return -1;
+    }
+
+    if(!(srcdb = cdiff_token(cmdstr, 1, 0))) {
+	logg("!cdiff_cmd_move: Can't get first argument\n");
+	free(start_str);
+	free(end_str);
+	return -1;
+    }
+
+    if(!(src = fopen(srcdb, "r"))) {
+	logg("!cdiff_cmd_move: Can't open %s for reading\n", srcdb);
+	free(start_str);
+	free(end_str);
+	free(srcdb);
+	return -1;
+    }
+
+    if(!(dstdb = cdiff_token(cmdstr, 2, 0))) {
+	logg("!cdiff_cmd_move: Can't get second argument\n");
+	free(start_str);
+	free(end_str);
+	free(srcdb);
+	fclose(src);
+	return -1;
+    }
+
+    if(!(dst = fopen(dstdb, "a"))) {
+	logg("!cdiff_cmd_move: Can't open %s for appending\n", dstdb);
+	free(start_str);
+	free(end_str);
+	free(srcdb);
+	fclose(src);
+	free(dstdb);
+	return -1;
+    }
+
+    if(!(tmpdb = cli_gentemp("."))) {
+	logg("!cdiff_cmd_move: Can't generate temporary name\n");
+	free(start_str);
+	free(end_str);
+	free(srcdb);
+	fclose(src);
+	free(dstdb);
+	fclose(dst);
+	return -1;
+    }
+
+    if(!(tmp = fopen(tmpdb, "w"))) {
+	logg("!cdiff_cmd_move: Can't open file %s for writing\n", tmpdb);
+	free(start_str);
+	free(end_str);
+	free(srcdb);
+	fclose(src);
+	free(dstdb);
+	fclose(dst);
+	free(tmpdb);
+	return -1;
+    }
+
+    while(fgets(line, sizeof(line), src)) {
+	lines++;
+
+	if(lines == start_line) {
+	    if(strncmp(line, start_str, strlen(start_str))) {
+		free(start_str);
+		free(end_str);
+		free(srcdb);
+		fclose(src);
+		free(dstdb);
+		fclose(dst);
+		fclose(tmp);
+		unlink(tmpdb);
+		free(tmpdb);
+		logg("!cdiff_cmd_close: Can't apply MOVE due to conflict at line %d\n", lines);
+		return -1;
+	    }
+
+	    do {
+		if(fputs(line, dst) == EOF) {
+		    free(start_str);
+		    free(end_str);
+		    free(srcdb);
+		    fclose(src);
+		    fclose(dst);
+		    fclose(tmp);
+		    unlink(tmpdb);
+		    free(tmpdb);
+		    logg("!cdiff_cmd_move: Can't write to %s\n", dstdb);
+		    free(dstdb);
+		    return -1;
+		}
+	    } while((lines < end_line) && fgets(line, sizeof(line), src) && lines++);
+
+	    fclose(dst);
+	    free(dstdb);
+	    dstdb = NULL;
+	    free(start_str);
+
+	    if(strncmp(line, end_str, strlen(end_str))) {
+		free(end_str);
+		free(srcdb);
+		fclose(src);
+		fclose(tmp);
+		unlink(tmpdb);
+		free(tmpdb);
+		logg("!cdiff_cmd_close: Can't apply MOVE due to conflict at line %d\n", lines);
+		return -1;
+	    }
+
+	    free(end_str);
+	    continue;
+	}
+
+	if(fputs(line, tmp) == EOF) {
+	    free(srcdb);
+	    fclose(src);
+	    fclose(tmp);
+	    unlink(tmpdb);
+	    logg("!cdiff_cmd_move: Can't write to %s\n", tmpdb);
+	    free(tmpdb);
+	    return -1;
+	}
+    }
+
+    fclose(src);
+    fclose(tmp);
+
+    if(dstdb) {
+	fclose(dst);
+	free(start_str);
+	free(end_str);
+	unlink(tmpdb);
+	free(tmpdb);
+	logg("!cdiff_cmd_move: No data was moved from %s to %s\n", srcdb, dstdb);
+	free(srcdb);
+	free(dstdb);
+	return -1;
+    }
+
+    if(unlink(srcdb) == -1) {
+	logg("!cdiff_cmd_move: Can't unlink %s\n", srcdb);
+	free(srcdb);
+	unlink(tmpdb);
+	free(tmpdb);
+	return -1;
+    }
+
+    if(rename(tmpdb, srcdb) == -1) {
+	logg("!cdiff_cmd_move: Can't rename %s to %s\n", tmpdb, srcdb);
+	free(srcdb);
+	unlink(tmpdb);
+	free(tmpdb);
+	return -1;
+    }
+
+    free(srcdb);
+    free(tmpdb);
+
+    return 0;
+}
+
+static int cdiff_cmd_unlink(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	char *db;
+	unsigned int i;
+
+
+    if(ctx->open_db) {
+	logg("!cdiff_cmd_unlink: Database %s is still open\n", ctx->open_db);
+	return -1;
+    }
+
+    if(!(db = cdiff_token(cmdstr, 1, 1))) {
+	logg("!cdiff_cmd_unlink: Can't get first argument\n");
+	return -1;
+    }
+
+    for(i = 0; i < strlen(db); i++) {
+	if((db[i] != '.' && !isalnum(db[i])) || strchr("/\\", db[i])) {
+	    logg("!cdiff_cmd_unlink: Forbidden characters found in database name\n");
+	    free(db);
+	    return -1;
+	}
+    }
+
+    if(unlink(db) == -1) {
+	logg("!cdiff_cmd_unlink: Can't unlink %s\n", db);
+	free(db);
+	return -1;
+    }
+
+    free(db);
+    return 0;
+}
+
+static int cdiff_execute(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+	char *cmd_name, *tmp;
+	int (*cmd_handler)(const char *, struct cdiff_ctx *) = NULL;
+	unsigned int i;
+
+
+    cmd_name = cdiff_token(cmdstr, 0, 0);
+    if(!cmd_name) {
+	logg("!cdiff_apply: Problem parsing line\n");
+	return -1;
+    }
+
+    for(i = 0; commands[i].name; i++) {
+	if(!strcmp(commands[i].name, cmd_name)) {
+	    cmd_handler = commands[i].handler;
+	    break;
+	}
+    }
+
+    if(!cmd_handler) {
+	logg("!cdiff_apply: Unknown command %s\n", cmd_name);
+	free(cmd_name);
+	return -1;
+    }
+
+    if(!(tmp = cdiff_token(cmdstr, commands[i].argc, 1))) {
+	logg("!cdiff_apply: Not enough arguments for %s\n", cmd_name);
+	free(cmd_name);
+	return -1;
+    }
+    free(tmp);
+
+    if(cmd_handler(cmdstr, ctx)) {
+	logg("!cdiff_apply: Can't execute command %s\n", cmd_name);
+	free(cmd_name);
+	return -1;
+    }
+
+    free(cmd_name);
+    return 0;
+}
+
+#ifdef HAVE_GMP
+static void pss_mgf(unsigned char *in, unsigned int inlen, unsigned char *out, unsigned int outlen)
+{
+	SHA256_CTX ctx;
+	unsigned int i, laps;
+	unsigned char cnt[4], digest[PSS_DIGEST_LENGTH];
+
+
+    laps = (outlen + PSS_DIGEST_LENGTH - 1) / PSS_DIGEST_LENGTH;
+
+    for(i = 0; i < laps; i++) {
+	cnt[0] = (unsigned char) 0;
+	cnt[1] = (unsigned char) 0;
+	cnt[2] = (unsigned char) (i / 256);
+	cnt[3] = (unsigned char) i;
+
+	sha256_init(&ctx);
+	sha256_update(&ctx, in, inlen);
+	sha256_update(&ctx, cnt, sizeof(cnt));
+	sha256_final(&ctx);
+	sha256_digest(&ctx, digest);
+
+	if(i != laps - 1)
+	    memcpy(&out[i * PSS_DIGEST_LENGTH], digest, PSS_DIGEST_LENGTH);
+	else
+	    memcpy(&out[i * PSS_DIGEST_LENGTH], digest, outlen - i * PSS_DIGEST_LENGTH);
+    }
+}
+
+static int pss_versig(const unsigned char *sha256, const char *dsig)
+{
+	mpz_t n, e;
+	SHA256_CTX ctx;
+	unsigned char *pt, digest1[PSS_DIGEST_LENGTH], digest2[PSS_DIGEST_LENGTH], *salt;
+	unsigned int plen = PSS_NBITS / 8, hlen, slen, i;
+	unsigned char dblock[PSS_NBITS / 8 - PSS_DIGEST_LENGTH - 1];
+	unsigned char mblock[PSS_NBITS / 8 - PSS_DIGEST_LENGTH - 1];
+	unsigned char fblock[8 + 2 * PSS_DIGEST_LENGTH];
+
+
+    hlen = slen = PSS_DIGEST_LENGTH;
+    mpz_init_set_str(n, PSS_NSTR, 10);
+    mpz_init_set_str(e, PSS_ESTR, 10);
+
+    if(!(pt = cli_decodesig(dsig, plen, e, n))) {
+	mpz_clear(n);
+	mpz_clear(e);
+	return -1;
+    }
+
+    mpz_clear(n);
+    mpz_clear(e);
+
+    if(pt[plen - 1] != 0xbc) {
+	/* cli_dbgmsg("cli_versigpss: Incorrect signature syntax (0xbc)\n"); */
+	free(pt);
+	return -1;
+    }
+
+    memcpy(mblock, pt, plen - hlen - 1);
+    memcpy(digest2, &pt[plen - hlen - 1], hlen);
+    free(pt);
+
+    pss_mgf(digest2, hlen, dblock, plen - hlen - 1);
+
+    for(i = 0; i < plen - hlen - 1; i++)
+	dblock[i] ^= mblock[i];
+
+    dblock[0] &= (0xff >> 1);
+
+    salt = memchr(dblock, 0x01, sizeof(dblock));
+    if(!salt) {
+	/* cli_dbgmsg("cli_versigpss: Can't find salt\n"); */
+	return -1;
+    }
+    salt++;
+
+    if((unsigned int) (dblock + sizeof(dblock) - salt) != slen) {
+	/* cli_dbgmsg("cli_versigpss: Bad salt size\n"); */
+	return -1;
+    }
+
+    memset(fblock, 0, 8);
+    memcpy(&fblock[8], sha256, hlen);
+    memcpy(&fblock[8 + hlen], salt, slen);
+
+    sha256_init(&ctx);
+    sha256_update(&ctx, fblock, sizeof(fblock));
+    sha256_final(&ctx);
+    sha256_digest(&ctx, digest1);
+
+    if(memcmp(digest1, digest2, hlen)) {
+	/* cli_dbgmsg("cli_versigpss: Signature doesn't match.\n"); */
+	return -1;
+    }
+
+    return 0;
+}
+#endif /* HAVE_GMP */
+
+int cdiff_apply(int fd, unsigned short mode)
+{
+	struct cdiff_ctx ctx;
+	FILE *fh;
+	gzFile *gzh;
+	char line[1024], buff[FILEBUFF], *dsig = NULL;
+	unsigned int lines = 0, cmds = 0;
+	unsigned int difflen, diffremain;
+	int end, i, n;
+	struct stat sb;
+	int desc;
+#ifdef HAVE_GMP
+	SHA256_CTX sha256ctx;
+	unsigned char digest[32];
+	int sum, bread;
+#endif
+#define DSIGBUFF 350
+
+    memset(&ctx, 0, sizeof(ctx));
+
+    if((desc = dup(fd)) == -1) {
+	logg("!cdiff_apply: Can't duplicate descriptor %d\n", fd);
+	return -1;
+    }
+
+    if(mode == 1) { /* .cdiff */
+
+	if(lseek(desc, -DSIGBUFF, SEEK_END) == -1) {
+	    logg("!cdiff_apply: lseek(desc, %d, SEEK_END) failed\n", -DSIGBUFF);
+	    close(desc);
+	    return -1;
+	}
+
+	memset(line, 0, sizeof(line));
+	if(read(desc, line, DSIGBUFF) != DSIGBUFF) {
+	    logg("!cdiff_apply: Can't read %d bytes\n", DSIGBUFF);
+	    close(desc);
+	    return -1;
+	}
+
+	for(i = DSIGBUFF - 1; i >= 0; i--) {
+	    if(line[i] == ':') {
+		dsig = &line[i + 1];
+		break;
+	    }
+	}
+
+	if(!dsig) {
+	    logg("!cdiff_apply: No digital signature in cdiff file\n");
+	    close(desc);
+	    return -1;
+	}
+
+	if(fstat(desc, &sb) == -1) {
+	    logg("!cdiff_apply: Can't fstat file\n");
+	    close(desc);
+	    return -1;
+	}
+
+	end = sb.st_size - (DSIGBUFF - i);
+	if(end < 0) {
+	    logg("!cdiff_apply: compressed data end offset < 0\n");
+	    close(desc);
+	    return -1;
+	}
+
+	if(lseek(desc, 0, SEEK_SET) == -1) {
+	    logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
+	    close(desc);
+	    return -1;
+	}
+
+#ifdef HAVE_GMP
+	sha256_init(&sha256ctx);
+	sum = 0;
+	while((bread = read(desc, buff, FILEBUFF)) > 0) {
+	    if(sum + bread >= end) {
+		sha256_update(&sha256ctx, (unsigned char *) buff, end - sum);
+		break;
+	    } else {
+		sha256_update(&sha256ctx, (unsigned char *) buff, bread);
+	    }
+	    sum += bread;
+	}
+	sha256_final(&sha256ctx);
+	sha256_digest(&sha256ctx, digest);
+
+	if(pss_versig(digest, dsig)) {
+	    logg("!cdiff_apply: Incorrect digital signature\n");
+	    close(desc);
+	    return -1;
+	}
+#endif
+
+	if(lseek(desc, 0, SEEK_SET) == -1) {
+	    logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
+	    close(desc);
+	    return -1;
+	}
+
+	i = 0;
+	n = 0;
+	while(n < FILEBUFF - 1 && read(desc, &buff[n], 1) > 0) {
+	    if(buff[n++] == ':')
+		if(++i == 3)
+		    break;
+	}
+	buff[n] = 0;
+
+	if(sscanf(buff, "ClamAV-Diff:%*u:%u:", &difflen) != 1) {
+	    logg("!cdiff_apply: Incorrect file format\n");
+	    close(desc);
+	    return -1;
+	}
+
+	if(!(gzh = gzdopen(desc, "rb"))) {
+	    logg("!cdiff_apply: Can't gzdopen descriptor %d\n", desc);
+	    close(desc);
+	    return -1;
+	}
+
+	diffremain = difflen;
+	while(diffremain) {
+	    unsigned int bufsize = diffremain < sizeof(line) ? diffremain + 1 : sizeof(line);
+
+	    if(!gzgets(gzh, line, bufsize)) {
+		logg("!cdiff_apply: Premature EOF at line %d\n", lines + 1);
+		cdiff_ctx_free(&ctx);
+		gzclose(gzh);
+		return -1;
+	    }
+	    diffremain -= strlen(line);
+	    lines++;
+	    cli_chomp(line);
+
+	    if(line[0] == '#' || !strlen(line))
+		continue;
+
+	    if(cdiff_execute(line, &ctx) == -1) {
+		logg("!cdiff_apply: Error executing command at line %d\n", lines);
+		cdiff_ctx_free(&ctx);
+		gzclose(gzh);
+		return -1;
+	    } else {
+		cmds++;
+	    }
+	}
+	gzclose(gzh);
+
+    } else { /* .script */
+
+	if(!(fh = fdopen(desc, "r"))) {
+	    logg("!cdiff_apply: fdopen() failed for descriptor %d\n", desc);
+	    close(desc);
+	    return -1;
+	}
+
+	while(fgets(line, sizeof(line), fh)) {
+	    lines++;
+	    cli_chomp(line);
+
+	    if(line[0] == '#' || !strlen(line))
+		continue;
+
+	    if(cdiff_execute(line, &ctx) == -1) {
+		logg("!cdiff_apply: Error executing command at line %d\n", lines);
+		cdiff_ctx_free(&ctx);
+		fclose(fh);
+		return -1;
+	    } else {
+		cmds++;
+	    }
+	}
+
+	fclose(fh);
+    }
+
+    if(ctx.open_db) {
+	logg("*cdiff_apply: File %s was not properly closed\n", ctx.open_db);
+	cdiff_ctx_free(&ctx);
+	return -1;
+    }
+
+    logg("*cdiff_apply: Parsed %d lines and executed %d commands\n", lines, cmds);
+    return 0;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,511 @@
+/*
+ *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "cfgparser.h"
+#include "misc.h"
+
+#include "str.h"
+
+struct cfgoption cfg_options[] = {
+    {"LogFile",	OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+    {"LogFileUnlock", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"LogFileMaxSize", OPT_COMPSIZE, 1048576, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"LogTime", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"LogClean", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"LogVerbose", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"LogSyslog", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"LogFacility", OPT_QUOTESTR, -1, "LOG_LOCAL6", 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"PidFile", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"TemporaryDirectory", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+    {"ScanPE", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"ScanELF", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"DetectBrokenExecutables", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"ScanMail", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"MailFollowURLs", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"MailMaxRecursion", OPT_NUM, 64, NULL, 0, OPT_CLAMD},
+    {"PhishingSignatures", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"PhishingScanURLs",OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    /* these are FP prone options, if default isn't used */
+    {"PhishingAlwaysBlockCloak", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"PhishingAlwaysBlockSSLMismatch", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"PhishingRestrictedScan", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    /* end of FP prone options */
+    {"DetectPUA", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"AlgorithmicDetection", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"ScanHTML", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"ScanOLE2", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"ScanPDF", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"ScanArchive", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"ArchiveMaxFileSize", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
+    {"ArchiveMaxRecursion", OPT_NUM, 8, NULL, 0, OPT_CLAMD},
+    {"ArchiveMaxFiles", OPT_NUM, 1000, NULL, 0, OPT_CLAMD},
+    {"ArchiveMaxCompressionRatio", OPT_NUM, 250, NULL, 0, OPT_CLAMD},
+    {"ArchiveLimitMemoryUsage", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"ArchiveBlockMax", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"DatabaseDirectory", OPT_QUOTESTR, -1, DATADIR, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"TCPAddr", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+    {"TCPSocket", OPT_NUM, -1, NULL, 0, OPT_CLAMD},
+    {"LocalSocket", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+    {"MaxConnectionQueueLength", OPT_NUM, 15, NULL, 0, OPT_CLAMD},
+    {"StreamMaxLength", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
+    {"StreamMinPort", OPT_NUM, 1024, NULL, 0, OPT_CLAMD},
+    {"StreamMaxPort", OPT_NUM, 2048, NULL, 0, OPT_CLAMD},
+    {"MaxThreads", OPT_NUM, 10, NULL, 0, OPT_CLAMD},
+    {"ReadTimeout", OPT_NUM, 120, NULL, 0, OPT_CLAMD},
+    {"IdleTimeout", OPT_NUM, 30, NULL, 0, OPT_CLAMD},
+    {"MaxDirectoryRecursion", OPT_NUM, 15, NULL, 0, OPT_CLAMD},
+    {"FollowDirectorySymlinks", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"FollowFileSymlinks", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"ExitOnOOM", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"Foreground", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"Debug", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"LeaveTemporaryFiles", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+    {"FixStaleSocket", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+    {"User", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+    {"AllowSupplementaryGroups", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+    {"SelfCheck", OPT_NUM, 1800, NULL, 0, OPT_CLAMD},
+    {"VirusEvent", OPT_FULLSTR, -1, NULL, 0, OPT_CLAMD},
+    {"ClamukoScanOnAccess", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+    {"ClamukoScanOnOpen", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+    {"ClamukoScanOnClose", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+    {"ClamukoScanOnExec", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+    {"ClamukoIncludePath", OPT_QUOTESTR, -1, NULL, 1, OPT_CLAMD},
+    {"ClamukoExcludePath", OPT_QUOTESTR, -1, NULL, 1, OPT_CLAMD},
+    {"ClamukoMaxFileSize", OPT_COMPSIZE, 5242880, NULL, 0, OPT_CLAMD},
+    {"DatabaseOwner", OPT_QUOTESTR, -1, CLAMAVUSER, 0, OPT_FRESHCLAM},
+    {"Checks", OPT_NUM, 12, NULL, 0, OPT_FRESHCLAM},
+    {"UpdateLogFile", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"DNSDatabaseInfo", OPT_QUOTESTR, -1, "current.cvd.clamav.net", 0, OPT_FRESHCLAM},
+    {"DatabaseMirror", OPT_QUOTESTR, -1, NULL, 1, OPT_FRESHCLAM},
+    {"MaxAttempts", OPT_NUM, 3, NULL, 0, OPT_FRESHCLAM},
+    {"ScriptedUpdates", OPT_BOOL, 1, NULL, 0, OPT_FRESHCLAM},
+    {"HTTPProxyServer", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"HTTPProxyPort", OPT_NUM, -1, NULL, 0, OPT_FRESHCLAM},
+    {"HTTPProxyUsername", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"HTTPProxyPassword", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"HTTPUserAgent", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"NotifyClamd", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"OnUpdateExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"OnErrorExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"OnOutdatedExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"LocalIPAddress", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+    {"ConnectTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM},
+    {"ReceiveTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM},
+
+    {"DevACOnly", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+    {"DevACDepth", OPT_NUM, -1, NULL, 0, OPT_CLAMD},
+
+    {NULL, 0, 0, NULL, 0, 0}
+};
+
+static int regcfg(struct cfgstruct **copt, const char *optname, char *strarg, int numarg, short multiple);
+
+struct cfgstruct *getcfg(const char *cfgfile, int verbose)
+{
+	char buff[LINE_LENGTH], *name, *arg, *c;
+	FILE *fs;
+	int line = 0, i, found, ctype, calc, val;
+	struct cfgstruct *copt = NULL;
+	struct cfgoption *pt;
+
+
+    for(i = 0; ; i++) {
+	pt = &cfg_options[i];
+	if(!pt->name)
+	    break;
+
+	if(regcfg(&copt, pt->name, pt->strarg ? strdup(pt->strarg) : NULL, pt->numarg, pt->multiple) < 0) {
+	    fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+	    freecfg(copt);
+	    return NULL;
+	}
+    }
+
+    if((fs = fopen(cfgfile, "rb")) == NULL) {
+	/* do not print error message here! */
+	freecfg(copt);
+	return NULL;
+    }
+
+    while(fgets(buff, LINE_LENGTH, fs)) {
+	line++;
+
+	if(buff[0] == '#')
+	    continue;
+
+	if(!strncmp("Example", buff, 7)) {
+	    if(verbose)
+		fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile);
+	    fclose(fs);
+	    freecfg(copt);
+	    return NULL;
+	}
+
+	if((name = cli_strtok(buff, 0, " \r\n"))) {
+	    arg = cli_strtok(buff, 1, " \r\n");
+	    found = 0;
+	    for(i = 0; ; i++) {
+		pt = &cfg_options[i];
+		if(pt->name) {
+		    if(!strcmp(name, pt->name)) {
+			found = 1;
+			switch(pt->argtype) {
+			    case OPT_STR:
+			    	/* deprecated.  Use OPT_QUOTESTR instead since it behaves like this, but supports quotes to allow values to contain whitespace */
+				if(!arg) {
+				    if(verbose)
+					fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name);
+				    fclose(fs);
+				    free(name);
+				    freecfg(copt);
+				    return NULL;
+				}
+				if(regcfg(&copt, name, arg, -1, pt->multiple) < 0) {
+				    fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				break;
+			    case OPT_FULLSTR:
+				/* an ugly hack of the above case */
+				if(!arg) {
+				    if(verbose)
+					fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name);
+				    fclose(fs);
+				    free(name);
+				    freecfg(copt);
+				    return NULL;
+				}
+				free(arg);
+				arg = strstr(buff, " ");
+				arg = strdup(++arg);
+				if((arg) && (c = strpbrk(arg, "\n\r")))
+				    *c = '\0';
+				if((!arg) || (regcfg(&copt, name, arg, -1, pt->multiple) < 0)) {
+				    fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				break;
+			    case OPT_QUOTESTR:
+				/* an ugly hack of the above case */
+				if(!arg) {
+				    if(verbose)
+					fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name);
+				    fclose(fs);
+				    free(name);
+				    freecfg(copt);
+				    return NULL;
+				}
+				if((*arg == '\'') || (*arg == '"')) {
+				    free(arg);
+				    c = strstr(buff, " ");
+				    arg = strdup(c+2);
+				    if(arg) {
+					if((c = strchr(arg, c[1])))
+					    *c = '\0';
+					else {
+					    if(verbose)
+						fprintf(stderr, "ERROR: Parse error at line %d: Option %s missing closing quote.\n", line, name);
+					    fclose(fs);
+					    free(name);
+					    free(arg);
+					    freecfg(copt);
+					    return NULL;
+					}
+				    }
+				}
+				if((!arg) || (regcfg(&copt, name, arg, -1, pt->multiple) < 0)) {
+				    fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				break;
+			    case OPT_NUM:
+				if(!arg || !isnumb(arg)) {
+				    if(verbose)
+					fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name);
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				if(regcfg(&copt, name, NULL, atoi(arg), pt->multiple) < 0) {
+				    fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				free(arg);
+				break;
+			    case OPT_COMPSIZE:
+				if(!arg) {
+				    if(verbose)
+					fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name);
+				    fclose(fs);
+				    free(name);
+				    freecfg(copt);
+				    return NULL;
+				}
+				ctype = tolower(arg[strlen(arg) - 1]);
+				if(ctype == 'm' || ctype == 'k') {
+				    char *cpy = (char *) calloc(strlen(arg), 1);
+				    strncpy(cpy, arg, strlen(arg) - 1);
+				    if(!isnumb(cpy)) {
+					if(verbose)
+					    fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
+					fclose(fs);
+					free(name);
+					free(arg);
+					freecfg(copt);
+					return NULL;
+				    }
+				    if(ctype == 'm')
+					calc = atoi(cpy) * 1024 * 1024;
+				    else
+					calc = atoi(cpy) * 1024;
+				    free(cpy);
+				} else {
+				    if(!isnumb(arg)) {
+					if(verbose)
+					    fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
+					fclose(fs);
+					free(name);
+					free(arg);
+					freecfg(copt);
+					return NULL;
+				    }
+				    calc = atoi(arg);
+				}
+				free(arg);
+				if(regcfg(&copt, name, NULL, calc, pt->multiple) < 0) {
+				    fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				break;
+			    case OPT_BOOL:
+
+				if(!arg) {
+				    if(verbose)
+					fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name);
+				    fclose(fs);
+				    free(name);
+				    freecfg(copt);
+				    return NULL;
+				}
+
+				if(!strcasecmp(arg, "yes") || !strcmp(arg, "1") || !strcasecmp(arg, "true")) {
+				    val = 1;
+				} else if(!strcasecmp(arg, "no") || !strcmp(arg, "0") || !strcasecmp(arg, "false")) {
+				    val = 0;
+				} else {
+				    if(verbose)
+					fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name);
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				free(arg);
+				if(regcfg(&copt, name, NULL, val, pt->multiple) < 0) {
+				    fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+				    fclose(fs);
+				    free(name);
+				    free(arg);
+				    freecfg(copt);
+				    return NULL;
+				}
+				break;
+			    default:
+				if(verbose)
+				    fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype);
+				fclose(fs);
+				free(name);
+				free(arg);
+				freecfg(copt);
+				return NULL;
+			}
+		    }
+		} else
+		    break;
+	    }
+
+	    if(!found) {
+		if(verbose)
+		    fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name);
+		free(name);
+		fclose(fs);
+		freecfg(copt);
+		return NULL;
+	    }
+	    free(name);
+	}
+    }
+
+    fclose(fs);
+    return copt;
+}
+
+void freecfg(struct cfgstruct *copt)
+{
+    	struct cfgstruct *handler;
+    	struct cfgstruct *arg;
+
+    while(copt) {
+	arg = copt->nextarg;
+	while(arg) {
+	    if(arg->strarg) {
+		free(arg->optname);
+		free(arg->strarg);
+		handler = arg;
+		arg = arg->nextarg;
+		free(handler);
+	    } else
+		arg = arg->nextarg;
+	}
+	if(copt->optname)
+	    free(copt->optname);
+
+	if(copt->strarg)
+	    free(copt->strarg);
+
+	handler = copt;
+	copt = copt->next;
+	free(handler);
+    }
+    return;
+}
+
+const struct cfgstruct *cfgopt(const struct cfgstruct *copt, const char *optname)
+{
+    while(copt) {
+	if(copt->optname && !strcmp(copt->optname, optname))
+	    return copt;
+
+	copt = copt->next;
+    }
+
+    return NULL;
+}
+
+static struct cfgstruct *cfgopt_i(struct cfgstruct *copt, const char *optname)
+{
+    while(copt) {
+	if(copt->optname && !strcmp(copt->optname, optname))
+	    return copt;
+
+	copt = copt->next;
+    }
+
+    return NULL;
+}
+
+static int regcfg(struct cfgstruct **copt, const char *optname, char *strarg, int numarg, short multiple)
+{
+	struct cfgstruct *newnode, *pt;
+
+
+    newnode = (struct cfgstruct *) malloc(sizeof(struct cfgstruct));
+
+    if(!newnode)
+	return -1;
+
+    newnode->optname = optname ? strdup(optname) : NULL;
+    newnode->nextarg = NULL;
+    newnode->next = NULL;
+    newnode->enabled = 0;
+    newnode->multiple = multiple;
+
+    if(strarg) {
+	newnode->strarg = strarg;
+	newnode->enabled = 1;
+    } else {
+	newnode->strarg = NULL;
+    }
+
+    newnode->numarg = numarg;
+    if(numarg != -1 && numarg != 0)
+	newnode->enabled = 1;
+
+    if((pt = cfgopt_i(*copt, optname))) {
+	if(pt->multiple) {
+
+	    if(pt->enabled) {
+		while(pt->nextarg)
+		    pt = pt->nextarg;
+
+		pt->nextarg = newnode;
+	    } else {
+		if(pt->strarg)
+		    free(pt->strarg);
+		pt->strarg = newnode->strarg;
+		pt->numarg = newnode->numarg;
+		pt->enabled = newnode->enabled;
+		if(newnode->optname)
+		    free(newnode->optname);
+		free(newnode);
+	    }
+	    return 3; /* registered additional argument */
+
+	} else {
+	    if(pt->strarg)
+		free(pt->strarg);
+	    pt->strarg = newnode->strarg;
+	    pt->numarg = newnode->numarg;
+	    pt->enabled = newnode->enabled;
+	    if(newnode->optname)
+		free(newnode->optname);
+	    free(newnode);
+	    return 2;
+	}
+
+    } else {
+	newnode->next = *copt;
+	*copt = newnode;
+	return 1;
+    }
+}
+

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1022 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to drepper at gnu.org
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+   	Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <clamav-config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+# ifndef const
+#  define const
+# endif
+#endif
+
+#include <stdio.h>
+
+#ifndef C_WINDOWS
+int strncmp(const char *s1, const char *s2, size_t n);
+#endif
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+# include <stdlib.h>
+# include <unistd.h>
+#endif	/* GNU C library.  */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.  */
+# if defined HAVE_LIBINTL_H || defined _LIBC
+#  include <libintl.h>
+#  ifndef _
+#   define _(msgid)	gettext (msgid)
+#  endif
+# else
+#  define _(msgid)	(msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+# include <string.h>
+# define my_index	strchr
+#else
+
+# if HAVE_STRING_H
+#  include <string.h>
+# else
+#  include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)						      \
+    {									      \
+      char __tmp = __getopt_nonoption_flags[ch1];			      \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];	      \
+      __getopt_nonoption_flags[ch2] = __tmp;				      \
+    }
+#else	/* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif	/* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#ifdef _LIBC
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+	 presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+	nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+	{
+	  memset (__mempcpy (new_str, __getopt_nonoption_flags,
+			     nonoption_flags_max_len),
+		  '\0', top + 1 - nonoption_flags_max_len);
+	  nonoption_flags_max_len = top + 1;
+	  __getopt_nonoption_flags = new_str;
+	}
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	      SWAP_FLAGS (bottom + i, middle + i);
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+	{
+	  if (__getopt_nonoption_flags == NULL
+	      || __getopt_nonoption_flags[0] == '\0')
+	    nonoption_flags_max_len = -1;
+	  else
+	    {
+	      const char *orig_str = __getopt_nonoption_flags;
+	      int len = nonoption_flags_max_len = strlen (orig_str);
+	      if (nonoption_flags_max_len < argc)
+		nonoption_flags_max_len = argc;
+	      __getopt_nonoption_flags =
+		(char *) malloc (nonoption_flags_max_len);
+	      if (__getopt_nonoption_flags == NULL)
+		nonoption_flags_max_len = -1;
+	      else
+		memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+			'\0', nonoption_flags_max_len - len);
+	    }
+	}
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int print_errors = opterr;
+  if (optstring[0] == ':')
+    print_errors = 0;
+
+  if (argc < 1)
+    return -1;
+
+  optarg = NULL;
+
+  if (optind == 0 || !__getopt_initialized)
+    {
+      if (optind == 0)
+	optind = 1;	/* Don't scan ARGV[0], the program name.  */
+      optstring = _getopt_initialize (argc, argv, optstring);
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		      || (optind < nonoption_flags_len			      \
+			  && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+	 moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+	last_nonopt = optind;
+      if (first_nonopt > optind)
+	first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc && NONOPTION_P)
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return -1;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return -1;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if ((unsigned int) (nameend - nextchar)
+		== (unsigned int) strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else if (long_only
+		     || pfound->has_arg != p->has_arg
+		     || pfound->flag != p->flag
+		     || pfound->val != p->val)
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (print_errors)
+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+		  if (print_errors)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+				 _("%s: option `--%s' doesn't allow an argument\n"),
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+				 _("%s: option `%c%s' doesn't allow an argument\n"),
+				 argv[0], argv[optind - 1][0], pfound->name);
+		    }
+
+		  nextchar += strlen (nextchar);
+
+		  optopt = pfound->val;
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (print_errors)
+		    fprintf (stderr,
+			   _("%s: option `%s' requires an argument\n"),
+			   argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  optopt = pfound->val;
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (print_errors)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (print_errors)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, _("%s: illegal option -- %c\n"),
+		       argv[0], c);
+	    else
+	      fprintf (stderr, _("%s: invalid option -- %c\n"),
+		       argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+	char *nameend;
+	const struct option *p;
+	const struct option *pfound = NULL;
+	int exact = 0;
+	int ambig = 0;
+	int indfound = 0;
+	int option_index;
+
+	/* This is an option that requires an argument.  */
+	if (*nextchar != '\0')
+	  {
+	    optarg = nextchar;
+	    /* If we end this ARGV-element by taking the rest as an arg,
+	       we must advance to the next element now.  */
+	    optind++;
+	  }
+	else if (optind == argc)
+	  {
+	    if (print_errors)
+	      {
+		/* 1003.2 specifies the format of this message.  */
+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+			 argv[0], c);
+	      }
+	    optopt = c;
+	    if (optstring[0] == ':')
+	      c = ':';
+	    else
+	      c = '?';
+	    return c;
+	  }
+	else
+	  /* We already incremented `optind' once;
+	     increment it again when taking next ARGV-elt as argument.  */
+	  optarg = argv[optind++];
+
+	/* optarg is now the argument, see if it's in the
+	   table of longopts.  */
+
+	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+	  /* Do nothing.  */ ;
+
+	/* Test all long options for either exact match
+	   or abbreviated matches.  */
+	for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	  if (!strncmp (p->name, nextchar, nameend - nextchar))
+	    {
+	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+		{
+		  /* Exact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		  exact = 1;
+		  break;
+		}
+	      else if (pfound == NULL)
+		{
+		  /* First nonexact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		}
+	      else
+		/* Second or later nonexact match found.  */
+		ambig = 1;
+	    }
+	if (ambig && !exact)
+	  {
+	    if (print_errors)
+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+		       argv[0], argv[optind]);
+	    nextchar += strlen (nextchar);
+	    optind++;
+	    return '?';
+	  }
+	if (pfound != NULL)
+	  {
+	    option_index = indfound;
+	    if (*nameend)
+	      {
+		/* Don't test has_arg with >, because some C compilers don't
+		   allow it to be used on enums.  */
+		if (pfound->has_arg)
+		  optarg = nameend + 1;
+		else
+		  {
+		    if (print_errors)
+		      fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+			       argv[0], pfound->name);
+
+		    nextchar += strlen (nextchar);
+		    return '?';
+		  }
+	      }
+	    else if (pfound->has_arg == 1)
+	      {
+		if (optind < argc)
+		  optarg = argv[optind++];
+		else
+		  {
+		    if (print_errors)
+		      fprintf (stderr,
+			       _("%s: option `%s' requires an argument\n"),
+			       argv[0], argv[optind - 1]);
+		    nextchar += strlen (nextchar);
+		    return optstring[0] == ':' ? ':' : '?';
+		  }
+	      }
+	    nextchar += strlen (nextchar);
+	    if (longind != NULL)
+	      *longind = option_index;
+	    if (pfound->flag)
+	      {
+		*(pfound->flag) = pfound->val;
+		return 0;
+	      }
+	    return pfound->val;
+	  }
+	  nextchar = NULL;
+	  return 'W';	/* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (print_errors)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr,
+			     _("%s: option requires an argument -- %c\n"),
+			     argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+#endif	/* Not ELIDE_CODE.  */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,293 @@
+/*
+ *  Copyright (C) 2004 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef	C_WINDOWS
+#include <dirent.h>
+#endif
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "cfgparser.h"
+#include "output.h"
+
+#include "clamav.h"
+#include "cvd.h"
+#include "others.h" /* for cli_rmdirs() */
+#include "misc.h"
+
+#ifndef	O_BINARY
+#define	O_BINARY	0
+#endif
+
+#ifdef CL_EXPERIMENTAL
+#define VERSION_EXP	VERSION"-exp"
+#else
+#define VERSION_EXP	VERSION
+#endif
+
+char *freshdbdir(void)
+{
+	struct cl_cvd *d1, *d2;
+	struct cfgstruct *copt;
+	const struct cfgstruct *cpt;
+	struct stat foo;
+	const char *dbdir;
+	char *retdir;
+
+
+    /* try to find fresh directory */
+    dbdir = cl_retdbdir();
+    if((copt = getcfg(CONFDIR"/clamd.conf", 0))) {
+	if((cpt = cfgopt(copt, "DatabaseDirectory"))->enabled || (cpt = cfgopt(copt, "DataDirectory"))->enabled) {
+	    if(strcmp(dbdir, cpt->strarg)) {
+		    char *daily = (char *) malloc(strlen(cpt->strarg) + strlen(dbdir) + 30);
+		sprintf(daily, "%s/daily.cvd", cpt->strarg);
+		if(stat(daily, &foo) == -1)
+		    sprintf(daily, "%s/daily.inc/daily.info", cpt->strarg);
+
+		if((d1 = cl_cvdhead(daily))) {
+		    sprintf(daily, "%s/daily.cvd", dbdir);
+		    if(stat(daily, &foo) == -1)
+			sprintf(daily, "%s/daily.inc/daily.info", dbdir);
+
+		    if((d2 = cl_cvdhead(daily))) {
+			free(daily);
+			if(d1->version > d2->version)
+			    dbdir = cpt->strarg;
+			cl_cvdfree(d2);
+		    } else {
+			free(daily);
+			dbdir = cpt->strarg;
+		    }
+		    cl_cvdfree(d1);
+		} else {
+		    free(daily);
+		}
+	    }
+	}
+    }
+
+    retdir = strdup(dbdir);
+
+    if(copt)
+	freecfg(copt);
+
+    return retdir;
+}
+
+void print_version(void)
+{
+	char *dbdir;
+	char *path;
+	struct cl_cvd *daily;
+	struct stat foo;
+
+
+    dbdir = freshdbdir();
+    if(!(path = malloc(strlen(dbdir) + 30))) {
+	free(dbdir);
+	return;
+    }
+
+    sprintf(path, "%s/daily.cvd", dbdir);
+    if(stat(path, &foo) == -1)
+	sprintf(path, "%s/daily.inc/daily.info", dbdir);
+    free(dbdir);
+
+    if((daily = cl_cvdhead(path))) {
+	    time_t t = (time_t) daily->stime;
+
+	printf("ClamAV "VERSION_EXP"/%d/%s", daily->version, ctime(&t));
+	cl_cvdfree(daily);
+    } else {
+	printf("ClamAV "VERSION_EXP"\n");
+    }
+
+    free(path);
+}
+
+int filecopy(const char *src, const char *dest)
+{
+
+#ifdef C_DARWIN
+	pid_t pid;
+
+    /* On Mac OS X use ditto and copy resource fork, too. */
+    switch(pid = fork()) {
+	case -1:
+	    return -1;
+	case 0:
+	    execl("/usr/bin/ditto", "ditto", "--rsrc", src, dest, NULL);
+	    perror("execl(ditto)");
+	    break;
+	default:
+	    wait(NULL);
+	    return 0;
+    }
+
+    return -1;
+
+#else
+	char buffer[FILEBUFF];
+	int s, d, bytes, ret;
+	struct stat sb;
+
+
+    if((s = open(src, O_RDONLY|O_BINARY)) == -1)
+	return -1;
+
+    if((d = open(dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 0644)) == -1) {
+	close(s);
+	return -1;
+    }
+
+    while((bytes = read(s, buffer, FILEBUFF)) > 0)
+	if(write(d, buffer, bytes) < bytes) {
+	    close(s);
+	    close(d);
+	    return -1;
+	}
+
+    close(s);
+    /* njh at bandsman.co.uk: check result of close for NFS file */
+    ret = close(d);
+
+    stat(src, &sb);
+    chmod(dest, sb.st_mode);
+
+    return ret;
+
+#endif
+
+}
+
+int dircopy(const char *src, const char *dest)
+{
+	DIR *dd;
+	struct dirent *dent;
+	struct stat sb;
+	char spath[512], dpath[512];
+
+
+    if(stat(dest, &sb) == -1) {
+	if(mkdir(dest, 0755)) {
+	    /* mprintf("!dircopy: Can't create temporary directory %s\n", dest); */
+	    return -1;
+	}
+    }
+
+    if((dd = opendir(src)) == NULL) {
+        /* mprintf("!dircopy: Can't open directory %s\n", src); */
+        return -1;
+    }
+
+    while((dent = readdir(dd))) {
+#if   (!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
+	if(dent->d_ino)
+#endif
+	{
+	    if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+		continue;
+
+	    snprintf(spath, sizeof(spath), "%s/%s", src, dent->d_name);
+	    snprintf(dpath, sizeof(dpath), "%s/%s", dest, dent->d_name);
+
+	    if(filecopy(spath, dpath) == -1) {
+		/* mprintf("!dircopy: Can't copy %s to %s\n", spath, dpath); */
+		cli_rmdirs(dest);
+		closedir(dd);
+		return -1;
+	    }
+	}
+    }
+
+    closedir(dd);
+    return 0;
+}
+
+int isnumb(const char *str)
+{
+    while(*str) {
+	if(!isdigit(*str & 0xff))
+	    return 0;
+	str++;
+    }
+
+    return 1;
+}
+
+int cvd_unpack(const char *cvd, const char *destdir)
+{
+	int fd;
+
+
+    if((fd = open(cvd, O_RDONLY|O_BINARY)) == -1)
+	return -1;
+
+    if(lseek(fd, 512, SEEK_SET) == -1) {
+	close(fd);
+	return -1;
+    }
+
+    if(cli_untgz(fd, destdir) == -1) /* cli_untgz() will close fd */
+	return -1;
+
+    return 0;
+}
+
+void daemonize(void)
+{
+#if	defined(C_OS2) || defined(C_WINDOWS)
+	fputs("Background mode is not supported on your operating system\n", stderr);
+    return;
+#else
+	int i;
+
+
+    if((i = open("/dev/null", O_RDWR)) == -1) {
+	for(i = 0; i <= 2; i++)
+	    close(i);
+
+    } else {
+	dup2(i, 0);
+	dup2(i, 1);
+	dup2(i, 2);
+	if(i > 2)
+	    close(i);
+    }
+
+    if(fork())
+	exit(0);
+
+    setsid();
+#endif
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ */
+
+#ifdef	_MSC_VER
+#include <windows.h>
+#include <winsock.h>
+#endif
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef C_WINDOWS
+#include <netdb.h>
+#endif
+
+#ifdef CL_NOTHREADS
+#undef CL_THREAD_SAFE
+#endif
+
+#ifdef  CL_THREAD_SAFE
+#include <pthread.h>
+#endif
+
+#include "network.h"
+
+/*
+ * TODO: gethostbyname_r is non-standard so different operating
+ * systems do it in different ways. Need more examples
+ * Perhaps we could use res_search()?
+ *
+ * Returns 0 for success
+ */
+int r_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len)
+{
+#if	defined(HAVE_GETHOSTBYNAME_R_6)
+	/* e.g. Linux */
+	struct hostent *hp2;
+	int ret = -1;
+
+	if((hostname == NULL) || (hp == NULL))
+		return -1;
+	if(gethostbyname_r(hostname, hp, buf, len, &hp2, &ret) < 0)
+		return ret;
+#elif	defined(HAVE_GETHOSTBYNAME_R_5)
+	/* e.g. BSD, Solaris, Cygwin */
+	int ret = -1;
+
+	if((hostname == NULL) || (hp == NULL))
+		return -1;
+	if(gethostbyname_r(hostname, hp, buf, len, &ret) == NULL)
+		return ret;
+#elif	defined(HAVE_GETHOSTBYNAME_R_3)
+	/* e.g. HP/UX, AIX */
+	if((hostname == NULL) || (hp == NULL))
+		return -1;
+	if(gethostbyname_r(hostname, &hp, (struct hostent_data *)buf) < 0)
+		return h_errno;
+#else
+	/* Single thread the code e.g. VS2005 */
+	struct hostent *hp2;
+#ifdef  CL_THREAD_SAFE
+	static pthread_mutex_t hostent_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+	if((hostname == NULL) || (hp == NULL))
+		return -1;
+#ifdef  CL_THREAD_SAFE
+	pthread_mutex_lock(&hostent_mutex);
+#endif
+	if((hp2 = gethostbyname(hostname)) == NULL) {
+#ifdef  CL_THREAD_SAFE
+		pthread_mutex_unlock(&hostent_mutex);
+#endif
+		return h_errno;
+	}
+	memcpy(hp, hp2, sizeof(struct hostent));
+#ifdef  CL_THREAD_SAFE
+	pthread_mutex_unlock(&hostent_mutex);
+#endif
+
+#endif
+	return 0;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,287 @@
+/*
+ *  Copyright (C) 2001 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define _GNU_SOURCE
+#include "getopt.h"
+
+#include "options.h"
+#include "output.h"
+
+
+static int register_option(struct optstruct *opt, const char *optlong, char optshort, const struct option *options_long, const char * const *accepted_long)
+{
+	struct optnode *newnode;
+	int i, found = 0;
+	const char *longname = NULL;
+
+
+    if(optshort) {
+	for(i = 0; options_long[i].name; i++) {
+	    if(options_long[i].val == optshort) {
+		longname = options_long[i].name;
+		break;
+	    }
+	}
+    } else
+	longname = optlong;
+
+    if(!longname) {
+	mprintf("!register_option: No long option for -%c\n", optshort);
+	return -1;
+    }
+
+    if(accepted_long) {
+	for(i = 0; accepted_long[i]; i++)
+	    if(!strcmp(accepted_long[i], longname))
+		found = 1;
+
+	if(!found) {
+	    if(optshort)
+		mprintf("WARNING: Ignoring option --%s (-%c)\n", longname, optshort);
+	    else
+		mprintf("WARNING: Ignoring option --%s\n", longname);
+
+	    return 0;
+	}
+    }
+
+    newnode = (struct optnode *) malloc(sizeof(struct optnode));
+    if(!newnode) {
+	mprintf("!register_long_option: malloc failed\n");
+	return -1;
+    }
+
+    newnode->optshort = optshort;
+
+    if(optarg) {
+	newnode->optarg = (char *) malloc(strlen(optarg) + 1);
+	if(!newnode->optarg) {
+	    mprintf("!register_long_option: malloc failed\n");
+	    free(newnode);
+	    return -1;
+	}
+	strcpy(newnode->optarg, optarg);
+    } else
+	newnode->optarg = NULL;
+
+    newnode->optlong = (char *) malloc(strlen(longname) + 1);
+    if(!newnode->optlong) {
+	mprintf("ERROR: register_long_option: malloc failed\n");
+	free(newnode->optarg);
+	free(newnode);
+	return -1;
+    }
+    strcpy(newnode->optlong, longname);
+
+    newnode->next = opt->optlist;
+    opt->optlist = newnode;
+    return 0;
+}
+
+void opt_free(struct optstruct *opt)
+{
+	struct optnode *handler, *prev;
+
+    if(!opt)
+	return;
+
+    handler = opt->optlist;
+    while(handler) {
+	if(handler->optarg)
+	    free(handler->optarg);
+	if(handler->optlong)
+	    free(handler->optlong);
+	prev = handler;
+	handler = handler->next;
+	free(prev);
+    }
+
+    if(opt->filename)
+    	free(opt->filename);
+
+    free(opt);
+}
+
+struct optstruct *opt_parse(int argc, char * const *argv, const char *getopt_short, const struct option *options_long, const char * const *accepted_long)
+{
+	int ret, opt_index, i, len;
+	struct optstruct *opt;
+	const char *longname;
+
+
+    opt = (struct optstruct *) calloc(1, sizeof(struct optstruct));
+    if(!opt) {
+	mprintf("!opt_parse: calloc failed\n");
+	return NULL;
+    }
+
+    while(1) {
+	opt_index = 0;
+	ret = getopt_long(argc, argv, getopt_short, options_long, &opt_index);
+
+	if(ret == -1)
+	    break;
+
+	switch(ret) {
+	    case 0:
+		if(register_option(opt, options_long[opt_index].name, 0, options_long, accepted_long) == -1) {
+		    opt_free(opt);
+		    return NULL;
+		}
+		break;
+
+    	    default:
+		if(strchr(getopt_short, ret)) {
+		    if(opt_index)
+			longname = options_long[opt_index].name;
+		    else
+			longname = NULL;
+
+		    if(register_option(opt, longname, ret, options_long, accepted_long) == -1) {
+			opt_free(opt);
+			return NULL;
+		    }
+
+		} else {
+		    mprintf("!Unknown option passed.\n");
+		    opt_free(opt);
+		    return NULL;
+		}
+	}
+    }
+
+    if(optind < argc) {
+        len = 0;
+
+	/* count length of non-option arguments */
+	for(i = optind; i < argc; i++)
+	    len += strlen(argv[i]);
+
+	len += argc - optind - 1;
+	opt->filename = (char *) calloc(len + 64, sizeof(char));
+	if(!opt->filename) {
+	    mprintf("!opt_parse: calloc failed\n");
+	    opt_free(opt);
+	    return NULL;
+	}
+
+        for(i = optind; i < argc; i++) {
+	    strncat(opt->filename, argv[i], strlen(argv[i]));
+	    if(i != argc - 1)
+		strncat(opt->filename, "\t", 1);
+	}
+    }
+
+    return opt;
+}
+
+int opt_check(const struct optstruct *opt, const char *optlong)
+{
+	struct optnode *handler;
+
+    if(!opt) {
+	mprintf("!opt_check: opt == NULL\n");
+	return 0;
+    }
+
+    handler = opt->optlist;
+
+    while(handler) {
+	if(handler->optlong && !strcmp(handler->optlong, optlong))
+	    return 1;
+
+	handler = handler->next;
+    }
+
+    return 0;
+}
+
+char *opt_arg(const struct optstruct *opt, const char *optlong)
+{
+	struct optnode *handler;
+
+    if(!opt) {
+	mprintf("!opt_arg: opt == NULL\n");
+	return 0;
+    }
+
+    handler = opt->optlist;
+
+    while(handler) {
+	if(handler->optlong && !strcmp(handler->optlong, optlong))
+	    return handler->optarg;
+
+	handler = handler->next;
+    }
+
+    return NULL;
+}
+
+char *opt_firstarg(const struct optstruct *opt, const char *optlong, const struct optnode **optnode)
+{
+	const struct optnode *handler;
+
+    if(!opt) {
+	mprintf("!opt_firstarg: opt == NULL\n");
+	return 0;
+    }
+
+    handler = opt->optlist;
+
+    while(handler) {
+	if(handler->optlong && !strcmp(handler->optlong, optlong)) {
+	    *optnode = handler;
+	    return handler->optarg;
+	}
+	handler = handler->next;
+    }
+
+    *optnode = NULL;
+    return NULL;
+}
+
+char *opt_nextarg(const struct optnode **optnode, const char *optlong)
+{
+	struct optnode *handler;
+
+    if(!optnode || !*optnode) {
+	mprintf("!opt_nextarg: *optnode == NULL\n");
+	return 0;
+    }
+
+    handler = (*optnode)->next;
+
+    while(handler) {
+	if(handler->optlong && !strcmp(handler->optlong, optlong)) {
+	    *optnode = handler;
+	    return handler->optarg;
+	}
+	handler = handler->next;
+    }
+
+    *optnode = NULL;
+    return NULL;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,395 @@
+/*
+ *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+#ifdef _MSC_VER
+#include <windows.h>
+#include <winsock.h>
+#endif
+
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef C_WINDOWS
+#include <sys/time.h>
+#include <sys/socket.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+#include <syslog.h>
+#endif
+
+#include "output.h"
+
+#ifdef CL_NOTHREADS
+#undef CL_THREAD_SAFE
+#endif
+
+#ifdef CL_THREAD_SAFE
+#include <pthread.h>
+pthread_mutex_t logg_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#ifdef  C_LINUX
+#include <libintl.h>
+#include <locale.h>
+
+#define gettext_noop(s) s
+#define _(s)    gettext(s)
+#define N_(s)   gettext_noop(s)
+
+#else
+
+#define _(s)    s
+#define N_(s)   s
+
+#endif
+
+FILE *logg_fd = NULL;
+
+short int logg_verbose = 0, logg_lock = 1, logg_time = 0, logg_foreground = 1;
+unsigned int logg_size = 0;
+const char *logg_file = NULL;
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+short logg_syslog;
+#endif
+
+short int mprintf_disabled = 0, mprintf_verbose = 0, mprintf_quiet = 0,
+	  mprintf_stdout = 0;
+
+int mdprintf(int desc, const char *str, ...)
+{
+	va_list args;
+	char buff[512];
+	int bytes;
+
+    va_start(args, str);
+    bytes = vsnprintf(buff, sizeof(buff), str, args);
+    va_end(args);
+
+    if(bytes == -1)
+	return bytes;
+
+    if(bytes >= (int) sizeof(buff))
+	bytes = sizeof(buff) - 1;
+
+    return send(desc, buff, bytes, 0);
+}
+
+void logg_close(void) {
+
+#ifdef CL_THREAD_SAFE
+    pthread_mutex_lock(&logg_mutex);
+#endif
+    if (logg_fd) {
+	fclose(logg_fd);
+	logg_fd = NULL;
+    }
+#ifdef CL_THREAD_SAFE
+    pthread_mutex_unlock(&logg_mutex);
+#endif
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+    if(logg_syslog) {
+    	closelog();
+    }
+#endif
+}
+
+int logg(const char *str, ...)
+{
+	va_list args, argscpy, argsout;
+#ifdef F_WRLCK
+	struct flock fl;
+#endif
+	char *pt, *timestr, vbuff[1025];
+	time_t currtime;
+	struct stat sb;
+	mode_t old_umask;
+
+
+    va_start(args, str);
+    /* va_copy is less portable so we just use va_start once more */
+    va_start(argscpy, str);
+    va_start(argsout, str);
+
+#ifdef CL_THREAD_SAFE
+    pthread_mutex_lock(&logg_mutex);
+#endif
+    if(logg_file) {
+	if(!logg_fd) {
+	    old_umask = umask(0037);
+	    if((logg_fd = fopen(logg_file, "at")) == NULL) {
+		umask(old_umask);
+#ifdef CL_THREAD_SAFE
+		pthread_mutex_unlock(&logg_mutex);
+#endif
+		printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file);
+		return -1;
+	    } else umask(old_umask);
+
+#ifdef F_WRLCK
+	    if(logg_lock) {
+		memset(&fl, 0, sizeof(fl));
+		fl.l_type = F_WRLCK;
+		if(fcntl(fileno(logg_fd), F_SETLK, &fl) == -1) {
+#ifdef CL_THREAD_SAFE
+		    pthread_mutex_unlock(&logg_mutex);
+#endif
+		    return -1;
+		}
+	    }
+#endif
+	}
+
+	if(logg_size) {
+	    if(stat(logg_file, &sb) != -1) {
+		if((unsigned int) sb.st_size > logg_size) {
+		    logg_file = NULL;
+		    fprintf(logg_fd, "Log size = %u, max = %u\n", (unsigned int) sb.st_size, logg_size);
+		    fprintf(logg_fd, "LOGGING DISABLED (Maximal log file size exceeded).\n");
+		    fclose(logg_fd);
+		    logg_fd = NULL;
+		}
+	    }
+	}
+
+	if(logg_fd) {
+            /* Need to avoid logging time for verbose messages when logverbose
+               is not set or we get a bunch of timestamps in the log without
+               newlines... */
+	    if(logg_time && ((*str != '*') || logg_verbose)) {
+		time(&currtime);
+		pt = ctime(&currtime);
+		timestr = calloc(strlen(pt), 1);
+		strncpy(timestr, pt, strlen(pt) - 1);
+		fprintf(logg_fd, "%s -> ", timestr);
+		free(timestr);
+	    }
+
+	    _(str);
+	    if(*str == '!') {
+		fprintf(logg_fd, "ERROR: ");
+		vfprintf(logg_fd, str + 1, args);
+	    } else if(*str == '^') {
+		fprintf(logg_fd, "WARNING: ");
+		vfprintf(logg_fd, str + 1, args);
+	    } else if(*str == '*') {
+		if(logg_verbose)
+		    vfprintf(logg_fd, str + 1, args);
+	    } else if(*str == '#') {
+		vfprintf(logg_fd, str + 1, args);
+	    } else vfprintf(logg_fd, str, args);
+
+
+	    fflush(logg_fd);
+	}
+    }
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+    if(logg_syslog) {
+        _(str);
+	vsnprintf(vbuff, 1024, str, argscpy);
+	vbuff[1024] = 0;
+
+	if(vbuff[0] == '!') {
+	    syslog(LOG_ERR, "%s", vbuff + 1);
+	} else if(vbuff[0] == '^') {
+	    syslog(LOG_WARNING, "%s", vbuff + 1);
+	} else if(vbuff[0] == '*') {
+	    if(logg_verbose) {
+		syslog(LOG_DEBUG, "%s", vbuff + 1);
+	    }
+	} else if(vbuff[0] == '#') {
+	    syslog(LOG_INFO, "%s", vbuff + 1);
+	} else syslog(LOG_INFO, "%s", vbuff);
+
+    }
+#endif
+
+    if(logg_foreground) {
+	_(str);
+        vsnprintf(vbuff, 1024, str, argsout);
+	vbuff[1024] = 0;
+	if(vbuff[0] != '#')
+	    mprintf("%s", vbuff);
+    }
+
+#ifdef CL_THREAD_SAFE
+    pthread_mutex_unlock(&logg_mutex);
+#endif
+
+    va_end(args);
+    va_end(argscpy);
+    va_end(argsout);
+    return 0;
+}
+
+void mprintf(const char *str, ...)
+{
+	va_list args;
+	FILE *fd;
+	char buff[512];
+
+
+    if(mprintf_disabled) 
+	return;
+
+    fd = stdout;
+
+/* legend:
+ * ! - error
+ * @ - error with logging
+ * ...
+ */
+
+/*
+ *             ERROR    WARNING    STANDARD
+ * normal      stderr   stderr     stdout
+ * 
+ * verbose     stderr   stderr     stdout
+ * 
+ * quiet       stderr     no         no
+ */
+
+    va_start(args, str);
+    vsnprintf(buff, sizeof(buff), str, args);
+    va_end(args);
+
+    if(buff[0] == '!') {
+       if(!mprintf_stdout)
+           fd = stderr;
+	fprintf(fd, "ERROR: %s", &buff[1]);
+    } else if(buff[0] == '@') {
+       if(!mprintf_stdout)
+           fd = stderr;
+	fprintf(fd, "ERROR: %s", &buff[1]);
+    } else if(!mprintf_quiet) {
+	if(buff[0] == '^') {
+           if(!mprintf_stdout)
+               fd = stderr;
+	    fprintf(fd, "WARNING: %s", &buff[1]);
+	} else if(buff[0] == '*') {
+	    if(mprintf_verbose)
+		fprintf(fd, "%s", &buff[1]);
+	} else fprintf(fd, "%s", buff);
+    }
+
+    if(fd == stdout)
+	fflush(stdout);
+}
+
+struct facstruct {
+    const char *name;
+    int code;
+};
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+static const struct facstruct facilitymap[] = {
+#ifdef LOG_AUTH
+    { "LOG_AUTH",	LOG_AUTH },
+#endif
+#ifdef LOG_AUTHPRIV
+    { "LOG_AUTHPRIV",	LOG_AUTHPRIV },
+#endif
+#ifdef LOG_CRON
+    { "LOG_CRON",	LOG_CRON },
+#endif
+#ifdef LOG_DAEMON
+    { "LOG_DAEMON",	LOG_DAEMON },
+#endif
+#ifdef LOG_FTP
+    { "LOG_FTP",	LOG_FTP },
+#endif
+#ifdef LOG_KERN
+    { "LOG_KERN",	LOG_KERN },
+#endif
+#ifdef LOG_LPR
+    { "LOG_LPR",	LOG_LPR },
+#endif
+#ifdef LOG_MAIL
+    { "LOG_MAIL",	LOG_MAIL },
+#endif
+#ifdef LOG_NEWS
+    { "LOG_NEWS",	LOG_NEWS },
+#endif
+#ifdef LOG_AUTH
+    { "LOG_AUTH",	LOG_AUTH },
+#endif
+#ifdef LOG_SYSLOG
+    { "LOG_SYSLOG",	LOG_SYSLOG },
+#endif
+#ifdef LOG_USER
+    { "LOG_USER",	LOG_USER },
+#endif
+#ifdef LOG_UUCP
+    { "LOG_UUCP",	LOG_UUCP },
+#endif
+#ifdef LOG_LOCAL0
+    { "LOG_LOCAL0",	LOG_LOCAL0 },
+#endif
+#ifdef LOG_LOCAL1
+    { "LOG_LOCAL1",	LOG_LOCAL1 },
+#endif
+#ifdef LOG_LOCAL2
+    { "LOG_LOCAL2",	LOG_LOCAL2 },
+#endif
+#ifdef LOG_LOCAL3
+    { "LOG_LOCAL3",	LOG_LOCAL3 },
+#endif
+#ifdef LOG_LOCAL4
+    { "LOG_LOCAL4",	LOG_LOCAL4 },
+#endif
+#ifdef LOG_LOCAL5
+    { "LOG_LOCAL5",	LOG_LOCAL5 },
+#endif
+#ifdef LOG_LOCAL6
+    { "LOG_LOCAL6",	LOG_LOCAL6 },
+#endif
+#ifdef LOG_LOCAL7
+    { "LOG_LOCAL7",	LOG_LOCAL7 },
+#endif
+    { NULL,		-1 }
+};
+
+int logg_facility(const char *name)
+{
+	int i;
+
+    for(i = 0; facilitymap[i].name; i++)
+	if(!strcmp(facilitymap[i].name, name))
+	    return facilitymap[i].code;
+
+    return -1;
+}
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2001 Niels Moller
+ *  
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/* Modelled after the sha1.c code by Peter Gutmann. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "sha256.h"
+
+/* A block, treated as a sequence of 32-bit words. */
+#define SHA256_DATA_LENGTH 16
+
+#define ROTR(n,x) ((x)>>(n) | ((x)<<(32-(n))))
+#define SHR(n,x) ((x)>>(n))
+
+#define Choice(x,y,z)   ( (z) ^ ( (x) & ( (y) ^ (z) ) ) )
+#define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
+
+#define S0(x) (ROTR(2,(x)) ^ ROTR(13,(x)) ^ ROTR(22,(x)))
+#define S1(x) (ROTR(6,(x)) ^ ROTR(11,(x)) ^ ROTR(25,(x)))
+
+#define s0(x) (ROTR(7,(x)) ^ ROTR(18,(x)) ^ SHR(3,(x)))
+#define s1(x) (ROTR(17,(x)) ^ ROTR(19,(x)) ^ SHR(10,(x)))
+
+static const uint32_t K[64] = {
+	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+	0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+	0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+	0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+	0xe49b69c1UL, 0xefbe4786UL, 0xfc19dc6UL, 0x240ca1ccUL,
+	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+	0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+	0xc6e00bf3UL, 0xd5a79147UL, 0x6ca6351UL, 0x14292967UL,
+	0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+	0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+	0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+	0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+	0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+	0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
+};
+
+#define EXPAND(W,i) \
+( W[(i) & 15 ] += (s1(W[((i)-2) & 15]) + W[((i)-7) & 15] + s0(W[((i)-15) & 15])) )
+
+#define ROUND(a,b,c,d,e,f,g,h,k,data) do {		\
+  uint32_t T1 = h + S1(e) + Choice(e,f,g) + k + data;	\
+  uint32_t T2 = S0(a) + Majority(a,b,c);		\
+  d += T1;						\
+  h = T1 + T2;						\
+} while (0)
+
+#ifndef EXTRACT_UCHAR
+#define EXTRACT_UCHAR(p)  (*(const unsigned char *)(p))
+#endif
+
+#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8)    \
+			 | EXTRACT_UCHAR(s+1)) << 8)  \
+			 | EXTRACT_UCHAR(s+2)) << 8)  \
+			 | EXTRACT_UCHAR(s+3))
+
+#ifndef EXTRACT_UCHAR
+#define EXTRACT_UCHAR(p)  (*(const mutils_word8 *)(p))
+#endif
+
+#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8)    \
+			 | EXTRACT_UCHAR(s+1)) << 8)  \
+			 | EXTRACT_UCHAR(s+2)) << 8)  \
+			 | EXTRACT_UCHAR(s+3))
+
+/* Initialize the SHA values */
+
+void sha256_init(struct sha256_ctx *ctx)
+{
+	/* Initial values, also generated by the shadata program. */
+	static const uint32_t H0[_SHA256_DIGEST_LENGTH] = {
+		0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL,
+		0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL,
+	};
+
+	memcpy(ctx->state, H0, sizeof(H0));
+
+	/* Initialize bit count */
+	ctx->count_low = ctx->count_high = 0;
+
+	/* Initialize buffer */
+	ctx->index = 0;
+}
+
+/* Perform the SHA transformation.  Note that this code, like MD5, seems to
+   break some optimizing compilers due to the complexity of the expressions
+   and the size of the basic block.  It may be necessary to split it into
+   sections, e.g. based on the four subrounds
+
+   Note that this function destroys the data area */
+
+static void sha256_transform(uint32_t *state, uint32_t *data)
+{
+	uint32_t A, B, C, D, E, F, G, H;	/* Local vars */
+	unsigned char i;
+	const uint32_t *k;
+	uint32_t *d;
+
+	/* Set up first buffer and local data buffer */
+	A = state[0];
+	B = state[1];
+	C = state[2];
+	D = state[3];
+	E = state[4];
+	F = state[5];
+	G = state[6];
+	H = state[7];
+
+	/* Heavy mangling */
+	/* First 16 subrounds that act on the original data */
+
+	for (i = 0, k = K, d = data; i < 16; i += 8, k += 8, d += 8) {
+		ROUND(A, B, C, D, E, F, G, H, k[0], d[0]);
+		ROUND(H, A, B, C, D, E, F, G, k[1], d[1]);
+		ROUND(G, H, A, B, C, D, E, F, k[2], d[2]);
+		ROUND(F, G, H, A, B, C, D, E, k[3], d[3]);
+		ROUND(E, F, G, H, A, B, C, D, k[4], d[4]);
+		ROUND(D, E, F, G, H, A, B, C, k[5], d[5]);
+		ROUND(C, D, E, F, G, H, A, B, k[6], d[6]);
+		ROUND(B, C, D, E, F, G, H, A, k[7], d[7]);
+	}
+
+	for (; i < 64; i += 16, k += 16) {
+		ROUND(A, B, C, D, E, F, G, H, k[0], EXPAND(data, 0));
+		ROUND(H, A, B, C, D, E, F, G, k[1], EXPAND(data, 1));
+		ROUND(G, H, A, B, C, D, E, F, k[2], EXPAND(data, 2));
+		ROUND(F, G, H, A, B, C, D, E, k[3], EXPAND(data, 3));
+		ROUND(E, F, G, H, A, B, C, D, k[4], EXPAND(data, 4));
+		ROUND(D, E, F, G, H, A, B, C, k[5], EXPAND(data, 5));
+		ROUND(C, D, E, F, G, H, A, B, k[6], EXPAND(data, 6));
+		ROUND(B, C, D, E, F, G, H, A, k[7], EXPAND(data, 7));
+		ROUND(A, B, C, D, E, F, G, H, k[8], EXPAND(data, 8));
+		ROUND(H, A, B, C, D, E, F, G, k[9], EXPAND(data, 9));
+		ROUND(G, H, A, B, C, D, E, F, k[10], EXPAND(data, 10));
+		ROUND(F, G, H, A, B, C, D, E, k[11], EXPAND(data, 11));
+		ROUND(E, F, G, H, A, B, C, D, k[12], EXPAND(data, 12));
+		ROUND(D, E, F, G, H, A, B, C, k[13], EXPAND(data, 13));
+		ROUND(C, D, E, F, G, H, A, B, k[14], EXPAND(data, 14));
+		ROUND(B, C, D, E, F, G, H, A, k[15], EXPAND(data, 15));
+	}
+
+	/* Update state */
+	state[0] += A;
+	state[1] += B;
+	state[2] += C;
+	state[3] += D;
+	state[4] += E;
+	state[5] += F;
+	state[6] += G;
+	state[7] += H;
+}
+
+static void sha256_block(struct sha256_ctx *ctx, const unsigned char *block)
+{
+	uint32_t data[SHA256_DATA_LENGTH];
+	uint16_t i;
+
+	/* Update block count */
+	if (!++ctx->count_low)
+		++ctx->count_high;
+
+	/* Endian independent conversion */
+	for (i = 0; i < SHA256_DATA_LENGTH; i++, block += 4)
+		data[i] = STRING2INT(block);
+
+	sha256_transform(ctx->state, data);
+}
+
+void
+sha256_update(struct sha256_ctx *ctx, const unsigned char *buffer, uint32_t length)
+{
+	uint32_t left;
+
+	if (ctx->index) {	/* Try to fill partial block */
+		left = SHA256_DATA_SIZE - ctx->index;
+		if (length < left) {
+			memcpy(ctx->block + ctx->index, buffer, length);
+			ctx->index += length;
+			return;	/* Finished */
+		} else {
+			memcpy(ctx->block + ctx->index, buffer, left);
+			sha256_block(ctx, ctx->block);
+			buffer += left;
+			length -= left;
+		}
+	}
+	while (length >= SHA256_DATA_SIZE) {
+		sha256_block(ctx, buffer);
+		buffer += SHA256_DATA_SIZE;
+		length -= SHA256_DATA_SIZE;
+	}
+	/* Buffer leftovers */
+	/* NOTE: The corresponding sha1 code checks for the special case length == 0.
+	 * That seems supoptimal, as I suspect it increases the number of branches. */
+
+	memcpy(ctx->block, buffer, length);
+	ctx->index = length;
+}
+
+/* Final wrapup - pad to SHA1_DATA_SIZE-byte boundary with the bit pattern
+   1 0* (64-bit count of bits processed, MSB-first) */
+
+void sha256_final(struct sha256_ctx *ctx)
+{
+	uint32_t data[SHA256_DATA_LENGTH];
+	uint32_t i;
+	uint32_t words;
+
+	i = ctx->index;
+
+	/* Set the first char of padding to 0x80.  This is safe since there is
+	   always at least one byte free */
+
+/*  assert(i < SHA256_DATA_SIZE);
+ */
+	ctx->block[i++] = 0x80;
+
+	/* Fill rest of word */
+	for (; i & 3; i++)
+		ctx->block[i] = 0;
+
+	/* i is now a multiple of the word size 4 */
+	words = i >> 2;
+	for (i = 0; i < words; i++)
+		data[i] = STRING2INT(ctx->block + 4 * i);
+
+	if (words > (SHA256_DATA_LENGTH - 2)) {	/* No room for length in this block. Process it and
+						 * pad with another one */
+		for (i = words; i < SHA256_DATA_LENGTH; i++)
+			data[i] = 0;
+		sha256_transform(ctx->state, data);
+		for (i = 0; i < (SHA256_DATA_LENGTH - 2); i++)
+			data[i] = 0;
+	} else
+		for (i = words; i < SHA256_DATA_LENGTH - 2; i++)
+			data[i] = 0;
+
+	/* There are 512 = 2^9 bits in one block */
+	data[SHA256_DATA_LENGTH - 2] =
+	    (ctx->count_high << 9) | (ctx->count_low >> 23);
+	data[SHA256_DATA_LENGTH - 1] =
+	    (ctx->count_low << 9) | (ctx->index << 3);
+	sha256_transform(ctx->state, data);
+}
+
+void sha256_digest(const struct sha256_ctx *ctx, unsigned char *s)
+{
+	uint32_t i;
+
+	if (s!=NULL)
+		for (i = 0; i < _SHA256_DIGEST_LENGTH; i++) {
+			*s++ = ctx->state[i] >> 24;
+			*s++ = 0xff & (ctx->state[i] >> 16);
+			*s++ = 0xff & (ctx->state[i] >> 8);
+			*s++ = 0xff & ctx->state[i];
+		}
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/sis.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/sis.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/sis.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/sis.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (C) 2006 Sensory Networks, Inc.
+ *	      Written by Tomasz Kojm
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __SIS_H
+#define __SIS_H
+
+#include "clamav.h"
+#include "others.h"
+
+struct sis_file_hdr {
+    uint32_t uid1;
+    uint32_t uid2;
+    uint32_t uid3;
+    uint32_t uid4;
+    uint16_t checksum;
+    uint16_t nlangs;
+    uint16_t nfiles;
+    uint16_t nreqs;
+    uint16_t ilang;
+    uint16_t ifiles;
+    uint16_t idrive;
+    uint16_t ncaps;
+    uint32_t iver;
+    uint16_t options;
+    uint16_t type;
+    uint16_t majorver;
+    uint16_t minorver;
+    uint16_t variant;
+    uint32_t plangs;
+    uint32_t pfiles;
+    uint32_t preqs;
+    uint32_t pcerts;
+    uint32_t pname;
+};
+
+struct sis_file_hdr6 {
+    uint32_t psig;
+    uint32_t pcaps;
+    uint32_t ispace;
+    uint32_t maxispace;
+    uint32_t reserved[4];
+};
+
+int cli_scansis(int desc, cli_ctx *ctx);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,16 @@
+#ifndef _SNPRINTF_H
+#define _SNPRINTF_H
+
+#include "clamav-config.h"
+
+#include <sys/types.h> /* For size_t */
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t count, const char *fmt, ...);
+#endif /* !HAVE_SNPRINTF */
+
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+#endif /* !HAVE_SNPRINTF */
+
+#endif /* _SNPRINTF_H */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/special.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/special.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/special.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/special.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2004 trog at uncon.org
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __SPECIAL_H
+#define __SPECIAL_H
+
+int cli_check_mydoom_log(int desc, const char **virname);
+int cli_check_jpeg_exploit(int fd);
+int cli_check_riff_exploit(int fd);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/spin.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/spin.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/spin.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/spin.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __SPIN_H
+#define __SPIN_H
+
+#include "cltypes.h"
+#include "rebuildpe.h"
+
+int unspin(char *, int, struct cli_exe_section *, int, uint32_t, int, cli_ctx *);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/str.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/str.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/str.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/str.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __STR_H
+#define __STR_H
+
+#include <sys/types.h>
+
+#include "cltypes.h"
+
+int cli_strbcasestr(const char *haystack, const char *needle);
+int cli_chomp(char *string);
+char *cli_strtok(const char *line, int field, const char *delim);
+uint16_t *cli_hex2ui(const char *hex);
+char *cli_hex2str(const char *hex);
+int cli_hex2num(const char *hex);
+char *cli_str2hex(const char *string, unsigned int len);
+char *cli_utf16toascii(const char *str, unsigned int length);
+char *cli_strtokbuf(const char *input, int fieldno, const char *delim, char *output);
+const char *cli_memstr(const char *haystack, int hs, const char *needle, int ns);
+char *cli_strrcpy(char *dest, const char *source);
+void cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens);
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2006 Sensory Networks, Inc.
+ *             Written by aCaB <acab at clamav.net>
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __UNSUE_H
+#define __UNSUE_H
+
+#include "cltypes.h"
+#include "execs.h"
+
+char *sudecrypt(int, size_t, struct cli_exe_section *, uint16_t, char *, uint32_t, uint32_t, uint32_t);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/table.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/table.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/table.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/table.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+/*
+ * Hashtable mapping strings to numbers
+ */
+typedef	struct	tableEntry {
+	char	*key;
+	int	value;
+	struct	tableEntry	*next;
+} tableEntry;
+
+typedef struct table {
+	tableEntry	*tableHead;
+	tableEntry	*tableLast;
+	unsigned	int	flags;
+} table_t;
+
+#define	TABLE_HAS_DELETED_ENTRIES	0x1
+
+struct	table	*tableCreate(void);
+void	tableDestroy(table_t *table);
+int	tableInsert(table_t *table, const char *key, int value);
+int	tableUpdate(table_t *table, const char *key, int new_value);
+int	tableFind(const table_t *table, const char *key);
+void	tableRemove(table_t *table, const char *key);
+void	tableIterate(table_t *table, void(*callback)(char *key, int value, void *arg), void *arg);

Added: test-suite/trunk/MultiSource/Applications/ClamAV/target.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/target.h?rev=46573&view=auto

==============================================================================
    (empty)

Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,374 @@
+/*
+ *  Copyright (C) 2007 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * Compare the results of scanning files on a set of machines
+ *	This is useful for regression testing versions, and for testing
+ *	across different operating systems and architectures
+ * The file is always copied which is slow, and could be removed for regression
+ *	testing, if we have some mechanism to sync the data
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <memory.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+
+#define	PORT	3310
+#define	LEN	128
+
+/*
+ * Ensure you don't have StreamMaxLength on any of the servers, or that it's
+ *	big enough for all your samples
+ * Uses SESSIONS, which isn't good
+ * If localhost is one of them, it's probably best to put it last so that it
+ *	can be scanning while waiting for the remote machines to respond
+ */
+static struct machine {
+	const	char	*name;
+	in_addr_t	ip;
+	int	sock;
+} machines[] = {
+	{	"eric",		0,	-1	},
+	/*{	"motorola",	0,	-1	},*/
+	/*{	"ultra60",	0,	-1	},*/
+	{	"mac",		0,	-1	},
+	{	"localhost",	0,	-1	},
+	{	NULL,		0,	-1	}
+};
+
+struct args {
+	const	char	*filename;
+	const	struct	machine	*m;
+	char	*ret;
+};
+
+static	void	dir(const char *dirname);
+static	in_addr_t	resolve(const char *machine);
+static	int	start(in_addr_t ip);
+static	void	*scan(void *v);
+
+int
+main(int argc, char **argv)
+{
+	struct machine *m;
+
+	if(argc <= 1) {
+		fputs("Arg count\n", stderr);
+		return 1;
+	}
+
+	for(m = machines; m->name; m++) {
+		m->ip = resolve(m->name);
+
+		if(m->ip == INADDR_NONE) {
+			fprintf(stderr, "Can't resolve %s\n", m->name);
+			return 1;
+		}
+		m->sock = start(m->ip);
+		if(m->sock < 0)
+			fprintf(stderr, "%s is down\n", m->name);
+	}
+
+	signal(SIGPIPE, SIG_IGN);
+
+	while(*++argv)
+		dir(*argv);
+
+	return 0;
+}
+
+static void
+dir(const char *dirname)
+{
+	int i, nmachines;
+	const struct dirent *dirent;
+	struct machine *m;
+	DIR *d = opendir(dirname);
+	char **results;
+
+	if(d == NULL) {
+		perror(dirname);
+		return;
+	}
+	for(nmachines = 0, m = machines; m->name; m++)
+		if(m->sock >= 0)
+			nmachines++;
+
+	if(nmachines < 2) {
+		fputs("Needs at least 2 machines up to run\n", stderr);
+		closedir(d);
+		return;
+	}
+
+	results = (char **)malloc(nmachines * sizeof(char *));
+	if(results == NULL)
+		return;
+	for(i = 0, m = machines; m->name; m++)
+		if(m->sock >= 0) {
+			results[i] = malloc(LEN);
+			if(results[i++] == NULL) {
+				free(results);
+				closedir(d);
+				return;
+			}
+		}
+
+	if(i != nmachines) {
+		fputs("Failed sanity check\n", stderr);
+		closedir(d);
+		return;
+	}
+
+	while((dirent = readdir(d)) != NULL) {
+		int nthreads, founddiffs;
+		pthread_t *tids;
+		struct args *args;
+		char name[PATH_MAX];
+
+		if(dirent->d_ino == (ino_t)0)
+			continue;
+		if(dirent->d_name[0] == '.')
+			continue;
+
+		tids = malloc(nmachines * sizeof(pthread_t));
+		if(tids == NULL) {
+			free(results);
+			closedir(d);
+			return;
+		}
+		args = malloc(nmachines * sizeof(struct args));
+		if(args == NULL) {
+			free(tids);
+			free(results);
+			closedir(d);
+			return;
+		}
+
+		snprintf(name, sizeof(name) -1, "%s/%s", dirname, dirent->d_name);
+		for(nthreads = 0, m = machines; m->name; m++) {
+			if(m->sock < 0)
+				continue;
+
+			args[nthreads].filename = name;
+			args[nthreads].m = m;
+			args[nthreads].ret = results[nthreads];
+			pthread_create(&tids[nthreads], NULL, scan, &args[nthreads]);
+			nthreads++;
+		}
+		/*printf("Scanning %s\n", name);*/
+		founddiffs = 0;
+		while(--nthreads >= 0)
+			/* TODO: timeout */
+			pthread_join(tids[nthreads], NULL);
+
+		free(args);
+		free(tids);
+		for(i = 0; i <= nmachines - 2; i++) {
+			int j;
+
+			for(j = i + 1; j <= nmachines - 1; j++) {
+				const char *s, *t;
+
+				s = strchr(results[i], ' ');
+				t = strchr(results[j], ' ');
+				if((s == NULL) || (t == NULL) || (strcmp(s, t) != 0)) {
+					printf("%s:\n", name);
+					printf("\t%s: %s\n", machines[i].name, s ? s : "null");
+					printf("\t%s: %s\n", machines[j].name, t ? t : "null");
+					founddiffs = 1;
+				}
+			}
+		}
+
+		/*if(!founddiffs)
+			printf("%s passed\n", name);*/
+	}
+	closedir(d);
+}
+
+static in_addr_t
+resolve(const char *machine)
+{
+	in_addr_t ret = inet_addr(machine);
+
+	if(ret == INADDR_NONE) {
+		const struct hostent *h = gethostbyname(machine);
+
+		if(h == NULL) {
+			fprintf(stderr, "Unknown host %s\n", machine);
+			return INADDR_NONE;
+		}
+
+		memcpy((char *)&ret, h->h_addr, sizeof(in_addr_t));
+	}
+	return ret;
+}
+
+static int
+start(in_addr_t ip)
+{
+	int sock;
+	const struct protoent *proto;
+	struct sockaddr_in server;
+
+	memset((char *)&server, 0, sizeof(struct sockaddr_in));
+	server.sin_family = AF_INET;
+	server.sin_port = (in_port_t)htons(PORT);
+	server.sin_addr.s_addr = ip;
+
+	proto = getprotobyname("tcp");
+	if(proto == NULL) {
+		fputs("Unknown prototol tcp, check /etc/protocols\n", stderr);
+		return -1;
+	} else if((sock = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) {
+		perror("socket");
+		return -1;
+	} else if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
+		perror("connect");
+		close(sock);
+		return -1;
+	} else if(send(sock, "SESSION\n", 8, 0) < 8) {
+		perror("send");
+		close(sock);
+		return -1;
+	}
+	return sock;
+}
+
+static void *
+scan(void *v)
+{
+	struct args *args;
+	FILE *fin;
+	int sock;
+	ssize_t nbytes;
+	size_t buflen;
+	in_port_t port;
+	struct sockaddr_in data;
+	const struct machine *m;
+	char buf[1024];	/* must be less than MTU */
+
+	args = (struct args *)v;
+	m = args->m;
+	if(m->sock < 0)
+		return NULL;
+	if(m->ip == htonl(INADDR_LOOPBACK)) {
+		char cmd[NAME_MAX + 7];
+
+		snprintf(cmd, sizeof(cmd) - 1, "SCAN %s\n", args->filename);
+		buflen = strlen(cmd);
+
+		if(send(m->sock, cmd, buflen, 0) != (ssize_t)buflen) {
+			perror(m->name);
+			return NULL;
+		}
+		nbytes = recv(m->sock, args->ret, LEN, 0);
+		if(nbytes < 0) {
+			perror(m->name);
+			return NULL;
+		}
+		args->ret[nbytes - 1] = '\0';	/* remove the trailing \n */
+
+		return NULL;
+	}
+	fin = fopen(args->filename, "r");
+	if(fin == NULL) {
+		perror(args->filename);
+		return NULL;
+	}
+	if(send(m->sock, "STREAM\n", 7, 0) != 7) {
+		perror(m->name);
+		fclose(fin);
+		return NULL;
+	}
+
+	if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket");
+		fputs("Failed to create TCPSocket to talk to clamd\n", stderr);
+		fclose(fin);
+		return NULL;
+	}
+
+	nbytes = recv(m->sock, buf, sizeof(buf), 0);
+	if(nbytes <= 0) {
+		perror(m->name);
+		close(sock);
+		fclose(fin);
+		return NULL;
+	}
+	buf[nbytes] = '\0';
+
+	if(sscanf(buf, "PORT %hu\n", &port) != 1) {
+		fprintf(stderr, "Expected port information from clamd, got '%s'",
+			buf);
+		close(sock);
+		fclose(fin);
+		return NULL;
+	}
+
+	memset((char *)&data, 0, sizeof(struct sockaddr_in));
+	data.sin_family = AF_INET;
+	data.sin_port = (in_port_t)htons(port);
+	data.sin_addr.s_addr = m->ip;
+
+	if(connect(sock, (struct sockaddr *)&data, sizeof(struct sockaddr_in)) < 0) {
+		perror(m->name);
+		fprintf(stderr, "Couldn't connect to port %d\n", port);
+		close(sock);
+		fclose(fin);
+		return NULL;
+	}
+
+	shutdown(sock, SHUT_RD);
+
+	while((buflen = fread(buf, 1, sizeof(buf), fin)) > 0) {
+		ssize_t sent = send(sock, buf, buflen, 0);
+
+		if(sent != (ssize_t)buflen) {
+			/* Probably hit scanstream len */
+			if(sent < 0)
+				perror(m->name);
+			else
+				fprintf(stderr, "%s: only sent %d bytes of %d to %s\n",
+					args->filename, sent, buflen, m->name);
+			break;
+		}
+	}
+
+	close(sock);
+	fclose(fin);
+
+	/* TODO: timeout */
+	nbytes = recv(m->sock, args->ret, LEN, 0);
+	if(nbytes < 0) {
+		perror(m->name);
+		return NULL;
+	}
+	args->ret[(nbytes) ? (nbytes - 1) : 0] = '\0';	/* remove the trailing \n */
+
+	return NULL;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,313 @@
+/*
+ *  Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * $CC $CFLAGS -I../.. -I../../libclamav debugm.c -lclamav
+ * Now try a.out /sbin/* or a.out /usr/bin/*
+ *
+ * njh at bandsman.co.uk
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <clamav.h>
+#include <sys/resource.h>
+#include <features.h>
+#include <unistd.h>
+#include <memory.h>
+#include <pthread.h>
+#include "clamav-config.h"
+#include "others.h"
+#include "mbox.h"
+#include "pdf.h"
+#include "binhex.h"
+#include "untar.h"
+#include "special.h"
+#include "tnef.h"
+#include "pst.h"
+#include "pe.h"
+
+struct args {
+	cli_ctx	ctx;
+	const	char	*filename;
+};
+
+static void *
+mbox(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cl_mbox(%s) returns %d\n",
+		args->filename, cli_mbox("/tmp/libclamav", fd, &args->ctx));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+pdf(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cl_pdf(%s) returns %d\n",
+		args->filename, cli_pdf("/tmp/libclamav", fd, &args->ctx));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+scandir(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cl_scandir(%s) returns %d\n",
+		args->filename, cli_scandir("/tmp/libclamav", &args->ctx));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+untar(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cl_untar(%s) returns %d\n",
+		args->filename, cli_untar("/tmp/libclamav", fd, 1));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+binhex(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cl_binhex(%s) returns %d\n",
+		args->filename, cli_binhex("/tmp/libclamav", fd));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+jpeg(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cli_check_jpeg_exploit(%s) returns %d\n",
+		args->filename, cli_check_jpeg_exploit(fd));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+tnef(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cli_tnef(%s) returns %d\n",
+		args->filename, cli_tnef("/tmp/libclamav", fd));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+uuencode(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cli_uuencode(%s) returns %d\n",
+		args->filename, cli_uuencode("/tmp/libclamav", fd));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+pst(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cli_pst(%s) returns %d\n",
+		args->filename, cli_pst("/tmp/libclamav", fd));
+	close(fd);
+
+	return NULL;
+}
+
+static void *
+pe(void *v)
+{
+	struct args *args = (struct args *)v;
+	int fd = open(args->filename, O_RDONLY);
+
+	if(fd < 0) {
+		perror(args->filename);
+		return NULL;
+	}
+	printf("cli_scanpe(%s) returns %d\n",
+		args->filename, cli_scanpe(fd, &args->ctx));
+	close(fd);
+
+	return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+	struct rlimit rlim;
+	const char *virname;
+	struct cl_engine engine;
+	struct cl_limits limits;
+	unsigned long scanned;
+	struct args args;
+
+	if(argc == 1) {
+		fprintf(stderr, "Usage: %s files...\n", argv[0]);
+		return 1;
+	}
+	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+	if(setrlimit(RLIMIT_CORE, &rlim) < 0)
+		perror("setrlimit");
+
+	if((mkdir("/tmp/libclamav", 0750) < 0) && (errno != EEXIST)) {
+		perror("/tmp/libclamav");
+		return errno;
+	}
+
+	memset(&args.ctx, '\0', sizeof(cli_ctx));
+	args.ctx.engine = &engine;
+	args.ctx.virname = &virname;
+	args.ctx.limits = &limits;
+	args.ctx.scanned = &scanned;
+	args.ctx.options = 0;
+
+	while(*++argv) {
+		pthread_t t;
+
+		args.filename = *argv;
+
+		if(pthread_create(&t, NULL, mbox, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, pdf, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, untar, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, binhex, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, jpeg, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, tnef, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, uuencode, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, pst, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		if(pthread_create(&t, NULL, pe, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+
+		/* TODO: pass through all in cli_magic_scandesc */
+		if(pthread_create(&t, NULL, scandir, &args) != 0)
+			perror("pthread_create");
+		if(pthread_detach(t) != 0)
+			perror("pthread_detach");
+	}
+	puts("Hit SIGINT when all is finished");
+	pause();
+	puts("Finished - don't forget to rm -rf /tmp/libclamav");
+
+	return 0;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,91 @@
+/*
+ * $CC $CFLAGS -I../.. debugm.c -lclamav -lefence (or what ever memory debugger)
+ * If you're going to use HAVE_BACKTRACE, ensure CFLAGS includes -g and doesn't
+ * include -fomit-frame-pointer
+ *
+ * njh at bandsman.co.uk
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <clamav.h>
+#include <sys/resource.h>
+#include <signal.h>
+#include <features.h>
+#include "clamav-config.h"
+
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
+/*#define HAVE_BACKTRACE	/* Only tested on Linux... */
+#endif
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+static	void	print_trace(void);
+static	void	sigsegv(int sig);
+
+static void
+sigsegv(int sig)
+{
+	signal(SIGSEGV, SIG_DFL);
+	print_trace();
+	_exit(SIGSEGV);
+}
+
+static void
+print_trace(void)
+{
+#ifdef HAVE_BACKTRACE
+	void *array[10];
+	size_t size, i;
+	char **strings;
+
+	puts("Segfault caught, backtrace:");
+
+	size = backtrace(array, 10);
+	strings = backtrace_symbols(array, size);
+
+	for(i = 0; i < size; i++)
+		printf("\t%s\n", strings[i]);
+
+	free(strings);
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+	struct rlimit rlim;
+
+	if(argc == 1) {
+		fprintf(stderr, "Usage: %s files...\n", argv[0]);
+		return 1;
+	}
+	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+	if(setrlimit(RLIMIT_CORE, &rlim) < 0)
+		perror("setrlimit");
+
+	if(mkdir("/tmp/mboxtest", 0750) < 0) {
+		perror("/tmp/mboxtest");
+		return errno;
+	}
+	signal(SIGSEGV, sigsegv);
+	while(*++argv) {
+		int fd = open(*argv, 0);
+
+		if(fd < 0) {
+			perror(*argv);
+			return errno;
+		}
+		printf("cl_mbox(%s) returns %d\n",
+			*argv, cl_mbox("/tmp/mboxtest", fd));
+		close(fd);
+	}
+	puts("Finished - don't forget to rm -rf /tmp/mboxtest");
+
+	return 0;
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,177 @@
+/*
+ * $CC -DHAVE_CONFIG_H $CFLAGS -I../.. debugpe.c -lclamav -lefence (or what
+ * ever memory debugger)
+ * If you're going to use HAVE_BACKTRACE, ensure CFLAGS includes -g and doesn't
+ * include -fomit-frame-pointer
+ *
+ * njh at bandsman.co.uk
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <clamav.h>
+#include <sys/resource.h>
+#include <signal.h>
+#include <features.h>
+#include <memory.h>
+#include <unistd.h>
+
+#include "clamav-config.h"
+#include "others.h"
+#include "pe.h"
+
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
+/*#define HAVE_BACKTRACE	/* Only tested on Linux... */
+#endif
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+static const uint16_t test1[] = {
+	0x5a4d, 0x0090, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+	0x00b8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+	0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+	0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+	0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+	0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+	0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+	0x6a83, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+static const uint16_t test2[] = {
+	0x5a4d, 0x0090, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+	0x00b8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+	0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+	0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+	0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+	0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+	0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+	0x6a82, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+static const uint16_t test3[] = {
+	0x5a4d, 0x0091, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+	0x00b8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+	0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+	0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+	0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+	0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+	0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+	0x6a83, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+static const uint16_t test4[] = {
+	0x5a4d, 0x0090, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+	0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+	0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+	0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+	0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+	0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+	0x6a83, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+
+static struct tests {
+	const uint16_t *test;
+	unsigned int size;
+} tests[] = {
+	{	test1,	sizeof(test1)	},
+	{	test2,	sizeof(test2)	},
+	{	test3,	sizeof(test3)	},
+	{	test4,	sizeof(test4)	},
+	{	NULL,	0		},
+};
+
+static	const	char	*tmp_file = "/tmp/petest";
+
+static	void	print_trace(void);
+static	void	sigsegv(int sig);
+
+static void
+sigsegv(int sig)
+{
+	signal(SIGSEGV, SIG_DFL);
+	print_trace();
+	_exit(SIGSEGV);
+}
+
+static void
+print_trace(void)
+{
+#ifdef HAVE_BACKTRACE
+	void *array[10];
+	size_t size, i;
+	char **strings;
+
+	puts("Segfault caught, backtrace:");
+
+	size = backtrace(array, 10);
+	strings = backtrace_symbols(array, size);
+
+	for(i = 0; i < size; i++)
+		printf("\t%s\n", strings[i]);
+
+	free(strings);
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+	const struct tests *t;
+	int fd;
+	struct rlimit rlim;
+	cli_ctx ctx;
+
+	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+	if(setrlimit(RLIMIT_CORE, &rlim) < 0)
+		perror("setrlimit");
+
+	memset(&ctx, '\0', sizeof(cli_ctx));
+	/*printf("cl_scanpe(-1) returns %d\n", cli_scanpe(-1, &ctx));
+	printf("cl_scanpe(10) returns %d\n", cli_scanpe(10, &ctx));
+	printf("cl_scanpe(10000) returns %d\n", cli_scanpe(10000, &ctx));*/
+	cli_scanpe(-1, &ctx);
+	cli_scanpe(-1, NULL);
+	cli_scanpe(10, &ctx);
+	cli_scanpe(10, NULL);
+	cli_scanpe(10000, &ctx);
+	cli_scanpe(10000, NULL);
+
+	for(t = tests; t->test; t++) {
+		int n;
+
+		for(n = t->size; n >= 1; --n) {
+			int m;
+
+			for(m = 0; m < n; m++) {
+				fd = open(tmp_file, O_CREAT|O_RDWR, 0600);
+
+				if(fd < 0) {
+					perror(tmp_file);
+					return errno;
+				}
+
+				write(fd, &t->test[m], n - m);
+
+				signal(SIGSEGV, sigsegv);
+
+				memset(&ctx, '\0', sizeof(cli_ctx));
+				cli_scanpe(fd, &ctx);
+				cli_scanpe(fd, NULL);
+				/*printf("cl_scanpe() returns %d\n", cli_scanpe(fd, &ctx));*/
+				close(fd);
+			}
+		}
+	}
+
+	return unlink(tmp_file);
+}

Added: test-suite/trunk/MultiSource/Applications/ClamAV/text.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/text.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/text.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/text.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * $Log: text.h,v $
+ * Revision 1.9  2006/07/01 16:17:35  njh
+ * Added destroy flag
+ *
+ * Revision 1.8  2006/04/09 19:59:28  kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.7  2004/12/04 16:03:55  nigelhorne
+ * Text/plain now handled as no encoding
+ *
+ * Revision 1.6  2004/08/22 10:34:24  nigelhorne
+ * Use fileblob
+ *
+ * Revision 1.5  2004/08/21 11:57:57  nigelhorne
+ * Use line.[ch]
+ *
+ * Revision 1.4  2004/07/20 14:35:29  nigelhorne
+ * Some MYDOOM.I were getting through
+ *
+ * Revision 1.3  2004/06/22 04:08:02  nigelhorne
+ * Optimise empty lines
+ *
+ */
+
+/* The contents could change, ONLY access in text.c */
+typedef struct text {
+	line_t	*t_line;	/* NULL if the line is empty */
+	struct	text	*t_next;
+} text;
+
+#include "message.h"
+
+void	textDestroy(text *t_head);
+text	*textAddMessage(text *aText, message *aMessage);
+text	*textMove(text *t_head, text *t);
+blob	*textToBlob(text *t, blob *b, int destroy);
+fileblob	*textToFileblob(text *t, fileblob *fb, int destroy);

Added: test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,20 @@
+/*
+ *  Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+int cli_tnef(const char *dir, int desc);

Added: test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (C) 2002, 2003 Tomasz Kojm <tkojm at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __TREEWALK_H
+#define __TREEWALK_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include "clamav.h"
+#include "options.h"
+
+struct s_du {
+    unsigned int files;
+    unsigned long int space; /* in kilobytes */
+};
+
+int treewalk(const char *dirname, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options, unsigned int depth);
+
+int clamav_rmdirs(const char *dir);
+int fixperms(const char *dirname);
+int du(const char *dirname, struct s_du *n);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,37 @@
+/*
+ *  Extract component parts of ARJ archives
+ *
+ *  Copyright (C) 2007 trog at uncon.org
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __UNARJ_H
+#define __UNARJ_H
+
+typedef struct arj_metadata_tag {
+	uint32_t comp_size;
+	uint32_t orig_size;
+	uint8_t method;
+	char *filename;
+	int encrypted;
+	int ofd;
+} arj_metadata_t;
+
+int cli_unarj_open(int fd, const char *dirname);
+int cli_unarj_prepare_file(int fd, const char *dirname, arj_metadata_t *metadata);
+int cli_unarj_extract_file(int fd, const char *dirname, arj_metadata_t *metadata);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (C) 2006 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __UNSP_H
+#define __UNSP_H
+
+#include "cltypes.h"
+#include "others.h"
+
+struct UNSP {
+  char *src_curr;
+  char *src_end;
+  uint32_t bitmap;
+  uint32_t oldval;
+  int error;
+  /* the following are not in the original structure */
+  char *table;
+  uint32_t tablesz;
+};
+
+uint32_t unspack(char *, char *, cli_ctx *, uint32_t, uint32_t, uint32_t, int);
+uint32_t very_real_unpack(uint16_t *, uint32_t, uint32_t, uint32_t, uint32_t, char *, uint32_t, char *, uint32_t);
+uint32_t get_byte(struct UNSP *);
+int getbit_from_table(uint16_t *, struct UNSP *);
+uint32_t get_100_bits_from_tablesize(uint16_t *, struct UNSP *, uint32_t);
+uint32_t get_100_bits_from_table(uint16_t *, struct UNSP *);
+uint32_t get_n_bits_from_table(uint16_t *, uint32_t, struct UNSP *);
+uint32_t get_n_bits_from_tablesize(uint16_t *, struct UNSP *, uint32_t);
+uint32_t get_bb(uint16_t *, uint32_t, struct UNSP *);
+uint32_t get_bitmap(struct UNSP *, uint32_t);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/untar.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/untar.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/untar.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/untar.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (C) 2004 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ * Change History:
+ * $Log: untar.h,v $
+ * Revision 1.5  2006/12/22 18:29:13  njh
+ * Recommit fix for bug 153
+ *
+ * Revision 1.4  2006/04/09 19:59:28  kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.3  2005/03/22 21:26:27  kojm
+ * add support for old fashioned tar archives
+ *
+ * Revision 1.2  2004/09/05 18:58:22  nigelhorne
+ * Extract files completed
+ *
+ * Revision 1.1  2004/09/05 15:28:10  nigelhorne
+ * First draft
+ *
+ */
+int cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits *limits);

Added: test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,222 @@
+/*
+ *  Copyright (C) 2003 - 2006 Tomasz Kojm <tkojm at clamav.net>
+ *	      (C) 2006 Sensory Networks, Inc.
+ *
+ *  The code of this module was based on zziplib 0.12.83:
+ *  (c) 1999 - 2002 Guido Draheim <guidod at gmx.de>, published under
+ *  the Lesser GNU General Public License
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __UNZIP_H
+#define __UNZIP_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "cltypes.h"
+
+#ifndef HAVE_ATTRIB_PACKED
+#define __attribute__(x)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+
+/******** Zip format structures *********/
+
+/* Local file header */
+struct zip_file_header
+{
+#   define ZIP_FILE_HEADER_MAGIC 0x04034b50
+    uint32_t	    z_magic;	    /* local file header signature */
+    uint16_t	    z_version;	    /* version needed to extract */
+    uint16_t	    z_flags;	    /* general purpose bit flag */
+    uint16_t	    z_compr;	    /* compression method */
+    uint16_t	    z_modtime;	    /* last mod file time */
+    uint16_t	    z_moddate;	    /* last mod file date */
+    uint32_t	    z_crc32;	    /* crc-32 */
+    uint32_t	    z_csize;	    /* compressed size */
+    uint32_t	    z_usize;	    /* uncompressed size */
+    uint16_t	    z_namlen;	    /* file name length */
+    uint16_t	    z_extras;	    /* extra field length */
+
+    /* followed by filename (of variable size) */
+    /* followed by extra field (of variable size) */
+} __attribute__((packed));
+
+/* Data descriptor (only if bit 3 of z_flags is set) */
+struct zip_file_trailer
+{
+#   define ZIP_FILE_TRAILER_MAGIC 0x08074B50
+    uint32_t z_magic; /* data descriptor signature (0x08074b50) */
+    uint32_t z_crc32; /* crc-32 */
+    uint32_t z_csize; /* compressed size */
+    uint32_t z_usize; /* uncompressed size */
+} __attribute__((packed));
+
+/* Central file header */
+struct zip_root_dirent
+{
+#   define ZIP_ROOT_DIRENT_MAGIC 0x02014b50
+    uint32_t	    z_magic;	    /* central file header signature */
+    uint16_t	    z_version1;	    /* version made by */
+    uint16_t	    z_version2;	    /* version needed to extract */
+    uint16_t	    z_flags;	    /* general purpose bit flag */
+    uint16_t	    z_compr;	    /* compression method */
+    uint16_t	    z_modtime;	    /* last mod file time */
+    uint16_t	    z_moddate;	    /* last mod file date */
+    uint32_t	    z_crc32;	    /* crc-32 */
+    uint32_t	    z_csize;	    /* compressed size */
+    uint32_t	    z_usize;	    /* uncompressed size */
+    uint16_t	    z_namlen;	    /* file name length */
+    uint16_t	    z_extras;	    /* extra field length */
+    uint16_t	    z_comment;	    /* file comment length */
+    uint16_t	    z_diskstart;    /* disk number start */
+    uint16_t	    z_filetype;	    /* internal file attributes */
+    uint32_t	    z_filemode;	    /* extrnal file attributes */
+    uint32_t	    z_off;	    /* relative offset of local header */
+
+    /* followed by filename (of variable size) */
+    /* followed by extra field (of variable size) */
+    /* followed by file comment (of variable size) */
+} __attribute__((packed));
+
+/* End of central directory record */
+struct zip_disk_trailer
+{
+#   define	    ZIP_DISK_TRAILER_MAGIC 0x06054b50
+    uint32_t	    z_magic;		/* end of central dir signature */
+    uint16_t	    z_disk;		/* number of this disk */
+    uint16_t	    z_finaldisk;	/* number of the disk with the start
+					 * of the central dir
+					 */
+    uint16_t	    z_entries;		/* total number of entries in the
+					 * central dir on this disk
+					 */
+    uint16_t	    z_finalentries;	/* total number of entries in the
+					 * central dir
+					 */
+    uint32_t	    z_rootsize;		/* size of the central directory */
+    uint32_t	    z_rootseek;		/* offset of start of central directory
+					 * with respect to the starting disk
+					 * number
+					 */
+    uint16_t	    z_comment;		/* zipfile comment length */
+
+    /* followed by zipfile comment (of variable size) */
+} __attribute__((packed));
+
+#define ZIP_METHOD_STORED	    0
+#define ZIP_METHOD_SHRUNK	    1
+#define ZIP_METHOD_REDUCEDx1	    2
+#define ZIP_METHOD_REDUCEDx2	    3
+#define ZIP_METHOD_REDUCEDx3	    4
+#define ZIP_METHOD_REDUCEDx4	    5
+#define ZIP_METHOD_IMPLODED	    6
+#define ZIP_METHOD_TOKENIZED	    7
+#define ZIP_METHOD_DEFLATED	    8
+#define ZIP_METHOD_DEFLATED64	    9
+#define ZIP_METHOD_IMPLODED_DCL	    10
+#define ZIP_METHOD_BZIP2	    12
+#define ZIP_METHOD_AES		    99
+
+
+/******** Internal structures *********/
+
+struct __zip_file
+{
+    struct __zip_dir *dir; 
+    uint16_t method;
+    int16_t *bf;
+    size_t restlen;
+    size_t crestlen;
+    size_t usize;
+    size_t csize;
+    char *buf32k;
+    z_stream d_stream;
+};
+
+struct __zip_dir_hdr
+{
+    uint32_t    d_usize;	/* uncompressed size */
+    uint32_t    d_csize;        /* compressed size */
+    uint32_t    d_crc32;        /* crc-32 */
+    uint32_t    d_off;          /* offset of file in zipfile */
+    uint16_t    d_reclen;       /* next dir_hdr structure offset */
+    uint16_t    d_namlen;       /* explicit namelen of d_name */
+    uint16_t    d_compr;        /* compression type */
+    int16_t	d_bf[2];	/* compression type/brute force */
+    uint16_t	d_flags;	/* general purpose flags */
+    char        d_name[1];      /* actual name of the entry */
+};
+
+struct __zip_dirent
+{
+    uint16_t 	d_compr;	/* compression method */
+    uint32_t    d_csize;        /* compressed size */
+    uint32_t 	st_size;	/* file size / decompressed size */
+    uint16_t	d_flags;	/* general purpose flags */
+    char	*d_name;	/* file name / strdupped name */
+    uint32_t    d_crc32;        /* crc-32 */
+    uint32_t    d_off;          /* the offset in the file */
+};
+
+struct __zip_dir
+{
+    int fd;
+    int errcode;
+    struct {
+        struct __zip_file *fp;
+        char *buf32k;
+    } cache;
+    struct __zip_dir_hdr *hdr0;
+    struct __zip_dir_hdr *hdr;
+    struct __zip_dirent dirent;
+}; 
+
+/* typedefs */
+typedef struct __zip_dir	zip_dir;
+typedef struct __zip_dir_hdr	zip_dir_hdr;
+typedef struct __zip_file	zip_file;
+typedef struct __zip_dirent 	zip_dirent;
+
+zip_dir *zip_dir_open(int fd, off_t start, int *errcode_p);
+int zip_dir_read(zip_dir *dir, zip_dirent *d);
+zip_file *zip_file_open(zip_dir *dir, const char *name, int d_off);
+ssize_t zip_file_read(zip_file *fp, char *buf, size_t len);
+int zip_file_close(zip_file *fp);
+int zip_dir_close(zip_dir *dir);
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack()
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack
+#endif
+
+#endif /* __UNZIP_H */

Added: test-suite/trunk/MultiSource/Applications/ClamAV/upack.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/upack.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/upack.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/upack.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,31 @@
+/*
+ *  Copyright (C) 2006 Michal 'GiM' Spadlinski http://gim.org.pl/
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __UPACK_H
+#define __UPACK_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+
+int unupack(int, char *, uint32_t, char *, uint32_t, uint32_t, uint32_t, uint32_t, int);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/upx.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/upx.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/upx.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/upx.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __UPX_H
+#define __UPX_H
+
+#include "cltypes.h"
+
+int upx_inflate2b(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
+int upx_inflate2d(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
+int upx_inflate2e(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/utils.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/utils.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/utils.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/utils.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,59 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)utils.h	8.3 (Berkeley) 3/20/94
+ */
+
+/* utility definitions */
+#define	DUPMAX		_POSIX2_RE_DUP_MAX	/* xxx is this right? */
+#define	INFINITY	(DUPMAX + 1)
+#define	NC		(CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifdef CL_DEBUG
+#define REDEBUG
+#endif
+
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define	NDEBUG	/* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define	memmove(d, s, c)	bcopy(s, d, c)
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __UUENCODE_H
+#define __UUENCODE_H
+
+int	cli_uuencode(const char *dir, int desc);
+int	uudecodeFile(message *m, const char *firstline, const char *dir, FILE *fin);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,48 @@
+/*
+ *  Extract VBA source code for component MS Office Documents
+ *
+ *  Copyright (C) 2004 trog at uncon.org
+ *
+ *  This code is based on the OpenOffice and libgsf sources.
+ *                  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __VBA_EXTRACT_H
+#define __VBA_EXTRACT_H
+
+#include "cltypes.h"
+
+typedef struct vba_project_tag {
+	int count;
+	char **name;
+	uint32_t *offset;
+	uint32_t *length;	/* for Word 6 macros */
+	unsigned char *key;	/* for Word 6 macros */
+	char *dir;
+} vba_project_t;
+
+vba_project_t *vba56_dir_read(const char *dir);
+unsigned char *vba_decompress(int fd, uint32_t offset, int *size);
+int cli_decode_ole_object(int fd, const char *dir);
+
+char *ppt_vba_read(const char *dir);
+
+vba_project_t *wm_dir_read(const char *dir);
+unsigned char *wm_decrypt_macro(int fd, uint32_t offset, uint32_t len,
+					unsigned char key);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2006 Sensory Networks, Inc.
+ *             Written by aCaB <acab at clamav.net>
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __WWP32_H
+#define __WWP32_H
+
+#include "cltypes.h"
+#include "rebuildpe.h"
+
+int wwunpack(char *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, char *, uint32_t, uint16_t);
+
+#endif

Added: test-suite/trunk/MultiSource/Applications/ClamAV/yc.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/yc.h?rev=46573&view=auto

==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/yc.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/yc.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it 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
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ */
+
+#ifndef __YC_H
+#define __YC_H
+
+#include "pe.h"
+#include "execs.h"
+#include "cltypes.h"
+
+int yc_decrypt(char *, unsigned int, struct cli_exe_section *, unsigned int, uint32_t, int);
+
+#endif

Modified: test-suite/trunk/MultiSource/Applications/Makefile
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/Makefile?rev=46573&r1=46572&r2=46573&view=diff

==============================================================================
--- test-suite/trunk/MultiSource/Applications/Makefile (original)
+++ test-suite/trunk/MultiSource/Applications/Makefile Wed Jan 30 15:17:10 2008
@@ -5,7 +5,7 @@
 include $(LEVEL)/Makefile.config
 
 PARALLEL_DIRS  = Burg aha sgefa siod lambda-0.1.3 d spiff hbd treecc SPASS \
-                 hexxagon oggenc JM viterbi minisat SIBsim4
+                 hexxagon oggenc JM viterbi minisat SIBsim4 ClamAV
 
 # Obsequi uses Linux-only features; need to fix that
 ifeq ($(OS),Linux)





More information about the llvm-commits mailing list