Annotation of embedaddon/php/ext/fileinfo/libmagic/ascmagic.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (c) Ian F. Darwin 1986-1995.
                      3:  * Software written by Ian F. Darwin and others;
                      4:  * maintained 1995-present by Christos Zoulas and others.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice immediately at the beginning of the file, without modification,
                     11:  *    this list of conditions, and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     20:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  */
                     28: /*
1.1.1.2 ! misho      29:  * ASCII magic -- try to detect text encoding.
1.1       misho      30:  *
                     31:  * Extensively modified by Eric Fischer <enf@pobox.com> in July, 2000,
                     32:  * to handle character codes other than ASCII on a unified basis.
                     33:  */
                     34: 
                     35: #include "file.h"
                     36: 
                     37: #ifndef        lint
1.1.1.2 ! misho      38: FILE_RCSID("@(#)$File: ascmagic.c,v 1.84 2011/12/08 12:38:24 rrt Exp $")
1.1       misho      39: #endif /* lint */
                     40: 
                     41: #include "magic.h"
                     42: #include <string.h>
                     43: #include <memory.h>
                     44: #include <ctype.h>
                     45: #include <stdlib.h>
                     46: #ifdef HAVE_UNISTD_H
                     47: #include <unistd.h>
                     48: #endif
                     49: 
                     50: #define MAXLINELEN 300 /* longest sane line length */
                     51: #define ISSPC(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n' \
                     52:                  || (x) == 0x85 || (x) == '\f')
                     53: 
                     54: private unsigned char *encode_utf8(unsigned char *, size_t, unichar *, size_t);
                     55: private size_t trim_nuls(const unsigned char *, size_t);
                     56: 
                     57: /*
                     58:  * Undo the NUL-termination kindly provided by process()
                     59:  * but leave at least one byte to look at
                     60:  */
                     61: private size_t
                     62: trim_nuls(const unsigned char *buf, size_t nbytes)
                     63: {
                     64:        while (nbytes > 1 && buf[nbytes - 1] == '\0')
                     65:                nbytes--;
                     66: 
                     67:        return nbytes;
                     68: }
                     69: 
                     70: protected int
1.1.1.2 ! misho      71: file_ascmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
        !            72:        int text)
1.1       misho      73: {
                     74:        unichar *ubuf = NULL;
                     75:        size_t ulen;
                     76:        int rv = 1;
                     77: 
                     78:        const char *code = NULL;
                     79:        const char *code_mime = NULL;
                     80:        const char *type = NULL;
                     81: 
                     82:        if (ms->flags & MAGIC_APPLE)
                     83:                return 0;
                     84: 
                     85:        nbytes = trim_nuls(buf, nbytes);
                     86: 
                     87:        /* If file doesn't look like any sort of text, give up. */
                     88:        if (file_encoding(ms, buf, nbytes, &ubuf, &ulen, &code, &code_mime,
1.1.1.2 ! misho      89:            &type) == 0)
1.1       misho      90:                rv = 0;
1.1.1.2 ! misho      91:         else
        !            92:                rv = file_ascmagic_with_encoding(ms, buf, nbytes, ubuf, ulen, code,
        !            93:                                                 type, text);
1.1       misho      94: 
1.1.1.2 ! misho      95:        free(ubuf);
1.1       misho      96: 
                     97:        return rv;
                     98: }
                     99: 
                    100: protected int
                    101: file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf,
                    102:     size_t nbytes, unichar *ubuf, size_t ulen, const char *code,
1.1.1.2 ! misho     103:     const char *type, int text)
1.1       misho     104: {
                    105:        unsigned char *utf8_buf = NULL, *utf8_end;
                    106:        size_t mlen, i;
                    107:        int rv = -1;
                    108:        int mime = ms->flags & MAGIC_MIME;
                    109: 
                    110:        const char *subtype = NULL;
                    111:        const char *subtype_mime = NULL;
                    112: 
                    113:        int has_escapes = 0;
                    114:        int has_backspace = 0;
                    115:        int seen_cr = 0;
                    116: 
                    117:        int n_crlf = 0;
                    118:        int n_lf = 0;
                    119:        int n_cr = 0;
                    120:        int n_nel = 0;
1.1.1.2 ! misho     121:        int executable = 0;
1.1       misho     122: 
                    123:        size_t last_line_end = (size_t)-1;
                    124:        int has_long_lines = 0;
                    125: 
                    126:        if (ms->flags & MAGIC_APPLE)
                    127:                return 0;
                    128: 
                    129:        nbytes = trim_nuls(buf, nbytes);
                    130: 
                    131:        /* If we have fewer than 2 bytes, give up. */
                    132:        if (nbytes <= 1) {
                    133:                rv = 0;
                    134:                goto done;
                    135:        }
                    136: 
1.1.1.2 ! misho     137:        if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
        !           138:                /* Convert ubuf to UTF-8 and try text soft magic */
        !           139:                /* malloc size is a conservative overestimate; could be
        !           140:                   improved, or at least realloced after conversion. */
        !           141:                mlen = ulen * 6;
        !           142:                utf8_buf = emalloc(mlen);
1.1       misho     143: 
1.1.1.2 ! misho     144:                if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen))
        !           145:                    == NULL)
        !           146:                        goto done;
        !           147:                if ((rv = file_softmagic(ms, utf8_buf,
        !           148:                    (size_t)(utf8_end - utf8_buf), TEXTTEST, text)) == 0)
        !           149:                        rv = -1;
