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

1.55      frystyk     1: /*                                                                  HTFormat.c
                      2: **     MANAGE DIFFERENT FILE FORMATS
                      3: **
1.62      frystyk     4: **     (c) COPYRIGHT MIT 1995.
1.55      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
1.1       timbl       6: **
                      7: ** Bugs:
                      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: **
1.45      duns       12: ** HISTORY:
1.52      frystyk    13: **     8 Jul 94  FM    Insulate free() from _free structure element.
                     14: **     8 Nov 94  HFN   Changed a lot to make reentrant
1.2       timbl      15: */
                     16: 
1.58      frystyk    17: /* Library Include files */
                     18: #include "tcp.h"
1.52      frystyk    19: #include "HTUtils.h"
1.58      frystyk    20: #include "HTString.h"
1.52      frystyk    21: #include "HTTCP.h"
1.58      frystyk    22: #include "HTFWrite.h"
1.52      frystyk    23: #include "HTGuess.h"
                     24: #include "HTThread.h"
                     25: #include "HTError.h"
                     26: #include "HTFormat.h"                                   /* Implemented here */
1.2       timbl      27: 
1.52      frystyk    28: /* Public variables */
                     29: PUBLIC HTList * HTConversions = NULL;
1.63    ! frystyk    30: PUBLIC HTList * HTCharsets = NULL;
        !            31: PUBLIC HTList * HTEncodings = NULL;
        !            32: PUBLIC HTList * HTLanguages = NULL;
        !            33: 
        !            34: #define NO_VALUE_FOUND -1e30            /* Stream Stack Value if none found */
        !            35: 
        !            36: /* Varlables and typedefs local to this moduel */
        !            37: PRIVATE double HTMaxSecs = 1e10;               /* No effective limit */
        !            38: PRIVATE double HTMaxLength = 1e10;             /* No effective limit */
1.17      luotonen   39: 
1.60      frystyk    40: struct _HTStream {
                     41:     CONST HTStreamClass *      isa;
                     42: };
                     43: 
1.52      frystyk    44: /* ------------------------------------------------------------------------- */
1.63    ! frystyk    45: /*       ACCEPT LISTS OF CONVERSIONS, ENCODINGS, LANGUAGE, AND CHARSET      */
1.61      frystyk    46: /* ------------------------------------------------------------------------- */
1.17      luotonen   47: 
1.52      frystyk    48: /*
1.63    ! frystyk    49: **     For all `accept lists' there is a local list and a global list. The
        !            50: **     local list is a part of the request structure and the global list is
        !            51: **     internal to the HTFormat module. The global lists can be used when
        !            52: **     specifying accept lists for ALL requests and the local list can be 
        !            53: **     used to add specific accept headers to the request.
        !            54: */
        !            55: 
        !            56: /*
        !            57: **     Cleanup memory after the LOCAL list of converters, language,
        !            58: **     charset, and encoding in the HTRequest structure. Note that
        !            59: **     all these also have a global representation.
1.2       timbl      60: */
1.52      frystyk    61: PUBLIC void HTFormatDelete ARGS1(HTRequest *, request)
1.31      frystyk    62: {
1.63    ! frystyk    63:     if (!request)
        !            64:        return;
        !            65: 
        !            66:     /* List of converters and presenters */
        !            67:     if (request->conversions) {
1.56      frystyk    68:        HTList *cur = request->conversions;
                     69:        HTPresentation *pres;
                     70:        while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
                     71:            FREE(pres->command); /* Leak fixed AL 6 Feb 1994 */
                     72:            free(pres);
                     73:        }
                     74:        HTList_delete(request->conversions);
                     75:        request->conversions = NULL;
1.31      frystyk    76:     }
1.63    ! frystyk    77: 
        !            78:     /* List of encoders (or decoders) */
        !            79:     if (request->encodings) {
        !            80:        HTList *cur = request->encodings;
        !            81:        HTAcceptNode *pres;
        !            82:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
        !            83:            free(pres);
        !            84:        }
        !            85:        HTList_delete(request->encodings);
        !            86:        request->encodings = NULL;
        !            87:     }
        !            88: 
        !            89:     /* List of natural languages */
        !            90:     if (request->languages) {
        !            91:        HTList *cur = request->languages;
        !            92:        HTAcceptNode *pres;
        !            93:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
        !            94:            free(pres);
        !            95:        }
        !            96:        HTList_delete(request->languages);
        !            97:        request->languages = NULL;
        !            98:     }
        !            99: 
        !           100:     /* List of charsets */
        !           101:     if (request->charsets) {
        !           102:        HTList *cur = request->charsets;
        !           103:        HTAcceptNode *pres;
        !           104:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
        !           105:            free(pres);
        !           106:        }
        !           107:        HTList_delete(request->charsets);
        !           108:        request->charsets = NULL;
        !           109:     }
