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