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

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

Webmaster