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

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.3   misho      38: FILE_RCSID("@(#)$File: ascmagic.c,v 1.85 2012/08/09 16:33:15 christos 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.3   misho     137:        if (ulen > 0 && (ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
1.1.1.2   misho     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;
1.1.1.3   misho     142:                if ((utf8_buf = CAST(unsigned char *, emalloc(mlen))) == NULL) {
                    143:                        file_oomem(ms, mlen);
                    144:                        goto done;
                    145:                }
1.1.1.2   misho     146:                if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen))
                    147:                    == NULL)
                    148:                        goto done;
                    149:                if ((rv = file_softmagic(ms, utf8_buf,
1.1.1.4 ! misho     150:                    (size_t)(utf8_end - utf8_buf), 0, TEXTTEST, text)) == 0)
1.1.1.2   misho     151:                        rv = -1;
1.1       misho     152:        }
                    153: 
                    154:        /* Now try to discover other details about the file. */
                    155:        for (i = 0; i < ulen; i++) {
                    156:                if (ubuf[i] == '\n') {
                    157:                        if (seen_cr)
                    158:                                n_crlf++;
                    159:                        else
                    160:                                n_lf++;
                    161:                        last_line_end = i;
                    162:                } else if (seen_cr)
                    163:                        n_cr++;
                    164: 
                    165:                seen_cr = (ubuf[i] == '\r');
                    166:                if (seen_cr)
                    167:                        last_line_end = i;
                    168: 
                    169:                if (ubuf[i] == 0x85) { /* X3.64/ECMA-43 "next line" character */
                    170:                        n_nel++;
                    171:                        last_line_end = i;
                    172:                }
                    173: 
                    174:                /* If this line is _longer_ than MAXLINELEN, remember it. */
                    175:                if (i > last_line_end + MAXLINELEN)
                    176:                        has_long_lines = 1;
                    177: 
                    178:                if (ubuf[i] == '\033')
                    179:                        has_escapes = 1;
                    180:                if (ubuf[i] == '\b')
                    181:                        has_backspace = 1;
                    182:        }
                    183: 
                    184:        /* Beware, if the data has been truncated, the final CR could have
                    185:           been followed by a LF.  If we have HOWMANY bytes, it indicates
                    186:           that the data might have been truncated, probably even before
                    187:           this function was called. */
                    188:        if (seen_cr && nbytes < HOWMANY)
                    189:                n_cr++;
                    190: 
                    191:        if (strcmp(type, "binary") == 0) {
                    192:                rv = 0;
                    193:                goto done;
                    194:        }
                    195:        if (mime) {
1.1.1.2   misho     196:                if (!file_printedlen(ms) && (mime & MAGIC_MIME_TYPE) != 0) {
1.1       misho     197:                        if (subtype_mime) {
                    198:                                if (file_printf(ms, "%s", subtype_mime) == -1)
                    199:                                        goto done;
                    200:                        } else {
                    201:                                if (file_printf(ms, "text/plain") == -1)
                    202:                                        goto done;
                    203:                        }
                    204:                }
                    205:        } else {
1.1.1.2   misho     206:                if (file_printedlen(ms)) {
                    207:                        switch (file_replace(ms, " text$", ", ")) {
                    208:                        case 0:
                    209:                                switch (file_replace(ms, " text executable$",
                    210:                                    ", ")) {
                    211:                                case 0:
                    212:                                        if (file_printf(ms, ", ") == -1)
                    213:                                                goto done;
1.1.1.3   misho     214:                                        break;
1.1.1.2   misho     215:                                case -1:
                    216:                                        goto done;
                    217:                                default:
                    218:                                        executable = 1;
                    219:                                        break;
                    220:                                }
                    221:                                break;
                    222:                        case -1:
                    223:                                goto done;
                    224:                        default:
                    225:                                break;
                    226:                        }
                    227:                }
                    228: 
1.1       misho     229:                if (file_printf(ms, "%s", code) == -1)
                    230:                        goto done;
                    231: 
                    232:                if (subtype) {
                    233:                        if (file_printf(ms, " %s", subtype) == -1)
                    234:                                goto done;
                    235:                }
                    236: 
                    237:                if (file_printf(ms, " %s", type) == -1)
                    238:                        goto done;
                    239: 
1.1.1.2   misho     240:                if (executable)
                    241:                        if (file_printf(ms, " executable") == -1)
                    242:                                goto done;
                    243: 
1.1       misho     244:                if (has_long_lines)
                    245:                        if (file_printf(ms, ", with very long lines") == -1)
                    246:                                goto done;
                    247: 
                    248:                /*
                    249:                 * Only report line terminators if we find one other than LF,
                    250:                 * or if we find none at all.
                    251:                 */
                    252:                if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) ||
                    253:                    (n_crlf != 0 || n_cr != 0 || n_nel != 0)) {
                    254:                        if (file_printf(ms, ", with") == -1)
                    255:                                goto done;
                    256: 
                    257:                        if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) {
                    258:                                if (file_printf(ms, " no") == -1)
                    259:                                        goto done;
                    260:                        } else {
                    261:                                if (n_crlf) {
                    262:                                        if (file_printf(ms, " CRLF") == -1)
                    263:                                                goto done;
                    264:                                        if (n_cr || n_lf || n_nel)
                    265:                                                if (file_printf(ms, ",") == -1)
                    266:                                                        goto done;
                    267:                                }
                    268:                                if (n_cr) {
                    269:                                        if (file_printf(ms, " CR") == -1)
                    270:                                                goto done;
                    271:                                        if (n_lf || n_nel)
                    272:                                                if (file_printf(ms, ",") == -1)
                    273:                                                        goto done;
                    274:                                }
                    275:                                if (n_lf) {
                    276:                                        if (file_printf(ms, " LF") == -1)
                    277:                                                goto done;
                    278:                                        if (n_nel)
                    279:                                                if (file_printf(ms, ",") == -1)
                    280:                                                        goto done;
                    281:                                }
                    282:                                if (n_nel)
                    283:                                        if (file_printf(ms, " NEL") == -1)
                    284:                                                goto done;
                    285:                        }
                    286: 
                    287:                        if (file_printf(ms, " line terminators") == -1)
                    288:                                goto done;
                    289:                }
                    290: 
                    291:                if (has_escapes)
                    292:                        if (file_printf(ms, ", with escape sequences") == -1)
                    293:                                goto done;
                    294:                if (has_backspace)
                    295:                        if (file_printf(ms, ", with overstriking") == -1)
                    296:                                goto done;
                    297:        }
                    298:        rv = 1;
                    299: done:
                    300:        if (utf8_buf)
                    301:                efree(utf8_buf);
                    302: 
                    303:        return rv;
                    304: }
                    305: 
                    306: /*
                    307:  * Encode Unicode string as UTF-8, returning pointer to character
                    308:  * after end of string, or NULL if an invalid character is found.
                    309:  */
                    310: private unsigned char *
                    311: encode_utf8(unsigned char *buf, size_t len, unichar *ubuf, size_t ulen)
                    312: {
                    313:        size_t i;
                    314:        unsigned char *end = buf + len;
                    315: 
                    316:        for (i = 0; i < ulen; i++) {
                    317:                if (ubuf[i] <= 0x7f) {
                    318:                        if (end - buf < 1)
                    319:                                return NULL;
                    320:                        *buf++ = (unsigned char)ubuf[i];
                    321:                } else if (ubuf[i] <= 0x7ff) {
                    322:                        if (end - buf < 2)
                    323:                                return NULL;
                    324:                        *buf++ = (unsigned char)((ubuf[i] >> 6) + 0xc0);
                    325:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    326:                } else if (ubuf[i] <= 0xffff) {
                    327:                        if (end - buf < 3)
                    328:                                return NULL;
                    329:                        *buf++ = (unsigned char)((ubuf[i] >> 12) + 0xe0);
                    330:                        *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
                    331:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    332:                } else if (ubuf[i] <= 0x1fffff) {
                    333:                        if (end - buf < 4)
                    334:                                return NULL;
                    335:                        *buf++ = (unsigned char)((ubuf[i] >> 18) + 0xf0);
                    336:                        *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
                    337:                        *buf++ = (unsigned char)(((ubuf[i] >>  6) & 0x3f) + 0x80);
                    338:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    339:                } else if (ubuf[i] <= 0x3ffffff) {
                    340:                        if (end - buf < 5)
                    341:                                return NULL;
                    342:                        *buf++ = (unsigned char)((ubuf[i] >> 24) + 0xf8);
                    343:                        *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
                    344:                        *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
                    345:                        *buf++ = (unsigned char)(((ubuf[i] >>  6) & 0x3f) + 0x80);
                    346:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    347:                } else if (ubuf[i] <= 0x7fffffff) {
                    348:                        if (end - buf < 6)
                    349:                                return NULL;
                    350:                        *buf++ = (unsigned char)((ubuf[i] >> 30) + 0xfc);
                    351:                        *buf++ = (unsigned char)(((ubuf[i] >> 24) & 0x3f) + 0x80);
                    352:                        *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
                    353:                        *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
                    354:                        *buf++ = (unsigned char)(((ubuf[i] >>  6) & 0x3f) + 0x80);
                    355:                        *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
                    356:                } else /* Invalid character */
                    357:                        return NULL;
                    358:        }
                    359: 
                    360:        return buf;
                    361: }

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