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

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.97    ! frystyk     6: **     @(#) $Id: HTFormat.c,v 1.96 1998/03/05 21:56:13 frystyk Exp $
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.97    ! frystyk    19: #include "wwwsys.h"
1.87      frystyk    20: #include "WWWUtil.h"
                     21: #include "HTStream.h"
1.93      frystyk    22: #include "HTWWWStr.h"
1.58      frystyk    23: #include "HTFWrite.h"
1.52      frystyk    24: #include "HTError.h"
                     25: #include "HTFormat.h"                                   /* Implemented here */
1.2       timbl      26: 
1.72      frystyk    27: #define NO_VALUE_FOUND -1e30            /* Stream Stack Value if none found */
1.63      frystyk    28: 
1.87      frystyk    29: PRIVATE HTList * HTConversions = NULL;                     /* Content types */
1.88      frystyk    30: PRIVATE HTList * HTContentCoders = NULL;                  /* Content coders */
                     31: PRIVATE HTList * HTTransferCoders = NULL;        /* Content transfer coders */
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.88      frystyk    41: struct _HTCoding {
                     42:     HTEncoding         encoding;
                     43:     HTCoder *          encoder;
                     44:     HTCoder *          decoder;
1.87      frystyk    45:     double             quality;
                     46: };
                     47: 
1.96      frystyk    48: PRIVATE HTStream       HTBaseConverterStreamInstance;
                     49: 
1.52      frystyk    50: /* ------------------------------------------------------------------------- */
1.87      frystyk    51: /*                             BASIC CONVERTERS                             */
                     52: /* ------------------------------------------------------------------------- */
                     53: 
1.96      frystyk    54: PRIVATE int HTBlackHoleConverter_put_character (HTStream * me, char c)
                     55: {
                     56:     return HT_OK;
                     57: }
                     58: 
                     59: PRIVATE int HTBlackHoleConverter_put_string (HTStream * me, const char * s)
                     60: {
                     61:     return HT_OK;
                     62: }
                     63: 
                     64: PRIVATE int HTBlackHoleConverter_write (HTStream * me, const char * s, int l)
                     65: {
                     66:     return HT_OK;
                     67: }
                     68: 
                     69: PRIVATE int HTBlackHoleConverter_flush (HTStream * me)
                     70: {
                     71:     return HT_OK;
                     72: }
                     73: 
                     74: PRIVATE int HTBlackHoleConverter_free (HTStream * me)
                     75: {
                     76:     return HT_OK;
                     77: }
                     78: 
                     79: PRIVATE int HTBlackHoleConverter_abort (HTStream * me, HTList * e)
                     80: {
                     81:     return HT_ERROR;
                     82: }
                     83: 
                     84: 
                     85: PRIVATE const HTStreamClass HTBlackHoleConverterClass =
                     86: {              
                     87:     "BlackHoleConverter",
                     88:     HTBlackHoleConverter_flush,
                     89:     HTBlackHoleConverter_free,
                     90:     HTBlackHoleConverter_abort,
                     91:     HTBlackHoleConverter_put_character,
                     92:     HTBlackHoleConverter_put_string,
                     93:     HTBlackHoleConverter_write
                     94: }; 
                     95: 
1.87      frystyk    96: PUBLIC HTStream * HTBlackHoleConverter (HTRequest *    request,
                     97:                                        void *          param,
                     98:                                        HTFormat        input_format,
                     99:                                        HTFormat        output_format,
                    100:                                        HTStream *      output_stream)
                    101: {
1.96      frystyk   102:     if (STREAM_TRACE) HTTrace("BlackHole... Converter Created\n");
                    103:     HTBaseConverterStreamInstance.isa = &HTBlackHoleConverterClass;
                    104:     return &HTBaseConverterStreamInstance;
1.87      frystyk   105: }
1.96      frystyk   106: 
1.87      frystyk   107: /*     HTThroughLine
                    108: **     -------------
                    109: **
                    110: ** This function is a dummy function that returns the same output stream
                    111: ** as given as a parameter. Henrik 01/03-94
                    112: */
                    113: PUBLIC HTStream* HTThroughLine (HTRequest *    request,
                    114:                                void *          param,
                    115:                                HTFormat        input_format,
                    116:                                HTFormat        output_format,
                    117:                                HTStream *      output_stream)
                    118: {
                    119:     return output_stream;
                    120: }
                    121: 
1.96      frystyk   122: /*     HTSaveConverter
                    123: **
                    124: ** This function is a place holder for a save to local file converter
                    125: */
                    126: PUBLIC HTStream * HTSaveConverter (HTRequest * request,
                    127:                                   void *       param,
                    128:                                   HTFormat     input_format,
                    129:                                   HTFormat     output_format,
                    130:                                   HTStream *   output_stream)
                    131: {
                    132:     return HTBlackHole();
                    133: }
                    134: 
1.52      frystyk   135: /*
1.63      frystyk   136: **     For all `accept lists' there is a local list and a global list. The
                    137: **     local list is a part of the request structure and the global list is
                    138: **     internal to the HTFormat module. The global lists can be used when
                    139: **     specifying accept lists for ALL requests and the local list can be 
                    140: **     used to add specific accept headers to the request.
                    141: */
                    142: 
1.88      frystyk   143: /* ------------------------------------------------------------------------- */
                    144: /*                             CONTENT TYPES                                */
                    145: /* ------------------------------------------------------------------------- */
1.61      frystyk   146: 
1.2       timbl     147: /*     Define a presentation system command for a content-type
                    148: **     -------------------------------------------------------
1.52      frystyk   149: ** INPUT:
                    150: **     conversions:    The list of conveters and presenters
                    151: **     representation: the MIME-style format name
                    152: **     command:        the MAILCAP-style command template
                    153: **     quality:        A degradation faction [0..1]
                    154: **     maxbytes:       A limit on the length acceptable as input (0 infinite)
                    155: **     maxsecs:        A limit on the time user will wait (0 for infinity)
1.2       timbl     156: */
1.72      frystyk   157: PUBLIC void HTPresentation_add (HTList *       conversions,
1.85      frystyk   158:                                const char *    representation,
                    159:                                const char *    command,
                    160:                                const char *    test_command,
1.72      frystyk   161:                                double          quality,
                    162:                                double          secs, 
                    163:                                double          secs_per_byte)
1.52      frystyk   164: {
1.83      frystyk   165:     HTPresentation * pres;
                    166:     if ((pres = (HTPresentation  *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
                    167:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     168:     
                    169:     pres->rep = HTAtom_for(representation);
                    170:     pres->rep_out = WWW_PRESENT;               /* Fixed for now ... :-) */
                    171:     pres->converter = HTSaveAndExecute;                /* Fixed for now ...     */
                    172:     pres->quality = quality;
                    173:     pres->secs = secs;
                    174:     pres->secs_per_byte = secs_per_byte;
                    175:     pres->rep = HTAtom_for(representation);
1.49      howcome   176:     pres->command = NULL;
1.2       timbl     177:     StrAllocCopy(pres->command, command);
1.49      howcome   178:     pres->test_command = NULL;
                    179:     StrAllocCopy(pres->test_command, test_command);
1.91      frystyk   180:     if (CORE_TRACE)
                    181:        HTTrace("Presentation Adding `%s\' with quality %.2f\n",
                    182:                command, quality);
1.12      timbl     183:     HTList_addObject(conversions, pres);
1.2       timbl     184: }
                    185: 
1.73      frystyk   186: PUBLIC void HTPresentation_deleteAll (HTList * list)
                    187: {
                    188:     if (list) {
                    189:        HTList *cur = list;
                    190:        HTPresentation *pres;
                    191:        while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
1.83      frystyk   192:            HT_FREE(pres->command);
                    193:            HT_FREE(pres);
1.73      frystyk   194:        }
                    195:        HTList_delete(list);
                    196:     }
                    197: }
1.2       timbl     198: 
                    199: /*     Define a built-in function for a content-type
                    200: **     ---------------------------------------------
                    201: */
1.72      frystyk   202: PUBLIC void HTConversion_add (HTList *         conversions,
1.85      frystyk   203:                              const char *      representation_in,
                    204:                              const char *      representation_out,
1.72      frystyk   205:                              HTConverter *     converter,
                    206:                              double            quality,
                    207:                              double            secs, 
                    208:                              double            secs_per_byte)
1.52      frystyk   209: {
1.83      frystyk   210:     HTPresentation * pres;
1.87      frystyk   211:     if ((pres = (HTPresentation*) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
1.83      frystyk   212:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     213:     pres->rep = HTAtom_for(representation_in);
                    214:     pres->rep_out = HTAtom_for(representation_out);
                    215:     pres->converter = converter;
                    216:     pres->command = NULL;              /* Fixed */
1.49      howcome   217:     pres->test_command = NULL;
1.2       timbl     218:     pres->quality = quality;
                    219:     pres->secs = secs;
                    220:     pres->secs_per_byte = secs_per_byte;
1.91      frystyk   221:     if (CORE_TRACE)
                    222:        HTTrace("Conversions. Adding %p with quality %.2f\n",
                    223:                converter, quality);
1.12      timbl     224:     HTList_addObject(conversions, pres);
1.56      frystyk   225: }
                    226: 
1.73      frystyk   227: PUBLIC void HTConversion_deleteAll (HTList * list)
                    228: {
                    229:     HTPresentation_deleteAll(list);
                    230: }
                    231: 
1.88      frystyk   232: /* ------------------------------------------------------------------------- */
                    233: /*             CONTENT ENCODING AND CONTENT TRANSFER ENCODING               */
                    234: /* ------------------------------------------------------------------------- */
                    235: 
                    236: PUBLIC BOOL HTCoding_add (HTList *     list,
                    237:                          const char *  encoding,
                    238:                          HTCoder *     encoder,
                    239:                          HTCoder *     decoder,
                    240:                          double        quality)
1.73      frystyk   241: {
1.88      frystyk   242:     if (list && encoding && (encoder || decoder)) {
                    243:        HTCoding * me;
                    244:        if ((me = (HTCoding *) HT_CALLOC(1, sizeof(HTCoding))) == NULL)
                    245:            HT_OUTOFMEM("HTCoding_add");
                    246:        me->encoding = HTAtom_for(encoding);
1.87      frystyk   247:        me->encoder = encoder;
                    248:        me->decoder = decoder;
                    249:        me->quality = quality;
                    250:        if (CORE_TRACE)
                    251:            HTTrace("Codings..... Adding %s with quality %.2f\n",
1.88      frystyk   252:                    encoding, quality);
1.87      frystyk   253:        return HTList_addObject(list, (void *) me);
1.73      frystyk   254:     }
1.87      frystyk   255:     if (CORE_TRACE) HTTrace("Codings..... Bad argument\n");
                    256:     return NO;
1.73      frystyk   257: }
                    258: 
1.88      frystyk   259: PUBLIC void HTCoding_deleteAll (HTList * list)
1.73      frystyk   260: {
                    261:     if (list) {
1.87      frystyk   262:        HTList * cur = list;
1.88      frystyk   263:        HTCoding * pres;
                    264:        while ((pres = (HTCoding *) HTList_nextObject(cur)))
1.83      frystyk   265:            HT_FREE(pres);
1.73      frystyk   266:        HTList_delete(list);
                    267:     }
                    268: }
                    269: 
1.88      frystyk   270: PUBLIC const char * HTCoding_name (HTCoding * me)
1.87      frystyk   271: {
1.88      frystyk   272:     return me ? HTAtom_name(me->encoding) : NULL;
1.95      frystyk   273: }
                    274: 
                    275: PUBLIC double HTCoding_quality (HTCoding * me)
                    276: {
                    277:     return me ? me->quality : 0.0;
1.87      frystyk   278: }
                    279: 
1.88      frystyk   280: /* ------------------------------------------------------------------------- */
                    281: /*                             CONTENT LANGUAGE                             */
                    282: /* ------------------------------------------------------------------------- */
                    283: 
1.73      frystyk   284: PUBLIC void HTLanguage_add (HTList *           list,
1.85      frystyk   285:                            const char *        lang,
1.73      frystyk   286:                            double              quality)
                    287: {
                    288:     HTAcceptNode * node;
                    289:     if (!list || !lang || !*lang)  {
1.87      frystyk   290:        if (CORE_TRACE)
1.84      eric      291:            HTTrace("Languages... Bad argument\n");
1.73      frystyk   292:        return;
                    293:     }
1.83      frystyk   294:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    295:         HT_OUTOFMEM("HTAcceptLanguage");
1.73      frystyk   296: 
                    297:     HTList_addObject(list, (void*)node);
                    298:     node->atom = HTAtom_for(lang);
                    299:     node->quality = quality;
                    300: }
                    301: 
                    302: PUBLIC void HTLanguage_deleteAll (HTList * list)
                    303: {
1.87      frystyk   304:     if (list) {
                    305:        HTList *cur = list;
                    306:        HTAcceptNode *pres;
                    307:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
                    308:            HT_FREE(pres);
                    309:        }
                    310:        HTList_delete(list);
                    311:     }
1.73      frystyk   312: }
                    313: 
1.88      frystyk   314: /* ------------------------------------------------------------------------- */
                    315: /*                             CONTENT CHARSET                              */
                    316: /* ------------------------------------------------------------------------- */
                    317: 
1.73      frystyk   318: PUBLIC void HTCharset_add (HTList *            list,
1.85      frystyk   319:                           const char *         charset,
1.73      frystyk   320:                           double               quality)
                    321: {
                    322:     HTAcceptNode * node;
                    323:     if (!list || !charset || !*charset)  {
1.87      frystyk   324:        if (CORE_TRACE)
1.84      eric      325:            HTTrace("Charset..... Bad argument\n");
1.73      frystyk   326:        return;
                    327:     }
1.83      frystyk   328:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    329:         HT_OUTOFMEM("HTAcceptCharsetuage");
1.73      frystyk   330: 
                    331:     HTList_addObject(list, (void*)node);
                    332:     node->atom = HTAtom_for(charset);
                    333:     node->quality = quality;
                    334: }
                    335: 
                    336: PUBLIC void HTCharset_deleteAll (HTList * list)
                    337: {
1.87      frystyk   338:     if (list) {
                    339:        HTList *cur = list;
                    340:        HTAcceptNode *pres;
                    341:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
                    342:            HT_FREE(pres);
                    343:        }
                    344:        HTList_delete(list);
                    345:     }
1.73      frystyk   346: }
                    347: 
                    348: /* ------------------------------------------------------------------------- */
                    349: /*                     GLOBAL LIST OF CONVERTERS ETC.                       */
                    350: /* ------------------------------------------------------------------------- */
                    351: 
1.72      frystyk   352: /*
                    353: **     Global Accept Format Types Conversions
                    354: **     list can be NULL
                    355: */
1.73      frystyk   356: PUBLIC void HTFormat_setConversion (HTList * list)
1.72      frystyk   357: {
                    358:     HTConversions = list;
                    359: }
                    360: 
                    361: PUBLIC HTList * HTFormat_conversion (void)
                    362: {
                    363:     return HTConversions;
                    364: }
                    365: 
1.92      frystyk   366: PUBLIC void HTFormat_addConversion (const char *       input_format,
                    367:                                    const char *        output_format,
                    368:                                    HTConverter *       converter,
                    369:                                    double              quality,
                    370:                                    double              secs, 
                    371:                                    double              secs_per_byte)
                    372: {
                    373:     if (!HTConversions) HTConversions = HTList_new();
                    374:     HTConversion_add(HTConversions, input_format, output_format,
                    375:                     converter, quality, secs, secs_per_byte);
                    376: }
                    377: 
1.72      frystyk   378: /*
1.88      frystyk   379: **     Global list of Content Encodings
1.72      frystyk   380: **     list can be NULL
                    381: */
1.88      frystyk   382: PUBLIC void HTFormat_setContentCoding (HTList *list)
1.72      frystyk   383: {
1.88      frystyk   384:     HTContentCoders = list;
1.72      frystyk   385: }
                    386: 
1.88      frystyk   387: PUBLIC HTList * HTFormat_contentCoding (void)
1.72      frystyk   388: {
1.88      frystyk   389:     return HTContentCoders;
1.72      frystyk   390: }
                    391: 
1.92      frystyk   392: PUBLIC BOOL HTFormat_addCoding ( char *                encoding,
                    393:                                 HTCoder *      encoder,
                    394:                                 HTCoder *      decoder,
                    395:                                 double         quality)
                    396: {
                    397:     if (!HTContentCoders) HTContentCoders = HTList_new();
                    398:     return HTCoding_add(HTContentCoders, encoding, encoder, decoder, quality);
                    399: }
                    400: 
1.72      frystyk   401: /*
1.88      frystyk   402: **     Global list of Content Transfer Encodings
                    403: **     list can be NULL
                    404: */
                    405: PUBLIC void HTFormat_setTransferCoding (HTList *list)
                    406: {
                    407:     HTTransferCoders = list;
                    408: }
                    409: 
                    410: PUBLIC HTList * HTFormat_transferCoding (void)
                    411: {
                    412:     return HTTransferCoders;
1.92      frystyk   413: }
                    414: 
                    415: PUBLIC BOOL HTFormat_addTransferCoding ( char *                encoding,
                    416:                                         HTCoder *      encoder,
                    417:                                         HTCoder *      decoder,
                    418:                                         double         quality)
                    419: {
                    420:     if (!HTTransferCoders) HTTransferCoders = HTList_new();
                    421:     return HTCoding_add(HTTransferCoders, encoding, encoder, decoder, quality);
1.88      frystyk   422: }
                    423: 
                    424: /*
1.72      frystyk   425: **     Global Accept Languages
                    426: **     list can be NULL
                    427: */
                    428: PUBLIC void HTFormat_setLanguage (HTList *list)
                    429: {
                    430:     HTLanguages = list;
                    431: }
                    432: 
                    433: PUBLIC HTList * HTFormat_language (void)
                    434: {
                    435:     return HTLanguages;
                    436: }
                    437: 
                    438: /*
                    439: **     Global Accept Charsets
                    440: **     list can be NULL
                    441: */
                    442: PUBLIC void HTFormat_setCharset (HTList *list)
                    443: {
                    444:     HTCharsets = list;
                    445: }
                    446: 
                    447: PUBLIC HTList * HTFormat_charset (void)
                    448: {
                    449:     return HTCharsets;
                    450: }
1.56      frystyk   451: 
1.73      frystyk   452: /*
                    453: **     Convenience function to clean up
                    454: */
                    455: PUBLIC void HTFormat_deleteAll (void)
1.17      luotonen  456: {
1.73      frystyk   457:     if (HTConversions) {
                    458:        HTConversion_deleteAll(HTConversions);
                    459:        HTConversions = NULL;
                    460:     }
                    461:     if (HTLanguages) {
                    462:        HTLanguage_deleteAll(HTLanguages);
                    463:        HTLanguages = NULL;
1.63      frystyk   464:     }
1.88      frystyk   465:     if (HTContentCoders) {
                    466:        HTCoding_deleteAll(HTContentCoders);
                    467:        HTContentCoders = NULL;
1.63      frystyk   468:     }
1.88      frystyk   469:     if (HTTransferCoders) {
                    470:        HTCoding_deleteAll(HTTransferCoders);
                    471:        HTTransferCoders = NULL;
                    472:     }
1.73      frystyk   473:     if (HTCharsets) {
                    474:        HTCharset_deleteAll(HTCharsets);
                    475:        HTCharsets = NULL;
1.63      frystyk   476:     }
1.17      luotonen  477: }
                    478: 
1.63      frystyk   479: /* ------------------------------------------------------------------------- */
1.90      frystyk   480: /*                             STREAM STACKS                                */
1.63      frystyk   481: /* ------------------------------------------------------------------------- */
                    482: 
1.77      frystyk   483: PRIVATE BOOL better_match (HTFormat f, HTFormat g)
1.63      frystyk   484: {
1.85      frystyk   485:     const char *p, *q;
1.63      frystyk   486: 
                    487:     if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
                    488:        int i,j;
                    489:        for(i=0 ; *p; p++) if (*p == '*') i++;
                    490:        for(j=0 ; *q; q++) if (*q == '*') j++;
                    491:        if (i < j) return YES;
                    492:     }
                    493:     return NO;
                    494: }
                    495: 
1.87      frystyk   496: /*     Create a Content Type filter stack
                    497: **     ----------------------------------
1.7       secret    498: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     499: **     structure is made to hold the destination format while the
                    500: **     new stack is generated. This is just to pass the out format to
                    501: **     MIME so far.  Storing the format of a stream in the stream might
                    502: **     be a lot neater.
1.10      timbl     503: **
1.29      frystyk   504: **     The star/star format is special, in that if you can take
1.40      frystyk   505: **     that you can take anything.
1.2       timbl     506: */
1.77      frystyk   507: PUBLIC HTStream * HTStreamStack (HTFormat      rep_in,
                    508:                                 HTFormat       rep_out,
                    509:                                 HTStream *     output_stream,
                    510:                                 HTRequest *    request,
                    511:                                 BOOL           guess)
1.2       timbl     512: {
1.14      timbl     513:     HTList * conversion[2];
                    514:     int which_list;
1.59      frystyk   515:     double best_quality = -1e30;               /* Pretty bad! */
1.65      frystyk   516:     HTPresentation *pres, *best_match=NULL;
1.80      frystyk   517:     if (rep_out == WWW_RAW) {
1.87      frystyk   518:        if (CORE_TRACE) HTTrace("StreamStack. Raw output...\n");
1.81      frystyk   519:        return output_stream ? output_stream : HTErrorStream();
1.34      luotonen  520:     }
1.79      frystyk   521: 
1.80      frystyk   522:     if (rep_out == rep_in) {
1.87      frystyk   523:        if (CORE_TRACE)
1.84      eric      524:            HTTrace("StreamStack. Identical input/output format (%s)\n",
1.80      frystyk   525:                     HTAtom_name(rep_out));
1.81      frystyk   526:        return output_stream ? output_stream : HTErrorStream();
1.74      frystyk   527:     }
1.87      frystyk   528:     if (CORE_TRACE) {
1.89      eric      529:        const char *p = HTAtom_name(rep_in);
                    530:        const char *q = HTAtom_name(rep_out); 
1.84      eric      531:        HTTrace("StreamStack. Constructing stream stack for %s to %s\n",
1.82      frystyk   532:                 p ? p : "<NULL>", q ? q : "<NULL>");
1.47      frystyk   533:     }
1.2       timbl     534: 
1.88      frystyk   535:     conversion[0] = HTRequest_conversion(request);
1.14      timbl     536:     conversion[1] = HTConversions;
1.17      luotonen  537: 
1.15      luotonen  538:     for(which_list = 0; which_list<2; which_list++) {
                    539:        HTList * cur = conversion[which_list];
                    540:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.93      frystyk   541:            if ((pres->rep==rep_in || HTMIMEMatch(pres->rep, rep_in)) &&
                    542:                (pres->rep_out==rep_out || HTMIMEMatch(pres->rep_out,rep_out))){
1.65      frystyk   543:                if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33      luotonen  544:                    (!better_match(best_match->rep, pres->rep) &&
                    545:                     pres->quality > best_quality)) {
1.85      frystyk   546: #ifdef HAVE_SYSTEM
1.65      frystyk   547:                    int result=0;
                    548:                    if (pres->test_command) {
                    549:                        result = system(pres->test_command);
1.87      frystyk   550:                        if (CORE_TRACE) 
1.84      eric      551:                            HTTrace("StreamStack. system(%s) returns %d\n", pres->test_command, result);
1.65      frystyk   552:                    }
                    553:                    if (!result) {
1.49      howcome   554:                        best_match = pres;
                    555:                        best_quality = pres->quality;
                    556:                    }
1.65      frystyk   557: #else
                    558:                    best_match = pres;
                    559:                    best_quality = pres->quality;
1.85      frystyk   560: #endif /* HAVE_SYSTEM */
1.10      timbl     561:                }
                    562:            }
1.2       timbl     563:        }
                    564:     }
1.80      frystyk   565: 
                    566:     if (best_match) {
                    567:        if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
1.87      frystyk   568:            if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   569:            return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   570:        }
1.65      frystyk   571:        return (*best_match->converter)(request, best_match->command,
                    572:                                        rep_in, rep_out, output_stream);
1.80      frystyk   573:     }
                    574:     if (rep_out == WWW_SOURCE) {
1.87      frystyk   575:        if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   576:        return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   577:     }
                    578: 
1.96      frystyk   579:     if (CORE_TRACE) HTTrace("StreamStack. NOT FOUND - error!\n");
                    580:     return HTBlackHole();
1.2       timbl     581: }
                    582:        
                    583: 
                    584: /*             Find the cost of a filter stack
                    585: **             -------------------------------
                    586: **
                    587: **     Must return the cost of the same stack which StreamStack would set up.
                    588: **
                    589: ** On entry,
                    590: **     length  The size of the data to be converted
                    591: */
1.77      frystyk   592: PUBLIC double HTStackValue (HTList *   theseConversions,
                    593:                            HTFormat    rep_in,
                    594:                            HTFormat    rep_out,
                    595:                            double      initial_value,
                    596:                            long int    length)
1.2       timbl     597: {
1.14      timbl     598:     int which_list;
                    599:     HTList* conversion[2];
                    600:     
1.87      frystyk   601:     if (CORE_TRACE) {
1.84      eric      602:        HTTrace("StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.65      frystyk   603:                HTAtom_name(rep_in),    initial_value,
                    604:                HTAtom_name(rep_out));
                    605:     }
1.2       timbl     606:     if (rep_out == WWW_SOURCE ||
1.10      timbl     607:        rep_out == rep_in) return 0.0;
1.2       timbl     608: 
1.14      timbl     609:     conversion[0] = theseConversions;
                    610:     conversion[1] = HTConversions;
                    611:     
                    612:     for(which_list = 0; which_list<2; which_list++)
                    613:      if (conversion[which_list]) {
1.15      luotonen  614:         HTList * cur = conversion[which_list];
1.2       timbl     615:        HTPresentation * pres;
1.15      luotonen  616:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    617:            if (pres->rep == rep_in &&
1.93      frystyk   618:                (pres->rep_out == rep_out || HTMIMEMatch(pres->rep_out, rep_out))) {
1.59      frystyk   619:                double value = initial_value * pres->quality;
1.2       timbl     620:                if (HTMaxSecs != 0.0)
1.15      luotonen  621:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     622:                                         /HTMaxSecs;
                    623:                return value;
                    624:            }
                    625:        }
                    626:     }
