Annotation of libwww/Library/src/HTFormat.c, revision 1.16

1.7       secret      1: 
1.1       timbl       2: /*             Manage different file formats                   HTFormat.c
                      3: **             =============================
                      4: **
                      5: ** Bugs:
                      6: **     Not reentrant.
                      7: **
                      8: **     Assumes the incoming stream is ASCII, rather than a local file
                      9: **     format, and so ALWAYS converts from ASCII on non-ASCII machines.
                     10: **     Therefore, non-ASCII machines can't read local files.
1.2       timbl      11: **
                     12: */
                     13: 
1.10      timbl      14: 
1.2       timbl      15: /* Implements:
1.1       timbl      16: */
1.2       timbl      17: #include "HTFormat.h"
                     18: 
                     19: PUBLIC float HTMaxSecs = 1e10;         /* No effective limit */
                     20: PUBLIC float HTMaxLength = 1e10;       /* No effective limit */
                     21: 
                     22: #ifdef unix
                     23: #ifdef NeXT
                     24: #define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n"
                     25: #else
                     26: #define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n" 
                     27:        /* Full pathname would be better! */
                     28: #endif
                     29: #endif
                     30: 
1.1       timbl      31: 
                     32: #include "HTUtils.h"
                     33: #include "tcp.h"
                     34: 
                     35: #include "HTML.h"
1.12      timbl      36: #include "HTMLPDTD.h"
1.1       timbl      37: #include "HText.h"
1.2       timbl      38: #include "HTAlert.h"
                     39: #include "HTList.h"
                     40: #include "HTInit.h"
                     41: /*     Streams and structured streams which we use:
                     42: */
                     43: #include "HTFWriter.h"
                     44: #include "HTPlain.h"
                     45: #include "SGML.h"
                     46: #include "HTML.h"
                     47: #include "HTMLGen.h"
                     48: 
                     49: PUBLIC BOOL HTOutputSource = NO;       /* Flag: shortcut parser to stdout */
                     50: extern  BOOL interactive;
                     51: 
1.10      timbl      52: #ifdef ORIGINAL
1.2       timbl      53: struct _HTStream {
                     54:       CONST HTStreamClass*     isa;
                     55:       /* ... */
                     56: };
1.10      timbl      57: #endif
                     58: 
                     59: /* this version used by the NetToText stream */
                     60: struct _HTStream {
                     61:        CONST HTStreamClass *           isa;
                     62:        BOOL                    had_cr;
                     63:        HTStream *              sink;
                     64: };
1.2       timbl      65: 
                     66: 
                     67: /*     Presentation methods
                     68: **     --------------------
                     69: */
                     70: 
1.14      timbl      71: PUBLIC HTList * HTConversions = NULL;
1.2       timbl      72: 
                     73: 
                     74: /*     Define a presentation system command for a content-type
                     75: **     -------------------------------------------------------
                     76: */
1.12      timbl      77: PUBLIC void HTSetPresentation ARGS6(
                     78:        HTList *,       conversions,
                     79:        CONST char *,   representation,
                     80:        CONST char *,   command,
                     81:        float,          quality,
                     82:        float,          secs, 
                     83:        float,          secs_per_byte
1.2       timbl      84: ){
                     85: 
                     86:     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
                     87:     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
                     88:     
                     89:     pres->rep = HTAtom_for(representation);
                     90:     pres->rep_out = WWW_PRESENT;               /* Fixed for now ... :-) */
                     91:     pres->converter = HTSaveAndExecute;                /* Fixed for now ...     */
                     92:     pres->quality = quality;
                     93:     pres->secs = secs;
                     94:     pres->secs_per_byte = secs_per_byte;
                     95:     pres->rep = HTAtom_for(representation);
                     96:     pres->command = 0;
                     97:     StrAllocCopy(pres->command, command);
                     98:     
1.12      timbl      99: /*    if (!HTPresentations) HTPresentations = HTList_new(); */
1.2       timbl     100:     
1.15      luotonen  101: #ifdef OLD_CODE
                    102:     if (strcmp(representation, "*")==0) {
1.2       timbl     103:         if (default_presentation) free(default_presentation);
                    104:        default_presentation = pres;
1.12      timbl     105:     } else 
                    106: #endif
                    107:     HTList_addObject(conversions, pres);
1.2       timbl     108: }
                    109: 
                    110: 
                    111: /*     Define a built-in function for a content-type
                    112: **     ---------------------------------------------
                    113: */
