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