1.63      frystyk   627:     return NO_VALUE_FOUND;             /* Really bad */
1.1       timbl     628: }
1.2       timbl     629: 
1.87      frystyk   630: /*     Create a new coder and insert it into stream chain
                    631: **     --------------------------------------------------
                    632: **     Creating the content decoding stack is not based on quality factors as
                    633: **     we don't have the freedom as with content types. Specify whether you
1.88      frystyk   634: **     you want encoding or decoding using the BOOL "encode" flag.
1.87      frystyk   635: */
1.88      frystyk   636: PUBLIC HTStream * HTContentCodingStack (HTEncoding     encoding,
                    637:                                        HTStream *      target,
                    638:                                        HTRequest *     request,
                    639:                                        void *          param,
                    640:                                        BOOL            encode)
1.87      frystyk   641: {
                    642:     HTList * coders[2];
                    643:     HTStream * top = target;
1.88      frystyk   644:     HTCoding * pres = NULL;
1.87      frystyk   645:     int cnt;
1.88      frystyk   646:     if (!encoding || !request) {
1.87      frystyk   647:        if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
                    648:        return target ? target : HTErrorStream();
                    649:     }
1.88      frystyk   650:     coders[0] = HTRequest_encoding(request);
                    651:     coders[1] = HTContentCoders;
1.87      frystyk   652:     if (CORE_TRACE)
1.94      frystyk   653:        HTTrace("C-E......... Looking for `%s\'\n", HTAtom_name(encoding));
1.87      frystyk   654:     for (cnt=0; cnt < 2; cnt++) {
                    655:        HTList * cur = coders[cnt];
1.88      frystyk   656:        while ((pres = (HTCoding *) HTList_nextObject(cur))) {
                    657:            if (pres->encoding == encoding) {
1.94      frystyk   658:                if (CORE_TRACE) HTTrace("C-E......... Found...\n");
1.88      frystyk   659:                if (encode) {
1.87      frystyk   660:                    if (pres->encoder)
1.88      frystyk   661:                        top = (*pres->encoder)(request, param, encoding, top);
1.87      frystyk   662:                    break;
                    663:                } else if (pres->decoder) {
1.88      frystyk   664:                    top = (*pres->decoder)(request, param, encoding, top);
1.87      frystyk   665:                    break;
                    666:                }
                    667:            }
                    668:        }
                    669:     }
1.94      frystyk   670: 
                    671:     /*
                    672:     **  If this is not a unity coding and we didn't find any coders
                    673:     **  that could handle it then put in a local file save stream
                    674:     **  instead of the stream that we got.
                    675:     */
                    676:     if (!HTFormat_isUnityContent(encoding) && target==top) {
1.96      frystyk   677:        if (encode) {
                    678:            if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - can't encode stream!\n");
1.94      frystyk   679:        } else {
1.96      frystyk   680:            if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - error!\n");
                    681:            top = HTBlackHole();
1.94      frystyk   682:        }
                    683:     }
1.87      frystyk   684:     return top;
                    685: }
