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

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.95    ! frystyk     6: **     @(#) $Id: HTFormat.c,v 1.94 1997/02/16 17:49:15 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.85      frystyk    19: #include "sysdep.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.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: 
1.52      frystyk    75: /*
1.63      frystyk    76: **     For all `accept lists' there is a local list and a global list. The
                     77: **     local list is a part of the request structure and the global list is
                     78: **     internal to the HTFormat module. The global lists can be used when
                     79: **     specifying accept lists for ALL requests and the local list can be 
                     80: **     used to add specific accept headers to the request.
                     81: */
                     82: 
1.88      frystyk    83: /* ------------------------------------------------------------------------- */
                     84: /*                             CONTENT TYPES                                */
                     85: /* ------------------------------------------------------------------------- */
1.61      frystyk    86: 
1.2       timbl      87: /*     Define a presentation system command for a content-type
                     88: **     -------------------------------------------------------
1.52      frystyk    89: ** INPUT:
                     90: **     conversions:    The list of conveters and presenters
                     91: **     representation: the MIME-style format name
                     92: **     command:        the MAILCAP-style command template
                     93: **     quality:        A degradation faction [0..1]
                     94: **     maxbytes:       A limit on the length acceptable as input (0 infinite)
                     95: **     maxsecs:        A limit on the time user will wait (0 for infinity)
1.2       timbl      96: */
1.72      frystyk    97: PUBLIC void HTPresentation_add (HTList *       conversions,
1.85      frystyk    98:                                const char *    representation,
                     99:                                const char *    command,
                    100:                                const char *    test_command,
1.72      frystyk   101:                                double          quality,
                    102:                                double          secs, 
                    103:                                double          secs_per_byte)
1.52      frystyk   104: {
1.83      frystyk   105:     HTPresentation * pres;
                    106:     if ((pres = (HTPresentation  *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
                    107:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     108:     
                    109:     pres->rep = HTAtom_for(representation);
                    110:     pres->rep_out = WWW_PRESENT;               /* Fixed for now ... :-) */
                    111:     pres->converter = HTSaveAndExecute;                /* Fixed for now ...     */
                    112:     pres->quality = quality;
                    113:     pres->secs = secs;
                    114:     pres->secs_per_byte = secs_per_byte;
                    115:     pres->rep = HTAtom_for(representation);
1.49      howcome   116:     pres->command = NULL;
1.2       timbl     117:     StrAllocCopy(pres->command, command);
1.49      howcome   118:     pres->test_command = NULL;
                    119:     StrAllocCopy(pres->test_command, test_command);
1.91      frystyk   120:     if (CORE_TRACE)
                    121:        HTTrace("Presentation Adding `%s\' with quality %.2f\n",
                    122:                command, quality);
1.12      timbl     123:     HTList_addObject(conversions, pres);
1.2       timbl     124: }
                    125: 
1.73      frystyk   126: PUBLIC void HTPresentation_deleteAll (HTList * list)
                    127: {
                    128:     if (list) {
                    129:        HTList *cur = list;
                    130:        HTPresentation *pres;
                    131:        while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
1.83      frystyk   132:            HT_FREE(pres->command);
                    133:            HT_FREE(pres);
1.73      frystyk   134:        }
                    135:        HTList_delete(list);
                    136:     }
                    137: }
1.2       timbl     138: 
                    139: /*     Define a built-in function for a content-type
                    140: **     ---------------------------------------------
                    141: */
1.72      frystyk   142: PUBLIC void HTConversion_add (HTList *         conversions,
1.85      frystyk   143:                              const char *      representation_in,
                    144:                              const char *      representation_out,
1.72      frystyk   145:                              HTConverter *     converter,
                    146:                              double            quality,
                    147:                              double            secs, 
                    148:                              double            secs_per_byte)
1.52      frystyk   149: {
1.83      frystyk   150:     HTPresentation * pres;
1.87      frystyk   151:     if ((pres = (HTPresentation*) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
1.83      frystyk   152:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     153:     pres->rep = HTAtom_for(representation_in);
                    154:     pres->rep_out = HTAtom_for(representation_out);
                    155:     pres->converter = converter;
                    156:     pres->command = NULL;              /* Fixed */
1.49      howcome   157:     pres->test_command = NULL;
1.2       timbl     158:     pres->quality = quality;
                    159:     pres->secs = secs;
                    160:     pres->secs_per_byte = secs_per_byte;
1.91      frystyk   161:     if (CORE_TRACE)
                    162:        HTTrace("Conversions. Adding %p with quality %.2f\n",
                    163:                converter, quality);
1.12      timbl     164:     HTList_addObject(conversions, pres);
1.56      frystyk   165: }
                    166: 
1.73      frystyk   167: PUBLIC void HTConversion_deleteAll (HTList * list)
                    168: {
                    169:     HTPresentation_deleteAll(list);
                    170: }
                    171: 
1.88      frystyk   172: /* ------------------------------------------------------------------------- */
                    173: /*             CONTENT ENCODING AND CONTENT TRANSFER ENCODING               */
                    174: /* ------------------------------------------------------------------------- */
                    175: 
                    176: PUBLIC BOOL HTCoding_add (HTList *     list,
                    177:                          const char *  encoding,
                    178:                          HTCoder *     encoder,
                    179:                          HTCoder *     decoder,
                    180:                          double        quality)
1.73      frystyk   181: {
1.88      frystyk   182:     if (list && encoding && (encoder || decoder)) {
                    183:        HTCoding * me;
                    184:        if ((me = (HTCoding *) HT_CALLOC(1, sizeof(HTCoding))) == NULL)
                    185:            HT_OUTOFMEM("HTCoding_add");
                    186:        me->encoding = HTAtom_for(encoding);
1.87      frystyk   187:        me->encoder = encoder;
                    188:        me->decoder = decoder;
                    189:        me->quality = quality;
                    190:        if (CORE_TRACE)
                    191:            HTTrace("Codings..... Adding %s with quality %.2f\n",
1.88      frystyk   192:                    encoding, quality);
1.87      frystyk   193:        return HTList_addObject(list, (void *) me);
1.73      frystyk   194:     }
1.87      frystyk   195:     if (CORE_TRACE) HTTrace("Codings..... Bad argument\n");
                    196:     return NO;
1.73      frystyk   197: }
                    198: 
1.88      frystyk   199: PUBLIC void HTCoding_deleteAll (HTList * list)
1.73      frystyk   200: {
                    201:     if (list) {
1.87      frystyk   202:        HTList * cur = list;
1.88      frystyk   203:        HTCoding * pres;
                    204:        while ((pres = (HTCoding *) HTList_nextObject(cur)))
1.83      frystyk   205:            HT_FREE(pres);
1.73      frystyk   206:        HTList_delete(list);
                    207:     }
                    208: }
                    209: 
1.88      frystyk   210: PUBLIC const char * HTCoding_name (HTCoding * me)
1.87      frystyk   211: {
1.88      frystyk   212:     return me ? HTAtom_name(me->encoding) : NULL;
1.95    ! frystyk   213: }
        !           214: 
        !           215: PUBLIC double HTCoding_quality (HTCoding * me)
        !           216: {
        !           217:     return me ? me->quality : 0.0;
1.87      frystyk   218: }
                    219: 
1.88      frystyk   220: /* ------------------------------------------------------------------------- */
                    221: /*                             CONTENT LANGUAGE                             */
                    222: /* ------------------------------------------------------------------------- */
                    223: 
1.73      frystyk   224: PUBLIC void HTLanguage_add (HTList *           list,
1.85      frystyk   225:                            const char *        lang,
1.73      frystyk   226:                            double              quality)
                    227: {
                    228:     HTAcceptNode * node;
                    229:     if (!list || !lang || !*lang)  {
1.87      frystyk   230:        if (CORE_TRACE)
1.84      eric      231:            HTTrace("Languages... Bad argument\n");
1.73      frystyk   232:        return;
                    233:     }
1.83      frystyk   234:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    235:         HT_OUTOFMEM("HTAcceptLanguage");
1.73      frystyk   236: 
                    237:     HTList_addObject(list, (void*)node);
                    238:     node->atom = HTAtom_for(lang);
                    239:     node->quality = quality;
                    240: }
                    241: 
                    242: PUBLIC void HTLanguage_deleteAll (HTList * list)
                    243: {
1.87      frystyk   244:     if (list) {
                    245:        HTList *cur = list;
                    246:        HTAcceptNode *pres;
                    247:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
                    248:            HT_FREE(pres);
                    249:        }
                    250:        HTList_delete(list);
                    251:     }
1.73      frystyk   252: }
                    253: 
1.88      frystyk   254: /* ------------------------------------------------------------------------- */
                    255: /*                             CONTENT CHARSET                              */
                    256: /* ------------------------------------------------------------------------- */
                    257: 
1.73      frystyk   258: PUBLIC void HTCharset_add (HTList *            list,
1.85      frystyk   259:                           const char *         charset,
1.73      frystyk   260:                           double               quality)
                    261: {
                    262:     HTAcceptNode * node;
                    263:     if (!list || !charset || !*charset)  {
1.87      frystyk   264:        if (CORE_TRACE)
1.84      eric      265:            HTTrace("Charset..... Bad argument\n");
1.73      frystyk   266:        return;
                    267:     }
1.83      frystyk   268:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    269:         HT_OUTOFMEM("HTAcceptCharsetuage");
1.73      frystyk   270: 
                    271:     HTList_addObject(list, (void*)node);
                    272:     node->atom = HTAtom_for(charset);
                    273:     node->quality = quality;
                    274: }
                    275: 
                    276: PUBLIC void HTCharset_deleteAll (HTList * list)
                    277: {
1.87      frystyk   278:     if (list) {
                    279:        HTList *cur = list;
                    280:        HTAcceptNode *pres;
                    281:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
                    282:            HT_FREE(pres);
                    283:        }
                    284:        HTList_delete(list);
                    285:     }
1.73      frystyk   286: }
                    287: 
                    288: /* ------------------------------------------------------------------------- */
                    289: /*                     GLOBAL LIST OF CONVERTERS ETC.                       */
                    290: /* ------------------------------------------------------------------------- */
                    291: 
1.72      frystyk   292: /*
                    293: **     Global Accept Format Types Conversions
                    294: **     list can be NULL
                    295: */
1.73      frystyk   296: PUBLIC void HTFormat_setConversion (HTList * list)
1.72      frystyk   297: {
                    298:     HTConversions = list;
                    299: }
                    300: 
                    301: PUBLIC HTList * HTFormat_conversion (void)
                    302: {
                    303:     return HTConversions;
                    304: }
                    305: 
1.92      frystyk   306: PUBLIC void HTFormat_addConversion (const char *       input_format,
                    307:                                    const char *        output_format,
                    308:                                    HTConverter *       converter,
                    309:                                    double              quality,
                    310:                                    double              secs, 
                    311:                                    double              secs_per_byte)
                    312: {
                    313:     if (!HTConversions) HTConversions = HTList_new();
                    314:     HTConversion_add(HTConversions, input_format, output_format,
                    315:                     converter, quality, secs, secs_per_byte);
                    316: }
                    317: 
1.72      frystyk   318: /*
1.88      frystyk   319: **     Global list of Content Encodings
1.72      frystyk   320: **     list can be NULL
                    321: */
1.88      frystyk   322: PUBLIC void HTFormat_setContentCoding (HTList *list)
1.72      frystyk   323: {
1.88      frystyk   324:     HTContentCoders = list;
1.72      frystyk   325: }
                    326: 
1.88      frystyk   327: PUBLIC HTList * HTFormat_contentCoding (void)
1.72      frystyk   328: {
1.88      frystyk   329:     return HTContentCoders;
1.72      frystyk   330: }
                    331: 
1.92      frystyk   332: PUBLIC BOOL HTFormat_addCoding ( char *                encoding,
                    333:                                 HTCoder *      encoder,
                    334:                                 HTCoder *      decoder,
                    335:                                 double         quality)
                    336: {
                    337:     if (!HTContentCoders) HTContentCoders = HTList_new();
                    338:     return HTCoding_add(HTContentCoders, encoding, encoder, decoder, quality);
                    339: }
                    340: 
1.72      frystyk   341: /*
1.88      frystyk   342: **     Global list of Content Transfer Encodings
                    343: **     list can be NULL
                    344: */
                    345: PUBLIC void HTFormat_setTransferCoding (HTList *list)
                    346: {
                    347:     HTTransferCoders = list;
                    348: }
                    349: 
                    350: PUBLIC HTList * HTFormat_transferCoding (void)
                    351: {
                    352:     return HTTransferCoders;
1.92      frystyk   353: }
                    354: 
                    355: PUBLIC BOOL HTFormat_addTransferCoding ( char *                encoding,
                    356:                                         HTCoder *      encoder,
                    357:                                         HTCoder *      decoder,
                    358:                                         double         quality)
                    359: {
                    360:     if (!HTTransferCoders) HTTransferCoders = HTList_new();
                    361:     return HTCoding_add(HTTransferCoders, encoding, encoder, decoder, quality);
1.88      frystyk   362: }
                    363: 
                    364: /*
1.72      frystyk   365: **     Global Accept Languages
                    366: **     list can be NULL
                    367: */
                    368: PUBLIC void HTFormat_setLanguage (HTList *list)
                    369: {
                    370:     HTLanguages = list;
                    371: }
                    372: 
                    373: PUBLIC HTList * HTFormat_language (void)
                    374: {
                    375:     return HTLanguages;
                    376: }
                    377: 
                    378: /*
                    379: **     Global Accept Charsets
                    380: **     list can be NULL
                    381: */
                    382: PUBLIC void HTFormat_setCharset (HTList *list)
                    383: {
                    384:     HTCharsets = list;
                    385: }
                    386: 
                    387: PUBLIC HTList * HTFormat_charset (void)
                    388: {
                    389:     return HTCharsets;
                    390: }
1.56      frystyk   391: 
1.73      frystyk   392: /*
                    393: **     Convenience function to clean up
                    394: */
                    395: PUBLIC void HTFormat_deleteAll (void)
1.17      luotonen  396: {
1.73      frystyk   397:     if (HTConversions) {
                    398:        HTConversion_deleteAll(HTConversions);
                    399:        HTConversions = NULL;
                    400:     }
                    401:     if (HTLanguages) {
                    402:        HTLanguage_deleteAll(HTLanguages);
                    403:        HTLanguages = NULL;
1.63      frystyk   404:     }
1.88      frystyk   405:     if (HTContentCoders) {
                    406:        HTCoding_deleteAll(HTContentCoders);
                    407:        HTContentCoders = NULL;
1.63      frystyk   408:     }
1.88      frystyk   409:     if (HTTransferCoders) {
                    410:        HTCoding_deleteAll(HTTransferCoders);
                    411:        HTTransferCoders = NULL;
                    412:     }
1.73      frystyk   413:     if (HTCharsets) {
                    414:        HTCharset_deleteAll(HTCharsets);
                    415:        HTCharsets = NULL;
1.63      frystyk   416:     }
1.17      luotonen  417: }
                    418: 
1.63      frystyk   419: /* ------------------------------------------------------------------------- */
1.90      frystyk   420: /*                             STREAM STACKS                                */
1.63      frystyk   421: /* ------------------------------------------------------------------------- */
                    422: 
1.77      frystyk   423: PRIVATE BOOL better_match (HTFormat f, HTFormat g)
1.63      frystyk   424: {
1.85      frystyk   425:     const char *p, *q;
1.63      frystyk   426: 
                    427:     if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
                    428:        int i,j;
                    429:        for(i=0 ; *p; p++) if (*p == '*') i++;
                    430:        for(j=0 ; *q; q++) if (*q == '*') j++;
                    431:        if (i < j) return YES;
                    432:     }
                    433:     return NO;
                    434: }
                    435: 
1.87      frystyk   436: /*     Create a Content Type filter stack
                    437: **     ----------------------------------
1.7       secret    438: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     439: **     structure is made to hold the destination format while the
                    440: **     new stack is generated. This is just to pass the out format to
                    441: **     MIME so far.  Storing the format of a stream in the stream might
                    442: **     be a lot neater.
1.10      timbl     443: **
1.29      frystyk   444: **     The star/star format is special, in that if you can take
1.40      frystyk   445: **     that you can take anything.
1.2       timbl     446: */
1.77      frystyk   447: PUBLIC HTStream * HTStreamStack (HTFormat      rep_in,
                    448:                                 HTFormat       rep_out,
                    449:                                 HTStream *     output_stream,
                    450:                                 HTRequest *    request,
                    451:                                 BOOL           guess)
1.2       timbl     452: {
1.14      timbl     453:     HTList * conversion[2];
                    454:     int which_list;
1.59      frystyk   455:     double best_quality = -1e30;               /* Pretty bad! */
1.65      frystyk   456:     HTPresentation *pres, *best_match=NULL;
1.80      frystyk   457:     if (rep_out == WWW_RAW) {
1.87      frystyk   458:        if (CORE_TRACE) HTTrace("StreamStack. Raw output...\n");
1.81      frystyk   459:        return output_stream ? output_stream : HTErrorStream();
1.34      luotonen  460:     }
1.79      frystyk   461: 
1.80      frystyk   462:     if (rep_out == rep_in) {
1.87      frystyk   463:        if (CORE_TRACE)
1.84      eric      464:            HTTrace("StreamStack. Identical input/output format (%s)\n",
1.80      frystyk   465:                     HTAtom_name(rep_out));
1.81      frystyk   466:        return output_stream ? output_stream : HTErrorStream();
1.74      frystyk   467:     }
1.87      frystyk   468:     if (CORE_TRACE) {
1.89      eric      469:        const char *p = HTAtom_name(rep_in);
                    470:        const char *q = HTAtom_name(rep_out); 
1.84      eric      471:        HTTrace("StreamStack. Constructing stream stack for %s to %s\n",
1.82      frystyk   472:                 p ? p : "<NULL>", q ? q : "<NULL>");
1.47      frystyk   473:     }
1.2       timbl     474: 
1.88      frystyk   475:     conversion[0] = HTRequest_conversion(request);
1.14      timbl     476:     conversion[1] = HTConversions;
1.17      luotonen  477: 
1.15      luotonen  478:     for(which_list = 0; which_list<2; which_list++) {
                    479:        HTList * cur = conversion[which_list];
                    480:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.93      frystyk   481:            if ((pres->rep==rep_in || HTMIMEMatch(pres->rep, rep_in)) &&
                    482:                (pres->rep_out==rep_out || HTMIMEMatch(pres->rep_out,rep_out))){
1.65      frystyk   483:                if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33      luotonen  484:                    (!better_match(best_match->rep, pres->rep) &&
                    485:                     pres->quality > best_quality)) {
1.85      frystyk   486: #ifdef HAVE_SYSTEM
1.65      frystyk   487:                    int result=0;
                    488:                    if (pres->test_command) {
                    489:                        result = system(pres->test_command);
1.87      frystyk   490:                        if (CORE_TRACE) 
1.84      eric      491:                            HTTrace("StreamStack. system(%s) returns %d\n", pres->test_command, result);
1.65      frystyk   492:                    }
                    493:                    if (!result) {
1.49      howcome   494:                        best_match = pres;
                    495:                        best_quality = pres->quality;
                    496:                    }
1.65      frystyk   497: #else
                    498:                    best_match = pres;
                    499:                    best_quality = pres->quality;
1.85      frystyk   500: #endif /* HAVE_SYSTEM */
1.10      timbl     501:                }
                    502:            }
1.2       timbl     503:        }
                    504:     }
1.80      frystyk   505: 
                    506:     if (best_match) {
                    507:        if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
1.87      frystyk   508:            if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   509:            return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   510:        }
1.65      frystyk   511:        return (*best_match->converter)(request, best_match->command,
                    512:                                        rep_in, rep_out, output_stream);
1.80      frystyk   513:     }
                    514:     if (rep_out == WWW_SOURCE) {
1.87      frystyk   515:        if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   516:        return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   517:     }
                    518: 
