diff options
author | SVN Migration <svn@php.net> | 2003-02-27 17:43:39 +0000 |
---|---|---|
committer | SVN Migration <svn@php.net> | 2003-02-27 17:43:39 +0000 |
commit | 078bcec0997ad0e07b720c43cc9e6d0e046a75ab (patch) | |
tree | 36cb0f6be2ef078fe3374de8c087b93ecf82f812 /ext/mime_magic/mime_magic.c | |
parent | fd61f69077f6156ca71dde60ecfd9ed9765a02db (diff) | |
download | php-git-PHP-5.tar.gz |
This commit was manufactured by cvs2svn to create branch 'PHP_5'.PHP-5
Diffstat (limited to 'ext/mime_magic/mime_magic.c')
-rw-r--r-- | ext/mime_magic/mime_magic.c | 1909 |
1 files changed, 0 insertions, 1909 deletions
diff --git a/ext/mime_magic/mime_magic.c b/ext/mime_magic/mime_magic.c deleted file mode 100644 index 7df87f1f6f..0000000000 --- a/ext/mime_magic/mime_magic.c +++ /dev/null @@ -1,1909 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 4 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2003 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 2.02 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.php.net/license/2_02.txt. | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Hartmut Holzgraefe <hholzgra@php.net> | - +----------------------------------------------------------------------+ - - $Id$ - - This module contains a lot of stuff taken from Apache mod_mime_magic, - so the license section is a little bit longer than usual: - - ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. All rights - * reserved. - * - * 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * mod_mime_magic: MIME type lookup via file magic numbers - * Copyright (c) 1996-1997 Cisco Systems, Inc. - * - * This software was submitted by Cisco Systems to the Apache Group in July - * 1997. Future revisions and derivatives of this source code must - * acknowledge Cisco Systems as the original contributor of this module. - * All other licensing and usage conditions are those of the Apache Group. - * - * Some of this code is derived from the free version of the file command - * originally posted to comp.sources.unix. Copyright info for that program - * is included below as required. - * --------------------------------------------------------------------------- - * - Copyright (c) Ian F. Darwin, 1987. Written by Ian F. Darwin. - * - * This software is not subject to any license of the American Telephone and - * Telegraph Company or of the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on any - * computer system, and to alter it and redistribute it freely, subject to - * the following restrictions: - * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, credits - * must appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users ever read - * sources, credits must appear in the documentation. - * - * 4. This notice may not be removed or altered. - * ------------------------------------------------------------------------- - * - * For compliance with Mr Darwin's terms: this has been very significantly - * modified from the free "file" command. - * - all-in-one file for compilation convenience when moving from one - * version of Apache to the next. - * - Memory allocation is done through the Apache API's pool structure. - * - All functions have had necessary Apache API request or server - * structures passed to them where necessary to call other Apache API - * routines. (i.e. usually for logging, files, or memory allocation in - * itself or a called function.) - * - struct magic has been converted from an array to a single-ended linked - * list because it only grows one record at a time, it's only accessed - * sequentially, and the Apache API has no equivalent of realloc(). - * - Functions have been changed to get their parameters from the server - * configuration instead of globals. (It should be reentrant now but has - * not been tested in a threaded environment.) - * - Places where it used to print results to stdout now saves them in a - * list where they're used to set the MIME type in the Apache request - * record. - * - Command-line flags have been removed since they will never be used here. - * - * Ian Kluft <ikluft@cisco.com> - * Engineering Information Framework - * Central Engineering - * Cisco Systems, Inc. - * San Jose, CA, USA - * - * Initial installation July/August 1996 - * Misc bug fixes May 1997 - * Submission to Apache Group July 1997 - * - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#include "php_streams.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "php_mime_magic.h" - -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#ifdef PHP_WIN32 -#define PHP_MIME_MAGIC_FILE_PATH PHP_PREFIX "\\magic.mime" -#endif - -static int apprentice(void); -static int ascmagic(unsigned char *, int); -static int is_tar(unsigned char *, int); -static int softmagic(unsigned char *, int); -static void tryit(unsigned char *, int, int); - -static int getvalue(struct magic *, char **); -static int hextoint(int); -static char *getstr(char *, char *, int, int *); -static int parse(char *, int); - -static int match(unsigned char *, int); -static int mget(union VALUETYPE *, unsigned char *, - struct magic *, int); -static int mcheck(union VALUETYPE *, struct magic *); -static void mprint(union VALUETYPE *, struct magic *); -static int mconvert(union VALUETYPE *, struct magic *); -static int magic_rsl_get(char **, char **); -static int magic_process(char * TSRMLS_DC); - -static long from_oct(int, char *); -static int fsmagic(char *fn TSRMLS_DC); - - -#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) -static int zmagic(unsigned char *, int); -#endif - -static magic_req_rec *magic_set_config(void); -static void magic_free_config(magic_req_rec *); - -ZEND_DECLARE_MODULE_GLOBALS(mime_magic) - - -/* True global resources - no need for thread safety here */ -static magic_server_config_rec mime_global; - -/* {{{ mime_magic_functions[] */ -function_entry mime_magic_functions[] = { - PHP_FE(mime_content_type, NULL) - {NULL, NULL, NULL} -}; -/* }}} */ - -/* {{{ mime_magic_module_entry - */ -zend_module_entry mime_magic_module_entry = { -#if ZEND_MODULE_API_NO >= 20010901 - STANDARD_MODULE_HEADER, -#endif - "mime_magic", - mime_magic_functions, - PHP_MINIT(mime_magic), - PHP_MSHUTDOWN(mime_magic), - NULL, - NULL, - PHP_MINFO(mime_magic), -#if ZEND_MODULE_API_NO >= 20010901 - "0.1", -#endif - STANDARD_MODULE_PROPERTIES -}; -/* }}} */ - -#ifdef COMPILE_DL_MIME_MAGIC -ZEND_GET_MODULE(mime_magic) -#endif - -/* {{{ PHP_INI - */ -PHP_INI_BEGIN() -STD_PHP_INI_ENTRY("mime_magic.magicfile", PHP_MIME_MAGIC_FILE_PATH, PHP_INI_SYSTEM, OnUpdateString, magicfile, zend_mime_magic_globals, mime_magic_globals) -STD_PHP_INI_ENTRY("mime_magic.debug", "0", PHP_INI_SYSTEM, OnUpdateBool, debug, zend_mime_magic_globals, mime_magic_globals) -PHP_INI_END() -/* }}} */ - -/* {{{ php_mime_magic_init_globals - */ -static void php_mime_magic_init_globals(zend_mime_magic_globals *mime_magic_globals) -{ - mime_global.magicfile = NULL; -} -/* }}} */ - -/* {{{ PHP_MINIT_FUNCTION - */ -PHP_MINIT_FUNCTION(mime_magic) -{ - ZEND_INIT_MODULE_GLOBALS(mime_magic, php_mime_magic_init_globals, NULL); - REGISTER_INI_ENTRIES(); - - mime_global.magicfile = MIME_MAGIC_G(magicfile); - - if(mime_global.magicfile) { - if(apprentice()) { - MIME_MAGIC_G(status) = "invalid magic file, disabled"; - } else { - MIME_MAGIC_G(status) = "enabled"; - } - } else { - MIME_MAGIC_G(status) = "no magic file given, disabled"; - } - - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_MSHUTDOWN_FUNCTION - */ -PHP_MSHUTDOWN_FUNCTION(mime_magic) -{ - UNREGISTER_INI_ENTRIES(); - if (mime_global.magic != NULL && mime_global.magic != (struct magic *) -1) { - struct magic *iter = mime_global.magic; - while (iter != NULL) { - struct magic *iter_next = iter->next; - free(iter); - iter = iter_next; - } - } - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_MINFO_FUNCTION - */ -PHP_MINFO_FUNCTION(mime_magic) -{ - php_info_print_table_start(); - php_info_print_table_header(2, "mime_magic support", MIME_MAGIC_G(status)); - php_info_print_table_end(); - - DISPLAY_INI_ENTRIES(); -} -/* }}} */ - - -/* {{{ proto string mime_content_type(string filename) - Return content-type for file */ -PHP_FUNCTION(mime_content_type) -{ - char *filename = NULL; - int filename_len; - magic_server_config_rec *conf = &mime_global; - char *content_type=NULL, *content_encoding=NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { - return; - } - - if (conf->magic == (struct magic *)-1) { - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_ERROR, "mime_magic could not be initialized, magic file %s is not avaliable", conf->magicfile); - RETURN_FALSE; - } - - if(!conf->magic) { - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, "mime_magic not initialized"); - RETURN_FALSE; - } - - MIME_MAGIC_G(req_dat) = magic_set_config(); - - if(MIME_MAGIC_OK != magic_process(filename TSRMLS_CC)) { - RETVAL_FALSE; - } else if(MIME_MAGIC_OK != magic_rsl_get(&content_type, &content_encoding)) { - RETVAL_FALSE; - } else { - RETVAL_STRING(content_type, 1); - } - - if(content_type) efree(content_type); - if(content_encoding) efree(content_encoding); - - magic_free_config(MIME_MAGIC_G(req_dat)); -} -/* }}} */ - -#define EATAB {while (isspace((unsigned char) *l)) ++l;} - -/* - * apprentice - load configuration from the magic file r - * API request record - */ -static int apprentice(void) -{ - FILE *f; - char line[BUFSIZ + 1]; - int errs = 0; - int lineno; - char *fname; - magic_server_config_rec *conf = &mime_global; - TSRMLS_FETCH(); - - fname = conf->magicfile; /* todo cwd? */ - f = fopen(fname, "rb"); - if (f == NULL) { - conf->magic = (struct magic *)-1; - return -1; - } - - /* set up the magic list (empty) */ - conf->magic = conf->last = NULL; - - /* parse it */ - for (lineno = 1; fgets(line, BUFSIZ, f) != NULL; lineno++) { - int ws_offset; - - /* delete newline */ - if (line[0]) { - line[strlen(line) - 1] = '\0'; - } - - /* skip leading whitespace */ - ws_offset = 0; - while (line[ws_offset] && isspace(line[ws_offset])) { - ws_offset++; - } - - /* skip blank lines */ - if (line[ws_offset] == 0) { - continue; - } - - /* comment, do not parse */ - if (line[ws_offset] == '#') - continue; - - /* parse it */ - if (parse(line + ws_offset, lineno) != 0) - ++errs; - - if(errs && !MIME_MAGIC_G(debug)) - break; - } - - (void) fclose(f); - - return (errs ? -1 : 0); -} - -/* - * extend the sign bit if the comparison is to be signed - */ -static unsigned long signextend(struct magic *m, unsigned long v) -{ - if (!(m->flag & UNSIGNED)) - switch (m->type) { - /* - * Do not remove the casts below. They are vital. When later - * compared with the data, the sign extension must have happened. - */ - case BYTE: - v = (char) v; - break; - case SHORT: - case BESHORT: - case LESHORT: - v = (short) v; - break; - case DATE: - case BEDATE: - case LEDATE: - case LONG: - case BELONG: - case LELONG: - v = (long) v; - break; - case STRING: - break; - default: - { - TSRMLS_FETCH(); - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, ": can't happen: m->type=%d", m->type); - return -1; - } - } - return v; -} - -/* - * - */ -static int is_valid_mimetype(char *p) -{ - do { - if(!isalnum(*p) && (*p != '-')) return 0; - } while(*(++p) != '/'); - ++p; - do { - if(!isalnum(*p) && (*p != '-')) return 0; - } while(*(++p)); - return 1; -} - -/* - * parse one line from magic file, put into magic[index++] if valid - */ -static int parse(char *l, int lineno) -{ - struct magic *m; - char *t, *s; - magic_server_config_rec *conf = &mime_global; - TSRMLS_FETCH(); - - /* allocate magic structure entry */ - m = (struct magic *) calloc(1, sizeof(struct magic)); - - /* append to linked list */ - m->next = NULL; - if (!conf->magic || !conf->last) { - conf->magic = conf->last = m; - } - else { - conf->last->next = m; - conf->last = m; - } - - /* set values in magic structure */ - m->flag = 0; - m->cont_level = 0; - m->lineno = lineno; - - while (*l == '>') { - ++l; /* step over */ - m->cont_level++; - } - - if (m->cont_level != 0 && *l == '(') { - ++l; /* step over */ - m->flag |= INDIR; - } - - /* get offset, then skip over it */ - m->offset = (int) strtol(l, &t, 0); - if (l == t) { - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, ": (%s:%d) offset `%s' invalid", MIME_MAGIC_G(magicfile), lineno, l); - } - l = t; - - if (m->flag & INDIR) { - m->in.type = LONG; - m->in.offset = 0; - /* - * read [.lbs][+-]nnnnn) - */ - if (*l == '.') { - switch (*++l) { - case 'l': - m->in.type = LONG; - break; - case 's': - m->in.type = SHORT; - break; - case 'b': - m->in.type = BYTE; - break; - default: - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, ": (%s:%d) indirect offset type %c invalid", MIME_MAGIC_G(magicfile), lineno, *l); - break; - } - l++; - } - s = l; - if (*l == '+' || *l == '-') - l++; - if (isdigit((unsigned char) *l)) { - m->in.offset = strtol(l, &t, 0); - if (*s == '-') - m->in.offset = -m->in.offset; - } - else - t = l; - if (*t++ != ')') { - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, ": (%s:%s) missing ')' in indirect offset", MIME_MAGIC_G(magicfile), lineno); - } - l = t; - } - - - while (isdigit((unsigned char) *l)) - ++l; - EATAB; - -#define NBYTE 4 -#define NSHORT 5 -#define NLONG 4 -#define NSTRING 6 -#define NDATE 4 -#define NBESHORT 7 -#define NBELONG 6 -#define NBEDATE 6 -#define NLESHORT 7 -#define NLELONG 6 -#define NLEDATE 6 - - if (*l == 'u') { - ++l; - m->flag |= UNSIGNED; - } - - /* get type, skip it */ - if (strncmp(l, "byte", NBYTE) == 0) { - m->type = BYTE; - l += NBYTE; - } - else if (strncmp(l, "short", NSHORT) == 0) { - m->type = SHORT; - l += NSHORT; - } - else if (strncmp(l, "long", NLONG) == 0) { - m->type = LONG; - l += NLONG; - } - else if (strncmp(l, "string", NSTRING) == 0) { - m->type = STRING; - l += NSTRING; - } - else if (strncmp(l, "date", NDATE) == 0) { - m->type = DATE; - l += NDATE; - } - else if (strncmp(l, "beshort", NBESHORT) == 0) { - m->type = BESHORT; - l += NBESHORT; - } - else if (strncmp(l, "belong", NBELONG) == 0) { - m->type = BELONG; - l += NBELONG; - } - else if (strncmp(l, "bedate", NBEDATE) == 0) { - m->type = BEDATE; - l += NBEDATE; - } - else if (strncmp(l, "leshort", NLESHORT) == 0) { - m->type = LESHORT; - l += NLESHORT; - } - else if (strncmp(l, "lelong", NLELONG) == 0) { - m->type = LELONG; - l += NLELONG; - } - else if (strncmp(l, "ledate", NLEDATE) == 0) { - m->type = LEDATE; - l += NLEDATE; - } - else { - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, ": (%s:%d) type %s invalid", MIME_MAGIC_G(magicfile), lineno, l); - return -1; - } - /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ - if (*l == '&') { - ++l; - m->mask = signextend(m, strtol(l, &l, 0)); - } - else - m->mask = ~0L; - EATAB; - - switch (*l) { - case '>': - case '<': - /* Old-style anding: "0 byte &0x80 dynamically linked" */ - case '&': - case '^': - case '=': - m->reln = *l; - ++l; - break; - case '!': - if (m->type != STRING) { - m->reln = *l; - ++l; - break; - } - /* FALL THROUGH */ - default: - if (*l == 'x' && isspace((unsigned char) l[1])) { - m->reln = *l; - ++l; - goto GetDesc; /* Bill The Cat */ - } - m->reln = '='; - break; - } - EATAB; - - if (getvalue(m, &l)) - return -1; - /* - * now get last part - the description - */ - GetDesc: - EATAB; - if (l[0] == '\b') { - ++l; - m->nospflag = 1; - } - else if ((l[0] == '\\') && (l[1] == 'b')) { - ++l; - ++l; - m->nospflag = 1; - } - else - m->nospflag = 0; - - if(!is_valid_mimetype(l)) { - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, ": (%s:%d) '%s' is not a valid mimetype, etry skipped", MIME_MAGIC_G(magicfile), lineno, l); - return -1; - } - - strncpy(m->desc, l, sizeof(m->desc) - 1); - m->desc[sizeof(m->desc) - 1] = '\0'; - - return 0; -} - -/* - * Read a numeric value from a pointer, into the value union of a magic - * pointer, according to the magic type. Update the string pointer to point - * just after the number read. Return 0 for success, non-zero for failure. - */ -static int getvalue(struct magic *m, char **p) -{ - int slen; - - if (m->type == STRING) { - *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen); - m->vallen = slen; - } - else if (m->reln != 'x') - m->value.l = signextend(m, strtol(*p, p, 0)); - return 0; -} - -/* - * Convert a string containing C character escapes. Stop at an unescaped - * space or tab. Copy the converted version to "p", returning its length in - * *slen. Return updated scan pointer as function result. - */ -static char *getstr(register char *s, register char *p, - int plen, int *slen) -{ - char *origs = s, *origp = p; - char *pmax = p + plen - 1; - register int c; - register int val; - - while ((c = *s++) != '\0') { - if (isspace((unsigned char) c)) - break; - if (p >= pmax) { - TSRMLS_FETCH(); - if(MIME_MAGIC_G(debug)) - php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, "string too long: %s", origs); - break; - } - if (c == '\\') { - switch (c = *s++) { - - case '\0': - goto out; - - default: - *p++ = (char) c; - break; - - case 'n': - *p++ = '\n'; - break; - - case 'r': - *p++ = '\r'; - break; - - case 'b': - *p++ = '\b'; - break; - - case 't': - *p++ = '\t'; - break; - - case 'f': - *p++ = '\f'; - break; - - case 'v': - *p++ = '\v'; - break; - - /* \ and up to 3 octal digits */ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - val = c - '0'; - c = *s++; /* try for 2 */ - if (c >= '0' && c <= '7') { - val = (val << 3) | (c - '0'); - c = *s++; /* try for 3 */ - if (c >= '0' && c <= '7') - val = (val << 3) | (c - '0'); - else - --s; - } - else - --s; - *p++ = (char) val; - break; - - /* \x and up to 3 hex digits */ - case 'x': - val = 'x'; /* Default if no digits */ - c = hextoint(*s++); /* Get next char */ - if (c >= 0) { - val = c; - c = hextoint(*s++); - if (c >= 0) { - val = (val << 4) + c; - c = hextoint(*s++); - if (c >= 0) { - val = (val << 4) + c; - } - else - --s; - } - else - --s; - } - else - --s; - *p++ = (char) val; - break; - } - } - else - *p++ = (char) c; - } - out: - *p = '\0'; - *slen = p - origp; - return s; -} - -/* Single hex char to int; -1 if not a hex char. */ -static int hextoint(int c) -{ - if (isdigit((unsigned char) c)) - return c - '0'; - if ((c >= 'a') && (c <= 'f')) - return c + 10 - 'a'; - if ((c >= 'A') && (c <= 'F')) - return c + 10 - 'A'; - return -1; -} - - -/* - * RSL (result string list) processing routines - * - * These collect strings that would have been printed in fragments by file(1) - * into a list of magic_rsl structures with the strings. When complete, - * they're concatenated together to become the MIME content and encoding - * types. - * - * return value conventions for these functions: functions which return int: - * failure = -1, other = result functions which return pointers: failure = 0, - * other = result - */ - -/* allocate a per-request structure and put it in the request record */ -static magic_req_rec *magic_set_config(void) -{ - magic_req_rec *req_dat = (magic_req_rec *) emalloc(sizeof(magic_req_rec)); - - req_dat->head = req_dat->tail = (magic_rsl *) NULL; - return req_dat; -} - -static void magic_free_config(magic_req_rec *req_dat) { - magic_rsl *curr, *next; - - if(!req_dat) return; - - curr = req_dat->head; - while(curr) { - next = curr->next; - efree(curr->str); - efree(curr); - curr = next; - } - - efree(req_dat); -} - -/* add a string to the result string list for this request */ -/* it is the responsibility of the caller to allocate "str" */ -static int magic_rsl_add(char *str) -{ - magic_req_rec *req_dat; - magic_rsl *rsl; - TSRMLS_FETCH(); - - req_dat = MIME_MAGIC_G(req_dat); - - /* make sure we have a list to put it in */ - if (!req_dat) { - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "request config should not be NULL"); - if (!(req_dat = magic_set_config())) { - /* failure */ - return -1; - } - } - - /* allocate the list entry */ - rsl = (magic_rsl *) emalloc(sizeof(magic_rsl)); - - /* fill it */ - rsl->str = estrdup(str); - rsl->next = (magic_rsl *) NULL; - - /* append to the list */ - if (req_dat->head && req_dat->tail) { - req_dat->tail->next = rsl; - req_dat->tail = rsl; - } - else { - req_dat->head = req_dat->tail = rsl; - } - - /* success */ - return 0; -} - -/* RSL hook for puts-type functions */ -static int magic_rsl_puts(char *str) -{ - return magic_rsl_add(str); -} - -/* RSL hook for printf-type functions */ -static int magic_rsl_printf(char *str,...) -{ - va_list ap; - - char buf[MAXMIMESTRING]; - - /* assemble the string into the buffer */ - va_start(ap, str); - vsnprintf(buf, sizeof(buf), str, ap); - va_end(ap); - - /* add the buffer to the list */ - return magic_rsl_add(buf); -} - -/* RSL hook for putchar-type functions */ -static int magic_rsl_putchar(char c) -{ - char str[2]; - - /* high overhead for 1 char - just hope they don't do this much */ - str[0] = c; - str[1] = '\0'; - return magic_rsl_add(str); -} - -/* allocate and copy a contiguous string from a result string list */ -static char *rsl_strdup(int start_frag, int start_pos, int len) -{ - char *result; /* return value */ - int cur_frag, /* current fragment number/counter */ - cur_pos, /* current position within fragment */ - res_pos; /* position in result string */ - magic_rsl *frag; /* list-traversal pointer */ - magic_req_rec *req_dat; - TSRMLS_FETCH(); - - req_dat = MIME_MAGIC_G(req_dat); - - /* allocate the result string */ - result = (char *) emalloc(len + 1); - - /* loop through and collect the string */ - res_pos = 0; - for (frag = req_dat->head, cur_frag = 0; - frag->next; - frag = frag->next, cur_frag++) { - /* loop to the first fragment */ - if (cur_frag < start_frag) - continue; - - /* loop through and collect chars */ - for (cur_pos = (cur_frag == start_frag) ? start_pos : 0; - frag->str[cur_pos]; - cur_pos++) { - if (cur_frag >= start_frag - && cur_pos >= start_pos - && res_pos <= len) { - result[res_pos++] = frag->str[cur_pos]; - if (res_pos > len) { - break; - } - } - } - } - - /* clean up and return */ - result[res_pos] = 0; - - return result; -} - -/* - * magic_process - process input file r Apache API request record - * (formerly called "process" in file command, prefix added for clarity) Opens - * the file and reads a fixed-size buffer to begin processing the contents. - */ -static int magic_process(char *filename TSRMLS_DC) -{ - php_stream *stream; - unsigned char buf[HOWMANY + 1]; /* one extra for terminating '\0' */ - int nbytes = 0; /* number of bytes read from a datafile */ - int result; - - /* - * first try judging the file based on its filesystem status - */ - switch ((result = fsmagic(filename TSRMLS_CC))) { - case MIME_MAGIC_DONE: - magic_rsl_putchar('\n'); - return MIME_MAGIC_OK; - case MIME_MAGIC_OK: - break; - default: - /* fatal error, bail out */ - return result; - } - - stream = php_stream_open_wrapper(filename, "rb", IGNORE_PATH | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL); - - if (stream == NULL) { - /* We can't open it, but we were able to stat it. */ - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't read `%s'", filename); - /* let some other handler decide what the problem is */ - return MIME_MAGIC_DECLINED; - } - - /* - * try looking at the first HOWMANY bytes - */ - if ((nbytes = php_stream_read(stream, (char *) buf, sizeof(buf) - 1)) == -1) { - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "read failed: %s", filename); - return MIME_MAGIC_ERROR; - } - - if (nbytes == 0) - magic_rsl_puts(MIME_TEXT_UNKNOWN); - else { - buf[nbytes++] = '\0'; /* null-terminate it */ - tryit(buf, nbytes, 1); - } - - (void) php_stream_close(stream); - (void) magic_rsl_putchar('\n'); - - return MIME_MAGIC_OK; -} - -static void tryit(unsigned char *buf, int nb, int checkzmagic) -{ - /* - * Try compression stuff - */ -#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) - if (checkzmagic == 1) { - if (zmagic(buf, nb) == 1) - return; - } -#endif - - /* - * try tests in /etc/magic (or surrogate magic file) - */ - if (softmagic(buf, nb) == 1) - return; - - /* - * try known keywords, check for ascii-ness too. - */ - if (ascmagic(buf, nb) == 1) - return; - - /* - * abandon hope, all ye who remain here - */ - magic_rsl_puts(MIME_BINARY_UNKNOWN); -} - - -/* - * return MIME_MAGIC_DONE to indicate it's been handled - * return MIME_MAGIC_OK to indicate it's a regular file still needing handling - * other returns indicate a failure of some sort - */ -static int fsmagic(char *filename TSRMLS_DC) -{ - php_stream_statbuf stat_ssb; - - if(!php_stream_stat_path(filename, &stat_ssb)) { - return MIME_MAGIC_OK; - } - - switch (stat_ssb.sb.st_mode & S_IFMT) { - case S_IFDIR: - magic_rsl_puts(DIR_MAGIC_TYPE); - return MIME_MAGIC_DONE; - case S_IFCHR: - /* - * (void) magic_rsl_printf(r,"character special (%d/%d)", - * major(sb->st_rdev), minor(sb->st_rdev)); - */ - (void) magic_rsl_puts(MIME_BINARY_UNKNOWN); - return MIME_MAGIC_DONE; -#ifdef S_IFBLK - case S_IFBLK: - /* - * (void) magic_rsl_printf(r,"block special (%d/%d)", - * major(sb->st_rdev), minor(sb->st_rdev)); - */ - (void) magic_rsl_puts(MIME_BINARY_UNKNOWN); - return MIME_MAGIC_DONE; - /* TODO add code to handle V7 MUX and Blit MUX files */ -#endif -#ifdef S_IFIFO - case S_IFIFO: - /* - * magic_rsl_puts(r,"fifo (named pipe)"); - */ - (void) magic_rsl_puts(MIME_BINARY_UNKNOWN); - return MIME_MAGIC_DONE; -#endif -#ifdef S_IFLNK - case S_IFLNK: - /* We used stat(), the only possible reason for this is that the - * symlink is broken. - */ - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "broken symlink (%s)", filename); - return MIME_MAGIC_ERROR; -#endif -#ifdef S_IFSOCK -#ifndef __COHERENT__ - case S_IFSOCK: - magic_rsl_puts(MIME_BINARY_UNKNOWN); - return MIME_MAGIC_DONE; -#endif -#endif - case S_IFREG: - break; - case 0: - break; - default: - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid mode 0%o.", (unsigned int)stat_ssb.sb.st_mode); - return MIME_MAGIC_ERROR; - } - - /* - * regular file, check next possibility - */ - if (stat_ssb.sb.st_size == 0) { - magic_rsl_puts(MIME_TEXT_UNKNOWN); - return MIME_MAGIC_DONE; - } - return MIME_MAGIC_OK; -} - -/* - * softmagic - lookup one file in database (already read from /etc/magic by - * apprentice.c). Passed the name and FILE * of one file to be typed. - */ -/* ARGSUSED1 *//* nbytes passed for regularity, maybe need later */ -static int softmagic(unsigned char *buf, int nbytes) -{ - if (match(buf, nbytes)) - return 1; - - return 0; -} - -/* - * Go through the whole list, stopping if you find a match. Process all the - * continuations of that match before returning. - * - * We support multi-level continuations: - * - * At any time when processing a successful top-level match, there is a current - * continuation level; it represents the level of the last successfully - * matched continuation. - * - * Continuations above that level are skipped as, if we see one, it means that - * the continuation that controls them - i.e, the lower-level continuation - * preceding them - failed to match. - * - * Continuations below that level are processed as, if we see one, it means - * we've finished processing or skipping higher-level continuations under the - * control of a successful or unsuccessful lower-level continuation, and are - * now seeing the next lower-level continuation and should process it. The - * current continuation level reverts to the level of the one we're seeing. - * - * Continuations at the current level are processed as, if we see one, there's - * no lower-level continuation that may have failed. - * - * If a continuation matches, we bump the current continuation level so that - * higher-level continuations are processed. - */ -static int match(unsigned char *s, int nbytes) -{ - int cont_level = 0; - int need_separator = 0; - union VALUETYPE p; - magic_server_config_rec *conf = &mime_global; - struct magic *m; - - for (m = conf->magic; m; m = m->next) { - /* check if main entry matches */ - if (!mget(&p, s, m, nbytes) || - !mcheck(&p, m)) { - struct magic *m_cont; - - /* - * main entry didn't match, flush its continuations - */ - if (!m->next || (m->next->cont_level == 0)) { - continue; - } - - m_cont = m->next; - while (m_cont && (m_cont->cont_level != 0)) { - /* - * this trick allows us to keep *m in sync when the continue - * advances the pointer - */ - m = m_cont; - m_cont = m_cont->next; - } - continue; - } - - /* if we get here, the main entry rule was a match */ - /* this will be the last run through the loop */ - - /* print the match */ - mprint(&p, m); - - /* - * If we printed something, we'll need to print a blank before we - * print something else. - */ - if (m->desc[0]) - need_separator = 1; - /* and any continuations that match */ - cont_level++; - /* - * while (m && m->next && m->next->cont_level != 0 && ( m = m->next - * )) - */ - m = m->next; - while (m && (m->cont_level != 0)) { - if (cont_level >= m->cont_level) { - if (cont_level > m->cont_level) { - /* - * We're at the end of the level "cont_level" - * continuations. - */ - cont_level = m->cont_level; - } - if (mget(&p, s, m, nbytes) && - mcheck(&p, m)) { - /* - * This continuation matched. Print its message, with a - * blank before it if the previous item printed and this - * item isn't empty. - */ - /* space if previous printed */ - if (need_separator - && (m->nospflag == 0) - && (m->desc[0] != '\0') - ) { - (void) magic_rsl_putchar(' '); - need_separator = 0; - } - mprint(&p, m); - if (m->desc[0]) - need_separator = 1; - - /* - * If we see any continuations at a higher level, process - * them. - */ - cont_level++; - } - } - - /* move to next continuation record */ - m = m->next; - } - return 1; /* all through */ - } - return 0; /* no match at all */ -} - -/* an optimization over plain strcmp() */ -#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) - -static int ascmagic(unsigned char *buf, int nbytes) -{ - int has_escapes = 0; - unsigned char *s; - char nbuf[HOWMANY + 1]; /* one extra for terminating '\0' */ - char *token; - register struct names *p; - int small_nbytes; - - /* these are easy, do them first */ - - /* - * for troff, look for . + letter + letter or .\"; this must be done to - * disambiguate tar archives' ./file and other trash from real troff - * input. - */ - if (*buf == '.') { - unsigned char *tp = buf + 1; - - while (isspace(*tp)) - ++tp; /* skip leading whitespace */ - if ((isalnum(*tp) || *tp == '\\') && - (isalnum(*(tp + 1)) || *tp == '"')) { - magic_rsl_puts("application/x-troff"); - return 1; - } - } - if ((*buf == 'c' || *buf == 'C') && isspace(*(buf + 1))) { - /* Fortran */ - magic_rsl_puts("text/plain"); - return 1; - } - - /* look for tokens from names.h - this is expensive!, so we'll limit - * ourselves to only SMALL_HOWMANY bytes */ - small_nbytes = (nbytes > SMALL_HOWMANY) ? SMALL_HOWMANY : nbytes; - /* make a copy of the buffer here because strtok() will destroy it */ - s = (unsigned char *) memcpy(nbuf, buf, small_nbytes); - s[small_nbytes] = '\0'; - has_escapes = (memchr(s, '\033', small_nbytes) != NULL); - /* XXX: not multithread safe */ - while ((token = strtok((char *) s, " \t\n\r\f")) != NULL) { - s = NULL; /* make strtok() keep on tokin' */ - for (p = names; p < names + NNAMES; p++) { - if (STREQ(p->name, token)) { - magic_rsl_puts(types[p->type]); - if (has_escapes) - magic_rsl_puts(" (with escape sequences)"); - return 1; - } - } - } - - switch (is_tar(buf, nbytes)) { - case 1: - /* V7 tar archive */ - magic_rsl_puts("application/x-tar"); - return 1; - case 2: - /* POSIX tar archive */ - magic_rsl_puts("application/x-tar"); - return 1; - } - - /* all else fails, but it is ascii... */ - if (has_escapes) { - /* text with escape sequences */ - /* we leave this open for further differentiation later */ - magic_rsl_puts("text/plain"); - } - else { - /* plain text */ - magic_rsl_puts("text/plain"); - } - return 1; -} - -/* - * is_tar() -- figure out whether file is a tar archive. - * - * Stolen (by author of file utility) from the public domain tar program: Public - * Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu). - * - * @(#)list.c 1.18 9/23/86 Public Domain - gnu $Id: mod_mime_magic.c,v 1.7 - * 1997/06/24 00:41:02 ikluft Exp ikluft $ - * - * Comments changed and some code/comments reformatted for file command by Ian - * Darwin. - */ - -#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) - -/* - * Return 0 if the checksum is bad (i.e., probably not a tar archive), 1 for - * old UNIX tar file, 2 for Unix Std (POSIX) tar file. - */ - -static int is_tar(unsigned char *buf, int nbytes) -{ - register union record *header = (union record *) buf; - register int i; - register long sum, recsum; - register char *p; - - if (nbytes < sizeof(union record)) - return 0; - - recsum = from_oct(8, header->header.chksum); - - sum = 0; - p = header->charptr; - for (i = sizeof(union record); --i >= 0;) { - /* - * We can't use unsigned char here because of old compilers, e.g. V7. - */ - sum += 0xFF & *p++; - } - - /* Adjust checksum to count the "chksum" field as blanks. */ - for (i = sizeof(header->header.chksum); --i >= 0;) - sum -= 0xFF & header->header.chksum[i]; - sum += ' ' * sizeof header->header.chksum; - - if (sum != recsum) - return 0; /* Not a tar archive */ - - if (0 == strcmp(header->header.magic, TMAGIC)) - return 2; /* Unix Standard tar archive */ - - return 1; /* Old fashioned tar archive */ -} - - -/* - * Quick and dirty octal conversion. - * - * Result is -1 if the field is invalid (all blank, or nonoctal). - */ -static long from_oct(int digs, char *where) -{ - register long value; - - while (isspace(*where)) { /* Skip spaces */ - where++; - if (--digs <= 0) - return -1; /* All blank field */ - } - value = 0; - while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */ - value = (value << 3) | (*where++ - '0'); - --digs; - } - - if (digs > 0 && *where && !isspace(*where)) - return -1; /* Ended on non-space/nul */ - - return value; -} - -static int mget(union VALUETYPE *p, unsigned char *s, - struct magic *m, int nbytes) -{ - long offset = m->offset; - - if (offset + (long)sizeof(union VALUETYPE) > nbytes) - return 0; - - memcpy(p, s + offset, sizeof(union VALUETYPE)); - - if (!mconvert(p, m)) - return 0; - - if (m->flag & INDIR) { - - switch (m->in.type) { - case BYTE: - offset = p->b + m->in.offset; - break; - case SHORT: - offset = p->h + m->in.offset; - break; - case LONG: - offset = p->l + m->in.offset; - break; - } - - if (offset + (long)sizeof(union VALUETYPE) > nbytes) - return 0; - - memcpy(p, s + offset, sizeof(union VALUETYPE)); - - if (!mconvert(p, m)) - return 0; - } - return 1; -} - -static int mcheck(union VALUETYPE *p, struct magic *m) -{ - register unsigned long l = m->value.l; - register unsigned long v; - int matched; - TSRMLS_FETCH(); - - if ((m->value.s[0] == 'x') && (m->value.s[1] == '\0')) { - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "BOINK"); - return 1; - } - - switch (m->type) { - case BYTE: - v = p->b; - break; - - case SHORT: - case BESHORT: - case LESHORT: - v = p->h; - break; - - case LONG: - case BELONG: - case LELONG: - case DATE: - case BEDATE: - case LEDATE: - v = p->l; - break; - - case STRING: - l = 0; - /* - * What we want here is: v = strncmp(m->value.s, p->s, m->vallen); - * but ignoring any nulls. bcmp doesn't give -/+/0 and isn't - * universally available anyway. - */ - v = 0; - { - register unsigned char *a = (unsigned char *) m->value.s; - register unsigned char *b = (unsigned char *) p->s; - register int len = m->vallen; - - while (--len >= 0) - if ((v = *b++ - *a++) != 0) - break; - } - break; - default: - /* bogosity, pretend that it just wasn't a match */ - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid type %d in mcheck().", m->type); - return 0; - } - - v = signextend(m, v) & m->mask; - - switch (m->reln) { - case 'x': - matched = 1; - break; - - case '!': - matched = v != l; - break; - - case '=': - matched = v == l; - break; - - case '>': - if (m->flag & UNSIGNED) { - matched = v > l; - } - else { - matched = (long) v > (long) l; - } - break; - - case '<': - if (m->flag & UNSIGNED) { - matched = v < l; - } - else { - matched = (long) v < (long) l; - } - break; - - case '&': - matched = (v & l) == l; - break; - - case '^': - matched = (v & l) != l; - break; - - default: - /* bogosity, pretend it didn't match */ - matched = 0; - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "mcheck: can't happen: invalid relation %d.", m->reln); - break; - } - - return matched; -} - -#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) -/* - * compress routines: zmagic() - returns 0 if not recognized, uncompresses - * and prints information if recognized uncompress(s, method, old, n, newch) - * - uncompress old into new, using method, return sizeof new - */ - -static int zmagic(unsigned char *buf, int nbytes) -{ - if (buf[0] != 0x1f) return 0; - - switch(buf[1]) { - case 0x9d: /* .Z "x-compress" */ - break; /* not yet supportet */ - - case 0x8b: /* .gz "x-gzip" */ -#if 0 - if ((newsize = magic_uncompress(i, &newbuf, nbytes)) > 0) { - tryit(newbuf, newsize, 0); - - /* set encoding type in the request record */ - /* TODO r->content_encoding = compr[i].encoding; */ - } -#endif - break; /* not yet supported */ - - case 0x1e: /* simply packed ? */ - break; /* not yet supported */ - } - - return 0; -} -#endif - -static void mprint(union VALUETYPE *p, struct magic *m) -{ - char *pp, *rt; - unsigned long v; - - switch (m->type) { - case BYTE: - v = p->b; - break; - - case SHORT: - case BESHORT: - case LESHORT: - v = p->h; - break; - - case LONG: - case BELONG: - case LELONG: - v = p->l; - break; - - case STRING: - if (m->reln == '=') { - (void) magic_rsl_printf(m->desc, m->value.s); - } - else { - (void) magic_rsl_printf(m->desc, p->s); - } - return; - - case DATE: - case BEDATE: - case LEDATE: - /* XXX: not multithread safe */ - pp = ctime((time_t *) & p->l); - if ((rt = strchr(pp, '\n')) != NULL) - *rt = '\0'; - (void) magic_rsl_printf(m->desc, pp); - return; - default: - { - TSRMLS_FETCH(); - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid m->type (%d) in mprint().", m->type); - return; - } - } - - v = signextend(m, v) & m->mask; - (void) magic_rsl_printf(m->desc, (unsigned long) v); -} - -/* - * Convert the byte order of the data we are looking at - */ -static int mconvert(union VALUETYPE *p, struct magic *m) -{ - char *rt; - - switch (m->type) { - case BYTE: - case SHORT: - case LONG: - case DATE: - return 1; - case STRING: - /* Null terminate and eat the return */ - p->s[sizeof(p->s) - 1] = '\0'; - if ((rt = strchr(p->s, '\n')) != NULL) - *rt = '\0'; - return 1; - case BESHORT: - p->h = (short) ((p->hs[0] << 8) | (p->hs[1])); - return 1; - case BELONG: - case BEDATE: - p->l = (long) - ((p->hl[0] << 24) | (p->hl[1] << 16) | (p->hl[2] << 8) | (p->hl[3])); - return 1; - case LESHORT: - p->h = (short) ((p->hs[1] << 8) | (p->hs[0])); - return 1; - case LELONG: - case LEDATE: - p->l = (long) - ((p->hl[3] << 24) | (p->hl[2] << 16) | (p->hl[1] << 8) | (p->hl[0])); - return 1; - default: - { - TSRMLS_FETCH(); - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid type %d in mconvert().", m->type); - return 0; - } - } -} - - -/* states for the state-machine algorithm in magic_rsl_to_request() */ -typedef enum { - rsl_leading_space, rsl_type, rsl_subtype, rsl_separator, rsl_encoding -} rsl_states; - -/* process the RSL and set the MIME info in the request record */ -static int magic_rsl_get(char **content_type, char **content_encoding) -{ - int cur_frag, /* current fragment number/counter */ - cur_pos, /* current position within fragment */ - type_frag, /* content type starting point: fragment */ - type_pos, /* content type starting point: position */ - type_len, /* content type length */ - encoding_frag, /* content encoding starting point: fragment */ - encoding_pos, /* content encoding starting point: position */ - encoding_len; /* content encoding length */ - - magic_rsl *frag; /* list-traversal pointer */ - rsl_states state; - - magic_req_rec *req_dat; - - TSRMLS_FETCH(); - - req_dat = MIME_MAGIC_G(req_dat); - - /* check if we have a result */ - if (!req_dat || !req_dat->head) { - /* empty - no match, we defer to other Apache modules */ - return MIME_MAGIC_DECLINED; - } - - /* start searching for the type and encoding */ - state = rsl_leading_space; - type_frag = type_pos = type_len = 0; - encoding_frag = encoding_pos = encoding_len = 0; - for (frag = req_dat->head, cur_frag = 0; - frag && frag->next; - frag = frag->next, cur_frag++) { - /* loop through the characters in the fragment */ - for (cur_pos = 0; frag->str[cur_pos]; cur_pos++) { - if (isspace(frag->str[cur_pos])) { - /* process whitespace actions for each state */ - if (state == rsl_leading_space) { - /* eat whitespace in this state */ - continue; - } - else if (state == rsl_type) { - /* whitespace: type has no slash! */ - return MIME_MAGIC_DECLINED; - } - else if (state == rsl_subtype) { - /* whitespace: end of MIME type */ - state++; - continue; - } - else if (state == rsl_separator) { - /* eat whitespace in this state */ - continue; - } - else if (state == rsl_encoding) { - /* whitespace: end of MIME encoding */ - /* we're done */ - frag = req_dat->tail; - break; - } - else { - /* should not be possible */ - /* abandon malfunctioning module */ - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, ": bad state %d (ws)", state); - return MIME_MAGIC_DECLINED; - } - /* NOTREACHED */ - } - else if (state == rsl_type && - frag->str[cur_pos] == '/') { - /* copy the char and go to rsl_subtype state */ - type_len++; - state++; - } - else { - /* process non-space actions for each state */ - if (state == rsl_leading_space) { - /* non-space: begin MIME type */ - state++; - type_frag = cur_frag; - type_pos = cur_pos; - type_len = 1; - continue; - } - else if (state == rsl_type || - state == rsl_subtype) { - /* non-space: adds to type */ - type_len++; - continue; - } - else if (state == rsl_separator) { - /* non-space: begin MIME encoding */ - state++; - encoding_frag = cur_frag; - encoding_pos = cur_pos; - encoding_len = 1; - continue; - } - else if (state == rsl_encoding) { - /* non-space: adds to encoding */ - encoding_len++; - continue; - } - else { - /* should not be possible */ - /* abandon malfunctioning module */ - if(MIME_MAGIC_G(debug)) - php_error_docref(NULL TSRMLS_CC, E_WARNING, "bad state %d (ns)", state); - return MIME_MAGIC_DECLINED; - } - /* NOTREACHED */ - } - /* NOTREACHED */ - } - } - - /* if we ended prior to state rsl_subtype, we had incomplete info */ - if (state != rsl_subtype && state != rsl_separator && - state != rsl_encoding) { - /* defer to other modules */ - return MIME_MAGIC_DECLINED; - } - - /* save the info in the request record */ - if (state == rsl_subtype || state == rsl_encoding || - state == rsl_encoding) { - char *tmp; - tmp = rsl_strdup(type_frag, type_pos, type_len); - /* XXX: this could be done at config time I'm sure... but I'm - * confused by all this magic_rsl stuff. -djg */ - /* TODO ap_content_type_tolower(tmp); */ - *content_type = tmp; - } - if (state == rsl_encoding) { - char *tmp; - tmp = rsl_strdup(encoding_frag, - encoding_pos, encoding_len); - /* XXX: this could be done at config time I'm sure... but I'm - * confused by all this magic_rsl stuff. -djg */ - /* TODO ap_str_tolower(tmp); */ - *content_encoding = tmp; - } - - /* detect memory allocation errors */ - if (!content_type || - (state == rsl_encoding && !*content_encoding)) { - return MIME_MAGIC_ERROR; - } - - /* success! */ - return MIME_MAGIC_OK; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ |