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

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

Webmaster