1.12      timbl     114: PUBLIC void HTSetConversion ARGS7(
                    115:        HTList *,       conversions,
                    116:        CONST char *,   representation_in,
                    117:        CONST char *,   representation_out,
1.6       timbl     118:        HTConverter*,   converter,
1.12      timbl     119:        float,          quality,
                    120:        float,          secs, 
                    121:        float,          secs_per_byte
1.2       timbl     122: ){
1.1       timbl     123: 
1.2       timbl     124:     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
                    125:     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
                    126:     
                    127:     pres->rep = HTAtom_for(representation_in);
                    128:     pres->rep_out = HTAtom_for(representation_out);
                    129:     pres->converter = converter;
                    130:     pres->command = NULL;              /* Fixed */
                    131:     pres->quality = quality;
                    132:     pres->secs = secs;
                    133:     pres->secs_per_byte = secs_per_byte;
                    134:     pres->command = 0;
                    135:     
1.12      timbl     136: /*    if (!HTPresentations) HTPresentations = HTList_new();  */
1.2       timbl     137:     
1.12      timbl     138: #ifdef OLD_CODE
1.2       timbl     139:     if (strcmp(representation_in, "*")==0) {
                    140:         if (default_presentation) free(default_presentation);
                    141:        default_presentation = pres;
1.12      timbl     142:     } else 
                    143: #endif
                    144:     HTList_addObject(conversions, pres);
1.2       timbl     145: }
1.1       timbl     146: 
                    147: 
                    148: 
1.13      timbl     149: /*                     Socket Input Buffering
                    150: **                     ----------------------
1.1       timbl     151: **
1.13      timbl     152: **     This code is used because one cannot in general open a
                    153: **     file descriptor for a socket.
                    154: **
1.1       timbl     155: **     The input file is read using the macro which can read from
1.13      timbl     156: **     a socket or a file, but this should not be used for files
                    157: **     as fopen() etc is more portable of course.
                    158: **
1.1       timbl     159: **     The input buffer size, if large will give greater efficiency and
                    160: **     release the server faster, and if small will save space on PCs etc.
                    161: */
                    162: 
                    163: 
                    164: /*     Set up the buffering
                    165: **
                    166: **     These routines are public because they are in fact needed by
                    167: **     many parsers, and on PCs and Macs we should not duplicate
                    168: **     the static buffer area.
                    169: */
1.13      timbl     170: PUBLIC HTInputSocket * HTInputSocket_new ARGS1 (int,file_number)
1.1       timbl     171: {
1.13      timbl     172:     HTInputSocket *isoc = (HTInputSocket *)malloc(sizeof(*isoc));
                    173:     if (!isoc) outofmem(__FILE__, "HTInputSocket_new");
                    174:     isoc->input_file_number = file_number;
                    175:     isoc->input_pointer = isoc->input_limit = isoc->input_buffer;
                    176:     return isoc;
1.1       timbl     177: }
                    178: 
                    179: 
