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

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.15    ! luotonen  209: PRIVATE int fill_in_buffer ARGS1(HTInputSocket *, isoc)
        !           210: {
        !           211:     if (isoc) {
        !           212:        int status;
        !           213: 
        !           214:        isoc->input_pointer = isoc->input_buffer;
        !           215:        status = NETREAD(isoc->input_file_number,
        !           216:                         isoc->input_buffer,
        !           217:                         INPUT_BUFFER_SIZE);
        !           218:        if (status <= 0) {
        !           219:            isoc->input_limit = isoc->input_buffer;
        !           220:            if (status < 0)
        !           221:                if (TRACE) fprintf(stderr,
        !           222:                                   "HTInputSocket: File read error %d\n",
        !           223:                                   status);
        !           224:        }
        !           225:        else 
        !           226:            isoc->input_limit = isoc->input_buffer + status;
        !           227:        return status;
        !           228:     }
        !           229:     return -1;
        !           230: }
        !           231: 
        !           232: 
        !           233: PRIVATE void ascii_cat ARGS3(char **,  linep,
        !           234:                             char *,    start,
        !           235:                             char *,    end)
        !           236: {
        !           237:     if (linep && start && end && start <= end) {
        !           238:        char *ptr;
        !           239: 
        !           240:        if (*linep) {
        !           241:            int len = strlen(*linep);
        !           242:            *linep = (char*)realloc(*linep, len + end-start + 1);
        !           243:            ptr = *linep + len;
        !           244:        }
        !           245:        else {
        !           246:            ptr = *linep = (char*)malloc(end-start + 1);
        !           247:        }
        !           248: 
        !           249:        while (start < end) {
        !           250:            *ptr = FROMASCII(*start);
        !           251:            ptr++;
        !           252:            start++;
        !           253:        }
        !           254:        *ptr = 0;
        !           255:     }
        !           256: }
        !           257: 
        !           258: 
        !           259: PRIVATE char * get_some_line ARGS2(HTInputSocket *,    isoc,
        !           260:                                   BOOL,                unfold)
        !           261: {
        !           262:     if (!isoc)
        !           263:        return NULL;
        !           264:     else {
        !           265:        BOOL check_unfold = NO;
        !           266:        int prev_cr = 0;
        !           267:        char *start = isoc->input_pointer;
        !           268:        char *cur = isoc->input_pointer;
        !           269:        char * line = NULL;
        !           270: 
        !           271:        for(;;) {
        !           272:            /*
        !           273:            ** Get more if needed to complete line
        !           274:            */
        !           275:            if (cur >= isoc->input_limit) { /* Need more data */
        !           276: #if 0
        !           277:                if (TRACE) fprintf(stderr, "HTInputSocket: reading more data\n");
        !           278: #endif
        !           279:                ascii_cat(&line, start, cur);
        !           280:                if (fill_in_buffer(isoc) <= 0)
        !           281:                    return line;
        !           282:                start = cur = isoc->input_pointer;
        !           283:            } /* if need more data */
        !           284: 
        !           285:            /*
        !           286:            ** Find a line feed if there is one
        !           287:            */
        !           288: #if 0
        !           289:            if (TRACE) fprintf(stderr, "HTInputSocket: processing read buffer\n");
        !           290: #endif
        !           291:            for(; cur < isoc->input_limit; cur++) {
        !           292:                char c = FROMASCII(*cur);
        !           293:                if (!c) {
        !           294: #if 0
        !           295:                    if (TRACE) fprintf(stderr, "HTInputSocket: panic, read zero!\n");
        !           296: #endif
        !           297:                    return NULL;        /* Panic! read a 0! */
        !           298:                }
        !           299:                if (check_unfold  &&  c != ' '  &&  c != '\t') {
        !           300: #if 0
        !           301:                    if (TRACE) fprintf(stderr, "HTInputSocket: returning \"%s\"\n",
        !           302:                                       (line ? line : "(null)"));
        !           303: #endif
        !           304:                    return line;  /* Note: didn't update isoc->input_pointer */
        !           305:                }
        !           306:                else {
        !           307:                    check_unfold = NO;
        !           308:                }
        !           309: 
        !           310:                if (c=='\r') {
        !           311: #if 0
        !           312:                    if (TRACE) fprintf(stderr, "HTInputSocket: found linefeed\n");
        !           313: #endif
        !           314:                    prev_cr = 1;
        !           315:                }
        !           316:                else {
        !           317:                    if (c=='\n') {              /* Found a line feed */
        !           318: #if 0
        !           319:                        if (TRACE) fprintf(stderr, "HTInputSocket: found newline\n");
        !           320: #endif
        !           321:                        ascii_cat(&line, start, cur-prev_cr);
        !           322:                        start = isoc->input_pointer = cur+1;
        !           323: 
        !           324:                        if (line && strlen(line) > 0 && unfold) {
        !           325: #if 0
        !           326:                            if (TRACE) fprintf(stderr, "HTInputSocket: next time check unfolding\n");
        !           327: #endif
        !           328:                            check_unfold = YES;
        !           329:                        }
        !           330:                        else {
        !           331: #if 0
        !           332:                            if (TRACE) fprintf(stderr,
        !           333:                                               "HTInputSocket: no unfold check -- just return \"%s\"\n",
        !           334:                                               (line ? line : "(line)"));
        !           335: #endif
        !           336:                            return line;
        !           337:                        }
        !           338:                    } /* if NL */
        !           339:                    /* else just a regular character */
        !           340:                    prev_cr = 0;
        !           341:                } /* if not CR */
        !           342:            } /* while characters in buffer remain */
        !           343:        } /* until line read or end-of-file */
        !           344:     } /* valid parameters to function */
        !           345: }
        !           346: 
        !           347: 
        !           348: PUBLIC char * HTInputSocket_getLine ARGS1(HTInputSocket *, isoc)
        !           349: {
        !           350:     return get_some_line(isoc, NO);
        !           351: }
        !           352: 
        !           353: PUBLIC char * HTInputSocket_getUnfoldedLine ARGS1(HTInputSocket *, isoc)
        !           354: {
        !           355:     return get_some_line(isoc, YES);
        !           356: }
        !           357: 
        !           358: 
        !           359: /*
        !           360: ** Read HTTP status line (if there is one).
        !           361: **
        !           362: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
        !           363: ** First look at the stub in ASCII and check if it starts "HTTP/".
        !           364: **
        !           365: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
        !           366: **      will be taken as a HTTP 1.0 server.  Failure.
        !           367: */
        !           368: #define STUB_LENGTH 20
        !           369: PUBLIC char * HTInputSocket_getStatusLine ARGS1(HTInputSocket *, isoc)
        !           370: {
        !           371:     if (!isoc) {
        !           372:        return NULL;
        !           373:     }
        !           374:     else {
        !           375:        char buf[STUB_LENGTH + 1];
        !           376:        int i;
        !           377:        char server_version[STUB_LENGTH+1];
        !           378:        int server_status;
        !           379: 
        !           380:        /*
        !           381:        ** Read initial buffer
        !           382:        */
        !           383:        if (isoc->input_pointer >= isoc->input_limit &&
        !           384:            fill_in_buffer(isoc) <= 0) {
        !           385:            return NULL;
        !           386:         }
        !           387: 
        !           388:        for (i=0; i < STUB_LENGTH; i++)
        !           389:            buf[i] = FROMASCII(isoc->input_buffer[i]);
        !           390:        buf[STUB_LENGTH] = 0;
        !           391: 
        !           392:        if (0 != strncmp(buf, "HTTP/", 5) ||
        !           393:            sscanf(buf, "%20s%d", server_version, &server_status) < 2)
        !           394:            return NULL;
        !           395:        else
        !           396:            return get_some_line(isoc, NO);
        !           397:     }
        !           398: }
        !           399: 
        !           400: 
        !           401: /*
        !           402: ** Do heuristic test to see if this is binary.
        !           403: **
        !           404: ** We check for characters above 128 in the first few bytes, and
        !           405: ** if we find them we forget the html default.
        !           406: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
        !           407: **
        !           408: ** Bugs: An HTTP 0.9 server returning a binary document with
        !           409: **      characters < 128 will be read as ASCII.
        !           410: */
        !           411: PUBLIC BOOL HTInputSocket_seemsBinary ARGS1(HTInputSocket *, isoc)
        !           412: {
        !           413:     if (isoc &&
        !           414:        (isoc->input_pointer < isoc->input_limit ||
        !           415:         fill_in_buffer(isoc) > 0)) {
        !           416:        char *p = isoc->input_buffer;
        !           417:        int i = STUB_LENGTH;
        !           418: 
        !           419:        for( ; i && p < isoc->input_limit; p++, i++)
        !           420:            if (((int)*p)&128)
        !           421:                return YES;
        !           422:     }
        !           423:     return NO;
        !           424: }
        !           425: 
        !           426: 
        !           427: 