1.10      timbl     686: 
1.87      frystyk   687: /*
                    688: **  Here you can provide a complete list instead of a single token.
                    689: **  The list has to filled up in the order the _encodings_ are to be applied
                    690: */
1.88      frystyk   691: PUBLIC HTStream * HTContentEncodingStack (HTList *     encodings,
                    692:                                          HTStream *    target,
                    693:                                          HTRequest *   request,
                    694:                                          void *        param)
1.87      frystyk   695: {
                    696:     if (encodings) {
                    697:        HTList * cur = encodings;
                    698:        HTEncoding pres;
                    699:        HTStream * top = target;
1.96      frystyk   700:        while ((pres = (HTEncoding) HTList_nextObject(cur))) {
1.88      frystyk   701:            top = HTContentCodingStack(pres, top, request, param, YES);
1.96      frystyk   702:            if (top == HTBlackHole()) break;
                    703:        }
1.87      frystyk   704:        return top;
                    705:     }
                    706:     return HTErrorStream();
                    707: }
                    708: 
                    709: /*
                    710: **  Here you can provide a complete list instead of a single token.
                    711: **  The list has to be in the order the _encodings_ were applied - that
                    712: **  is, the same way that _encodings_ are to be applied. This is all consistent
                    713: **  with the order of the Content-Encoding header.
                    714: */