1.31      frystyk   110: }
                    111: 
1.2       timbl     112: 
1.61      frystyk   113: /*
1.63    ! frystyk   114: **     Cleanup memory after the GLOBAL list of converters, encodings,
        !           115: **     languages, charsets etc. Note that there
1.61      frystyk   116: **     is also a LOCAL conversion list associated with each HTRequest
                    117: **     structure. Written by Eric Sink, eric@spyglass.com
                    118: */
                    119: PUBLIC void HTDisposeConversions NOARGS
                    120: {
1.63    ! frystyk   121:     /* List of converters/preenters */
1.61      frystyk   122:     if (HTConversions) {
                    123:        HTList *cur = HTConversions;
                    124:        HTPresentation *pres;
                    125:        while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
                    126:            FREE(pres->command);
                    127:            free(pres);
                    128:        }
                    129:        HTList_delete(HTConversions);
                    130:        HTConversions = NULL;
                    131:     }
1.63    ! frystyk   132: 
        !           133:     /* List of encoders */
        !           134:     if (HTEncodings) {
        !           135:        HTList *cur = HTEncodings;
        !           136:        HTAcceptNode *pres;
        !           137:        while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
        !           138:            free(pres);
        !           139:        }
        !           140:        HTList_delete(HTEncodings);
        !           141:        HTEncodings = NULL;
        !           142:     }
        !           143: 
        !           144:     /* List of Languages */
        !           145:     if (HTLanguages) {
        !           146:        HTList *cur = HTLanguages;
        !           147:        HTAcceptNode *pres;
        !           148:        while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
        !           149:            free(pres);
        !           150:        }
        !           151:        HTList_delete(HTLanguages);
        !           152:        HTLanguages = NULL;
        !           153:     }
        !           154: 
        !           155:     /* List of Charsets */
        !           156:     if (HTCharsets) {
        !           157:        HTList *cur = HTCharsets;
        !           158:        HTAcceptNode *pres;
        !           159:        while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
        !           160:            free(pres);
        !           161:        }
        !           162:        HTList_delete(HTCharsets);
        !           163:        HTCharsets = NULL;
        !           164:     }
1.61      frystyk   165: }
                    166: 
                    167: 
1.2       timbl     168: /*     Define a presentation system command for a content-type
                    169: **     -------------------------------------------------------
1.52      frystyk   170: ** INPUT:
                    171: **     conversions:    The list of conveters and presenters
                    172: **     representation: the MIME-style format name
                    173: **     command:        the MAILCAP-style command template
                    174: **     quality:        A degradation faction [0..1]
                    175: **     maxbytes:       A limit on the length acceptable as input (0 infinite)
                    176: **     maxsecs:        A limit on the time user will wait (0 for infinity)
1.2       timbl     177: */
1.49      howcome   178: PUBLIC void HTSetPresentation ARGS7(
1.12      timbl     179:        HTList *,       conversions,
                    180:        CONST char *,   representation,
                    181:        CONST char *,   command,
1.52      frystyk   182:        CONST char *,   test_command,  /* HWL 27/9/94: mailcap functionality */
1.59      frystyk   183:        double,         quality,
                    184:        double,         secs, 
                    185:        double,         secs_per_byte)