1.1       timbl     428: /*     Stream the data to an ouput file as binary
                    429: */
1.13      timbl     430: PUBLIC int HTOutputBinary ARGS3( HTInputSocket *, isoc,
                    431:                                int,            input,
                    432:                                FILE *,         output)
1.1       timbl     433: {
                    434:     do {
                    435:            int status = NETREAD(
1.13      timbl     436:                    input, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1       timbl     437:            if (status <= 0) {
                    438:                if (status == 0) return 0;
                    439:                if (TRACE) fprintf(stderr,
                    440:                    "HTFormat: File read error %d\n", status);
                    441:                return 2;                       /* Error */
                    442:            }
1.13      timbl     443:            fwrite(isoc->input_buffer, sizeof(char), status, output);
1.1       timbl     444:     } while (YES);
                    445: }
                    446: 
                    447: 
1.2       timbl     448: /*             Create a filter stack
                    449: **             ---------------------
                    450: **
1.7       secret    451: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     452: **     structure is made to hold the destination format while the
                    453: **     new stack is generated. This is just to pass the out format to
                    454: **     MIME so far.  Storing the format of a stream in the stream might
                    455: **     be a lot neater.
1.10      timbl     456: **
                    457: **     The www/source format is special, in that if you can take
                    458: **     that you can take anything. However, we
1.2       timbl     459: */
1.12      timbl     460: PUBLIC HTStream * HTStreamStack ARGS2(
1.10      timbl     461:        HTFormat,               rep_in,
1.12      timbl     462:        HTRequest *,            request)
1.2       timbl     463: {
1.12      timbl     464:     HTFormat rep_out = request->output_format; /* Could be a param */
1.14      timbl     465:     HTList * conversion[2];
1.2       timbl     466:     HTAtom * wildcard = HTAtom_for("*");
1.10      timbl     467:     HTFormat source = WWW_SOURCE;
1.14      timbl     468:     int which_list;
                    469:     HTPresentation * pres, *match, *wildcard_match=0,
                    470:                        *source_match=0, *source_wildcard_match=0;
                    471:     
1.2       timbl     472:     if (TRACE) fprintf(stderr,
                    473:        "HTFormat: Constructing stream stack for %s to %s\n",
1.10      timbl     474:        HTAtom_name(rep_in),    
1.2       timbl     475:        HTAtom_name(rep_out));
                    476:                
1.14      timbl     477: 
1.15    ! luotonen  478: #ifdef BUG_OUT /* by Lou Montulli 16 Aug 93, put in by AL 6 Dec 93 */
1.2       timbl     479:     if (rep_out == WWW_SOURCE ||
1.12      timbl     480:        rep_out == rep_in) return request->output_stream;
1.15    ! luotonen  481: #endif
        !           482:     if (rep_out == rep_in) return request->output_stream;
1.2       timbl     483: 
1.14      timbl     484:     conversion[0] = request->conversions;
                    485:     conversion[1] = HTConversions;
1.2       timbl     486:     
1.15    ! luotonen  487:     for(which_list = 0; which_list<2; which_list++) {
        !           488:        HTList * cur = conversion[which_list];
        !           489:        
        !           490:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.10      timbl     491:            if (pres->rep == rep_in) {
1.2       timbl     492:                if (pres->rep_out == rep_out)
1.12      timbl     493:                    return (*pres->converter)(request, pres->command,
1.15    ! luotonen  494:                                              rep_in, pres->rep_out,
        !           495:                                              request->output_stream);
1.2       timbl     496:                if (pres->rep_out == wildcard) {
1.10      timbl     497:                    wildcard_match = pres;
                    498:                }
                    499:            }
                    500:            if (pres->rep == source) {
                    501:                if (pres->rep_out == rep_out)
                    502:                    source_match = pres;
                    503:                if (pres->rep_out == wildcard) {
                    504:                    source_wildcard_match = pres;
1.2       timbl     505:                }
                    506:            }
                    507:        }
                    508:     }
1.14      timbl     509:     match = wildcard_match ? wildcard_match :
                    510:            source_match ?      source_match : 
                    511:            source_wildcard_match;
                    512:     
                    513:     if (match) return (*match->converter)(
                    514:                request, match->command, rep_in, rep_out,
                    515:                request->output_stream);
1.10      timbl     516: 
1.2       timbl     517:     return NULL;
                    518: }
                    519:        
                    520: 
                    521: /*             Find the cost of a filter stack
                    522: **             -------------------------------
                    523: **
                    524: **     Must return the cost of the same stack which StreamStack would set up.
                    525: **
                    526: ** On entry,
                    527: **     length  The size of the data to be converted
                    528: */
