Annotation of libwww/Library/src/HTGuess.c, revision 2.17

2.10      frystyk     1: /*                                                                   HTGuess.c
                      2: **     STREAM TO GUESS CONTENT-TYPE
                      3: **
2.14      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.10      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.1       luotonen    6: **
                      7: **     This version of the stream object just writes its input
                      8: **     to its output, but prepends Content-Type: field and an
                      9: **     empty line after it.
                     10: **
2.8       duns       11: ** HISTORY:
                     12: **      8 Jul 94  FM   Insulate free() from _free structure element.
                     13: **
2.1       luotonen   14: */
                     15: 
2.12      frystyk    16: /* Library include files */
                     17: #include "tcp.h"
                     18: #include "HTUtils.h"
                     19: #include "HTString.h"
2.1       luotonen   20: #include "HTFormat.h"
                     21: #include "HTAlert.h"
                     22: #include "HTList.h"
2.13      frystyk    23: #include "HTFWrite.h"
2.12      frystyk    24: #include "HTGuess.h"
                     25: 
                     26: #define SAMPLE_SIZE    200     /* Number of chars to look at */
2.1       luotonen   27: 
                     28: /*             Stream Object
                     29: **             ------------
                     30: */
                     31: 
                     32: struct _HTStream {
                     33:        CONST HTStreamClass *   isa;
                     34: 
                     35:        HTRequest *             req;
2.13      frystyk    36:        HTParentAnchor *        anchor;
2.9       frystyk    37:        HTFormat                output_format;
2.1       luotonen   38:        HTStream *              output_stream;
2.9       frystyk    39:        HTStream *              target;
2.1       luotonen   40: 
2.13      frystyk    41:        BOOL                    transparent;
2.1       luotonen   42:        int                     cnt;
                     43:        int                     text_cnt;
                     44:        int                     lf_cnt;
                     45:        int                     cr_cnt;
                     46:        int                     pg_cnt;
                     47:        int                     ctrl_cnt;
                     48:        int                     high_cnt;
                     49:        char *                  write_ptr;
                     50:        char                    buffer[ SAMPLE_SIZE + 1 ];
                     51: };
                     52: 
2.13      frystyk    53: #define PUT_CHAR(c)            (*me->target->isa->put_character)(me->target,c)
                     54: #define PUT_STRING(s)          (*me->target->isa->put_string)(me->target,s)
                     55: #define PUT_BLOCK(b,l)         (*me->target->isa->put_block)(me->target,b,l)
                     56: 
                     57: #define CONTENT_TYPE(t)                HTAnchor_setFormat(me->anchor, HTAtom_for(t))
                     58: #define CONTENT_ENCODING(t)    HTAnchor_setEncoding(me->anchor, HTAtom_for(t))
                     59: 
                     60: /* ------------------------------------------------------------------------- */
2.1       luotonen   61: 
                     62: PRIVATE BOOL is_html ARGS1(char *, buf)
                     63: {
                     64:     char * p = strchr(buf,'<');
                     65: 
                     66:     if (p && (!strncasecomp(p, "<HTML>", 6) ||
                     67:              !strncasecomp(p, "<HEAD", 5) ||
                     68:              !strncasecomp(p, "<TITLE>", 7) ||
                     69:              !strncasecomp(p, "<BODY>", 6) ||
                     70:              !strncasecomp(p, "<PLAINTEXT>", 11) ||
                     71:              (p[0]=='<' && TOUPPER(p[1]) == 'H' && p[3]=='>')))
                     72:        return YES;
                     73:     else
                     74:        return NO;
                     75: }
                     76: 