1.13      timbl     180: PUBLIC char HTInputSocket_getCharacter ARGS1(HTInputSocket*, isoc)
1.1       timbl     181: {
                    182:     char ch;
                    183:     do {
1.13      timbl     184:        if (isoc-> input_pointer >= isoc->input_limit) {
1.1       timbl     185:            int status = NETREAD(
1.13      timbl     186:                   isoc->input_file_number,
                    187:                   isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1       timbl     188:            if (status <= 0) {
                    189:                if (status == 0) return (char)EOF;
                    190:                if (TRACE) fprintf(stderr,
                    191:                    "HTFormat: File read error %d\n", status);
                    192:                return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
                    193:            }
1.13      timbl     194:            isoc-> input_pointer = isoc->input_buffer;
                    195:            isoc->input_limit = isoc->input_buffer + status;
1.1       timbl     196:        }
1.13      timbl     197:        ch = *isoc-> input_pointer++;
1.1       timbl     198:     } while (ch == (char) 13); /* Ignore ASCII carriage return */
                    199:     
                    200:     return FROMASCII(ch);
                    201: }
                    202: 
1.13      timbl     203: PUBLIC void HTInputSocket_free(HTInputSocket * me)
                    204: {
                    205:     if (me) free(me);
                    206: }
                    207: 
                    208: 
1.16    ! luotonen  209: PUBLIC char * HTInputSocket_getBlock ARGS2(HTInputSocket*,     isoc,
        !           210:                                           int *,               len)
        !           211: {
        !           212:     if (isoc->input_pointer >= isoc->input_limit) {
        !           213:        int status = NETREAD(isoc->input_file_number,
        !           214:                             isoc->input_buffer,
        !           215:                             ((*len < INPUT_BUFFER_SIZE) ?
        !           216:                              *len : INPUT_BUFFER_SIZE));
        !           217:        if (status <= 0) {
        !           218:            isoc->input_limit = isoc->input_buffer;
        !           219:            if (status < 0)
        !           220:                CTRACE(stderr, "HTInputSocket: File read error %d\n", status);
        !           221:            *len = 0;
        !           222:            return NULL;
        !           223:        }
        !           224:        else {
        !           225:            *len = status;
        !           226:            return isoc->input_buffer;
        !           227:        }
        !           228:     }
        !           229:     else {
        !           230:        char * ret = isoc->input_pointer;
        !           231:        *len = isoc->input_limit - isoc->input_pointer;
        !           232:        isoc->input_pointer = isoc->input_limit;
        !           233:        return ret;
        !           234:     }
        !           235: }
        !           236: 
        !           237: 
1.15      luotonen  238: PRIVATE int fill_in_buffer ARGS1(HTInputSocket *, isoc)
                    239: {
                    240:     if (isoc) {
                    241:        int status;
                    242: 
                    243:        isoc->input_pointer = isoc->input_buffer;
                    244:        status = NETREAD(isoc->input_file_number,
                    245:                         isoc->input_buffer,
                    246:                         INPUT_BUFFER_SIZE);
                    247:        if (status <= 0) {
                    248:            isoc->input_limit = isoc->input_buffer;
                    249:            if (status < 0)
                    250:                if (TRACE) fprintf(stderr,
                    251:                                   "HTInputSocket: File read error %d\n",
                    252:                                   status);
                    253:        }
                    254:        else 
                    255:            isoc->input_limit = isoc->input_buffer + status;
                    256:        return status;
                    257:     }
                    258:     return -1;
                    259: }
                    260: 
                    261: 
                    262: PRIVATE void ascii_cat ARGS3(char **,  linep,
                    263:                             char *,    start,
                    264:                             char *,    end)
                    265: {
                    266:     if (linep && start && end && start <= end) {
                    267:        char *ptr;
                    268: 
                    269:        if (*linep) {
                    270:            int len = strlen(*linep);
                    271:            *linep = (char*)realloc(*linep, len + end-start + 1);
                    272:            ptr = *linep + len;
                    273:        }
                    274:        else {
                    275:            ptr = *linep = (char*)malloc(end-start + 1);
                    276:        }
                    277: 
                    278:        while (start < end) {
                    279:            *ptr = FROMASCII(*start);
                    280:            ptr++;
                    281:            start++;
                    282:        }
                    283:        *ptr = 0;
                    284:     }
                    285: }
                    286: 
                    287: 
                    288: PRIVATE char * get_some_line ARGS2(HTInputSocket *,    isoc,
                    289:                                   BOOL,                unfold)
                    290: {
                    291:     if (!isoc)
                    292:        return NULL;
                    293:     else {
                    294:        BOOL check_unfold = NO;
                    295:        int prev_cr = 0;
                    296:        char *start = isoc->input_pointer;
                    297:        char *cur = isoc->input_pointer;
                    298:        char * line = NULL;
                    299: 
                    300:        for(;;) {
                    301:            /*
                    302:            ** Get more if needed to complete line
                    303:            */
                    304:            if (cur >= isoc->input_limit) { /* Need more data */
                    305: #if 0
                    306:                if (TRACE) fprintf(stderr, "HTInputSocket: reading more data\n");
                    307: #endif
                    308:                ascii_cat(&line, start, cur);
                    309:                if (fill_in_buffer(isoc) <= 0)
                    310:                    return line;
                    311:                start = cur = isoc->input_pointer;
                    312:            } /* if need more data */
                    313: 
                    314:            /*
                    315:            ** Find a line feed if there is one
                    316:            */
                    317: #if 0
                    318:            if (TRACE) fprintf(stderr, "HTInputSocket: processing read buffer\n");
                    319: #endif
                    320:            for(; cur < isoc->input_limit; cur++) {
                    321:                char c = FROMASCII(*cur);
                    322:                if (!c) {
                    323: #if 0
                    324:                    if (TRACE) fprintf(stderr, "HTInputSocket: panic, read zero!\n");
                    325: #endif
                    326:                    return NULL;        /* Panic! read a 0! */
                    327:                }
                    328:                if (check_unfold  &&  c != ' '  &&  c != '\t') {
                    329: #if 0
                    330:                    if (TRACE) fprintf(stderr, "HTInputSocket: returning \"%s\"\n",
                    331:                                       (line ? line : "(null)"));
                    332: #endif
                    333:                    return line;  /* Note: didn't update isoc->input_pointer */
                    334:                }
                    335:                else {
                    336:                    check_unfold = NO;
                    337:                }
                    338: 
                    339:                if (c=='\r') {
                    340: #if 0
                    341:                    if (TRACE) fprintf(stderr, "HTInputSocket: found linefeed\n");
                    342: #endif
                    343:                    prev_cr = 1;
                    344:                }
                    345:                else {
                    346:                    if (c=='\n') {              /* Found a line feed */
                    347: #if 0
                    348:                        if (TRACE) fprintf(stderr, "HTInputSocket: found newline\n");
                    349: #endif
                    350:                        ascii_cat(&line, start, cur-prev_cr);
                    351:                        start = isoc->input_pointer = cur+1;
                    352: 
                    353:                        if (line && strlen(line) > 0 && unfold) {
                    354: #if 0
                    355:                            if (TRACE) fprintf(stderr, "HTInputSocket: next time check unfolding\n");
                    356: #endif
                    357:                            check_unfold = YES;
                    358:                        }
                    359:                        else {
                    360: #if 0
                    361:                            if (TRACE) fprintf(stderr,
                    362:                                               "HTInputSocket: no unfold check -- just return \"%s\"\n",
                    363:                                               (line ? line : "(line)"));
                    364: #endif
                    365:                            return line;
                    366:                        }
                    367:                    } /* if NL */
                    368:                    /* else just a regular character */
                    369:                    prev_cr = 0;
                    370:                } /* if not CR */
                    371:            } /* while characters in buffer remain */
                    372:        } /* until line read or end-of-file */
                    373:     } /* valid parameters to function */
                    374: }
                    375: 
                    376: 
                    377: PUBLIC char * HTInputSocket_getLine ARGS1(HTInputSocket *, isoc)
                    378: {
                    379:     return get_some_line(isoc, NO);
                    380: }
                    381: 
                    382: PUBLIC char * HTInputSocket_getUnfoldedLine ARGS1(HTInputSocket *, isoc)
                    383: {
                    384:     return get_some_line(isoc, YES);
                    385: }
                    386: 
                    387: 
                    388: /*
                    389: ** Read HTTP status line (if there is one).
                    390: **
                    391: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
                    392: ** First look at the stub in ASCII and check if it starts "HTTP/".
                    393: **
                    394: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
                    395: **      will be taken as a HTTP 1.0 server.  Failure.
                    396: */
                    397: #define STUB_LENGTH 20
                    398: PUBLIC char * HTInputSocket_getStatusLine ARGS1(HTInputSocket *, isoc)
                    399: {
                    400:     if (!isoc) {
                    401:        return NULL;
                    402:     }
                    403:     else {
                    404:        char buf[STUB_LENGTH + 1];
                    405:        int i;
                    406:        char server_version[STUB_LENGTH+1];
                    407:        int server_status;
                    408: 
                    409:        /*
                    410:        ** Read initial buffer
                    411:        */
                    412:        if (isoc->input_pointer >= isoc->input_limit &&
                    413:            fill_in_buffer(isoc) <= 0) {
                    414:            return NULL;
                    415:         }
                    416: 
                    417:        for (i=0; i < STUB_LENGTH; i++)
                    418:            buf[i] = FROMASCII(isoc->input_buffer[i]);
                    419:        buf[STUB_LENGTH] = 0;
                    420: 
                    421:        if (0 != strncmp(buf, "HTTP/", 5) ||
                    422:            sscanf(buf, "%20s%d", server_version, &server_status) < 2)
                    423:            return NULL;
                    424:        else
                    425:            return get_some_line(isoc, NO);
                    426:     }
                    427: }
                    428: 
                    429: 
                    430: /*
                    431: ** Do heuristic test to see if this is binary.
                    432: **
                    433: ** We check for characters above 128 in the first few bytes, and
                    434: ** if we find them we forget the html default.
                    435: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
                    436: **
                    437: ** Bugs: An HTTP 0.9 server returning a binary document with
                    438: **      characters < 128 will be read as ASCII.
                    439: */
                    440: PUBLIC BOOL HTInputSocket_seemsBinary ARGS1(HTInputSocket *, isoc)
                    441: {
                    442:     if (isoc &&
                    443:        (isoc->input_pointer < isoc->input_limit ||
                    444:         fill_in_buffer(isoc) > 0)) {
                    445:        char *p = isoc->input_buffer;
                    446:        int i = STUB_LENGTH;
                    447: 
                    448:        for( ; i && p < isoc->input_limit; p++, i++)
                    449:            if (((int)*p)&128)
                    450:                return YES;
                    451:     }
                    452:     return NO;
                    453: }
                    454: 
                    455: 
                    456: 
1.1       timbl     457: /*     Stream the data to an ouput file as binary
                    458: */
1.13      timbl     459: PUBLIC int HTOutputBinary ARGS3( HTInputSocket *, isoc,
                    460:                                int,            input,
                    461:                                FILE *,         output)
1.1       timbl     462: {
                    463:     do {
                    464:            int status = NETREAD(
1.13      timbl     465:                    input, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1       timbl     466:            if (status <= 0) {
                    467:                if (status == 0) return 0;
                    468:                if (TRACE) fprintf(stderr,
                    469:                    "HTFormat: File read error %d\n", status);
                    470:                return 2;                       /* Error */
                    471:            }
1.13      timbl     472:            fwrite(isoc->input_buffer, sizeof(char), status, output);
1.1       timbl     473:     } while (YES);
                    474: }
                    475: 
                    476: 
1.2       timbl     477: /*             Create a filter stack
                    478: **             ---------------------
                    479: **
1.7       secret    480: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     481: **     structure is made to hold the destination format while the
                    482: **     new stack is generated. This is just to pass the out format to
                    483: **     MIME so far.  Storing the format of a stream in the stream might
                    484: **     be a lot neater.
1.10      timbl     485: **
                    486: **     The www/source format is special, in that if you can take
                    487: **     that you can take anything. However, we
1.2       timbl     488: */
1.12      timbl     489: PUBLIC HTStream * HTStreamStack ARGS2(
1.10      timbl     490:        HTFormat,               rep_in,
1.12      timbl     491:        HTRequest *,            request)
1.2       timbl     492: {
1.12      timbl     493:     HTFormat rep_out = request->output_format; /* Could be a param */
1.14      timbl     494:     HTList * conversion[2];
1.2       timbl     495:     HTAtom * wildcard = HTAtom_for("*");
1.10      timbl     496:     HTFormat source = WWW_SOURCE;
1.14      timbl     497:     int which_list;
                    498:     HTPresentation * pres, *match, *wildcard_match=0,
                    499:                        *source_match=0, *source_wildcard_match=0;
                    500:     
1.2       timbl     501:     if (TRACE) fprintf(stderr,
                    502:        "HTFormat: Constructing stream stack for %s to %s\n",
1.10      timbl     503:        HTAtom_name(rep_in),    
1.2       timbl     504:        HTAtom_name(rep_out));
                    505:                
1.14      timbl     506: 
1.15      luotonen  507: #ifdef BUG_OUT /* by Lou Montulli 16 Aug 93, put in by AL 6 Dec 93 */
1.2       timbl     508:     if (rep_out == WWW_SOURCE ||
1.12      timbl     509:        rep_out == rep_in) return request->output_stream;
1.15      luotonen  510: #endif
                    511:     if (rep_out == rep_in) return request->output_stream;
1.2       timbl     512: 
1.14      timbl     513:     conversion[0] = request->conversions;
                    514:     conversion[1] = HTConversions;
1.2       timbl     515:     
1.15      luotonen  516:     for(which_list = 0; which_list<2; which_list++) {
                    517:        HTList * cur = conversion[which_list];
                    518:        
                    519:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.10      timbl     520:            if (pres->rep == rep_in) {
1.2       timbl     521:                if (pres->rep_out == rep_out)
1.12      timbl     522:                    return (*pres->converter)(request, pres->command,
1.15      luotonen  523:                                              rep_in, pres->rep_out,
                    524:                                              request->output_stream);
1.2       timbl     525:                if (pres->rep_out == wildcard) {
1.10      timbl     526:                    wildcard_match = pres;
                    527:                }
                    528:            }
                    529:            if (pres->rep == source) {
                    530:                if (pres->rep_out == rep_out)
                    531:                    source_match = pres;
                    532:                if (pres->rep_out == wildcard) {
                    533:                    source_wildcard_match = pres;
1.2       timbl     534:                }
                    535:            }
                    536:        }
                    537:     }
1.14      timbl     538:     match = wildcard_match ? wildcard_match :
                    539:            source_match ?      source_match : 
                    540:            source_wildcard_match;
                    541:     
                    542:     if (match) return (*match->converter)(
                    543:                request, match->command, rep_in, rep_out,
                    544:                request->output_stream);
1.10      timbl     545: 
1.2       timbl     546:     return NULL;
                    547: }
                    548:        
                    549: 
                    550: /*             Find the cost of a filter stack
                    551: **             -------------------------------
                    552: **
                    553: **     Must return the cost of the same stack which StreamStack would set up.
                    554: **
                    555: ** On entry,
                    556: **     length  The size of the data to be converted
                    557: */
1.12      timbl     558: PUBLIC float HTStackValue ARGS5(
1.14      timbl     559:        HTList *,               theseConversions,
1.10      timbl     560:        HTFormat,               rep_in,
1.2       timbl     561:        HTFormat,               rep_out,
                    562:        float,                  initial_value,
                    563:        long int,               length)
                    564: {
                    565:     HTAtom * wildcard = HTAtom_for("*");
1.14      timbl     566:     int which_list;
                    567:     HTList* conversion[2];
                    568:     
1.2       timbl     569:     if (TRACE) fprintf(stderr,
                    570:        "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
1.10      timbl     571:        HTAtom_name(rep_in),    initial_value,
1.2       timbl     572:        HTAtom_name(rep_out));
                    573:                
                    574:     if (rep_out == WWW_SOURCE ||
1.10      timbl     575:        rep_out == rep_in) return 0.0;
1.2       timbl     576: 
1.12      timbl     577:  /*   if (!HTPresentations) HTFormatInit();     set up the list */
1.2       timbl     578:     
1.14      timbl     579:     conversion[0] = theseConversions;
                    580:     conversion[1] = HTConversions;
                    581:     
                    582:     for(which_list = 0; which_list<2; which_list++)
                    583:      if (conversion[which_list]) {
1.15      luotonen  584:         HTList * cur = conversion[which_list];
1.2       timbl     585:        HTPresentation * pres;
1.15      luotonen  586:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    587:            if (pres->rep == rep_in &&
                    588:                (pres->rep_out == rep_out || pres->rep_out == wildcard)) {
1.2       timbl     589:                float value = initial_value * pres->quality;
                    590:                if (HTMaxSecs != 0.0)
1.15      luotonen  591:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     592:                                         /HTMaxSecs;
                    593:                return value;
                    594:            }
                    595:        }
                    596:     }
                    597:     
                    598:     return -1e30;              /* Really bad */
                    599: 
                    600: }
                    601:        
