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

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.87    ! frystyk     6: **     @(#) $Id: Date Author State $
1.1       timbl       7: **
                      8: ** Bugs:
                      9: **     Assumes the incoming stream is ASCII, rather than a local file
                     10: **     format, and so ALWAYS converts from ASCII on non-ASCII machines.
                     11: **     Therefore, non-ASCII machines can't read local files.
1.2       timbl      12: **
1.45      duns       13: ** HISTORY:
1.86      frystyk    14: **     8 Jul 94  FM    Insulate free from _free structure element.
1.52      frystyk    15: **     8 Nov 94  HFN   Changed a lot to make reentrant
1.2       timbl      16: */
                     17: 
1.58      frystyk    18: /* Library Include files */
1.85      frystyk    19: #include "sysdep.h"
1.87    ! frystyk    20: #include "WWWUtil.h"
        !            21: #include "HTReqMan.h"
        !            22: #include "HTNetMan.h"
        !            23: #include "HTStream.h"
1.58      frystyk    24: #include "HTFWrite.h"
1.52      frystyk    25: #include "HTError.h"
                     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.87    ! frystyk    30: PRIVATE HTList * HTConversions = NULL;                     /* Content types */
        !            31: PRIVATE HTList * HTEncodings = NULL;                    /* Content encoders */
1.72      frystyk    32: PRIVATE HTList * HTCharsets = 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.87    ! frystyk    41: struct _HTContentCoding {
        !            42:     HTEncoding         coding;
        !            43:     HTContentCoder *   encoder;
        !            44:     HTContentCoder *   decoder;
        !            45:     double             quality;
        !            46: };
        !            47: 
1.52      frystyk    48: /* ------------------------------------------------------------------------- */
1.87    ! frystyk    49: /*                             BASIC CONVERTERS                             */
        !            50: /* ------------------------------------------------------------------------- */
        !            51: 
        !            52: PUBLIC HTStream * HTBlackHoleConverter (HTRequest *    request,
        !            53:                                        void *          param,
        !            54:                                        HTFormat        input_format,
        !            55:                                        HTFormat        output_format,
        !            56:                                        HTStream *      output_stream)
        !            57: {
        !            58:     return HTBlackHole();
        !            59: }
        !            60: /*     HTThroughLine
        !            61: **     -------------
        !            62: **
        !            63: ** This function is a dummy function that returns the same output stream
        !            64: ** as given as a parameter. Henrik 01/03-94
        !            65: */
        !            66: PUBLIC HTStream* HTThroughLine (HTRequest *    request,
        !            67:                                void *          param,
        !            68:                                HTFormat        input_format,
        !            69:                                HTFormat        output_format,
        !            70:                                HTStream *      output_stream)
        !            71: {
        !            72:     return output_stream;
        !            73: }
        !            74: 
        !            75: /* ------------------------------------------------------------------------- */
1.63      frystyk    76: /*       ACCEPT LISTS OF CONVERSIONS, ENCODINGS, LANGUAGE, AND CHARSET      */
1.61      frystyk    77: /* ------------------------------------------------------------------------- */
1.17      luotonen   78: 
1.52      frystyk    79: /*
1.63      frystyk    80: **     For all `accept lists' there is a local list and a global list. The
                     81: **     local list is a part of the request structure and the global list is
                     82: **     internal to the HTFormat module. The global lists can be used when
                     83: **     specifying accept lists for ALL requests and the local list can be 
                     84: **     used to add specific accept headers to the request.
                     85: */
                     86: 
1.61      frystyk    87: 
1.2       timbl      88: /*     Define a presentation system command for a content-type
                     89: **     -------------------------------------------------------
1.52      frystyk    90: ** INPUT:
                     91: **     conversions:    The list of conveters and presenters
                     92: **     representation: the MIME-style format name
                     93: **     command:        the MAILCAP-style command template
                     94: **     quality:        A degradation faction [0..1]
                     95: **     maxbytes:       A limit on the length acceptable as input (0 infinite)
                     96: **     maxsecs:        A limit on the time user will wait (0 for infinity)
1.2       timbl      97: */
1.72      frystyk    98: PUBLIC void HTPresentation_add (HTList *       conversions,
1.85      frystyk    99:                                const char *    representation,
                    100:                                const char *    command,
                    101:                                const char *    test_command,
1.72      frystyk   102:                                double          quality,
                    103:                                double          secs, 
                    104:                                double          secs_per_byte)
1.52      frystyk   105: {
1.83      frystyk   106:     HTPresentation * pres;
                    107:     if ((pres = (HTPresentation  *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
                    108:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     109:     
                    110:     pres->rep = HTAtom_for(representation);
                    111:     pres->rep_out = WWW_PRESENT;               /* Fixed for now ... :-) */
                    112:     pres->converter = HTSaveAndExecute;                /* Fixed for now ...     */
                    113:     pres->quality = quality;
                    114:     pres->secs = secs;
                    115:     pres->secs_per_byte = secs_per_byte;
                    116:     pres->rep = HTAtom_for(representation);
1.49      howcome   117:     pres->command = NULL;
1.2       timbl     118:     StrAllocCopy(pres->command, command);
1.49      howcome   119:     pres->test_command = NULL;
                    120:     StrAllocCopy(pres->test_command, test_command);
1.12      timbl     121:     HTList_addObject(conversions, pres);
1.2       timbl     122: }
                    123: 
1.73      frystyk   124: PUBLIC void HTPresentation_deleteAll (HTList * list)
                    125: {
                    126:     if (list) {
                    127:        HTList *cur = list;
                    128:        HTPresentation *pres;
                    129:        while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
1.83      frystyk   130:            HT_FREE(pres->command);
                    131:            HT_FREE(pres);
1.73      frystyk   132:        }
                    133:        HTList_delete(list);
                    134:     }
                    135: }
1.2       timbl     136: 
                    137: /*     Define a built-in function for a content-type
                    138: **     ---------------------------------------------
                    139: */
1.72      frystyk   140: PUBLIC void HTConversion_add (HTList *         conversions,
1.85      frystyk   141:                              const char *      representation_in,
                    142:                              const char *      representation_out,
1.72      frystyk   143:                              HTConverter *     converter,
                    144:                              double            quality,
                    145:                              double            secs, 
                    146:                              double            secs_per_byte)
1.52      frystyk   147: {
1.83      frystyk   148:     HTPresentation * pres;
1.87    ! frystyk   149:     if ((pres = (HTPresentation*) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
1.83      frystyk   150:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     151:     pres->rep = HTAtom_for(representation_in);
                    152:     pres->rep_out = HTAtom_for(representation_out);
                    153:     pres->converter = converter;
                    154:     pres->command = NULL;              /* Fixed */
1.49      howcome   155:     pres->test_command = NULL;
1.2       timbl     156:     pres->quality = quality;
                    157:     pres->secs = secs;
                    158:     pres->secs_per_byte = secs_per_byte;
1.12      timbl     159:     HTList_addObject(conversions, pres);
1.56      frystyk   160: }
                    161: 
1.73      frystyk   162: PUBLIC void HTConversion_deleteAll (HTList * list)
                    163: {
                    164:     HTPresentation_deleteAll(list);
                    165: }
                    166: 
1.87    ! frystyk   167: PUBLIC BOOL HTContentCoding_add (HTList *              list,
        !           168:                                 const char *           coding,
        !           169:                                 HTContentCoder *       encoder,
        !           170:                                 HTContentCoder *       decoder,
        !           171:                                 double                 quality)
1.73      frystyk   172: {
1.87    ! frystyk   173:     if (list && coding && (encoder || decoder)) {
        !           174:        HTContentCoding * me;
        !           175:        if ((me=(HTContentCoding*)HT_CALLOC(1, sizeof(HTContentCoding)))==NULL)
        !           176:            HT_OUTOFMEM("HTContentCoding_add");
        !           177:        me->coding = HTAtom_for(coding);
        !           178:        me->encoder = encoder;
        !           179:        me->decoder = decoder;
        !           180:        me->quality = quality;
        !           181:        if (CORE_TRACE)
        !           182:            HTTrace("Codings..... Adding %s with quality %.2f\n",
        !           183:                    coding, quality);
        !           184:        return HTList_addObject(list, (void *) me);
1.73      frystyk   185:     }
1.87    ! frystyk   186:     if (CORE_TRACE) HTTrace("Codings..... Bad argument\n");
        !           187:     return NO;
1.73      frystyk   188: }
                    189: 
1.87    ! frystyk   190: PUBLIC void HTContentCoding_deleteAll (HTList * list)
1.73      frystyk   191: {
                    192:     if (list) {
1.87    ! frystyk   193:        HTList * cur = list;
        !           194:        HTContentCoding * pres;
        !           195:        while ((pres = (HTContentCoding *) HTList_nextObject(cur)))
1.83      frystyk   196:            HT_FREE(pres);
1.73      frystyk   197:        HTList_delete(list);
                    198:     }
                    199: }
                    200: 
1.87    ! frystyk   201: PUBLIC const char * HTContentCoding_name (HTContentCoding * me)
        !           202: {
        !           203:     return me ? HTAtom_name(me->coding) : NULL;
        !           204: }
        !           205: 
1.73      frystyk   206: PUBLIC void HTLanguage_add (HTList *           list,
1.85      frystyk   207:                            const char *        lang,
1.73      frystyk   208:                            double              quality)
                    209: {
                    210:     HTAcceptNode * node;
                    211:     if (!list || !lang || !*lang)  {
1.87    ! frystyk   212:        if (CORE_TRACE)
1.84      eric      213:            HTTrace("Languages... Bad argument\n");
1.73      frystyk   214:        return;
                    215:     }
1.83      frystyk   216:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    217:         HT_OUTOFMEM("HTAcceptLanguage");
1.73      frystyk   218: 
                    219:     HTList_addObject(list, (void*)node);
                    220:     node->atom = HTAtom_for(lang);
                    221:     node->quality = quality;
                    222: }
                    223: 
                    224: PUBLIC void HTLanguage_deleteAll (HTList * list)
                    225: {
1.87    ! frystyk   226:     if (list) {
        !           227:        HTList *cur = list;
        !           228:        HTAcceptNode *pres;
        !           229:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
        !           230:            HT_FREE(pres);
        !           231:        }
        !           232:        HTList_delete(list);
        !           233:     }
1.73      frystyk   234: }
                    235: 
                    236: PUBLIC void HTCharset_add (HTList *            list,
1.85      frystyk   237:                           const char *         charset,
1.73      frystyk   238:                           double               quality)
                    239: {
                    240:     HTAcceptNode * node;
                    241:     if (!list || !charset || !*charset)  {
1.87    ! frystyk   242:        if (CORE_TRACE)
1.84      eric      243:            HTTrace("Charset..... Bad argument\n");
1.73      frystyk   244:        return;
                    245:     }
1.83      frystyk   246:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    247:         HT_OUTOFMEM("HTAcceptCharsetuage");
1.73      frystyk   248: 
                    249:     HTList_addObject(list, (void*)node);
                    250:     node->atom = HTAtom_for(charset);
                    251:     node->quality = quality;
                    252: }
                    253: 
                    254: PUBLIC void HTCharset_deleteAll (HTList * list)
                    255: {
1.87    ! frystyk   256:     if (list) {
        !           257:        HTList *cur = list;
        !           258:        HTAcceptNode *pres;
        !           259:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
        !           260:            HT_FREE(pres);
        !           261:        }
        !           262:        HTList_delete(list);
        !           263:     }
1.73      frystyk   264: }
                    265: 
                    266: /* ------------------------------------------------------------------------- */
                    267: /*                     GLOBAL LIST OF CONVERTERS ETC.                       */
                    268: /* ------------------------------------------------------------------------- */
                    269: 
1.72      frystyk   270: /*
                    271: **     Global Accept Format Types Conversions
                    272: **     list can be NULL
                    273: */
1.73      frystyk   274: PUBLIC void HTFormat_setConversion (HTList * list)
1.72      frystyk   275: {
                    276:     HTConversions = list;
                    277: }
                    278: 
                    279: PUBLIC HTList * HTFormat_conversion (void)
                    280: {
                    281:     return HTConversions;
                    282: }
                    283: 
                    284: /*
1.87    ! frystyk   285: **     Global Content Encodings
1.72      frystyk   286: **     list can be NULL
                    287: */
                    288: PUBLIC void HTFormat_setEncoding (HTList *list)
                    289: {
                    290:     HTEncodings = list;
                    291: }
                    292: 
                    293: PUBLIC HTList * HTFormat_encoding (void)
                    294: {
                    295:     return HTEncodings;
                    296: }
                    297: 
                    298: /*
                    299: **     Global Accept Languages
                    300: **     list can be NULL
                    301: */
                    302: PUBLIC void HTFormat_setLanguage (HTList *list)
                    303: {
                    304:     HTLanguages = list;
                    305: }
                    306: 
                    307: PUBLIC HTList * HTFormat_language (void)
                    308: {
                    309:     return HTLanguages;
                    310: }
                    311: 
                    312: /*
                    313: **     Global Accept Charsets
                    314: **     list can be NULL
                    315: */
                    316: PUBLIC void HTFormat_setCharset (HTList *list)
                    317: {
                    318:     HTCharsets = list;
                    319: }
                    320: 
                    321: PUBLIC HTList * HTFormat_charset (void)
                    322: {
                    323:     return HTCharsets;
                    324: }
1.56      frystyk   325: 
1.73      frystyk   326: /*
                    327: **     Convenience function to clean up
                    328: */
                    329: PUBLIC void HTFormat_deleteAll (void)
1.17      luotonen  330: {
1.73      frystyk   331:     if (HTConversions) {
                    332:        HTConversion_deleteAll(HTConversions);
                    333:        HTConversions = NULL;
                    334:     }
                    335:     if (HTLanguages) {
                    336:        HTLanguage_deleteAll(HTLanguages);
                    337:        HTLanguages = NULL;
1.63      frystyk   338:     }
1.73      frystyk   339:     if (HTEncodings) {
1.87    ! frystyk   340:        HTContentCoding_deleteAll(HTEncodings);
1.73      frystyk   341:        HTEncodings = NULL;
1.63      frystyk   342:     }
1.73      frystyk   343:     if (HTCharsets) {
                    344:        HTCharset_deleteAll(HTCharsets);
                    345:        HTCharsets = NULL;
1.63      frystyk   346:     }
1.17      luotonen  347: }
                    348: 
1.63      frystyk   349: /* ------------------------------------------------------------------------- */
                    350: /*                             FORMAT NEGOTIATION                           */
                    351: /* ------------------------------------------------------------------------- */
                    352: 
1.77      frystyk   353: PRIVATE BOOL better_match (HTFormat f, HTFormat g)
1.63      frystyk   354: {
1.85      frystyk   355:     const char *p, *q;
1.63      frystyk   356: 
                    357:     if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
                    358:        int i,j;
                    359:        for(i=0 ; *p; p++) if (*p == '*') i++;
                    360:        for(j=0 ; *q; q++) if (*q == '*') j++;
                    361:        if (i < j) return YES;
                    362:     }
                    363:     return NO;
                    364: }
                    365: 
                    366: 
1.77      frystyk   367: PRIVATE BOOL wild_match (HTAtom * tmplate, HTAtom * actual)
1.17      luotonen  368: {
                    369:     char *t, *a, *st, *sa;
                    370:     BOOL match = NO;
                    371: 
1.48      frystyk   372:     if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22      luotonen  373:        if (!strcmp(t, "*"))
                    374:            return YES;
1.17      luotonen  375: 
1.22      luotonen  376:        if (strchr(t, '*') &&
                    377:            (a = HTAtom_name(actual)) &&
                    378:            (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17      luotonen  379: 
1.22      luotonen  380:            *sa = 0;
                    381:            *st = 0;
                    382: 
                    383:            if ((*(st-1)=='*' &&
                    384:                 (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
                    385:                (*(st+1)=='*' && !strcasecomp(t,a)))
                    386:                match = YES;
                    387: 
                    388:            *sa = '/';
                    389:            *st = '/';
                    390:        }    
                    391:     }
1.23      luotonen  392:     return match;
1.17      luotonen  393: }
                    394: 
1.36      luotonen  395: /*
                    396:  * Added by takada@seraph.ntt.jp (94/04/08)
                    397:  */
1.77      frystyk   398: PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
1.36      luotonen  399: {
                    400:     char *t, *a, *st, *sa;
                    401:     BOOL match = NO;
                    402: 
1.48      frystyk   403:     if (tmplate && actual &&
                    404:        (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36      luotonen  405:        st = strchr(t, '_');
                    406:        sa = strchr(a, '_');
                    407:        if ((st != NULL) && (sa != NULL)) {
                    408:            if (!strcasecomp(t, a))
                    409:              match = YES;
                    410:            else
                    411:              match = NO;
                    412:        }
                    413:        else {
                    414:            if (st != NULL) *st = 0;
                    415:            if (sa != NULL) *sa = 0;
                    416:            if (!strcasecomp(t, a))
                    417:              match = YES;
                    418:            else
                    419:              match = NO;
                    420:            if (st != NULL) *st = '_';
                    421:            if (sa != NULL) *sa = '_';
                    422:        }
                    423:     }
                    424:     return match;
                    425: }
                    426: /* end of addition */
                    427: 
                    428: 
1.17      luotonen  429: 
1.77      frystyk   430: PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
1.17      luotonen  431: {
                    432:     HTList * cur = accepted;
                    433:     HTPresentation * pres;
                    434:     HTPresentation * wild = NULL;
                    435: 
                    436:     if (!content_type || !accepted) return -1;
                    437: 
                    438:     while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    439:        if (pres->rep == content_type)
                    440:            return pres->quality;
                    441:        else if (wild_match(pres->rep, content_type))
                    442:            wild = pres;
                    443:     }
                    444:     if (wild) return wild->quality;
                    445:     else return -1;
                    446: }
                    447: 
                    448: 
1.77      frystyk   449: PRIVATE double lang_value (HTAtom * language, HTList * accepted)
1.17      luotonen  450: {
                    451:     HTList * cur = accepted;
                    452:     HTAcceptNode * node;
                    453:     HTAcceptNode * wild = NULL;
                    454: 
                    455:     if (!language || !accepted || HTList_isEmpty(accepted)) {
                    456:        return 0.1;
                    457:     }
                    458: 
                    459:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    460:        if (node->atom == language) {
                    461:            return node->quality;
                    462:        }
1.36      luotonen  463:        /*
                    464:         * patch by takada@seraph.ntt.jp (94/04/08)
                    465:         * the original line was
                    466:         * else if (wild_match(node->atom, language)) {
                    467:         * and the new line is
                    468:         */
                    469:        else if (lang_match(node->atom, language)) {
1.17      luotonen  470:            wild = node;
                    471:        }
                    472:     }
                    473: 
                    474:     if (wild) {
                    475:        return wild->quality;
                    476:     }
                    477:     else {
                    478:        return 0.1;
                    479:     }
                    480: }
                    481: 
                    482: 
1.77      frystyk   483: PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
1.17      luotonen  484: {
                    485:     HTList * cur = accepted;
                    486:     HTAcceptNode * node;
                    487:     HTAcceptNode * wild = NULL;
                    488:     char * e;
                    489: 
                    490:     if (!encoding || !accepted || HTList_isEmpty(accepted))
                    491:        return 1;
                    492: 
                    493:     e = HTAtom_name(encoding);
                    494:     if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
                    495:        return 1;
                    496: 
                    497:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    498:        if (node->atom == encoding)
                    499:            return node->quality;
                    500:        else if (wild_match(node->atom, encoding))
                    501:            wild = node;
                    502:     }
                    503:     if (wild) return wild->quality;
                    504:     else return 1;
                    505: }
                    506: 
                    507: 
1.77      frystyk   508: PUBLIC BOOL HTRank (HTList * possibilities,
                    509:                    HTList * accepted_content_types,
                    510:                    HTList * accepted_languages,
                    511:                    HTList * accepted_encodings)
1.17      luotonen  512: {
                    513:     int accepted_cnt = 0;
                    514:     HTList * accepted;
                    515:     HTList * sorted;
                    516:     HTList * cur;
                    517:     HTContentDescription * d;
                    518: 
                    519:     if (!possibilities) return NO;
                    520: 
                    521:     accepted = HTList_new();
                    522:     cur = possibilities;
                    523:     while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
1.59      frystyk   524:        double tv = type_value(d->content_type, accepted_content_types);
                    525:        double lv = lang_value(d->content_language, accepted_languages);
                    526:        double ev = encoding_value(d->content_encoding, accepted_encodings);
1.17      luotonen  527: 
                    528:        if (tv > 0) {
                    529:            d->quality *= tv * lv * ev;
                    530:            HTList_addObject(accepted, d);
                    531:            accepted_cnt++;
                    532:        }
1.18      luotonen  533:        else {
1.86      frystyk   534:            HT_FREE(d->filename);
1.83      frystyk   535:            HT_FREE(d);
1.18      luotonen  536:        }
1.17      luotonen  537:     }
                    538: 
1.87    ! frystyk   539:     if (CORE_TRACE) HTTrace("Ranking.....\n");
        !           540:     if (CORE_TRACE) HTTrace(
1.18      luotonen  541:           "\nRANK QUALITY CONTENT-TYPE         LANGUAGE ENCODING    FILE\n");
1.17      luotonen  542: 
                    543:     sorted = HTList_new();
                    544:     while (accepted_cnt-- > 0) {
                    545:        HTContentDescription * worst = NULL;
                    546:        cur = accepted;
                    547:        while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
                    548:            if (!worst || d->quality < worst->quality)
                    549:                worst = d;
                    550:        }
                    551:        if (worst) {
1.87    ! frystyk   552:            if (CORE_TRACE)
1.84      eric      553:                HTTrace("%d.   %.4f  %-20.20s %-8.8s %-10.10s %s\n",
1.58      frystyk   554:                        accepted_cnt+1,
                    555:                        worst->quality,
                    556:                        (worst->content_type
1.17      luotonen  557:                         ? HTAtom_name(worst->content_type)      : "-"),
1.58      frystyk   558:                        (worst->content_language
1.17      luotonen  559:                         ? HTAtom_name(worst->content_language)  :"-"),
1.58      frystyk   560:                        (worst->content_encoding
1.17      luotonen  561:                         ? HTAtom_name(worst->content_encoding)  :"-"),
1.58      frystyk   562:                        (worst->filename
1.17      luotonen  563:                         ? worst->filename                       :"-"));
                    564:            HTList_removeObject(accepted, (void*)worst);
                    565:            HTList_addObject(sorted, (void*)worst);
                    566:        }
                    567:     }
1.87    ! frystyk   568:     if (CORE_TRACE) HTTrace("\n");
1.17      luotonen  569:     HTList_delete(accepted);
                    570:     HTList_delete(possibilities->next);
                    571:     possibilities->next = sorted->next;
                    572:     sorted->next = NULL;
                    573:     HTList_delete(sorted);
                    574: 
                    575:     if (!HTList_isEmpty(possibilities)) return YES;
                    576:     else return NO;
                    577: }
                    578: 
                    579: 