1.87      frystyk   519:     if (CORE_TRACE)
1.84      eric      520:        HTTrace("StreamStack. No match found, dumping to local file\n");
1.65      frystyk   521:     return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2       timbl     522: }
                    523:        
                    524: 
                    525: /*             Find the cost of a filter stack
                    526: **             -------------------------------
                    527: **
                    528: **     Must return the cost of the same stack which StreamStack would set up.
                    529: **
                    530: ** On entry,
                    531: **     length  The size of the data to be converted
                    532: */
1.77      frystyk   533: PUBLIC double HTStackValue (HTList *   theseConversions,
                    534:                            HTFormat    rep_in,
                    535:                            HTFormat    rep_out,
                    536:                            double      initial_value,
                    537:                            long int    length)
1.2       timbl     538: {
1.14      timbl     539:     int which_list;
                    540:     HTList* conversion[2];
                    541:     
1.87      frystyk   542:     if (CORE_TRACE) {
1.84      eric      543:        HTTrace("StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.65      frystyk   544:                HTAtom_name(rep_in),    initial_value,
                    545:                HTAtom_name(rep_out));
                    546:     }
1.2       timbl     547:     if (rep_out == WWW_SOURCE ||
1.10      timbl     548:        rep_out == rep_in) return 0.0;
1.2       timbl     549: 
1.14      timbl     550:     conversion[0] = theseConversions;
                    551:     conversion[1] = HTConversions;
                    552:     
                    553:     for(which_list = 0; which_list<2; which_list++)
                    554:      if (conversion[which_list]) {
1.15      luotonen  555:         HTList * cur = conversion[which_list];
1.2       timbl     556:        HTPresentation * pres;
1.15      luotonen  557:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    558:            if (pres->rep == rep_in &&
1.93      frystyk   559:                (pres->rep_out == rep_out || HTMIMEMatch(pres->rep_out, rep_out))) {
1.59      frystyk   560:                double value = initial_value * pres->quality;
1.2       timbl     561:                if (HTMaxSecs != 0.0)
1.15      luotonen  562:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     563:                                         /HTMaxSecs;
                    564:                return value;
                    565:            }
                    566:        }
                    567:     }