1.1       timbl     602: 
1.2       timbl     603: /*     Push data from a socket down a stream
                    604: **     -------------------------------------
1.1       timbl     605: **
1.2       timbl     606: **   This routine is responsible for creating and PRESENTING any
1.1       timbl     607: **   graphic (or other) objects described by the file.
1.2       timbl     608: **
                    609: **   The file number given is assumed to be a TELNET stream ie containing
                    610: **   CRLF at the end of lines which need to be stripped to LF for unix
                    611: **   when the format is textual.
                    612: **
1.1       timbl     613: */
1.2       timbl     614: PUBLIC void HTCopy ARGS2(
                    615:        int,                    file_number,
                    616:        HTStream*,              sink)
1.1       timbl     617: {
1.2       timbl     618:     HTStreamClass targetClass;    
1.13      timbl     619:     HTInputSocket * isoc;
1.2       timbl     620:     
1.5       timbl     621: /*     Push the data down the stream
1.2       timbl     622: **
                    623: */
                    624:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
1.13      timbl     625:     isoc = HTInputSocket_new(file_number);
1.2       timbl     626:     
                    627:     /* Push binary from socket down sink
1.10      timbl     628:     **
                    629:     **         This operation could be put into a main event loop
1.2       timbl     630:     */
                    631:     for(;;) {
                    632:        int status = NETREAD(
1.13      timbl     633:                file_number, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.2       timbl     634:        if (status <= 0) {
                    635:            if (status == 0) break;
                    636:            if (TRACE) fprintf(stderr,
                    637:                "HTFormat: Read error, read returns %d\n", status);
                    638:            break;
                    639:        }
1.8       timbl     640:        
                    641: #ifdef NOT_ASCII
                    642:        {
                    643:            char * p;
1.13      timbl     644:            for(p = isoc->input_buffer; p < isoc->input_buffer+status; p++) {
1.8       timbl     645:                *p = FROMASCII(*p);
                    646:            }
                    647:        }
                    648: #endif
                    649: 
1.13      timbl     650:        (*targetClass.put_block)(sink, isoc->input_buffer, status);
1.2       timbl     651:     } /* next bufferload */
1.13      timbl     652:     HTInputSocket_free(isoc);
1.2       timbl     653: }
                    654: 
1.1       timbl     655: 
1.7       secret    656: 
                    657: /*     Push data from a file pointer down a stream
                    658: **     -------------------------------------
                    659: **
                    660: **   This routine is responsible for creating and PRESENTING any
                    661: **   graphic (or other) objects described by the file.
                    662: **
                    663: **
                    664: */
                    665: PUBLIC void HTFileCopy ARGS2(
                    666:        FILE *,                 fp,
                    667:        HTStream*,              sink)
                    668: {
                    669:     HTStreamClass targetClass;    
1.13      timbl     670:     char input_buffer[INPUT_BUFFER_SIZE];
1.7       secret    671:     
                    672: /*     Push the data down the stream
                    673: **
                    674: */
                    675:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    676:     
                    677:     /* Push binary from socket down sink
                    678:     */
                    679:     for(;;) {
                    680:        int status = fread(
                    681:               input_buffer, 1, INPUT_BUFFER_SIZE, fp);
                    682:        if (status == 0) { /* EOF or error */
                    683:            if (ferror(fp) == 0) break;
                    684:            if (TRACE) fprintf(stderr,
                    685:                "HTFormat: Read error, read returns %d\n", ferror(fp));
                    686:            break;
                    687:        }
                    688:        (*targetClass.put_block)(sink, input_buffer, status);
1.13      timbl     689:     } /* next bufferload */    
1.7       secret    690: }
                    691: 
                    692: 
                    693: 
                    694: 
1.2       timbl     695: /*     Push data from a socket down a stream STRIPPING CR
                    696: **     --------------------------------------------------
                    697: **
                    698: **   This routine is responsible for creating and PRESENTING any
1.8       timbl     699: **   graphic (or other) objects described by the socket.
1.2       timbl     700: **
                    701: **   The file number given is assumed to be a TELNET stream ie containing
                    702: **   CRLF at the end of lines which need to be stripped to LF for unix
                    703: **   when the format is textual.
                    704: **
1.1       timbl     705: */
1.2       timbl     706: PUBLIC void HTCopyNoCR ARGS2(
                    707:        int,                    file_number,
                    708:        HTStream*,              sink)
                    709: {
1.13      timbl     710:     HTStreamClass targetClass;
                    711:     HTInputSocket * isoc;   
1.1       timbl     712:     
1.2       timbl     713: /*     Push the data, ignoring CRLF, down the stream
                    714: **
                    715: */
                    716:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    717: 
                    718: /*     Push text from telnet socket down sink
                    719: **
                    720: **     @@@@@ To push strings could be faster? (especially is we
                    721: **     cheat and don't ignore CR! :-}
                    722: */  
1.13      timbl     723:     isoc = HTInputSocket_new(file_number);
1.2       timbl     724:     for(;;) {
                    725:        char character;
1.13      timbl     726:        character = HTInputSocket_getCharacter(isoc);
1.2       timbl     727:        if (character == (char)EOF) break;
                    728:        (*targetClass.put_character)(sink, character);           
                    729:     }
1.13      timbl     730:     HTInputSocket_free(isoc);
1.2       timbl     731: }
1.1       timbl     732: 
1.2       timbl     733: 
1.7       secret    734: 
1.2       timbl     735: /*     Parse a socket given format and file number
                    736: **
                    737: **   This routine is responsible for creating and PRESENTING any
                    738: **   graphic (or other) objects described by the file.
                    739: **
                    740: **   The file number given is assumed to be a TELNET stream ie containing
                    741: **   CRLF at the end of lines which need to be stripped to LF for unix
                    742: **   when the format is textual.
                    743: **
                    744: */
1.14      timbl     745: 
1.12      timbl     746: PUBLIC int HTParseSocket ARGS3(
1.10      timbl     747:        HTFormat,               rep_in,
1.2       timbl     748:        int,                    file_number,
1.12      timbl     749:        HTRequest *,            request)
1.2       timbl     750: {
                    751:     HTStream * stream;
                    752:     HTStreamClass targetClass;    
1.1       timbl     753: 
1.12      timbl     754:     stream = HTStreamStack(rep_in, request);
1.2       timbl     755:     
                    756:     if (!stream) {
                    757:         char buffer[1024];     /* @@@@@@@@ */
                    758:        sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12      timbl     759:                HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.3       timbl     760:        if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
1.16    ! luotonen  761:         return HTLoadError(request, 501, buffer);
1.2       timbl     762:     }
1.1       timbl     763:     
1.3       timbl     764: /*     Push the data, ignoring CRLF if necessary, down the stream
                    765: **
1.2       timbl     766: **
1.3       timbl     767: **   @@  Bug:  This decision ought to be made based on "encoding"
1.9       timbl     768: **   rather than on format.  @@@  When we handle encoding.
1.3       timbl     769: **   The current method smells anyway.
1.2       timbl     770: */
                    771:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
1.10      timbl     772:     if (rep_in == WWW_BINARY || HTOutputSource
                    773:         || strstr(HTAtom_name(rep_in), "image/")
                    774:        || strstr(HTAtom_name(rep_in), "video/")) { /* @@@@@@ */
1.2       timbl     775:         HTCopy(file_number, stream);
                    776:     } else {   /* ascii text with CRLFs :-( */
                    777:         HTCopyNoCR(file_number, stream);
                    778:     }
1.7       secret    779:     (*targetClass.free)(stream);
                    780:     
                    781:     return HT_LOADED;
                    782: }
                    783: 
                    784: 
                    785: 
                    786: /*     Parse a file given format and file pointer
                    787: **
                    788: **   This routine is responsible for creating and PRESENTING any
                    789: **   graphic (or other) objects described by the file.
                    790: **
                    791: **   The file number given is assumed to be a TELNET stream ie containing
1.10      timbl     792: **   CRLF at the end of lines which need to be stripped to \n for unix
1.7       secret    793: **   when the format is textual.
                    794: **
                    795: */
1.12      timbl     796: PUBLIC int HTParseFile ARGS3(
1.10      timbl     797:        HTFormat,               rep_in,
1.7       secret    798:        FILE *,                 fp,
1.12      timbl     799:        HTRequest *,            request)
1.7       secret    800: {
                    801:     HTStream * stream;
                    802:     HTStreamClass targetClass;    
                    803: 
1.12      timbl     804:     stream = HTStreamStack(rep_in, request);
1.7       secret    805:     
                    806:     if (!stream) {
                    807:         char buffer[1024];     /* @@@@@@@@ */
                    808:        sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12      timbl     809:                HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.7       secret    810:        if (TRACE) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
1.16    ! luotonen  811:         return HTLoadError(request, 501, buffer);
1.7       secret    812:     }
                    813:     
1.9       timbl     814: /*     Push the data down the stream
1.7       secret    815: **
                    816: **
                    817: **   @@  Bug:  This decision ought to be made based on "encoding"
1.10      timbl     818: **   rather than on content-type.  @@@  When we handle encoding.
1.7       secret    819: **   The current method smells anyway.
                    820: */
                    821:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
                    822:     HTFileCopy(fp, stream);
1.2       timbl     823:     (*targetClass.free)(stream);
1.1       timbl     824:     
1.2       timbl     825:     return HT_LOADED;
1.1       timbl     826: }
1.2       timbl     827: 
1.10      timbl     828: 
                    829: /*     Converter stream: Network Telnet to internal character text
                    830: **     -----------------------------------------------------------
                    831: **
                    832: **     The input is assumed to be in ASCII, with lines delimited
                    833: **     by (13,10) pairs, These pairs are converted into (CR,LF)
                    834: **     pairs in the local representation.  The (CR,LF) sequence
                    835: **     when found is changed to a '\n' character, the internal
                    836: **     C representation of a new line.
                    837: */
                    838: 
                    839: 
1.11      timbl     840: PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
1.10      timbl     841: {
                    842:     char c = FROMASCII(net_char);
                    843:     if (me->had_cr) {
                    844:         if (c==LF) {
                    845:            me->sink->isa->put_character(me->sink, '\n');       /* Newline */
                    846:            me->had_cr = NO;
                    847:            return;
                    848:         } else {
                    849:            me->sink->isa->put_character(me->sink, CR); /* leftover */
                    850:        }
                    851:     }
                    852:     me->had_cr = (c==CR);
                    853:     if (!me->had_cr)
                    854:        me->sink->isa->put_character(me->sink, c);              /* normal */
                    855: }
                    856: 
1.11      timbl     857: PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
1.10      timbl     858: {
                    859:     CONST char * p;
                    860:     for(p=s; *p; p++) NetToText_put_character(me, *p);
                    861: }
                    862: 
1.11      timbl     863: PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
1.10      timbl     864: {
                    865:     CONST char * p;
                    866:     for(p=s; p<(s+l); p++) NetToText_put_character(me, *p);
                    867: }
                    868: 
                    869: PRIVATE void NetToText_free ARGS1(HTStream *, me)
                    870: {
                    871:     me->sink->isa->free(me->sink);             /* Close rest of pipe */
                    872:     free(me);
                    873: }
                    874: 
                    875: PRIVATE void NetToText_abort ARGS2(HTStream *, me, HTError, e)
                    876: {
                    877:     me->sink->isa->abort(me->sink,e);          /* Abort rest of pipe */
                    878:     free(me);
                    879: }
                    880: 
                    881: /*     The class structure
                    882: */
                    883: PRIVATE HTStreamClass NetToTextClass = {
                    884:     "NetToText",
                    885:     NetToText_free,
                    886:     NetToText_abort,
                    887:     NetToText_put_character,
                    888:     NetToText_put_string,
                    889:     NetToText_put_block
                    890: };
                    891: 
                    892: /*     The creation method
                    893: */
                    894: PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
                    895: {
                    896:     HTStream* me = (HTStream*)malloc(sizeof(*me));
                    897:     if (me == NULL) outofmem(__FILE__, "NetToText");
                    898:     me->isa = &NetToTextClass;
                    899:     
                    900:     me->had_cr = NO;
                    901:     me->sink = sink;
                    902:     return me;
                    903: }
1.2       timbl     904: 
                    905: 

Webmaster