1.87    ! frystyk   580: /*     Create a Content Type filter stack
        !           581: **     ----------------------------------
1.7       secret    582: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     583: **     structure is made to hold the destination format while the
                    584: **     new stack is generated. This is just to pass the out format to
                    585: **     MIME so far.  Storing the format of a stream in the stream might
                    586: **     be a lot neater.
1.10      timbl     587: **
1.29      frystyk   588: **     The star/star format is special, in that if you can take
1.40      frystyk   589: **     that you can take anything.
1.2       timbl     590: */
1.77      frystyk   591: PUBLIC HTStream * HTStreamStack (HTFormat      rep_in,
                    592:                                 HTFormat       rep_out,
                    593:                                 HTStream *     output_stream,
                    594:                                 HTRequest *    request,
                    595:                                 BOOL           guess)
1.2       timbl     596: {
1.14      timbl     597:     HTList * conversion[2];
                    598:     int which_list;
1.59      frystyk   599:     double best_quality = -1e30;               /* Pretty bad! */
1.65      frystyk   600:     HTPresentation *pres, *best_match=NULL;
1.80      frystyk   601:     if (rep_out == WWW_RAW) {
1.87    ! frystyk   602:        if (CORE_TRACE) HTTrace("StreamStack. Raw output...\n");
1.81      frystyk   603:        return output_stream ? output_stream : HTErrorStream();
1.34      luotonen  604:     }
1.79      frystyk   605: 
1.80      frystyk   606:     if (rep_out == rep_in) {
1.87    ! frystyk   607:        if (CORE_TRACE)
1.84      eric      608:            HTTrace("StreamStack. Identical input/output format (%s)\n",
1.80      frystyk   609:                     HTAtom_name(rep_out));
1.81      frystyk   610:        return output_stream ? output_stream : HTErrorStream();
1.74      frystyk   611:     }
1.87    ! frystyk   612:     if (CORE_TRACE) {
1.82      frystyk   613:        char *p = HTAtom_name(rep_in);
                    614:        char *q = HTAtom_name(rep_out); 
1.84      eric      615:        HTTrace("StreamStack. Constructing stream stack for %s to %s\n",
1.82      frystyk   616:                 p ? p : "<NULL>", q ? q : "<NULL>");
1.47      frystyk   617:     }
1.2       timbl     618: 
1.14      timbl     619:     conversion[0] = request->conversions;
                    620:     conversion[1] = HTConversions;
1.17      luotonen  621: 
1.15      luotonen  622:     for(which_list = 0; which_list<2; which_list++) {
                    623:        HTList * cur = conversion[which_list];
                    624:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.65      frystyk   625:            if ((pres->rep==rep_in || wild_match(pres->rep, rep_in)) &&
                    626:                (pres->rep_out==rep_out || wild_match(pres->rep_out,rep_out))){
                    627:                if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33      luotonen  628:                    (!better_match(best_match->rep, pres->rep) &&
                    629:                     pres->quality > best_quality)) {
1.85      frystyk   630: #ifdef HAVE_SYSTEM
1.65      frystyk   631:                    int result=0;
                    632:                    if (pres->test_command) {
                    633:                        result = system(pres->test_command);
1.87    ! frystyk   634:                        if (CORE_TRACE) 
1.84      eric      635:                            HTTrace("StreamStack. system(%s) returns %d\n", pres->test_command, result);
1.65      frystyk   636:                    }
                    637:                    if (!result) {
1.49      howcome   638:                        best_match = pres;
                    639:                        best_quality = pres->quality;
                    640:                    }
1.65      frystyk   641: #else
                    642:                    best_match = pres;
                    643:                    best_quality = pres->quality;
1.85      frystyk   644: #endif /* HAVE_SYSTEM */
1.10      timbl     645:                }
                    646:            }
1.2       timbl     647:        }
                    648:     }