1.63      frystyk   568:     return NO_VALUE_FOUND;             /* Really bad */
1.1       timbl     569: }
1.2       timbl     570: 
1.87      frystyk   571: /*     Create a new coder and insert it into stream chain
                    572: **     --------------------------------------------------
                    573: **     Creating the content decoding stack is not based on quality factors as
                    574: **     we don't have the freedom as with content types. Specify whether you
1.88      frystyk   575: **     you want encoding or decoding using the BOOL "encode" flag.
1.87      frystyk   576: */
1.88      frystyk   577: PUBLIC HTStream * HTContentCodingStack (HTEncoding     encoding,
                    578:                                        HTStream *      target,
                    579:                                        HTRequest *     request,
                    580:                                        void *          param,
                    581:                                        BOOL            encode)
1.87      frystyk   582: {
                    583:     HTList * coders[2];
                    584:     HTStream * top = target;
1.88      frystyk   585:     HTCoding * pres = NULL;
1.87      frystyk   586:     int cnt;
1.88      frystyk   587:     if (!encoding || !request) {
1.87      frystyk   588:        if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
                    589:        return target ? target : HTErrorStream();
                    590:     }
1.88      frystyk   591:     coders[0] = HTRequest_encoding(request);
                    592:     coders[1] = HTContentCoders;
1.87      frystyk   593:     if (CORE_TRACE)
1.94      frystyk   594:        HTTrace("C-E......... Looking for `%s\'\n", HTAtom_name(encoding));
1.87      frystyk   595:     for (cnt=0; cnt < 2; cnt++) {
                    596:        HTList * cur = coders[cnt];
1.88      frystyk   597:        while ((pres = (HTCoding *) HTList_nextObject(cur))) {
                    598:            if (pres->encoding == encoding) {
1.94      frystyk   599:                if (CORE_TRACE) HTTrace("C-E......... Found...\n");
1.88      frystyk   600:                if (encode) {
1.87      frystyk   601:                    if (pres->encoder)
1.88      frystyk   602:                        top = (*pres->encoder)(request, param, encoding, top);
1.87      frystyk   603:                    break;
                    604:                } else if (pres->decoder) {
1.88      frystyk   605:                    top = (*pres->decoder)(request, param, encoding, top);
1.87      frystyk   606:                    break;
                    607:                }
                    608:            }
                    609:        }
                    610:     }
1.94      frystyk   611: 
                    612:     /*
                    613:     **  If this is not a unity coding and we didn't find any coders
                    614:     **  that could handle it then put in a local file save stream
                    615:     **  instead of the stream that we got.
                    616:     */
                    617:     if (!HTFormat_isUnityContent(encoding) && target==top) {
                    618:        if (encode) {       
                    619:            if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - removing encoding!\n");
                    620:            HTAnchor_removeEncoding(HTRequest_anchor(request), encoding);
                    621:        } else {
                    622:            if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - inserting save stream!\n");
                    623:            (*top->isa->abort)(top, NULL);
                    624:            top = HTSaveLocally(request, NULL, NULL,
                    625:                                HTRequest_outputFormat(request),
                    626:                                HTRequest_outputStream(request));
                    627:        }
                    628:     }
1.87      frystyk   629:     return top;
                    630: }
