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