1.52      frystyk   186: {
1.63    ! frystyk   187:     HTPresentation * pres = (HTPresentation *)calloc(1,sizeof(HTPresentation));
1.2       timbl     188:     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
                    189:     
                    190:     pres->rep = HTAtom_for(representation);
                    191:     pres->rep_out = WWW_PRESENT;               /* Fixed for now ... :-) */
                    192:     pres->converter = HTSaveAndExecute;                /* Fixed for now ...     */
                    193:     pres->quality = quality;
                    194:     pres->secs = secs;
                    195:     pres->secs_per_byte = secs_per_byte;
                    196:     pres->rep = HTAtom_for(representation);
1.49      howcome   197:     pres->command = NULL;
1.2       timbl     198:     StrAllocCopy(pres->command, command);
1.49      howcome   199:     pres->test_command = NULL;
                    200:     StrAllocCopy(pres->test_command, test_command);
1.12      timbl     201:     HTList_addObject(conversions, pres);
1.2       timbl     202: }
                    203: 
                    204: 
                    205: /*     Define a built-in function for a content-type
                    206: **     ---------------------------------------------
                    207: */
1.12      timbl     208: PUBLIC void HTSetConversion ARGS7(
                    209:        HTList *,       conversions,
                    210:        CONST char *,   representation_in,
                    211:        CONST char *,   representation_out,
1.6       timbl     212:        HTConverter*,   converter,
1.59      frystyk   213:        double,         quality,
                    214:        double,         secs, 
                    215:        double,         secs_per_byte)
1.52      frystyk   216: {
1.63    ! frystyk   217:     HTPresentation * pres = (HTPresentation *)calloc(1,sizeof(HTPresentation));
1.2       timbl     218:     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
                    219:     
                    220:     pres->rep = HTAtom_for(representation_in);
                    221:     pres->rep_out = HTAtom_for(representation_out);
                    222:     pres->converter = converter;
                    223:     pres->command = NULL;              /* Fixed */
1.49      howcome   224:     pres->test_command = NULL;
1.2       timbl     225:     pres->quality = quality;
                    226:     pres->secs = secs;
                    227:     pres->secs_per_byte = secs_per_byte;
1.12      timbl     228:     HTList_addObject(conversions, pres);
1.56      frystyk   229: }
                    230: 
                    231: 
1.17      luotonen  232: PUBLIC void HTAcceptEncoding ARGS3(HTList *,   list,
1.63    ! frystyk   233:                                   CONST char *,enc,
1.59      frystyk   234:                                   double,      quality)
1.17      luotonen  235: {
                    236:     HTAcceptNode * node;
1.63    ! frystyk   237:     if (!list || !enc || !*enc) {
        !           238:        if (TRACE)
        !           239:            fprintf(TDEST, "Encodings... Bad argument\n");
        !           240:        return;
        !           241:     }
1.17      luotonen  242:     node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
                    243:     if (!node) outofmem(__FILE__, "HTAcceptEncoding");
                    244:     HTList_addObject(list, (void*)node);
                    245: 
                    246:     node->atom = HTAtom_for(enc);
                    247:     node->quality = quality;
                    248: }
                    249: 
                    250: 
                    251: PUBLIC void HTAcceptLanguage ARGS3(HTList *,   list,
1.63    ! frystyk   252:                                   CONST char *,lang,
1.59      frystyk   253:                                   double,      quality)
1.17      luotonen  254: {
                    255:     HTAcceptNode * node;
1.63    ! frystyk   256:     if (!list || !lang || !*lang)  {
        !           257:        if (TRACE)
        !           258:            fprintf(TDEST, "Languages... Bad argument\n");
        !           259:        return;
        !           260:     }
        !           261:     node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
        !           262:     if (!node) outofmem(__FILE__, "HTAcceptLanguage");
        !           263: 
        !           264:     HTList_addObject(list, (void*)node);
        !           265:     node->atom = HTAtom_for(lang);
        !           266:     node->quality = quality;
        !           267: }
1.17      luotonen  268: 
                    269: 
1.63    ! frystyk   270: PUBLIC void HTAcceptCharset ARGS3(HTList *,    list,
        !           271:                                  CONST char *, charset,
        !           272:                                  double,       quality)
        !           273: {
        !           274:     HTAcceptNode * node;
        !           275:     if (!list || !charset || !*charset)  {
        !           276:        if (TRACE)
        !           277:            fprintf(TDEST, "Charset..... Bad argument\n");
        !           278:        return;
        !           279:     }
1.17      luotonen  280:     node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
1.63    ! frystyk   281:     if (!node) outofmem(__FILE__, "HTAcceptCharsetuage");
1.17      luotonen  282: 
                    283:     HTList_addObject(list, (void*)node);
1.63    ! frystyk   284:     node->atom = HTAtom_for(charset);
1.17      luotonen  285:     node->quality = quality;
                    286: }
                    287: 
                    288: 
