1 /*
2  *  Copyright (C) 2004-2008 Christos Tsantilas
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  *  MA  02110-1301  USA.
18  */
19 
20 #include "common.h"
21 #include "c-icap.h"
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <errno.h>
25 
26 #ifdef HAVE_ZLIB
27 #include <zlib.h>
28 #endif
29 #ifdef HAVE_BZLIB
30 #include <bzlib.h>
31 #endif
32 
33 #include "simple_api.h"
34 #include "debug.h"
35 #include "request.h"
36 #include "mem.h"
37 #include "filetype.h"
38 
39 static struct ci_magics_db *_MAGIC_DB = NULL;
40 
41 struct ci_data_type predefined_types[] = {
42     {"ASCII", "ASCII text file", {CI_TEXT_DATA, -1}},
43     {"ISO-8859", "ISO-8859 text file", {CI_TEXT_DATA, -1}},
44     {"EXT-ASCII", "Extended ASCII (Mac,IBM PC etc.)", {CI_TEXT_DATA, -1}},
45     {"UTF", "Unicode text file ", {CI_TEXT_DATA, -1}},
46     {"HTML", "HTML text", {CI_TEXT_DATA, -1}},
47     {"BINARY", "Unknown data", {CI_OCTET_DATA, -1}},
48     {"", "", {-1}}
49 };
50 
51 struct ci_data_group predefined_groups[] = {
52     {"TEXT", "All texts"},
53     {"DATA", "Undefined data type"},
54     {"", ""}
55 };
56 
57 struct ci_magic_record {
58     int offset;
59     unsigned char magic[MAGIC_SIZE + 1];
60     size_t len;
61     char type[NAME_SIZE + 1];
62     char *groups[MAX_GROUPS + 1];
63     char descr[DESCR_SIZE + 1];
64 };
65 
66 #define DECLARE_ARRAY_FUNCTIONS(structure,array,type,size) int array##_init(structure *db){ \
67                                                      if((db->array=malloc(size*sizeof(type)))==NULL) \
68                                                       return 0; \
69                                                      db->array##_num=0; \
70                                                      db->array##_size=size;\
71                                                      return 1; \
72                                                     }
73 
74 #define CHECK_SIZE(db,array,type,size)   if(db->array##_num >= db->array##_size){\
75                                                if((newdata=realloc(db->array,(db->array##_size+size)*sizeof(type)))==NULL)\
76                                                          return -1;\
77                                                     db->array##_size +=size; \
78                                                 db->array =newdata;\
79                                         }
80 
81 DECLARE_ARRAY_FUNCTIONS(struct ci_magics_db, types, struct ci_data_type, 50)
82 DECLARE_ARRAY_FUNCTIONS(struct ci_magics_db, groups, struct ci_data_group, 15)
83 DECLARE_ARRAY_FUNCTIONS(struct ci_magics_db, magics, struct ci_magic, 50)
84 
85 
types_add(struct ci_magics_db * db,const char * name,const char * descr,int * groups)86 int types_add(struct ci_magics_db *db, const char *name, const char *descr, int *groups)
87 {
88     struct ci_data_type *newdata;
89     int indx, i;
90 
91     CHECK_SIZE(db, types, struct ci_data_type, 50);
92     indx = db->types_num;
93     db->types_num++;
94     strcpy(db->types[indx].name, name);
95     strcpy(db->types[indx].descr, descr);
96     i = 0;
97     while (groups[i] >= 0 && i < MAX_GROUPS) {
98         db->types[indx].groups[i] = groups[i];
99         i++;
100     }
101     db->types[indx].groups[i] = -1;
102     return indx;
103 }
104 
groups_add(struct ci_magics_db * db,const char * name,const char * descr)105 int groups_add(struct ci_magics_db *db, const char *name, const char *descr)
106 {
107     struct ci_data_group *newdata;
108     int indx;
109 
110     CHECK_SIZE(db, groups, struct ci_data_group, 15);
111     indx = db->groups_num;
112     db->groups_num++;
113     strcpy(db->groups[indx].name, name);
114     strcpy(db->groups[indx].descr, descr);
115     return indx;
116 }
117 
magics_add(struct ci_magics_db * db,int offset,unsigned char * magic,size_t len,int type)118 int magics_add(struct ci_magics_db *db, int offset, unsigned char *magic,
119                size_t len, int type)
120 {
121     struct ci_magic *newdata;
122     int indx;
123 
124     CHECK_SIZE(db, magics, struct ci_magic, 50) indx = db->magics_num;
125     db->magics_num++;
126 
127     db->magics[indx].type = type;
128     db->magics[indx].offset = offset;
129     db->magics[indx].len = len;
130     memcpy(db->magics[indx].magic, magic, len);
131 
132     return indx;
133 }
134 
ci_get_data_type_id(struct ci_magics_db * db,const char * name)135 int ci_get_data_type_id(struct ci_magics_db *db, const char *name)
136 {
137     int i = 0;
138     for (i = 0; i < db->types_num; i++) {
139         if (strcasecmp(name, db->types[i].name) == 0)
140             return i;
141     }
142     return -1;
143 }
144 
ci_get_data_group_id(struct ci_magics_db * db,const char * group)145 int ci_get_data_group_id(struct ci_magics_db *db, const char *group)
146 {
147     int i = 0;
148     for (i = 0; i < db->groups_num; i++) {
149         if (strcasecmp(group, db->groups[i].name) == 0)
150             return i;
151     }
152     return -1;
153 }
154 
ci_belongs_to_group(struct ci_magics_db * db,int type,int group)155 int ci_belongs_to_group(struct ci_magics_db *db, int type, int group)
156 {
157     int i;
158     if (db->types_num < type)
159         return 0;
160     i = 0;
161     while (db->types[type].groups[i] >= 0 && i < MAX_GROUPS) {
162         if (db->types[type].groups[i] == group)
163             return 1;
164         i++;
165     }
166     return 0;
167 }
168 
free_records_group(struct ci_magic_record * record)169 void free_records_group(struct ci_magic_record *record)
170 {
171     int i;
172     i = 0;
173     while (record->groups[i] != NULL) {
174         free(record->groups[i]);
175         record->groups[i] = NULL;
176         i++;
177     }
178 }
179 
180 #define RECORD_LINE 32768
parse_record(char * line,struct ci_magic_record * record)181 static int parse_record(char *line, struct ci_magic_record *record)
182 {
183     char *s, *end, num[4];
184     int len, c, i;
185 
186     if ((len = strlen(line)) < 4)      /*must have at least 4 ':' */
187         return 0;
188     if (line[0] == '#')        /*Comment ....... */
189         return 0;
190     line[--len] = '\0';        /*the \n at the end of */
191     s = line;
192     errno = 0;
193     record->offset = strtol(s, &end, 10);
194     if (*end != ':' || errno != 0)
195         return 0;
196 
197     s = end + 1;
198     i = 0;
199     end = line + len;
200     while (*s != ':' && s < end && i < MAGIC_SIZE) {
201         if (*s == '\\') {
202             s++;
203             if (*s == 'x') {
204                 s++;
205                 num[0] = *(s++);
206                 num[1] = *(s++);
207                 num[2] = '\0';
208                 c = strtol(num, NULL, 16);
209             } else {
210                 num[0] = *(s++);
211                 num[1] = *(s++);
212                 num[2] = *(s++);
213                 num[3] = '\0';
214                 c = strtol(num, NULL, 8);
215             }
216             if (c > 256 || c < 0) {
217                 return -2;
218             }
219             record->magic[i++] = c;
220         } else {
221             record->magic[i++] = *s;
222             s++;
223         }
224     }
225     record->len = i;
226 
227     if (s >= end || *s != ':') {       /*End of the line..... parse error */
228         return -2;
229     }
230     s++;
231     if ((end = strchr(s, ':')) == NULL) {
232         return -2;            /*Parse error */
233     }
234     *end = '\0';
235     strncpy(record->type, s, NAME_SIZE);
236     record->type[NAME_SIZE] = '\0';
237     s = end + 1;
238 
239     if ((end = strchr(s, ':')) == NULL) {
240         return -2;            /*Parse error */
241     }
242     *end = '\0';
243     strncpy(record->descr, s, DESCR_SIZE);
244     record->descr[DESCR_SIZE] = '\0';
245 
246     s = end + 1;
247     i = 0;
248     while ((end = strchr(s, ':')) != NULL) {
249         *end = '\0';
250         record->groups[i] = malloc(NAME_SIZE + 1);
251         strncpy(record->groups[i], s, NAME_SIZE);
252         record->groups[i][NAME_SIZE] = '\0';
253         i++;
254         if (i >= MAX_GROUPS - 1)
255             break;
256         s = end + 1;
257     }
258 
259     record->groups[i] = malloc(NAME_SIZE + 1);
260     strncpy(record->groups[i], s, NAME_SIZE);
261     record->groups[i][NAME_SIZE] = '\0';
262     i++;
263     record->groups[i] = NULL;
264     return 1;
265 }
266 
ci_magics_db_init()267 struct ci_magics_db *ci_magics_db_init()
268 {
269     struct ci_magics_db *db;
270     int i, ret;
271     db = malloc(sizeof(struct ci_magics_db));
272     if (!db)
273         return NULL;
274 
275     memset(db, 0, sizeof(struct ci_magics_db));
276     ret = types_init(db) && groups_init(db) && magics_init(db);
277     if (!ret) {
278         ci_magics_db_release(db);
279         return NULL;
280     }
281 
282     i = 0;                     /*Copy predefined types */
283     while (predefined_types[i].name[0] != '\0') {
284         ret = types_add(db, predefined_types[i].name, predefined_types[i].descr,
285                         predefined_types[i].groups);
286         if (ret < 0) { /*memory allocation ?*/
287             ci_magics_db_release(db);
288             return NULL;
289         }
290         i++;
291     }
292 
293     i = 0;                     /*Copy predefined groups */
294     while (predefined_groups[i].name[0] != '\0') {
295         ret = groups_add(db, predefined_groups[i].name, predefined_groups[i].descr);
296         if (ret < 0) { /*memory allocation ?*/
297             ci_magics_db_release(db);
298             return NULL;
299         }
300         i++;
301     }
302     return db;
303 }
304 
ci_magics_db_release(struct ci_magics_db * db)305 void ci_magics_db_release(struct ci_magics_db *db)
306 {
307     if (db->types)
308         free(db->types);
309     if (db->groups)
310         free(db->groups);
311     if (db->magics)
312         free(db->magics);
313     free(db);
314 }
315 
ci_magics_db_file_add(struct ci_magics_db * db,const char * filename)316 int ci_magics_db_file_add(struct ci_magics_db *db, const char *filename)
317 {
318     int type;
319     int ret, error, group, i, lineNum;
320     int groups[MAX_GROUPS + 1];
321     char line[RECORD_LINE];
322     struct ci_magic_record record;
323     FILE *f;
324 
325     if ((f = fopen(filename, "r")) == NULL) {
326         ci_debug_printf(1, "Error opening magic file: %s\n", filename);
327         return 0;
328     }
329 
330     memset(&record, 0, sizeof(struct ci_magic_record));
331     lineNum = 0;
332     error = 0;
333     while (!error && fgets(line, RECORD_LINE, f) != NULL) {
334         lineNum ++;
335         ret = parse_record(line, &record);
336         if (!ret)
337             continue;
338         if (ret < 0) {
339             error = 1;
340             break;
341         }
342         if ((type = ci_get_data_type_id(db, record.type)) < 0) {
343             for (i=0; record.groups[i] != NULL && !error && i < MAX_GROUPS; ++i) {
344                 if ((group = ci_get_data_group_id(db, record.groups[i])) < 0) {
345                     group = groups_add(db, record.groups[i], "");
346                 }
347                 groups[i] = group;
348                 if (group < 0)
349                     error = 1;
350             }
351             if (!error) {
352                 groups[i] = -1;
353                 type = types_add(db, record.type, record.descr, groups);
354                 if (type < 0)
355                     error = 1;
356             }
357         }
358         if (magics_add(db, record.offset, record.magic, record.len, (unsigned int) type) < 0)
359             error = 1;
360         free_records_group(&record);
361     }
362     fclose(f);
363     if (error) {            /*An error occured ..... */
364         ci_debug_printf(1, "Error reading magic file (%d), line number: %d\nBuggy line: %s\n", ret, lineNum, line);
365         return 0;
366     }
367     ci_debug_printf(3, "In database: magic: %d, types: %d, groups: %d\n",
368                     db->magics_num, db->types_num, db->groups_num);
369     return 1;
370 
371 
372 }
373 
ci_magics_db_build(const char * filename)374 struct ci_magics_db *ci_magics_db_build(const char *filename)
375 {
376     struct ci_magics_db *db;
377 
378 
379     if ((db = ci_magics_db_init()) != NULL)
380         ci_magics_db_file_add(db, filename);
381     return db;
382 }
383 
check_magics(struct ci_magics_db * db,const char * buf,int buflen)384 int check_magics(struct ci_magics_db *db, const char *buf, int buflen)
385 {
386     int i;
387     for (i = 0; i < db->magics_num; i++) {
388         if (buflen >= db->magics[i].offset + db->magics[i].len) {
389             if (memcmp
390                     (buf + db->magics[i].offset, db->magics[i].magic,
391                      db->magics[i].len) == 0) {
392                 return db->magics[i].type;
393             }
394         }
395     }
396     return -1;
397 }
398 
399 /*The folowing table taking from the file project........*/
400 
401 /*0 are the characters which never appears in text */
402 #define T 1                     /* character appears in plain ASCII text */
403 #define I 2                     /* character appears in ISO-8859 text */
404 #define X 4                     /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
405 
406 static const char text_chars[256] = {
407     /*                  BEL BS HT LF    FF CR    */
408     0, 0, 0, 0, 0, 0, 0, T, T, T, T, 0, T, T, 0, 0,    /* 0x0X */
409     /*                              ESC          */
410     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, T, 0, 0, 0, 0,    /* 0x1X */
411     T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,    /* 0x2X */
412     T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,    /* 0x3X */
413     T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,    /* 0x4X */
414     T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,    /* 0x5X */
415     T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,    /* 0x6X */
416     T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, 0,    /* 0x7X */
417     /*            NEL                            */
418     X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,    /* 0x8X */
419     X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,    /* 0x9X */
420     I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,    /* 0xaX */
421     I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,    /* 0xbX */
422     I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,    /* 0xcX */
423     I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,    /* 0xdX */
424     I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,    /* 0xeX */
425     I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I     /* 0xfX */
426 };
427 
428 
429 /*
430 ASCII if res <= 1
431 ISO if res <= 3
432 EXTEND if res <= 7
433 */
434 
check_ascii(unsigned char * buf,int buflen)435 int check_ascii(unsigned char *buf, int buflen)
436 {
437     unsigned int i, res = 0, type;
438     for (i = 0; i < buflen; i++) {     /*May be only a small number (30-50 bytes) of the first data must be checked */
439         if ((type = text_chars[buf[i]]) == 0)
440             return -1;
441         res = res | type;
442     }
443     if (res <= 1)
444         return CI_ASCII_DATA;
445     if (res <= 3)
446         return CI_ISO8859_DATA;
447 
448     return CI_XASCII_DATA; /*Extend ascii for web pages? */
449 }
450 
451 
452 static unsigned int utf_boundaries[] =
453 { 0x0, 0x0, 0x07F, 0x7FF, 0xFFFF, 0x1FFFFF, 0x3FFFFFF };
454 
isUTF8(unsigned char * c,int size)455 int isUTF8(unsigned char *c, int size)
456 {
457     int i, r_size = 0;
458     unsigned int ucs_c = 0;
459 
460     if (text_chars[(int) *c] == T)
461         return 1;
462 
463     if ((*c & 0xE0) == 0xC0) { /*2 byte unicode char ... */
464         ucs_c = (*c) & 0x1F;
465         r_size = 2;
466     } else if ((*c & 0xF0) == 0xE0) {  /*3 byte unicode char */
467         ucs_c = (*c) & 0x0F;
468         r_size = 3;
469     } else if ((*c & 0xF8) == 0xF0) {  /*4 byte unicode char */
470         ucs_c = (*c) & 0x07;
471         r_size = 4;
472     } else if ((*c & 0xFC) == 0xF8) {  /*5 byte unicode char */
473         ucs_c = (*c) & 0x03;
474         r_size = 5;
475     } else if ((*c & 0xFE) == 0xFC) {  /*6 byte unicode char */
476         ucs_c = (*c) & 0x01;
477         r_size = 6;
478     }
479 
480     if (!r_size /*|| r_size >4 */ )    /*In practice there are not yet 5 and 6 sized utf characters */
481         return 0;
482 
483     for (i = 1; i < r_size && i < size; i++) {
484         if ((*(c + i) & 0xC0) != 0x80)
485             return 0;
486         ucs_c = (ucs_c << 6) | (*(c + i) & 0x3F);
487     }
488 
489     if (i < r_size) {
490         /*Not enough length ... */
491         return -1;
492     }
493 
494     if (ucs_c <= utf_boundaries[r_size]) {
495         /*Over long character .... */
496         return 0;
497     }
498 
499     /* check UTF-16 surrogates? ........ */
500     if ((ucs_c >= 0xd800 && ucs_c <= 0xdfff) || ucs_c == 0xfffe
501             || ucs_c == 0xffff) {
502         return 0;
503     }
504     return r_size;
505 }
506 
check_unicode(unsigned char * buf,int buflen)507 int check_unicode(unsigned char *buf, int buflen)
508 {
509     int i, ret = 0;
510     int endian = 0;
511     /*check for utf8 ........ */
512     for (i = 0; i < buflen; i += ret) {
513         if ((ret = isUTF8(buf + i, buflen - i)) <= 0)
514             break;
515     }
516 
517     if (ret < 0 && i == 0)
518         ret = 0;              /*Not enough data to check */
519 
520     if (ret)                   /*Even if the last char is unknown ret != 0 mean is utf */
521         return CI_UTF_DATA;   /*... but what about if buflen is about 2 or 3 bytes long ? */
522 
523     /*check for utf16 .... */
524     if (buflen < 2)
525         return -1;
526     /*I read somewhere that only Microsoft uses the first 2 bytes to identify utf16 documents */
527     if (buf[0] == 0xff && buf[1] == 0xfe)      /*Litle endian utf16 */
528         endian = 0;
529     else if (buf[0] == 0xfe && buf[1] == 0xff) /*big endian utf16 .... */
530         endian = 1;
531     else
532         return -1;
533 
534     /*The only check we can do is for the ascii characters ...... */
535     for (i = 2; i < buflen; i += 2) {
536         if (endian) {
537             if (buf[i] == 0 && buf[i + 1] < 128
538                     && text_chars[buf[i + 1]] != T)
539                 return -1;
540         } else {
541             if (buf[i + 1] == 0 && buf[i] < 128 && text_chars[buf[i]] != T)
542                 return -1;
543         }
544     }
545 
546 
547     /*utf32 ????? who are using it? */
548 
549     return CI_UTF_DATA;
550 }
551 
ci_filetype(struct ci_magics_db * db,const char * buf,int buflen)552 int ci_filetype(struct ci_magics_db *db, const char *buf, int buflen)
553 {
554     int ret;
555 
556     if ((ret = check_magics(db, buf, buflen)) >= 0)
557         return ret;
558 
559     /*At the feature the check_ascii and check_unicode must be merged ....*/
560     if ((ret = check_ascii((unsigned char *) buf, buflen)) >= 0)
561         return ret;
562 
563     if ((ret = check_unicode((unsigned char *) buf, buflen)) >= 0) {
564         return CI_UTF_DATA;
565     }
566 
567     return CI_BIN_DATA;        /*binary data */
568 }
569 
extend_object_type(struct ci_magics_db * db,ci_headers_list_t * headers,const char * buf,int len,int * iscompressed)570 int extend_object_type(struct ci_magics_db *db, ci_headers_list_t *headers, const char *buf,
571                        int len, int *iscompressed)
572 {
573     int file_type;
574     int unzipped_buf_len = 0;
575     char *unzipped_buf = NULL;
576     const char *checkbuf = buf;
577     const char *content_type = NULL;
578     const char *content_encoding = NULL;
579 
580     *iscompressed = CI_ENCODE_NONE;
581 
582     if (len <= 0)
583         return CI_BIN_DATA;
584 
585     if (headers) {
586         content_encoding = ci_headers_value(headers, "Content-Encoding");
587         if (content_encoding) {
588             ci_debug_printf(8, "Content-Encoding: %s\n", content_encoding);
589             *iscompressed = ci_encoding_method(content_encoding);
590 
591             /*
592               Bzip2 comressed data are not usefull on preview data, because ci_uncompress_preview
593               in most cases will not be able to decompress preview data window, because requires
594               large blocks of data to start decompression.
595             */
596             if (*iscompressed == CI_ENCODE_GZIP
597 #if 0
598                     || *iscompressed == CI_ENCODE_BZIP2
599 #endif
600                     || *iscompressed == CI_ENCODE_DEFLATE
601                     || *iscompressed == CI_ENCODE_BROTLI) {
602                 unzipped_buf = ci_buffer_alloc(len); /*Will I implement memory pools? when????? */
603                 unzipped_buf_len = len;
604                 if (ci_uncompress_preview
605                         (*iscompressed, buf, len, unzipped_buf,
606                          &unzipped_buf_len) != CI_ERROR) {
607                     /* 1) unzip and
608                        2) checkbuf eq to unziped data
609                        3) len eq to unzipped data len
610                      */
611                     checkbuf = unzipped_buf;
612                     len = unzipped_buf_len;
613                 } else {
614                     ci_debug_printf(3,
615                                     "Error uncompressing encoded object\n");
616                     ci_buffer_free(unzipped_buf);
617                     unzipped_buf = NULL;
618                     /* The checkbuf points to raw buf,
619                        type will be zipped data*/
620                 }
621             }
622         }
623     }
624 
625     file_type = ci_filetype(db, checkbuf, len);
626 
627     ci_debug_printf(7, "File type returned: %s,%s\n",
628                     ci_data_type_name(db, file_type),
629                     ci_data_type_descr(db, file_type));
630     /*The following until we have an internal html recognizer ..... */
631     if (ci_belongs_to_group(db, file_type, CI_TEXT_DATA)
632             && headers
633             && (content_type = ci_headers_value(headers, "Content-Type")) != NULL) {
634         if (strcasestr(content_type, "text/html")
635                 || strcasestr(content_type, "text/css")
636                 || strcasestr(content_type, "text/javascript"))
637             file_type = CI_HTML_DATA;
638     }
639 #ifndef HAVE_ZLIB               /*if we do not have a zlib try to get file info from headers....... */
640     else if (file_type == ci_get_data_type_id(db, "GZip")
641              && content_encoding != NULL) {
642         if (content_type && (strcasestr(content_type, "text/html")
643                              || strcasestr(content_type, "text/css")
644                              || strcasestr(content_type, "text/javascript")))
645             file_type = CI_HTML_DATA;
646     }
647 #endif
648 
649 
650     ci_debug_printf(7, "The file type now is: %s,%s\n",
651                     ci_data_type_name(db, file_type),
652                     ci_data_type_descr(db, file_type));
653 #ifdef HAVE_ZLIB
654     if (unzipped_buf)
655         ci_buffer_free(unzipped_buf);
656 #endif
657     return file_type;
658 }
659 
ci_extend_filetype(struct ci_magics_db * db,ci_request_t * req,const char * buf,int len,int * iscompressed)660 int ci_extend_filetype(struct ci_magics_db *db, ci_request_t *req, const char *buf,
661                        int len, int *iscompressed)
662 {
663     ci_headers_list_t *heads;
664     if (ci_req_type(req) == ICAP_RESPMOD)
665         heads = ci_http_response_headers(req);
666     else
667         heads = NULL;
668 
669     return extend_object_type(db, heads, buf, len, iscompressed);
670 }
671 
672 
ci_magic_db_load(const char * filename)673 struct ci_magics_db *ci_magic_db_load(const char *filename)
674 {
675     if (!_MAGIC_DB)
676         return (_MAGIC_DB = ci_magics_db_build(filename));
677 
678     if (ci_magics_db_file_add(_MAGIC_DB, filename))
679         return _MAGIC_DB;
680     else
681         return NULL;
682 }
683 
ci_magic_db_free()684 void ci_magic_db_free()
685 {
686     if (_MAGIC_DB)
687         ci_magics_db_release(_MAGIC_DB);
688 
689     _MAGIC_DB = NULL;
690 }
691 
692 
ci_magic_req_data_type(ci_request_t * req,int * isencoded)693 int ci_magic_req_data_type(ci_request_t *req, int *isencoded)
694 {
695     if (!_MAGIC_DB)
696         return -1;
697 
698     if (!req->preview_data.used)
699         return -1;
700 
701     if (req->preview_data_type <0 ) /*if there is not a cached value compute it*/
702         req->preview_data_type =
703             ci_extend_filetype(_MAGIC_DB, req,
704                                req->preview_data.buf, req->preview_data.used,
705                                isencoded);
706 
707     return req->preview_data_type;
708 }
709 
ci_magic_data_type(const char * buf,int len)710 int ci_magic_data_type(const char *buf, int len)
711 {
712     if (!_MAGIC_DB)
713         return -1;
714 
715     return ci_filetype(_MAGIC_DB, buf, len);
716 
717 }
718 
ci_magic_data_type_ext(ci_headers_list_t * headers,const char * buf,int len,int * iscompressed)719 int ci_magic_data_type_ext(ci_headers_list_t *headers, const char *buf, int len, int *iscompressed)
720 {
721     if (!_MAGIC_DB)
722         return -1;
723 
724     return extend_object_type(_MAGIC_DB, headers, buf, len, iscompressed);
725 }
726 
727 
ci_magic_type_id(const char * name)728 int ci_magic_type_id(const char *name)
729 {
730     if (!_MAGIC_DB)
731         return -1;
732 
733     return ci_get_data_type_id(_MAGIC_DB, name);
734 }
735 
ci_magic_group_id(const char * group)736 int ci_magic_group_id(const char *group)
737 {
738     if (!_MAGIC_DB)
739         return -1;
740 
741     return ci_get_data_group_id(_MAGIC_DB, group);
742 }
743 
ci_magic_group_check(int type,int group)744 int ci_magic_group_check(int type, int group)
745 {
746     if (!_MAGIC_DB)
747         return 0;
748 
749     return ci_belongs_to_group(_MAGIC_DB, type, group);
750 }
751 
752 
ci_magic_types_count()753 int ci_magic_types_count()
754 {
755     return ci_magic_types_num(_MAGIC_DB);
756 }
757 
758 
ci_magic_groups_count()759 int ci_magic_groups_count()
760 {
761     return  ci_magic_groups_num(_MAGIC_DB);
762 }
763 
ci_magic_type_name(int type)764 char * ci_magic_type_name(int type)
765 {
766     if (!_MAGIC_DB ||
767             type <= 0 || type >= ci_magic_types_num(_MAGIC_DB))
768         return NULL;
769 
770     return ci_data_type_name(_MAGIC_DB, type);
771 }
772 
ci_magic_type_descr(int type)773 char * ci_magic_type_descr(int type)
774 {
775     if (!_MAGIC_DB ||
776             type <= 0 || type >= ci_magic_types_num(_MAGIC_DB))
777         return NULL;
778 
779     return ci_data_type_descr(_MAGIC_DB, type);
780 }
781 
ci_magic_group_name(int group)782 char * ci_magic_group_name(int group)
783 {
784     if (!_MAGIC_DB ||
785             group <= 0 || group >= ci_magic_groups_num(_MAGIC_DB))
786         return NULL;
787 
788     return ci_data_group_name(_MAGIC_DB, group);
789 }
790