1.1       misho     150:        }
                    151: 
                    152:        /* Now try to discover other details about the file. */
                    153:        for (i = 0; i < ulen; i++) {
                    154:                if (ubuf[i] == '\n') {
                    155:                        if (seen_cr)
                    156:                                n_crlf++;
                    157:                        else
                    158:                                n_lf++;
                    159:                        last_line_end = i;
                    160:                } else if (seen_cr)
                    161:                        n_cr++;
                    162: 
                    163:                seen_cr = (ubuf[i] == '\r');
                    164:                if (seen_cr)
                    165:                        last_line_end = i;
                    166: 
                    167:                if (ubuf[i] == 0x85) { /* X3.64/ECMA-43 "next line" character */
                    168:                        n_nel++;
                    169:                        last_line_end = i;
                    170:                }
                    171: 
                    172:                /* If this line is _longer_ than MAXLINELEN, remember it. */
                    173:                if (i > last_line_end + MAXLINELEN)
                    174:                        has_long_lines = 1;
                    175: 
                    176:                if (ubuf[i] == '\033')
                    177:                        has_escapes = 1;
                    178:                if (ubuf[i] == '\b')
                    179:                        has_backspace = 1;
                    180:        }
                    181: 
                    182:        /* Beware, if the data has been truncated, the final CR could have
                    183:           been followed by a LF.  If we have HOWMANY bytes, it indicates
                    184:           that the data might have been truncated, probably even before
                    185:           this function was called. */
                    186:        if (seen_cr && nbytes < HOWMANY)
                    187:                n_cr++;
                    188: 
                    189:        if (strcmp(type, "binary") == 0) {
                    190:                rv = 0;
                    191:                goto done;
                    192:        }
                    193:        if (mime) {
1.1.1.2 ! misho     194:                if (!file_printedlen(ms) && (mime & MAGIC_MIME_TYPE) != 0) {
1.1       misho     195:                        if (subtype_mime) {
                    196:                                if (file_printf(ms, "%s", subtype_mime) == -1)
                    197:                                        goto done;
                    198:                        } else {
                    199:                                if (file_printf(ms, "text/plain") == -1)
                    200:                                        goto done;
                    201:                        }
                    202:                }
                    203:        } else {
1.1.1.2 ! misho     204:                if (file_printedlen(ms)) {
        !           205:                        switch (file_replace(ms, " text$", ", ")) {
        !           206:                        case 0:
        !           207:                                switch (file_replace(ms, " text executable$",
        !           208:                                    ", ")) {
        !           209:                                case 0:
        !           210:                                        if (file_printf(ms, ", ") == -1)
        !           211:                                                goto done;
        !           212:                                case -1:
        !           213:                                        goto done;
        !           214:                                default:
        !           215:                                        executable = 1;
        !           216:                                        break;
        !           217:                                }
        !           218:                                break;
        !           219:                        case -1:
        !           220:                                goto done;
        !           221:                        default:
        !           222:                                break;
        !           223:                        }
        !           224:                }
        !           225: 
1.1       misho     226:                if (file_printf(ms, "%s", code) == -1)
                    227:                        goto done;
                    228: 
                    229:                if (subtype) {
                    230:                        if (file_printf(ms, " %s", subtype) == -1)
                    231:                                goto done;
                    232:                }
                    233: 
                    234:                if (file_printf(ms, " %s", type) == -1)
                    235:                        goto done;
                    236: 
1.1.1.2 ! misho     237:                if (executable)
        !           238:                        if (file_printf(ms, " executable") == -1)
        !           239:                                goto done;
        !           240: 
1.1       misho     241:                if (has_long_lines)
                    242:                        if (file_printf(ms, ", with very long lines") == -1)
                    243:                                goto done;
                    244: 
                    245:                /*
                    246:                 * Only report line terminators if we find one other than LF,
                    247:                 * or if we find none at all.
                    248:                 */
                    249:                if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) ||
                    250:                    (n_crlf != 0 || n_cr != 0 || n_nel != 0)) {
                    251:                        if (file_printf(ms, ", with") == -1)
                    252:                                goto done;
                    253: 
                    254:                        if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) {
                    255:                                if (file_printf(ms, " no") == -1)
                    256:                                        goto done;
                    257:                        } else {
                    258:                                if (n_crlf) {
                    259:                                        if (file_printf(ms, " CRLF") == -1)
                    260:                                                goto done;
                    261:                                        if (n_cr || n_lf || n_nel)
                    262:                                                if (file_printf(ms, ",") == -1)
                    263:                                                        goto done;
                    264:                                }
                    265:                                if (n_cr) {
                    266:                                        if (file_printf(ms, " CR") == -1)
                    267:                                                goto done;
                    268:                                        if (n_lf || n_nel)
                    269:                                                if (file_printf(ms, ",") == -1)
                    270:                                                        goto done;
                    271:                                }
                    272:                                if (n_lf) {
                    273:                                        if (file_printf(ms, " LF") == -1)
                    274:                                                goto done;
                    275:                                        if (n_nel)
                    276:                                                if (file_printf(ms, ",") == -1)
                    277:                                                        goto done;
                    278:                                }
                    279:                                if (n_nel)
                    280:                                        if (file_printf(ms, " NEL") == -1)
                    281:                                                goto done;
                    282:                        }
                    283: 
                    284:                        if (file_printf(ms, " line terminators") == -1)
                    285:                                goto done;
                    286:                }
                    287: 
                    288:                if (has_escapes)
                    289:                        if (file_printf(ms, ", with escape sequences") == -1)
                    290:                                goto done;
                    291:                if (has_backspace)
                    292:                        if (file_printf(ms, ", with overstriking") == -1)
                    293:                                goto done;
                    294:        }
                    295:        rv = 1;
                    296: done:
                    297:        if (utf8_buf)
                    298:                efree(utf8_buf);
                    299: 
                    300:        return rv;
                    301: }
                    302: 
                    303: /*
                    304:  * Encode Unicode string as UTF-8, returning pointer to character
                    305:  * after end of string, or NULL if an invalid character is found.
                    306:  */
                    307: private unsigned char *
                    308: encode_utf8(unsigned char *buf, size_t len, unichar *ubuf, size_t ulen)
                    309: {
                    310:        size_t i;
                    311:        unsigned char *end = buf + len;
                    312: 
                    313:        for (i = 0; i < ulen; i++) {
                    314:                if (ubuf[i] <= 0x7f) {
                    315:                        if (end - buf < 1)
                    316:                                return NULL;
                    317:                        *buf++ = (unsigned char)ubuf[i];
                    318:                } else if (ubuf[i] <= 0x7ff) {
                    319:                        if (end - buf < 2)
                    320:                                return NULL;
                    321:                        *buf++ = (unsigned char)((ubuf[i] >> 6) + 0xc0);
                    322:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    323:                } else if (ubuf[i] <= 0xffff) {
                    324:                        if (end - buf < 3)
                    325:                                return NULL;
                    326:                        *buf++ = (unsigned char)((ubuf[i] >> 12) + 0xe0);
                    327:                        *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
                    328:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    329:                } else if (ubuf[i] <= 0x1fffff) {
                    330:                        if (end - buf < 4)
                    331:                                return NULL;
                    332:                        *buf++ = (unsigned char)((ubuf[i] >> 18) + 0xf0);
                    333:                        *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
                    334:                        *buf++ = (unsigned char)(((ubuf[i] >>  6) & 0x3f) + 0x80);
                    335:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    336:                } else if (ubuf[i] <= 0x3ffffff) {
                    337:                        if (end - buf < 5)
                    338:                                return NULL;
                    339:                        *buf++ = (unsigned char)((ubuf[i] >> 24) + 0xf8);
                    340:                        *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
                    341:                        *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
                    342:                        *buf++ = (unsigned char)(((ubuf[i] >>  6) & 0x3f) + 0x80);
                    343:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    344:                } else if (ubuf[i] <= 0x7fffffff) {
                    345:                        if (end - buf < 6)
                    346:                                return NULL;
                    347:                        *buf++ = (unsigned char)((ubuf[i] >> 30) + 0xfc);
                    348:                        *buf++ = (unsigned char)(((ubuf[i] >> 24) & 0x3f) + 0x80);
                    349:                        *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
                    350:                        *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
                    351:                        *buf++ = (unsigned char)(((ubuf[i] >>  6) & 0x3f) + 0x80);
                    352:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    353:                } else /* Invalid character */
                    354:                        return NULL;
                    355:        }
                    356: 
                    357:        return buf;
                    358: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>