1.63    ! frystyk   289: /* ------------------------------------------------------------------------- */
        !           290: /*                             FORMAT NEGOTIATION                           */
        !           291: /* ------------------------------------------------------------------------- */
        !           292: 
        !           293: PRIVATE BOOL better_match ARGS2(HTFormat, f,
        !           294:                                HTFormat, g)
        !           295: {
        !           296:     CONST char *p, *q;
        !           297: 
        !           298:     if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
        !           299:        int i,j;
        !           300:        for(i=0 ; *p; p++) if (*p == '*') i++;
        !           301:        for(j=0 ; *q; q++) if (*q == '*') j++;
        !           302:        if (i < j) return YES;
        !           303:     }
        !           304:     return NO;
        !           305: }
        !           306: 
        !           307: 
1.48      frystyk   308: PRIVATE BOOL wild_match ARGS2(HTAtom *,        tmplate,
1.17      luotonen  309:                              HTAtom *, actual)
                    310: {
                    311:     char *t, *a, *st, *sa;
                    312:     BOOL match = NO;
                    313: 
1.48      frystyk   314:     if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22      luotonen  315:        if (!strcmp(t, "*"))
                    316:            return YES;
1.17      luotonen  317: 
1.22      luotonen  318:        if (strchr(t, '*') &&
                    319:            (a = HTAtom_name(actual)) &&
                    320:            (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17      luotonen  321: 
1.22      luotonen  322:            *sa = 0;
                    323:            *st = 0;
                    324: 
                    325:            if ((*(st-1)=='*' &&
                    326:                 (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
                    327:                (*(st+1)=='*' && !strcasecomp(t,a)))
                    328:                match = YES;
                    329: 
                    330:            *sa = '/';
                    331:            *st = '/';
                    332:        }    
                    333:     }
1.23      luotonen  334:     return match;
1.17      luotonen  335: }
                    336: 
1.36      luotonen  337: /*
                    338:  * Added by takada@seraph.ntt.jp (94/04/08)
                    339:  */
1.48      frystyk   340: PRIVATE BOOL lang_match ARGS2(HTAtom *,        tmplate,
1.36      luotonen  341:                              HTAtom *, actual)
                    342: {
                    343:     char *t, *a, *st, *sa;
                    344:     BOOL match = NO;
                    345: 
1.48      frystyk   346:     if (tmplate && actual &&
                    347:        (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36      luotonen  348:        st = strchr(t, '_');
                    349:        sa = strchr(a, '_');
                    350:        if ((st != NULL) && (sa != NULL)) {
                    351:            if (!strcasecomp(t, a))
                    352:              match = YES;
                    353:            else
                    354:              match = NO;
                    355:        }
                    356:        else {
                    357:            if (st != NULL) *st = 0;
                    358:            if (sa != NULL) *sa = 0;
                    359:            if (!strcasecomp(t, a))
                    360:              match = YES;
                    361:            else
                    362:              match = NO;
                    363:            if (st != NULL) *st = '_';
                    364:            if (sa != NULL) *sa = '_';
                    365:        }
                    366:     }
                    367:     return match;
                    368: }
                    369: /* end of addition */
                    370: 
                    371: 
1.17      luotonen  372: 
1.59      frystyk   373: PRIVATE double type_value ARGS2(HTAtom *,      content_type,
1.17      luotonen  374:                               HTList *,        accepted)
                    375: {
                    376:     HTList * cur = accepted;
                    377:     HTPresentation * pres;
                    378:     HTPresentation * wild = NULL;
                    379: 
                    380:     if (!content_type || !accepted) return -1;
                    381: 
                    382:     while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    383:        if (pres->rep == content_type)
                    384:            return pres->quality;
                    385:        else if (wild_match(pres->rep, content_type))
                    386:            wild = pres;
                    387:     }
                    388:     if (wild) return wild->quality;
                    389:     else return -1;
                    390: }
                    391: 
                    392: 
1.59      frystyk   393: PRIVATE double lang_value ARGS2(HTAtom *,      language,
1.17      luotonen  394:                               HTList *,        accepted)
                    395: {
                    396:     HTList * cur = accepted;
                    397:     HTAcceptNode * node;
                    398:     HTAcceptNode * wild = NULL;
                    399: 
                    400:     if (!language || !accepted || HTList_isEmpty(accepted)) {
                    401:        return 0.1;
                    402:     }
                    403: 
                    404:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    405:        if (node->atom == language) {
                    406:            return node->quality;
                    407:        }
1.36      luotonen  408:        /*
                    409:         * patch by takada@seraph.ntt.jp (94/04/08)
                    410:         * the original line was
                    411:         * else if (wild_match(node->atom, language)) {
                    412:         * and the new line is
                    413:         */
                    414:        else if (lang_match(node->atom, language)) {
1.17      luotonen  415:            wild = node;
                    416:        }
                    417:     }
                    418: 
                    419:     if (wild) {
                    420:        return wild->quality;
                    421:     }
                    422:     else {
                    423:        return 0.1;
                    424:     }
                    425: }
                    426: 
                    427: 
1.59      frystyk   428: PRIVATE double encoding_value ARGS2(HTAtom *,  encoding,
1.17      luotonen  429:                                   HTList *,    accepted)
                    430: {
                    431:     HTList * cur = accepted;
                    432:     HTAcceptNode * node;
                    433:     HTAcceptNode * wild = NULL;
                    434:     char * e;
                    435: 
                    436:     if (!encoding || !accepted || HTList_isEmpty(accepted))
                    437:        return 1;
                    438: 
                    439:     e = HTAtom_name(encoding);
                    440:     if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
                    441:        return 1;
                    442: 
                    443:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    444:        if (node->atom == encoding)
                    445:            return node->quality;
                    446:        else if (wild_match(node->atom, encoding))
                    447:            wild = node;
                    448:     }
                    449:     if (wild) return wild->quality;
                    450:     else return 1;
                    451: }
                    452: 
                    453: 
                    454: PUBLIC BOOL HTRank ARGS4(HTList *, possibilities,
                    455:                         HTList *, accepted_content_types,
                    456:                         HTList *, accepted_languages,
                    457:                         HTList *, accepted_encodings)
                    458: {
                    459:     int accepted_cnt = 0;
                    460:     HTList * accepted;
                    461:     HTList * sorted;
                    462:     HTList * cur;
                    463:     HTContentDescription * d;
                    464: 
                    465:     if (!possibilities) return NO;
                    466: 
                    467:     accepted = HTList_new();
                    468:     cur = possibilities;
                    469:     while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
1.59      frystyk   470:        double tv = type_value(d->content_type, accepted_content_types);
                    471:        double lv = lang_value(d->content_language, accepted_languages);
                    472:        double ev = encoding_value(d->content_encoding, accepted_encodings);
1.17      luotonen  473: 
                    474:        if (tv > 0) {
                    475:            d->quality *= tv * lv * ev;
                    476:            HTList_addObject(accepted, d);
                    477:            accepted_cnt++;
                    478:        }
1.18      luotonen  479:        else {
                    480:            if (d->filename) free(d->filename);
                    481:            free(d);
                    482:        }
1.17      luotonen  483:     }
                    484: 