2.13      frystyk    77: PRIVATE int HTGuess_flush ARGS1(HTStream *, me)
                     78: {
                     79:     if (!me->transparent) {
2.17    ! frystyk    80:        if (STREAM_TRACE)
2.13      frystyk    81:            fprintf(TDEST,"GUESSING.... text=%d newlines=%d ctrl=%d high=%d\n",
                     82:                    me->text_cnt, me->lf_cnt, me->ctrl_cnt, me->high_cnt);
                     83:        if (me->cnt) {
2.17    ! frystyk    84:            if (STREAM_TRACE) fprintf(TDEST,
2.13      frystyk    85:                                    "Percentages. text=%d%% newlines=%d%% ctrl=%d%% high=%d%%\n",
                     86:                                    (int)(100*me->text_cnt/me->cnt + 0.5),
                     87:                                    (int)(100*me->lf_cnt  /me->cnt + 0.5),
                     88:                                    (int)(100*me->ctrl_cnt/me->cnt + 0.5),
                     89:                                    (int)(100*me->high_cnt/me->cnt + 0.5));
                     90:        }
                     91:        
                     92:        if (!me->ctrl_cnt ||
                     93:            me->text_cnt + me->lf_cnt >= 16 * (me->ctrl_cnt + me->high_cnt)) {
2.15      frystyk    94:            char *ptr;
2.13      frystyk    95:            /* some kind of text */
                     96:            
                     97:            *me->write_ptr = 0; /* terminate buffer */
                     98:            
                     99:            if (me->high_cnt > 0)
                    100:                CONTENT_ENCODING("8bit");
                    101:            else
                    102:                CONTENT_ENCODING("7bit");
                    103:            
                    104:            if (is_html(me->buffer))
                    105:                CONTENT_TYPE("text/html");
                    106:            
                    107:            else if (!strncmp(me->buffer, "%!", 2))
                    108:                CONTENT_TYPE("application/postscript");
                    109:            
                    110:            else if (strstr(me->buffer, "#define") &&
                    111:                     strstr(me->buffer, "_width") &&
                    112:                     strstr(me->buffer, "_bits"))
                    113:                CONTENT_TYPE("image/x-xbitmap");
                    114:            
2.15      frystyk   115:            else if ((ptr = strstr(me->buffer, "converted with BinHex"))!=NULL)
                    116:                CONTENT_ENCODING("macbinhex");
                    117: 
2.13      frystyk   118:            else if (!strncmp(me->buffer, "begin ", 6))
                    119:                CONTENT_ENCODING("base64");
2.15      frystyk   120: 
2.13      frystyk   121:            else
                    122:                CONTENT_TYPE("text/plain");
                    123:        }
                    124:        else {
                    125:            if (!strncmp(me->buffer, "GIF", 3))
                    126:                CONTENT_TYPE("image/gif");
2.1       luotonen  127: 
2.13      frystyk   128:            else if (!strncmp(me->buffer, "\377\330\377\340", 4))
                    129:                CONTENT_TYPE("image/jpeg");
2.1       luotonen  130: 
2.13      frystyk   131:            else if (!strcmp(me->buffer, "MM")) /* MM followed by a zero */
                    132:                CONTENT_TYPE("image/tiff");
2.1       luotonen  133: 
2.16      frystyk   134:            else if (!strncmp(me->buffer, "\211PNG\r\n\032\n", 8))
                    135:                CONTENT_TYPE("image/x-png");
                    136: 
2.13      frystyk   137:            else if (!strncmp(me->buffer, ".snd", 4))
                    138:                CONTENT_TYPE("audio/basic");
2.1       luotonen  139: 
2.13      frystyk   140:            else if (!strncmp(me->buffer, "\037\235", 2))
                    141:                CONTENT_ENCODING("x-compress");
2.1       luotonen  142: 
2.13      frystyk   143:            else if (!strncmp(me->buffer, "\037\213", 2))
                    144:                CONTENT_ENCODING("x-gzip");
2.1       luotonen  145: 
2.13      frystyk   146:            else
                    147:                CONTENT_TYPE("application/octet-stream");
                    148:        }
                    149:        
                    150:        if (!me->anchor->content_type)  CONTENT_TYPE("www/unknown");
                    151:        if (!me->anchor->content_encoding)  CONTENT_ENCODING("binary");
                    152:        
2.17    ! frystyk   153:        if (STREAM_TRACE) fprintf(TDEST,"Guessed..... %s\n",
2.13      frystyk   154:                                HTAtom_name(me->anchor->content_type));
2.17    ! frystyk   155:        if (STREAM_TRACE) fprintf(TDEST,"Encoding.... %s\n",
2.13      frystyk   156:                                HTAtom_name(me->anchor->content_encoding));
                    157:        if ((me->target = HTStreamStack(me->anchor->content_type,
                    158:                                        me->output_format, me->output_stream,
                    159:                                        me->req, NO)) == NULL) {
2.17    ! frystyk   160:            if (STREAM_TRACE)
2.13      frystyk   161:                fprintf(TDEST, "HTGuess..... Can't convert media type\n");
                    162:            me->target = HTBlackHole();
                    163:        }
2.1       luotonen  164:     }
2.13      frystyk   165:     return PUT_BLOCK(me->buffer, me->cnt);
2.1       luotonen  166: }
                    167: 
                    168: 