1.10      timbl     631: 
1.87      frystyk   632: /*
                    633: **  Here you can provide a complete list instead of a single token.
                    634: **  The list has to filled up in the order the _encodings_ are to be applied
                    635: */
1.88      frystyk   636: PUBLIC HTStream * HTContentEncodingStack (HTList *     encodings,
                    637:                                          HTStream *    target,
                    638:                                          HTRequest *   request,
                    639:                                          void *        param)
1.87      frystyk   640: {
                    641:     if (encodings) {
                    642:        HTList * cur = encodings;
                    643:        HTEncoding pres;
                    644:        HTStream * top = target;
                    645:        while ((pres = (HTEncoding) HTList_nextObject(cur)))
1.88      frystyk   646:            top = HTContentCodingStack(pres, top, request, param, YES);
1.87      frystyk   647:        return top;
                    648:     }
                    649:     return HTErrorStream();
                    650: }
                    651: 
                    652: /*
                    653: **  Here you can provide a complete list instead of a single token.
                    654: **  The list has to be in the order the _encodings_ were applied - that
                    655: **  is, the same way that _encodings_ are to be applied. This is all consistent
                    656: **  with the order of the Content-Encoding header.
                    657: */
1.88      frystyk   658: PUBLIC HTStream * HTContentDecodingStack (HTList *     encodings,
                    659:                                          HTStream *    target,
                    660:                                          HTRequest *   request,
                    661:                                          void *        param)