1.58      frystyk   485:     if (PROT_TRACE) fprintf(TDEST, "Ranking.....\n");
                    486:     if (PROT_TRACE) fprintf(TDEST,
1.18      luotonen  487:           "\nRANK QUALITY CONTENT-TYPE         LANGUAGE ENCODING    FILE\n");
1.17      luotonen  488: 
                    489:     sorted = HTList_new();
                    490:     while (accepted_cnt-- > 0) {
                    491:        HTContentDescription * worst = NULL;
                    492:        cur = accepted;
                    493:        while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
                    494:            if (!worst || d->quality < worst->quality)
                    495:                worst = d;
                    496:        }
                    497:        if (worst) {
1.58      frystyk   498:            if (PROT_TRACE)
                    499:                fprintf(TDEST, "%d.   %.4f  %-20.20s %-8.8s %-10.10s %s\n",
                    500:                        accepted_cnt+1,
                    501:                        worst->quality,
                    502:                        (worst->content_type
1.17      luotonen  503:                         ? HTAtom_name(worst->content_type)      : "-"),
1.58      frystyk   504:                        (worst->content_language
1.17      luotonen  505:                         ? HTAtom_name(worst->content_language)  :"-"),
1.58      frystyk   506:                        (worst->content_encoding
1.17      luotonen  507:                         ? HTAtom_name(worst->content_encoding)  :"-"),
1.58      frystyk   508:                        (worst->filename
1.17      luotonen  509:                         ? worst->filename                       :"-"));
                    510:            HTList_removeObject(accepted, (void*)worst);
                    511:            HTList_addObject(sorted, (void*)worst);
                    512:        }
                    513:     }
