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