1.88      frystyk   715: PUBLIC HTStream * HTContentDecodingStack (HTList *     encodings,
                    716:                                          HTStream *    target,
                    717:                                          HTRequest *   request,
                    718:                                          void *        param)
1.87      frystyk   719: {
                    720:     if (encodings) {
                    721:        HTEncoding pres;
                    722:        int cnt = HTList_count(encodings);
                    723:        HTStream * top = target;
                    724:        while (cnt > 0) {
                    725:            pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
1.88      frystyk   726:            top = HTContentCodingStack(pres, top, request, param, NO);
1.96      frystyk   727:            if (top == HTBlackHole()) break;
1.87      frystyk   728:        }
                    729:        return top;
                    730:     }
                    731:     return HTErrorStream();
                    732: }
1.88      frystyk   733: 
1.96      frystyk   734: /*     Create a new coder and insert it into stream chain
                    735: **     --------------------------------------------------
                    736: **     Creating the transfer decoding stack is not based on quality factors as
1.88      frystyk   737: **     we don't have the freedom as with content types. Specify whether you
                    738: **     you want encoding or decoding using the BOOL "encode" flag.
                    739: */
                    740: PUBLIC HTStream * HTTransferCodingStack (HTEncoding    encoding,
                    741:                                         HTStream *     target,
                    742:                                         HTRequest *    request,
                    743:                                         void *         param,
                    744:                                         BOOL           encode)
                    745: {
                    746:     HTList * coders[2];
                    747:     HTStream * top = target;
                    748:     HTCoding * pres = NULL;
                    749:     int cnt;
                    750:     if (!encoding || !request) {
1.96      frystyk   751:        if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
                    752:        return target ? target : HTErrorStream();
                    753:     }
                    754:     coders[0] = HTRequest_transfer(request);
                    755:     coders[1] = HTTransferCoders;
                    756:     if (CORE_TRACE)
                    757:        HTTrace("C-E......... Looking for `%s\'\n", HTAtom_name(encoding));
                    758:     for (cnt=0; cnt < 2; cnt++) {
                    759:        HTList * cur = coders[cnt];
                    760:        while ((pres = (HTCoding *) HTList_nextObject(cur))) {
                    761:            if (pres->encoding == encoding) {
                    762:                if (CORE_TRACE) HTTrace("C-E......... Found...\n");
                    763:                if (encode) {
                    764:                    if (pres->encoder)
                    765:                        top = (*pres->encoder)(request, param, encoding, top);
                    766:                    break;
                    767:                } else if (pres->decoder) {
                    768:                    top = (*pres->decoder)(request, param, encoding, top);
                    769:                    break;
                    770:                }
                    771:            }
                    772:        }
                    773:     }
                    774: 
                    775:     /*
                    776:     **  If this is not a unity coding and we didn't find any coders
                    777:     **  that could handle it then put in a local file save stream
                    778:     **  instead of the stream that we got.
                    779:     */
                    780:     if (!HTFormat_isUnityContent(encoding) && target==top) {
                    781:        if (encode) {
                    782:            if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - can't encode stream!\n");
                    783:        } else {
                    784:            if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - error!\n");
                    785:            top = HTBlackHole();
                    786:        }
                    787:     }
                    788:     return top;
                    789: }
                    790: 
                    791: /*
                    792: **  Here you can provide a complete list instead of a single token.
                    793: **  The list has to filled up in the order the _encodings_ are to be applied
                    794: */
                    795: PUBLIC HTStream * HTTransferEncodingStack (HTList *    encodings,
                    796:                                           HTStream *   target,
                    797:                                           HTRequest *  request,
                    798:                                           void *       param)
                    799: {
                    800:     if (encodings) {
                    801:        HTList * cur = encodings;
                    802:        HTEncoding pres;
                    803:        HTStream * top = target;
                    804:        while ((pres = (HTEncoding) HTList_nextObject(cur))) {
                    805:            top = HTTransferCodingStack(pres, top, request, param, YES);
                    806:            if (top == HTBlackHole()) break;
                    807:        }
                    808:        return top;
                    809:     }
                    810:     return HTErrorStream();
                    811: }
                    812: 
                    813: /*
                    814: **  Here you can provide a complete list instead of a single token.
                    815: **  The list has to be in the order the _encodings_ were applied - that
                    816: **  is, the same way that _encodings_ are to be applied. This is all consistent
                    817: **  with the order of the Content-Encoding header.
                    818: */
                    819: PUBLIC HTStream * HTTransferDecodingStack (HTList *    encodings,
                    820:                                           HTStream *   target,
                    821:                                           HTRequest *  request,
                    822:                                           void *       param)
                    823: {
                    824:     if (encodings) {
                    825:        HTEncoding pres;
                    826:        int cnt = HTList_count(encodings);
                    827:        HTStream * top = target;
                    828:        while (cnt > 0) {
                    829:            pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
                    830:            top = HTTransferCodingStack(pres, top, request, param, NO);
                    831:            if (top == HTBlackHole()) break;
                    832:        }
                    833:        return top;
                    834:     }
                    835:     return HTErrorStream();
                    836: }
                    837: 
                    838: /*     Create a new transfer coder and insert it into stream chain
                    839: **     -----------------------------------------------------------
                    840: **     Creating the content decoding stack is not based on quality factors as
                    841: **     we don't have the freedom as with content types. Specify whether you
                    842: **     you want encoding or decoding using the BOOL "encode" flag.
                    843: */
                    844: PUBLIC HTStream * HTContentTransferCodingStack (HTEncoding     encoding,
                    845:                                                HTStream *      target,
                    846:                                                HTRequest *     request,
                    847:                                                void *          param,
                    848:                                                BOOL            encode)
                    849: {
                    850:     HTList * coders[2];
                    851:     HTStream * top = target;
                    852:     HTCoding * pres = NULL;
                    853:     int cnt;
                    854:     if (!encoding || !request) {
1.88      frystyk   855:        if (CORE_TRACE) HTTrace("C-T-E..... Nothing applied...\n");
                    856:        return target ? target : HTErrorStream();
                    857:     }
1.96      frystyk   858: 
                    859:     /*
                    860:     **  We use the same encoders/decoders as for Transfer-Encodings
                    861:     */
1.88      frystyk   862:     coders[0] = HTRequest_transfer(request);
                    863:     coders[1] = HTTransferCoders;
                    864:     if (CORE_TRACE)
                    865:        HTTrace("C-T-E....... Looking for %s\n", HTAtom_name(encoding));
                    866:     for (cnt=0; cnt < 2; cnt++) {
                    867:        HTList * cur = coders[cnt];
                    868:        while ((pres = (HTCoding *) HTList_nextObject(cur))) {
                    869:            if (pres->encoding == encoding) {
                    870:                if (CORE_TRACE) HTTrace("C-T-E....... Found...\n");
                    871:                if (encode) {
                    872:                    if (pres->encoder)
                    873:                        top = (*pres->encoder)(request, param, encoding, top);
                    874:                    break;
                    875:                } else if (pres->decoder) {
                    876:                    top = (*pres->decoder)(request, param, encoding, top);
                    877:                    break;
                    878:                }
                    879:            }
                    880:        }
                    881:     }
1.94      frystyk   882: 
                    883:     /*
                    884:     **  If this is not a unity coding and we didn't find any coders
                    885:     **  that could handle it then put in a local file save stream
                    886:     **  instead of the stream that we got.
                    887:     */
                    888:     if (!HTFormat_isUnityTransfer(encoding) && target==top) {
                    889:        if (encode) {       
                    890:            if (CORE_TRACE) HTTrace("C-T-E....... NOT FOUND - removing encoding!\n");
1.96      frystyk   891:            HTAnchor_setContentTransferEncoding(HTRequest_anchor(request), NULL);
1.94      frystyk   892:        } else {
1.96      frystyk   893:            if (CORE_TRACE) HTTrace("C-T-E....... NOT FOUND - error!\n");
                    894:            top = HTBlackHole();
1.94      frystyk   895:        }
                    896:     }
1.88      frystyk   897:     return top;
                    898: }
                    899: 

Webmaster