1.58      frystyk   514:     if (PROT_TRACE) fprintf(TDEST, "\n");
1.17      luotonen  515:     HTList_delete(accepted);
                    516:     HTList_delete(possibilities->next);
                    517:     possibilities->next = sorted->next;
                    518:     sorted->next = NULL;
                    519:     HTList_delete(sorted);
                    520: 
                    521:     if (!HTList_isEmpty(possibilities)) return YES;
                    522:     else return NO;
                    523: }
                    524: 
                    525: 
1.2       timbl     526: /*             Create a filter stack
                    527: **             ---------------------
                    528: **
1.7       secret    529: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     530: **     structure is made to hold the destination format while the
                    531: **     new stack is generated. This is just to pass the out format to
                    532: **     MIME so far.  Storing the format of a stream in the stream might
                    533: **     be a lot neater.
1.10      timbl     534: **
1.29      frystyk   535: **     The star/star format is special, in that if you can take
1.40      frystyk   536: **     that you can take anything.
                    537: **
                    538: **     On succes, request->error_block is set to YES so no more error
                    539: **     messages to the stream as the stream might be of any format.
1.2       timbl     540: */
1.52      frystyk   541: PUBLIC HTStream * HTStreamStack ARGS5(HTFormat,                rep_in,
                    542:                                      HTFormat,         rep_out,
                    543:                                      HTStream *,       output_stream,
1.34      luotonen  544:                                      HTRequest *,      request,
                    545:                                      BOOL,             guess)