1.87      frystyk   662: {
                    663:     if (encodings) {
                    664:        HTEncoding pres;
                    665:        int cnt = HTList_count(encodings);
                    666:        HTStream * top = target;
                    667:        while (cnt > 0) {
                    668:            pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
1.88      frystyk   669:            top = HTContentCodingStack(pres, top, request, param, NO);
1.87      frystyk   670:        }
                    671:        return top;
                    672:     }
                    673:     return HTErrorStream();
                    674: }
1.88      frystyk   675: 
                    676: /*     Create a new transfer coder and insert it into stream chain
                    677: **     -----------------------------------------------------------
                    678: **     Creating the content decoding stack is not based on quality factors as
                    679: **     we don't have the freedom as with content types. Specify whether you
                    680: **     you want encoding or decoding using the BOOL "encode" flag.
                    681: */
                    682: PUBLIC HTStream * HTTransferCodingStack (HTEncoding    encoding,
                    683:                                         HTStream *     target,
                    684:                                         HTRequest *    request,
                    685:                                         void *         param,
                    686:                                         BOOL           encode)
                    687: {
                    688:     HTList * coders[2];
                    689:     HTStream * top = target;
                    690:     HTCoding * pres = NULL;
                    691:     int cnt;
                    692:     if (!encoding || !request) {
                    693:        if (CORE_TRACE) HTTrace("C-T-E..... Nothing applied...\n");
                    694:        return target ? target : HTErrorStream();
                    695:     }
                    696:     coders[0] = HTRequest_transfer(request);
                    697:     coders[1] = HTTransferCoders;
                    698:     if (CORE_TRACE)
                    699:        HTTrace("C-T-E....... Looking for %s\n", HTAtom_name(encoding));
                    700:     for (cnt=0; cnt < 2; cnt++) {
                    701:        HTList * cur = coders[cnt];
                    702:        while ((pres = (HTCoding *) HTList_nextObject(cur))) {
                    703:            if (pres->encoding == encoding) {
                    704:                if (CORE_TRACE) HTTrace("C-T-E....... Found...\n");
                    705:                if (encode) {
                    706:                    if (pres->encoder)
                    707:                        top = (*pres->encoder)(request, param, encoding, top);
                    708:                    break;
                    709:                } else if (pres->decoder) {
                    710:                    top = (*pres->decoder)(request, param, encoding, top);
                    711:                    break;
                    712:                }
                    713:            }
                    714:        }
                    715:     }
1.94      frystyk   716: 
                    717:     /*
                    718:     **  If this is not a unity coding and we didn't find any coders
                    719:     **  that could handle it then put in a local file save stream
                    720:     **  instead of the stream that we got.
                    721:     */
                    722:     if (!HTFormat_isUnityTransfer(encoding) && target==top) {
                    723:        if (encode) {       
                    724:            if (CORE_TRACE) HTTrace("C-T-E....... NOT FOUND - removing encoding!\n");
                    725:            HTAnchor_setTransfer(HTRequest_anchor(request), NULL);
                    726:        } else {
                    727:            if (CORE_TRACE) HTTrace("C-T-E....... NOT FOUND - inserting save stream!\n");
                    728:            (*top->isa->abort)(top, NULL);
                    729:            top = HTSaveLocally(request, NULL, NULL,
                    730:                                HTRequest_outputFormat(request),
                    731:                                HTRequest_outputStream(request));
                    732:        }
                    733:     }
1.88      frystyk   734:     return top;
                    735: }
                    736: 

Webmaster