2.13      frystyk   169: PRIVATE int HTGuess_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
2.1       luotonen  170: {
2.13      frystyk   171:     while (!me->transparent && l-- > 0) {
                    172:        int status;
                    173:        if (me->target) {
                    174:            if ((status = HTGuess_flush(me)) != HT_OK)
                    175:                return status;
                    176:        } else {
                    177:            me->cnt++;
                    178:            if (*b == LF)
                    179:                me->lf_cnt++;
                    180:            else if (*b == CR)
                    181:                me->cr_cnt++;
                    182:            else if (*b == 12)
                    183:                me->pg_cnt++;
                    184:            else if (*b =='\t')
                    185:                me->text_cnt++;
                    186:            else if ((unsigned char)*b < 32)
                    187:                me->ctrl_cnt++;
                    188:            else if ((unsigned char)*b < 128)
                    189:                me->text_cnt++;
                    190:            else
                    191:                me->high_cnt++;
                    192:            *me->write_ptr++ = *b++;
                    193:            if (me->cnt >= SAMPLE_SIZE) {
                    194:                if ((status = HTGuess_flush(me)) != HT_OK)
                    195:                    return status;
                    196:                else
                    197:                    me->transparent = YES;
                    198:            }
                    199:        }
2.1       luotonen  200:     }
2.13      frystyk   201:     if (l > 0)
                    202:        return PUT_BLOCK(b, l);
                    203:     return HT_OK;
2.1       luotonen  204: }
                    205: 
2.13      frystyk   206: PRIVATE int HTGuess_put_character ARGS2(HTStream *, me, char, c)
2.1       luotonen  207: {
2.13      frystyk   208:     return HTGuess_put_block(me, &c, 1);
2.1       luotonen  209: }
                    210: 
2.13      frystyk   211: PRIVATE int HTGuess_put_string ARGS2(HTStream *, me, CONST char*, s)
2.1       luotonen  212: {
2.13      frystyk   213:     return HTGuess_put_block(me, s, (int) strlen(s));
2.1       luotonen  214: }
                    215: 
2.9       frystyk   216: PRIVATE int HTGuess_free ARGS1(HTStream *, me)
2.1       luotonen  217: {
2.13      frystyk   218:     int status;
                    219:     if (!me->transparent && (status = HTGuess_flush(me)) != HT_OK)
                    220:        return status;
                    221:     else
                    222:        me->transparent = YES;
                    223:     if ((status = (*me->target->isa->_free)(me->target)) != HT_OK)
                    224:        return status;
2.1       luotonen  225:     free(me);
2.13      frystyk   226:     return HT_OK;
2.1       luotonen  227: }
                    228: 
2.9       frystyk   229: PRIVATE int HTGuess_abort ARGS2(HTStream *, me, HTError, e)
2.1       luotonen  230: {
2.9       frystyk   231:     if (me->target)
                    232:        (*me->target->isa->abort)(me,e);
2.1       luotonen  233:     free(me);
2.13      frystyk   234:     return HT_ERROR;
2.1       luotonen  235: }
                    236: 
                    237: 
                    238: /*     Guessing stream
                    239: **     ---------------
                    240: */
                    241: PRIVATE CONST HTStreamClass HTGuessClass =
                    242: {              
2.13      frystyk   243:        "GuessWhat",
                    244:        HTGuess_flush,
2.1       luotonen  245:        HTGuess_free,
                    246:        HTGuess_abort,
                    247:        HTGuess_put_character,
                    248:        HTGuess_put_string,
                    249:        HTGuess_put_block
                    250: };
                    251: 
                    252: 
2.9       frystyk   253: PUBLIC HTStream * HTGuess_new ARGS5(HTRequest *,       req,
                    254:                                    void *,             param,
                    255:                                    HTFormat,           input_format,
                    256:                                    HTFormat,           output_format,
                    257:                                    HTStream *,         output_stream)
2.1       luotonen  258: {
2.13      frystyk   259:     HTStream * me = (HTStream *) calloc(1,sizeof(HTStream));
2.1       luotonen  260:     if (!me) outofmem(__FILE__, "HTGuess_new");
                    261: 
                    262:     me->isa = &HTGuessClass;
2.9       frystyk   263:     me->req = req;
2.17    ! frystyk   264:     me->anchor = HTRequest_anchor(req);
2.9       frystyk   265:     me->output_format = output_format;
                    266:     me->output_stream = output_stream;
2.1       luotonen  267:     me->write_ptr = me->buffer;
                    268:     return me;
                    269: }

Webmaster