1.80      frystyk   649: 
                    650:     if (best_match) {
                    651:        if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
1.87    ! frystyk   652:            if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   653:            return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   654:        }
1.65      frystyk   655:        return (*best_match->converter)(request, best_match->command,
                    656:                                        rep_in, rep_out, output_stream);
1.80      frystyk   657:     }
                    658:     if (rep_out == WWW_SOURCE) {
1.87    ! frystyk   659:        if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   660:        return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   661:     }
                    662: 
1.87    ! frystyk   663:     if (CORE_TRACE)
1.84      eric      664:        HTTrace("StreamStack. No match found, dumping to local file\n");
1.65      frystyk   665:     return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2       timbl     666: }
                    667:        
                    668: 
                    669: /*             Find the cost of a filter stack
                    670: **             -------------------------------
                    671: **
                    672: **     Must return the cost of the same stack which StreamStack would set up.
                    673: **
                    674: ** On entry,
                    675: **     length  The size of the data to be converted
                    676: */
1.77      frystyk   677: PUBLIC double HTStackValue (HTList *   theseConversions,
                    678:                            HTFormat    rep_in,
                    679:                            HTFormat    rep_out,
                    680:                            double      initial_value,
                    681:                            long int    length)
1.2       timbl     682: {
1.14      timbl     683:     int which_list;
                    684:     HTList* conversion[2];
                    685:     
1.87    ! frystyk   686:     if (CORE_TRACE) {
1.84      eric      687:        HTTrace("StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.65      frystyk   688:                HTAtom_name(rep_in),    initial_value,
                    689:                HTAtom_name(rep_out));
                    690:     }
1.2       timbl     691:     if (rep_out == WWW_SOURCE ||
1.10      timbl     692:        rep_out == rep_in) return 0.0;
1.2       timbl     693: 
1.14      timbl     694:     conversion[0] = theseConversions;
                    695:     conversion[1] = HTConversions;
                    696:     
                    697:     for(which_list = 0; which_list<2; which_list++)
                    698:      if (conversion[which_list]) {
1.15      luotonen  699:         HTList * cur = conversion[which_list];
1.2       timbl     700:        HTPresentation * pres;
1.15      luotonen  701:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    702:            if (pres->rep == rep_in &&
1.17      luotonen  703:                (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.59      frystyk   704:                double value = initial_value * pres->quality;
1.2       timbl     705:                if (HTMaxSecs != 0.0)
1.15      luotonen  706:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     707:                                         /HTMaxSecs;
                    708:                return value;
                    709:            }
                    710:        }
                    711:     }
1.63      frystyk   712:     return NO_VALUE_FOUND;             /* Really bad */
1.1       timbl     713: }
1.2       timbl     714: 
1.87    ! frystyk   715: /*     Create a new coder and insert it into stream chain
        !           716: **     --------------------------------------------------
        !           717: **     Creating the content decoding stack is not based on quality factors as
        !           718: **     we don't have the freedom as with content types. Specify whether you
        !           719: **     you want encoding or decoding using the BOOL "encoding" flag.
        !           720: */
        !           721: PUBLIC HTStream * HTCodingStack (HTEncoding    coding,
        !           722:                                 HTStream *     target,
        !           723:                                 HTRequest *    request,
        !           724:                                 void *         param,
        !           725:                                 BOOL           encoding)
        !           726: {
        !           727:     HTList * coders[2];
        !           728:     HTStream * top = target;
        !           729:     HTContentCoding * pres = NULL;
        !           730:     int cnt;
        !           731:     if (!coding || !request) {
        !           732:        if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
        !           733:        return target ? target : HTErrorStream();
        !           734:     }
        !           735:     coders[0] = request->encodings;
        !           736:     coders[1] = HTEncodings;
        !           737:     if (CORE_TRACE)
        !           738:        HTTrace("Codings..... Looking for %s\n", HTAtom_name(coding));
        !           739:     for (cnt=0; cnt < 2; cnt++) {
        !           740:        HTList * cur = coders[cnt];
        !           741:        while ((pres = (HTContentCoding *) HTList_nextObject(cur))) {
        !           742:            if (pres->coding == coding) {
        !           743:                if (CORE_TRACE) HTTrace("Codings..... Found...\n");
        !           744:                if (encoding) {
        !           745:                    if (pres->encoder)
        !           746:                        top = (*pres->encoder)(request, param, coding, top);
        !           747:                    break;
        !           748:                } else if (pres->decoder) {
        !           749:                    top = (*pres->decoder)(request, param, coding, top);
        !           750:                    break;
        !           751:                }
        !           752:            }
        !           753:        }
        !           754:     }
        !           755:     return top;
        !           756: }