1.2       timbl     546: {
1.14      timbl     547:     HTList * conversion[2];
                    548:     int which_list;
1.59      frystyk   549:     double best_quality = -1e30;               /* Pretty bad! */
1.29      frystyk   550:     HTPresentation *pres, *match, *best_match=0;
1.14      timbl     551:     
1.47      frystyk   552:     request->error_block = YES;                   /* No more error output to stream */
1.58      frystyk   553:     if (TRACE) fprintf(TDEST,
1.39      frystyk   554:        "StreamStack. Constructing stream stack for %s to %s\n",
1.10      timbl     555:        HTAtom_name(rep_in),    
1.2       timbl     556:        HTAtom_name(rep_out));
1.34      luotonen  557: 
                    558:     if (guess  &&  rep_in == WWW_UNKNOWN) {
1.58      frystyk   559:        if (PROT_TRACE) fprintf(TDEST, "Returning... guessing stream\n");
1.52      frystyk   560:        return HTGuess_new(request, NULL, rep_in, rep_out, output_stream);
1.34      luotonen  561:     }
                    562: 
1.47      frystyk   563:     if (rep_out == WWW_SOURCE || rep_out == rep_in) {
1.52      frystyk   564:        return output_stream;
1.47      frystyk   565:     }
1.2       timbl     566: 
1.14      timbl     567:     conversion[0] = request->conversions;
                    568:     conversion[1] = HTConversions;
1.17      luotonen  569: 
1.15      luotonen  570:     for(which_list = 0; which_list<2; which_list++) {
                    571:        HTList * cur = conversion[which_list];
                    572:        
                    573:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.25      frystyk   574:            if  ((pres->rep == rep_in || wild_match(pres->rep, rep_in)) &&
1.33      luotonen  575:                 (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
                    576:                if (!best_match ||
                    577:                    better_match(pres->rep, best_match->rep) ||
                    578:                    (!better_match(best_match->rep, pres->rep) &&
                    579:                     pres->quality > best_quality)) {
1.58      frystyk   580: #ifdef GOT_SYSTEM
                    581:                    if (!pres->test_command||(system(pres->test_command)==0)){ 
1.49      howcome   582:                        if (TRACE && pres->test_command) 
1.58      frystyk   583:                            fprintf(TDEST, "HTStreamStack testing %s %d\n",pres->test_command,system(pres->test_command)); 
1.49      howcome   584:                        best_match = pres;
                    585:                        best_quality = pres->quality;
                    586:                    }
1.58      frystyk   587: #endif /* GOT_SYSTEM */
1.10      timbl     588:                }
                    589:            }
1.2       timbl     590:        }
                    591:     }
1.33      luotonen  592: 
1.29      frystyk   593:     match = best_match ? best_match : NULL;
                    594:     if (match) {
                    595:        if (match->rep == WWW_SOURCE) {
1.58      frystyk   596:            if (TRACE) fprintf(TDEST, "StreamStack. Don't know how to handle this, so put out %s to %s\n",
1.29      frystyk   597:                               HTAtom_name(match->rep), 
                    598:                               HTAtom_name(rep_out));
                    599:        }
1.52      frystyk   600:        return (*match->converter)(request, match->command, rep_in, rep_out,
                    601:                                   output_stream);
1.29      frystyk   602:     }
1.42      frystyk   603:     {
                    604:        char *msg = NULL;
                    605:        StrAllocCopy(msg, "Can't convert from ");
                    606:        StrAllocCat(msg, HTAtom_name(rep_in));
                    607:        StrAllocCat(msg, " to ");
                    608:        StrAllocCat(msg, HTAtom_name(rep_out));
                    609:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
                    610:                   (void *) msg, (int) strlen(msg), "HTStreamStack");
                    611:        free(msg);
                    612:     }
1.47      frystyk   613:     request->error_block = NO;          /* We didn't put up a stream anyway */
1.2       timbl     614:     return NULL;
                    615: }
                    616:        
                    617: 
                    618: /*             Find the cost of a filter stack
                    619: **             -------------------------------
                    620: **
                    621: **     Must return the cost of the same stack which StreamStack would set up.
                    622: **
                    623: ** On entry,
                    624: **     length  The size of the data to be converted
                    625: */
1.59      frystyk   626: PUBLIC double HTStackValue ARGS5(
1.14      timbl     627:        HTList *,               theseConversions,
1.10      timbl     628:        HTFormat,               rep_in,
1.2       timbl     629:        HTFormat,               rep_out,
1.59      frystyk   630:        double,                 initial_value,
1.2       timbl     631:        long int,               length)
                    632: {
1.14      timbl     633:     int which_list;
                    634:     HTList* conversion[2];
                    635:     
1.58      frystyk   636:     if (TRACE) fprintf(TDEST,
1.39      frystyk   637:        "StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.10      timbl     638:        HTAtom_name(rep_in),    initial_value,
1.2       timbl     639:        HTAtom_name(rep_out));
                    640:                
                    641:     if (rep_out == WWW_SOURCE ||
1.10      timbl     642:        rep_out == rep_in) return 0.0;
1.2       timbl     643: 
1.14      timbl     644:     conversion[0] = theseConversions;
                    645:     conversion[1] = HTConversions;
                    646:     
                    647:     for(which_list = 0; which_list<2; which_list++)
                    648:      if (conversion[which_list]) {
1.15      luotonen  649:         HTList * cur = conversion[which_list];
1.2       timbl     650:        HTPresentation * pres;
1.15      luotonen  651:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    652:            if (pres->rep == rep_in &&
1.17      luotonen  653:                (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.59      frystyk   654:                double value = initial_value * pres->quality;
1.2       timbl     655:                if (HTMaxSecs != 0.0)
1.15      luotonen  656:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     657:                                         /HTMaxSecs;
                    658:                return value;
                    659:            }
                    660:        }
                    661:     }
1.63    ! frystyk   662:     return NO_VALUE_FOUND;             /* Really bad */
1.1       timbl     663: }
1.2       timbl     664: 
1.10      timbl     665: 

Webmaster