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

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

Webmaster