1.12      timbl     529: PUBLIC float HTStackValue ARGS5(
1.14      timbl     530:        HTList *,               theseConversions,
1.10      timbl     531:        HTFormat,               rep_in,
1.2       timbl     532:        HTFormat,               rep_out,
                    533:        float,                  initial_value,
                    534:        long int,               length)
                    535: {
                    536:     HTAtom * wildcard = HTAtom_for("*");
1.14      timbl     537:     int which_list;
                    538:     HTList* conversion[2];
                    539:     
1.2       timbl     540:     if (TRACE) fprintf(stderr,
                    541:        "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
1.10      timbl     542:        HTAtom_name(rep_in),    initial_value,
1.2       timbl     543:        HTAtom_name(rep_out));
                    544:                
                    545:     if (rep_out == WWW_SOURCE ||
1.10      timbl     546:        rep_out == rep_in) return 0.0;
1.2       timbl     547: 
1.12      timbl     548:  /*   if (!HTPresentations) HTFormatInit();     set up the list */
1.2       timbl     549:     
1.14      timbl     550:     conversion[0] = theseConversions;
                    551:     conversion[1] = HTConversions;
                    552:     
                    553:     for(which_list = 0; which_list<2; which_list++)
                    554:      if (conversion[which_list]) {
1.15    ! luotonen  555:         HTList * cur = conversion[which_list];
1.2       timbl     556:        HTPresentation * pres;
1.15    ! luotonen  557:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
        !           558:            if (pres->rep == rep_in &&
        !           559:                (pres->rep_out == rep_out || pres->rep_out == wildcard)) {
1.2       timbl     560:                float value = initial_value * pres->quality;
                    561:                if (HTMaxSecs != 0.0)
1.15    ! luotonen  562:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     563:                                         /HTMaxSecs;
                    564:                return value;
                    565:            }
                    566:        }
                    567:     }
                    568:     
                    569:     return -1e30;              /* Really bad */
                    570: 
                    571: }
                    572:        
