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

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

Webmaster