1.10      timbl     757: 
1.87    ! frystyk   758: /*
        !           759: **  Here you can provide a complete list instead of a single token.
        !           760: **  The list has to filled up in the order the _encodings_ are to be applied
        !           761: */
        !           762: PUBLIC HTStream * HTEncodingStack (HTList *    encodings,
        !           763:                                   HTStream *   target,
        !           764:                                   HTRequest *  request,
        !           765:                                   void *       param)
        !           766: {
        !           767:     if (encodings) {
        !           768:        HTList * cur = encodings;
        !           769:        HTEncoding pres;
        !           770:        HTStream * top = target;
        !           771:        while ((pres = (HTEncoding) HTList_nextObject(cur)))
        !           772:            top = HTCodingStack(pres, top, request, param, YES);
        !           773:        return top;
        !           774:     }
        !           775:     return HTErrorStream();
        !           776: }
        !           777: 
        !           778: /*
        !           779: **  Here you can provide a complete list instead of a single token.
        !           780: **  The list has to be in the order the _encodings_ were applied - that
        !           781: **  is, the same way that _encodings_ are to be applied. This is all consistent
        !           782: **  with the order of the Content-Encoding header.
        !           783: */
        !           784: PUBLIC HTStream * HTDecodingStack (HTList *    encodings,
        !           785:                                   HTStream *   target,
        !           786:                                   HTRequest *  request,
        !           787:                                   void *       param)
        !           788: {
        !           789:     if (encodings) {
        !           790:        HTEncoding pres;
        !           791:        int cnt = HTList_count(encodings);
        !           792:        HTStream * top = target;
        !           793:        while (cnt > 0) {
        !           794:            pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
        !           795:            top = HTCodingStack(pres, top, request, param, NO);
        !           796:        }
        !           797:        return top;
        !           798:     }
        !           799:     return HTErrorStream();
        !           800: }

Webmaster