1.1       timbl     573: 
1.2       timbl     574: /*     Push data from a socket down a stream
                    575: **     -------------------------------------
1.1       timbl     576: **
1.2       timbl     577: **   This routine is responsible for creating and PRESENTING any
1.1       timbl     578: **   graphic (or other) objects described by the file.
1.2       timbl     579: **
                    580: **   The file number given is assumed to be a TELNET stream ie containing
                    581: **   CRLF at the end of lines which need to be stripped to LF for unix
                    582: **   when the format is textual.
                    583: **
1.1       timbl     584: */
1.2       timbl     585: PUBLIC void HTCopy ARGS2(
                    586:        int,                    file_number,
                    587:        HTStream*,              sink)
1.1       timbl     588: {
1.2       timbl     589:     HTStreamClass targetClass;    
1.13      timbl     590:     HTInputSocket * isoc;
1.2       timbl     591:     
1.5       timbl     592: /*     Push the data down the stream
1.2       timbl     593: **
                    594: */
                    595:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
1.13      timbl     596:     isoc = HTInputSocket_new(file_number);
1.2       timbl     597:     
                    598:     /* Push binary from socket down sink
1.10      timbl     599:     **
                    600:     **         This operation could be put into a main event loop
1.2       timbl     601:     */
                    602:     for(;;) {
                    603:        int status = NETREAD(
1.13      timbl     604:                file_number, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.2       timbl     605:        if (status <= 0) {
                    606:            if (status == 0) break;
                    607:            if (TRACE) fprintf(stderr,
                    608:                "HTFormat: Read error, read returns %d\n", status);
                    609:            break;
                    610:        }
1.8       timbl     611:        
                    612: #ifdef NOT_ASCII
                    613:        {
                    614:            char * p;
1.13      timbl     615:            for(p = isoc->input_buffer; p < isoc->input_buffer+status; p++) {
1.8       timbl     616:                *p = FROMASCII(*p);
                    617:            }
                    618:        }
                    619: #endif
                    620: 
1.13      timbl     621:        (*targetClass.put_block)(sink, isoc->input_buffer, status);
1.2       timbl     622:     } /* next bufferload */
1.13      timbl     623:     HTInputSocket_free(isoc);
1.2       timbl     624: }
                    625: 
1.1       timbl     626: 
1.7       secret    627: 
                    628: /*     Push data from a file pointer down a stream
                    629: **     -------------------------------------
                    630: **
                    631: **   This routine is responsible for creating and PRESENTING any
                    632: **   graphic (or other) objects described by the file.
                    633: **
                    634: **
                    635: */
                    636: PUBLIC void HTFileCopy ARGS2(
                    637:        FILE *,                 fp,
                    638:        HTStream*,              sink)
                    639: {
                    640:     HTStreamClass targetClass;    
1.13      timbl     641:     char input_buffer[INPUT_BUFFER_SIZE];
1.7       secret    642:     
                    643: /*     Push the data down the stream
                    644: **
                    645: */
                    646:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    647:     
                    648:     /* Push binary from socket down sink
                    649:     */
                    650:     for(;;) {
                    651:        int status = fread(
                    652:               input_buffer, 1, INPUT_BUFFER_SIZE, fp);
                    653:        if (status == 0) { /* EOF or error */
                    654:            if (ferror(fp) == 0) break;
                    655:            if (TRACE) fprintf(stderr,
                    656:                "HTFormat: Read error, read returns %d\n", ferror(fp));
                    657:            break;
                    658:        }
                    659:        (*targetClass.put_block)(sink, input_buffer, status);
1.13      timbl     660:     } /* next bufferload */    
1.7       secret    661: }
                    662: 
                    663: 
                    664: 
                    665: 
1.2       timbl     666: /*     Push data from a socket down a stream STRIPPING CR
                    667: **     --------------------------------------------------
                    668: **
                    669: **   This routine is responsible for creating and PRESENTING any
1.8       timbl     670: **   graphic (or other) objects described by the socket.
1.2       timbl     671: **
                    672: **   The file number given is assumed to be a TELNET stream ie containing
                    673: **   CRLF at the end of lines which need to be stripped to LF for unix
                    674: **   when the format is textual.
                    675: **
1.1       timbl     676: */
1.2       timbl     677: PUBLIC void HTCopyNoCR ARGS2(
                    678:        int,                    file_number,
                    679:        HTStream*,              sink)
                    680: {
1.13      timbl     681:     HTStreamClass targetClass;
                    682:     HTInputSocket * isoc;   
1.1       timbl     683:     
1.2       timbl     684: /*     Push the data, ignoring CRLF, down the stream
                    685: **
                    686: */
                    687:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    688: 
                    689: /*     Push text from telnet socket down sink
                    690: **
                    691: **     @@@@@ To push strings could be faster? (especially is we
                    692: **     cheat and don't ignore CR! :-}
                    693: */  
1.13      timbl     694:     isoc = HTInputSocket_new(file_number);
1.2       timbl     695:     for(;;) {
                    696:        char character;
1.13      timbl     697:        character = HTInputSocket_getCharacter(isoc);
1.2       timbl     698:        if (character == (char)EOF) break;
                    699:        (*targetClass.put_character)(sink, character);           
                    700:     }
1.13      timbl     701:     HTInputSocket_free(isoc);
1.2       timbl     702: }
1.1       timbl     703: 
1.2       timbl     704: 
1.7       secret    705: 
1.2       timbl     706: /*     Parse a socket given format and file number
                    707: **
                    708: **   This routine is responsible for creating and PRESENTING any
                    709: **   graphic (or other) objects described by the file.
                    710: **
                    711: **   The file number given is assumed to be a TELNET stream ie containing
                    712: **   CRLF at the end of lines which need to be stripped to LF for unix
                    713: **   when the format is textual.
                    714: **
                    715: */
1.14      timbl     716: 
1.12      timbl     717: PUBLIC int HTParseSocket ARGS3(
1.10      timbl     718:        HTFormat,               rep_in,
1.2       timbl     719:        int,                    file_number,
1.12      timbl     720:        HTRequest *,            request)
1.2       timbl     721: {
                    722:     HTStream * stream;
                    723:     HTStreamClass targetClass;    
1.1       timbl     724: 
1.12      timbl     725:     stream = HTStreamStack(rep_in, request);
1.2       timbl     726:     
                    727:     if (!stream) {
                    728:         char buffer[1024];     /* @@@@@@@@ */
                    729:        sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12      timbl     730:                HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.3       timbl     731:        if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
1.12      timbl     732:         return HTLoadError(request->output_stream, 501, buffer);
1.2       timbl     733:     }
1.1       timbl     734:     
1.3       timbl     735: /*     Push the data, ignoring CRLF if necessary, down the stream
                    736: **
1.2       timbl     737: **
1.3       timbl     738: **   @@  Bug:  This decision ought to be made based on "encoding"
1.9       timbl     739: **   rather than on format.  @@@  When we handle encoding.
1.3       timbl     740: **   The current method smells anyway.
1.2       timbl     741: */
                    742:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
1.10      timbl     743:     if (rep_in == WWW_BINARY || HTOutputSource
                    744:         || strstr(HTAtom_name(rep_in), "image/")
                    745:        || strstr(HTAtom_name(rep_in), "video/")) { /* @@@@@@ */
1.2       timbl     746:         HTCopy(file_number, stream);
                    747:     } else {   /* ascii text with CRLFs :-( */
                    748:         HTCopyNoCR(file_number, stream);
                    749:     }
1.7       secret    750:     (*targetClass.free)(stream);
                    751:     
                    752:     return HT_LOADED;
                    753: }
                    754: 
                    755: 
                    756: 
                    757: /*     Parse a file given format and file pointer
                    758: **
                    759: **   This routine is responsible for creating and PRESENTING any
                    760: **   graphic (or other) objects described by the file.
                    761: **
                    762: **   The file number given is assumed to be a TELNET stream ie containing
1.10      timbl     763: **   CRLF at the end of lines which need to be stripped to \n for unix
1.7       secret    764: **   when the format is textual.
                    765: **
                    766: */
1.12      timbl     767: PUBLIC int HTParseFile ARGS3(
1.10      timbl     768:        HTFormat,               rep_in,
1.7       secret    769:        FILE *,                 fp,
1.12      timbl     770:        HTRequest *,            request)
1.7       secret    771: {
                    772:     HTStream * stream;
                    773:     HTStreamClass targetClass;    
                    774: 
1.12      timbl     775:     stream = HTStreamStack(rep_in, request);
1.7       secret    776:     
                    777:     if (!stream) {
                    778:         char buffer[1024];     /* @@@@@@@@ */
                    779:        sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12      timbl     780:                HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.7       secret    781:        if (TRACE) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
1.12      timbl     782:         return HTLoadError(request->output_stream, 501, buffer);
1.7       secret    783:     }
                    784:     
1.9       timbl     785: /*     Push the data down the stream
1.7       secret    786: **
                    787: **
                    788: **   @@  Bug:  This decision ought to be made based on "encoding"
1.10      timbl     789: **   rather than on content-type.  @@@  When we handle encoding.
1.7       secret    790: **   The current method smells anyway.
                    791: */
                    792:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
                    793:     HTFileCopy(fp, stream);
1.2       timbl     794:     (*targetClass.free)(stream);
1.1       timbl     795:     
1.2       timbl     796:     return HT_LOADED;
1.1       timbl     797: }
1.2       timbl     798: 
1.10      timbl     799: 
                    800: /*     Converter stream: Network Telnet to internal character text
                    801: **     -----------------------------------------------------------
                    802: **
                    803: **     The input is assumed to be in ASCII, with lines delimited
                    804: **     by (13,10) pairs, These pairs are converted into (CR,LF)
                    805: **     pairs in the local representation.  The (CR,LF) sequence
                    806: **     when found is changed to a '\n' character, the internal
                    807: **     C representation of a new line.
                    808: */
                    809: 
                    810: 
1.11      timbl     811: PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
1.10      timbl     812: {
                    813:     char c = FROMASCII(net_char);
                    814:     if (me->had_cr) {
                    815:         if (c==LF) {
                    816:            me->sink->isa->put_character(me->sink, '\n');       /* Newline */
                    817:            me->had_cr = NO;
                    818:            return;
                    819:         } else {
                    820:            me->sink->isa->put_character(me->sink, CR); /* leftover */
                    821:        }
                    822:     }
                    823:     me->had_cr = (c==CR);
                    824:     if (!me->had_cr)
                    825:        me->sink->isa->put_character(me->sink, c);              /* normal */
                    826: }
                    827: 
1.11      timbl     828: PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
1.10      timbl     829: {
                    830:     CONST char * p;
                    831:     for(p=s; *p; p++) NetToText_put_character(me, *p);
                    832: }
                    833: 
1.11      timbl     834: PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
1.10      timbl     835: {
                    836:     CONST char * p;
                    837:     for(p=s; p<(s+l); p++) NetToText_put_character(me, *p);
                    838: }
                    839: 
                    840: PRIVATE void NetToText_free ARGS1(HTStream *, me)
                    841: {
                    842:     me->sink->isa->free(me->sink);             /* Close rest of pipe */
                    843:     free(me);
                    844: }
                    845: 
                    846: PRIVATE void NetToText_abort ARGS2(HTStream *, me, HTError, e)
                    847: {
                    848:     me->sink->isa->abort(me->sink,e);          /* Abort rest of pipe */
                    849:     free(me);
                    850: }
                    851: 
                    852: /*     The class structure
                    853: */
                    854: PRIVATE HTStreamClass NetToTextClass = {
                    855:     "NetToText",
                    856:     NetToText_free,
                    857:     NetToText_abort,
                    858:     NetToText_put_character,
                    859:     NetToText_put_string,
                    860:     NetToText_put_block
                    861: };
                    862: 
                    863: /*     The creation method
                    864: */
                    865: PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
                    866: {
                    867:     HTStream* me = (HTStream*)malloc(sizeof(*me));
                    868:     if (me == NULL) outofmem(__FILE__, "NetToText");
                    869:     me->isa = &NetToTextClass;
                    870:     
                    871:     me->had_cr = NO;
                    872:     me->sink = sink;
                    873:     return me;
                    874: }
1.2       timbl     875: 
                    876: 

Webmaster