Annotation of libwww/Library/src/HTFormat.c, revision 1.87
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.87 ! frystyk 6: ** @(#) $Id: Date Author State $
1.1 timbl 7: **
8: ** Bugs:
9: ** Assumes the incoming stream is ASCII, rather than a local file
10: ** format, and so ALWAYS converts from ASCII on non-ASCII machines.
11: ** Therefore, non-ASCII machines can't read local files.
1.2 timbl 12: **
1.45 duns 13: ** HISTORY:
1.86 frystyk 14: ** 8 Jul 94 FM Insulate free from _free structure element.
1.52 frystyk 15: ** 8 Nov 94 HFN Changed a lot to make reentrant
1.2 timbl 16: */
17:
1.58 frystyk 18: /* Library Include files */
1.85 frystyk 19: #include "sysdep.h"
1.87 ! frystyk 20: #include "WWWUtil.h"
! 21: #include "HTReqMan.h"
! 22: #include "HTNetMan.h"
! 23: #include "HTStream.h"
1.58 frystyk 24: #include "HTFWrite.h"
1.52 frystyk 25: #include "HTError.h"
26: #include "HTFormat.h" /* Implemented here */
1.2 timbl 27:
1.72 frystyk 28: #define NO_VALUE_FOUND -1e30 /* Stream Stack Value if none found */
1.63 frystyk 29:
1.87 ! frystyk 30: PRIVATE HTList * HTConversions = NULL; /* Content types */
! 31: PRIVATE HTList * HTEncodings = NULL; /* Content encoders */
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.87 ! frystyk 41: struct _HTContentCoding {
! 42: HTEncoding coding;
! 43: HTContentCoder * encoder;
! 44: HTContentCoder * decoder;
! 45: double quality;
! 46: };
! 47:
1.52 frystyk 48: /* ------------------------------------------------------------------------- */
1.87 ! frystyk 49: /* BASIC CONVERTERS */
! 50: /* ------------------------------------------------------------------------- */
! 51:
! 52: PUBLIC HTStream * HTBlackHoleConverter (HTRequest * request,
! 53: void * param,
! 54: HTFormat input_format,
! 55: HTFormat output_format,
! 56: HTStream * output_stream)
! 57: {
! 58: return HTBlackHole();
! 59: }
! 60: /* HTThroughLine
! 61: ** -------------
! 62: **
! 63: ** This function is a dummy function that returns the same output stream
! 64: ** as given as a parameter. Henrik 01/03-94
! 65: */
! 66: PUBLIC HTStream* HTThroughLine (HTRequest * request,
! 67: void * param,
! 68: HTFormat input_format,
! 69: HTFormat output_format,
! 70: HTStream * output_stream)
! 71: {
! 72: return output_stream;
! 73: }
! 74:
! 75: /* ------------------------------------------------------------------------- */
1.63 frystyk 76: /* ACCEPT LISTS OF CONVERSIONS, ENCODINGS, LANGUAGE, AND CHARSET */
1.61 frystyk 77: /* ------------------------------------------------------------------------- */
1.17 luotonen 78:
1.52 frystyk 79: /*
1.63 frystyk 80: ** For all `accept lists' there is a local list and a global list. The
81: ** local list is a part of the request structure and the global list is
82: ** internal to the HTFormat module. The global lists can be used when
83: ** specifying accept lists for ALL requests and the local list can be
84: ** used to add specific accept headers to the request.
85: */
86:
1.61 frystyk 87:
1.2 timbl 88: /* Define a presentation system command for a content-type
89: ** -------------------------------------------------------
1.52 frystyk 90: ** INPUT:
91: ** conversions: The list of conveters and presenters
92: ** representation: the MIME-style format name
93: ** command: the MAILCAP-style command template
94: ** quality: A degradation faction [0..1]
95: ** maxbytes: A limit on the length acceptable as input (0 infinite)
96: ** maxsecs: A limit on the time user will wait (0 for infinity)
1.2 timbl 97: */
1.72 frystyk 98: PUBLIC void HTPresentation_add (HTList * conversions,
1.85 frystyk 99: const char * representation,
100: const char * command,
101: const char * test_command,
1.72 frystyk 102: double quality,
103: double secs,
104: double secs_per_byte)
1.52 frystyk 105: {
1.83 frystyk 106: HTPresentation * pres;
107: if ((pres = (HTPresentation *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
108: HT_OUTOFMEM("HTSetPresentation");
1.2 timbl 109:
110: pres->rep = HTAtom_for(representation);
111: pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
112: pres->converter = HTSaveAndExecute; /* Fixed for now ... */
113: pres->quality = quality;
114: pres->secs = secs;
115: pres->secs_per_byte = secs_per_byte;
116: pres->rep = HTAtom_for(representation);
1.49 howcome 117: pres->command = NULL;
1.2 timbl 118: StrAllocCopy(pres->command, command);
1.49 howcome 119: pres->test_command = NULL;
120: StrAllocCopy(pres->test_command, test_command);
1.12 timbl 121: HTList_addObject(conversions, pres);
1.2 timbl 122: }
123:
1.73 frystyk 124: PUBLIC void HTPresentation_deleteAll (HTList * list)
125: {
126: if (list) {
127: HTList *cur = list;
128: HTPresentation *pres;
129: while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
1.83 frystyk 130: HT_FREE(pres->command);
131: HT_FREE(pres);
1.73 frystyk 132: }
133: HTList_delete(list);
134: }
135: }
1.2 timbl 136:
137: /* Define a built-in function for a content-type
138: ** ---------------------------------------------
139: */
1.72 frystyk 140: PUBLIC void HTConversion_add (HTList * conversions,
1.85 frystyk 141: const char * representation_in,
142: const char * representation_out,
1.72 frystyk 143: HTConverter * converter,
144: double quality,
145: double secs,
146: double secs_per_byte)
1.52 frystyk 147: {
1.83 frystyk 148: HTPresentation * pres;
1.87 ! frystyk 149: if ((pres = (HTPresentation*) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
1.83 frystyk 150: HT_OUTOFMEM("HTSetPresentation");
1.2 timbl 151: pres->rep = HTAtom_for(representation_in);
152: pres->rep_out = HTAtom_for(representation_out);
153: pres->converter = converter;
154: pres->command = NULL; /* Fixed */
1.49 howcome 155: pres->test_command = NULL;
1.2 timbl 156: pres->quality = quality;
157: pres->secs = secs;
158: pres->secs_per_byte = secs_per_byte;
1.12 timbl 159: HTList_addObject(conversions, pres);
1.56 frystyk 160: }
161:
1.73 frystyk 162: PUBLIC void HTConversion_deleteAll (HTList * list)
163: {
164: HTPresentation_deleteAll(list);
165: }
166:
1.87 ! frystyk 167: PUBLIC BOOL HTContentCoding_add (HTList * list,
! 168: const char * coding,
! 169: HTContentCoder * encoder,
! 170: HTContentCoder * decoder,
! 171: double quality)
1.73 frystyk 172: {
1.87 ! frystyk 173: if (list && coding && (encoder || decoder)) {
! 174: HTContentCoding * me;
! 175: if ((me=(HTContentCoding*)HT_CALLOC(1, sizeof(HTContentCoding)))==NULL)
! 176: HT_OUTOFMEM("HTContentCoding_add");
! 177: me->coding = HTAtom_for(coding);
! 178: me->encoder = encoder;
! 179: me->decoder = decoder;
! 180: me->quality = quality;
! 181: if (CORE_TRACE)
! 182: HTTrace("Codings..... Adding %s with quality %.2f\n",
! 183: coding, quality);
! 184: return HTList_addObject(list, (void *) me);
1.73 frystyk 185: }
1.87 ! frystyk 186: if (CORE_TRACE) HTTrace("Codings..... Bad argument\n");
! 187: return NO;
1.73 frystyk 188: }
189:
1.87 ! frystyk 190: PUBLIC void HTContentCoding_deleteAll (HTList * list)
1.73 frystyk 191: {
192: if (list) {
1.87 ! frystyk 193: HTList * cur = list;
! 194: HTContentCoding * pres;
! 195: while ((pres = (HTContentCoding *) HTList_nextObject(cur)))
1.83 frystyk 196: HT_FREE(pres);
1.73 frystyk 197: HTList_delete(list);
198: }
199: }
200:
1.87 ! frystyk 201: PUBLIC const char * HTContentCoding_name (HTContentCoding * me)
! 202: {
! 203: return me ? HTAtom_name(me->coding) : NULL;
! 204: }
! 205:
1.73 frystyk 206: PUBLIC void HTLanguage_add (HTList * list,
1.85 frystyk 207: const char * lang,
1.73 frystyk 208: double quality)
209: {
210: HTAcceptNode * node;
211: if (!list || !lang || !*lang) {
1.87 ! frystyk 212: if (CORE_TRACE)
1.84 eric 213: HTTrace("Languages... Bad argument\n");
1.73 frystyk 214: return;
215: }
1.83 frystyk 216: if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
217: HT_OUTOFMEM("HTAcceptLanguage");
1.73 frystyk 218:
219: HTList_addObject(list, (void*)node);
220: node->atom = HTAtom_for(lang);
221: node->quality = quality;
222: }
223:
224: PUBLIC void HTLanguage_deleteAll (HTList * list)
225: {
1.87 ! frystyk 226: if (list) {
! 227: HTList *cur = list;
! 228: HTAcceptNode *pres;
! 229: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
! 230: HT_FREE(pres);
! 231: }
! 232: HTList_delete(list);
! 233: }
1.73 frystyk 234: }
235:
236: PUBLIC void HTCharset_add (HTList * list,
1.85 frystyk 237: const char * charset,
1.73 frystyk 238: double quality)
239: {
240: HTAcceptNode * node;
241: if (!list || !charset || !*charset) {
1.87 ! frystyk 242: if (CORE_TRACE)
1.84 eric 243: HTTrace("Charset..... Bad argument\n");
1.73 frystyk 244: return;
245: }
1.83 frystyk 246: if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
247: HT_OUTOFMEM("HTAcceptCharsetuage");
1.73 frystyk 248:
249: HTList_addObject(list, (void*)node);
250: node->atom = HTAtom_for(charset);
251: node->quality = quality;
252: }
253:
254: PUBLIC void HTCharset_deleteAll (HTList * list)
255: {
1.87 ! frystyk 256: if (list) {
! 257: HTList *cur = list;
! 258: HTAcceptNode *pres;
! 259: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
! 260: HT_FREE(pres);
! 261: }
! 262: HTList_delete(list);
! 263: }
1.73 frystyk 264: }
265:
266: /* ------------------------------------------------------------------------- */
267: /* GLOBAL LIST OF CONVERTERS ETC. */
268: /* ------------------------------------------------------------------------- */
269:
1.72 frystyk 270: /*
271: ** Global Accept Format Types Conversions
272: ** list can be NULL
273: */
1.73 frystyk 274: PUBLIC void HTFormat_setConversion (HTList * list)
1.72 frystyk 275: {
276: HTConversions = list;
277: }
278:
279: PUBLIC HTList * HTFormat_conversion (void)
280: {
281: return HTConversions;
282: }
283:
284: /*
1.87 ! frystyk 285: ** Global Content Encodings
1.72 frystyk 286: ** list can be NULL
287: */
288: PUBLIC void HTFormat_setEncoding (HTList *list)
289: {
290: HTEncodings = list;
291: }
292:
293: PUBLIC HTList * HTFormat_encoding (void)
294: {
295: return HTEncodings;
296: }
297:
298: /*
299: ** Global Accept Languages
300: ** list can be NULL
301: */
302: PUBLIC void HTFormat_setLanguage (HTList *list)
303: {
304: HTLanguages = list;
305: }
306:
307: PUBLIC HTList * HTFormat_language (void)
308: {
309: return HTLanguages;
310: }
311:
312: /*
313: ** Global Accept Charsets
314: ** list can be NULL
315: */
316: PUBLIC void HTFormat_setCharset (HTList *list)
317: {
318: HTCharsets = list;
319: }
320:
321: PUBLIC HTList * HTFormat_charset (void)
322: {
323: return HTCharsets;
324: }
1.56 frystyk 325:
1.73 frystyk 326: /*
327: ** Convenience function to clean up
328: */
329: PUBLIC void HTFormat_deleteAll (void)
1.17 luotonen 330: {
1.73 frystyk 331: if (HTConversions) {
332: HTConversion_deleteAll(HTConversions);
333: HTConversions = NULL;
334: }
335: if (HTLanguages) {
336: HTLanguage_deleteAll(HTLanguages);
337: HTLanguages = NULL;
1.63 frystyk 338: }
1.73 frystyk 339: if (HTEncodings) {
1.87 ! frystyk 340: HTContentCoding_deleteAll(HTEncodings);
1.73 frystyk 341: HTEncodings = NULL;
1.63 frystyk 342: }
1.73 frystyk 343: if (HTCharsets) {
344: HTCharset_deleteAll(HTCharsets);
345: HTCharsets = NULL;
1.63 frystyk 346: }
1.17 luotonen 347: }
348:
1.63 frystyk 349: /* ------------------------------------------------------------------------- */
350: /* FORMAT NEGOTIATION */
351: /* ------------------------------------------------------------------------- */
352:
1.77 frystyk 353: PRIVATE BOOL better_match (HTFormat f, HTFormat g)
1.63 frystyk 354: {
1.85 frystyk 355: const char *p, *q;
1.63 frystyk 356:
357: if (f && g && (p = HTAtom_name(f)) && (q = HTAtom_name(g))) {
358: int i,j;
359: for(i=0 ; *p; p++) if (*p == '*') i++;
360: for(j=0 ; *q; q++) if (*q == '*') j++;
361: if (i < j) return YES;
362: }
363: return NO;
364: }
365:
366:
1.77 frystyk 367: PRIVATE BOOL wild_match (HTAtom * tmplate, HTAtom * actual)
1.17 luotonen 368: {
369: char *t, *a, *st, *sa;
370: BOOL match = NO;
371:
1.48 frystyk 372: if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22 luotonen 373: if (!strcmp(t, "*"))
374: return YES;
1.17 luotonen 375:
1.22 luotonen 376: if (strchr(t, '*') &&
377: (a = HTAtom_name(actual)) &&
378: (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17 luotonen 379:
1.22 luotonen 380: *sa = 0;
381: *st = 0;
382:
383: if ((*(st-1)=='*' &&
384: (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
385: (*(st+1)=='*' && !strcasecomp(t,a)))
386: match = YES;
387:
388: *sa = '/';
389: *st = '/';
390: }
391: }
1.23 luotonen 392: return match;
1.17 luotonen 393: }
394:
1.36 luotonen 395: /*
396: * Added by takada@seraph.ntt.jp (94/04/08)
397: */
1.77 frystyk 398: PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
1.36 luotonen 399: {
400: char *t, *a, *st, *sa;
401: BOOL match = NO;
402:
1.48 frystyk 403: if (tmplate && actual &&
404: (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36 luotonen 405: st = strchr(t, '_');
406: sa = strchr(a, '_');
407: if ((st != NULL) && (sa != NULL)) {
408: if (!strcasecomp(t, a))
409: match = YES;
410: else
411: match = NO;
412: }
413: else {
414: if (st != NULL) *st = 0;
415: if (sa != NULL) *sa = 0;
416: if (!strcasecomp(t, a))
417: match = YES;
418: else
419: match = NO;
420: if (st != NULL) *st = '_';
421: if (sa != NULL) *sa = '_';
422: }
423: }
424: return match;
425: }
426: /* end of addition */
427:
428:
1.17 luotonen 429:
1.77 frystyk 430: PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
1.17 luotonen 431: {
432: HTList * cur = accepted;
433: HTPresentation * pres;
434: HTPresentation * wild = NULL;
435:
436: if (!content_type || !accepted) return -1;
437:
438: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
439: if (pres->rep == content_type)
440: return pres->quality;
441: else if (wild_match(pres->rep, content_type))
442: wild = pres;
443: }
444: if (wild) return wild->quality;
445: else return -1;
446: }
447:
448:
1.77 frystyk 449: PRIVATE double lang_value (HTAtom * language, HTList * accepted)
1.17 luotonen 450: {
451: HTList * cur = accepted;
452: HTAcceptNode * node;
453: HTAcceptNode * wild = NULL;
454:
455: if (!language || !accepted || HTList_isEmpty(accepted)) {
456: return 0.1;
457: }
458:
459: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
460: if (node->atom == language) {
461: return node->quality;
462: }
1.36 luotonen 463: /*
464: * patch by takada@seraph.ntt.jp (94/04/08)
465: * the original line was
466: * else if (wild_match(node->atom, language)) {
467: * and the new line is
468: */
469: else if (lang_match(node->atom, language)) {
1.17 luotonen 470: wild = node;
471: }
472: }
473:
474: if (wild) {
475: return wild->quality;
476: }
477: else {
478: return 0.1;
479: }
480: }
481:
482:
1.77 frystyk 483: PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
1.17 luotonen 484: {
485: HTList * cur = accepted;
486: HTAcceptNode * node;
487: HTAcceptNode * wild = NULL;
488: char * e;
489:
490: if (!encoding || !accepted || HTList_isEmpty(accepted))
491: return 1;
492:
493: e = HTAtom_name(encoding);
494: if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
495: return 1;
496:
497: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
498: if (node->atom == encoding)
499: return node->quality;
500: else if (wild_match(node->atom, encoding))
501: wild = node;
502: }
503: if (wild) return wild->quality;
504: else return 1;
505: }
506:
507:
1.77 frystyk 508: PUBLIC BOOL HTRank (HTList * possibilities,
509: HTList * accepted_content_types,
510: HTList * accepted_languages,
511: HTList * accepted_encodings)
1.17 luotonen 512: {
513: int accepted_cnt = 0;
514: HTList * accepted;
515: HTList * sorted;
516: HTList * cur;
517: HTContentDescription * d;
518:
519: if (!possibilities) return NO;
520:
521: accepted = HTList_new();
522: cur = possibilities;
523: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
1.59 frystyk 524: double tv = type_value(d->content_type, accepted_content_types);
525: double lv = lang_value(d->content_language, accepted_languages);
526: double ev = encoding_value(d->content_encoding, accepted_encodings);
1.17 luotonen 527:
528: if (tv > 0) {
529: d->quality *= tv * lv * ev;
530: HTList_addObject(accepted, d);
531: accepted_cnt++;
532: }
1.18 luotonen 533: else {
1.86 frystyk 534: HT_FREE(d->filename);
1.83 frystyk 535: HT_FREE(d);
1.18 luotonen 536: }
1.17 luotonen 537: }
538:
1.87 ! frystyk 539: if (CORE_TRACE) HTTrace("Ranking.....\n");
! 540: if (CORE_TRACE) HTTrace(
1.18 luotonen 541: "\nRANK QUALITY CONTENT-TYPE LANGUAGE ENCODING FILE\n");
1.17 luotonen 542:
543: sorted = HTList_new();
544: while (accepted_cnt-- > 0) {
545: HTContentDescription * worst = NULL;
546: cur = accepted;
547: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
548: if (!worst || d->quality < worst->quality)
549: worst = d;
550: }
551: if (worst) {
1.87 ! frystyk 552: if (CORE_TRACE)
1.84 eric 553: HTTrace("%d. %.4f %-20.20s %-8.8s %-10.10s %s\n",
1.58 frystyk 554: accepted_cnt+1,
555: worst->quality,
556: (worst->content_type
1.17 luotonen 557: ? HTAtom_name(worst->content_type) : "-"),
1.58 frystyk 558: (worst->content_language
1.17 luotonen 559: ? HTAtom_name(worst->content_language) :"-"),
1.58 frystyk 560: (worst->content_encoding
1.17 luotonen 561: ? HTAtom_name(worst->content_encoding) :"-"),
1.58 frystyk 562: (worst->filename
1.17 luotonen 563: ? worst->filename :"-"));
564: HTList_removeObject(accepted, (void*)worst);
565: HTList_addObject(sorted, (void*)worst);
566: }
567: }
1.87 ! frystyk 568: if (CORE_TRACE) HTTrace("\n");
1.17 luotonen 569: HTList_delete(accepted);
570: HTList_delete(possibilities->next);
571: possibilities->next = sorted->next;
572: sorted->next = NULL;
573: HTList_delete(sorted);
574:
575: if (!HTList_isEmpty(possibilities)) return YES;
576: else return NO;
577: }
578:
579:
1.87 ! frystyk 580: /* Create a Content Type filter stack
! 581: ** ----------------------------------
1.7 secret 582: ** If a wildcard match is made, a temporary HTPresentation
1.2 timbl 583: ** structure is made to hold the destination format while the
584: ** new stack is generated. This is just to pass the out format to
585: ** MIME so far. Storing the format of a stream in the stream might
586: ** be a lot neater.
1.10 timbl 587: **
1.29 frystyk 588: ** The star/star format is special, in that if you can take
1.40 frystyk 589: ** that you can take anything.
1.2 timbl 590: */
1.77 frystyk 591: PUBLIC HTStream * HTStreamStack (HTFormat rep_in,
592: HTFormat rep_out,
593: HTStream * output_stream,
594: HTRequest * request,
595: BOOL guess)
1.2 timbl 596: {
1.14 timbl 597: HTList * conversion[2];
598: int which_list;
1.59 frystyk 599: double best_quality = -1e30; /* Pretty bad! */
1.65 frystyk 600: HTPresentation *pres, *best_match=NULL;
1.80 frystyk 601: if (rep_out == WWW_RAW) {
1.87 ! frystyk 602: if (CORE_TRACE) HTTrace("StreamStack. Raw output...\n");
1.81 frystyk 603: return output_stream ? output_stream : HTErrorStream();
1.34 luotonen 604: }
1.79 frystyk 605:
1.80 frystyk 606: if (rep_out == rep_in) {
1.87 ! frystyk 607: if (CORE_TRACE)
1.84 eric 608: HTTrace("StreamStack. Identical input/output format (%s)\n",
1.80 frystyk 609: HTAtom_name(rep_out));
1.81 frystyk 610: return output_stream ? output_stream : HTErrorStream();
1.74 frystyk 611: }
1.87 ! frystyk 612: if (CORE_TRACE) {
1.82 frystyk 613: char *p = HTAtom_name(rep_in);
614: char *q = HTAtom_name(rep_out);
1.84 eric 615: HTTrace("StreamStack. Constructing stream stack for %s to %s\n",
1.82 frystyk 616: p ? p : "<NULL>", q ? q : "<NULL>");
1.47 frystyk 617: }
1.2 timbl 618:
1.14 timbl 619: conversion[0] = request->conversions;
620: conversion[1] = HTConversions;
1.17 luotonen 621:
1.15 luotonen 622: for(which_list = 0; which_list<2; which_list++) {
623: HTList * cur = conversion[which_list];
624: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.65 frystyk 625: if ((pres->rep==rep_in || wild_match(pres->rep, rep_in)) &&
626: (pres->rep_out==rep_out || wild_match(pres->rep_out,rep_out))){
627: if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33 luotonen 628: (!better_match(best_match->rep, pres->rep) &&
629: pres->quality > best_quality)) {
1.85 frystyk 630: #ifdef HAVE_SYSTEM
1.65 frystyk 631: int result=0;
632: if (pres->test_command) {
633: result = system(pres->test_command);
1.87 ! frystyk 634: if (CORE_TRACE)
1.84 eric 635: HTTrace("StreamStack. system(%s) returns %d\n", pres->test_command, result);
1.65 frystyk 636: }
637: if (!result) {
1.49 howcome 638: best_match = pres;
639: best_quality = pres->quality;
640: }
1.65 frystyk 641: #else
642: best_match = pres;
643: best_quality = pres->quality;
1.85 frystyk 644: #endif /* HAVE_SYSTEM */
1.10 timbl 645: }
646: }
1.2 timbl 647: }
648: }
1.80 frystyk 649:
650: if (best_match) {
651: if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
1.87 ! frystyk 652: if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81 frystyk 653: return output_stream ? output_stream : HTErrorStream();
1.80 frystyk 654: }
1.65 frystyk 655: return (*best_match->converter)(request, best_match->command,
656: rep_in, rep_out, output_stream);
1.80 frystyk 657: }
658: if (rep_out == WWW_SOURCE) {
1.87 ! frystyk 659: if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81 frystyk 660: return output_stream ? output_stream : HTErrorStream();
1.80 frystyk 661: }
662:
1.87 ! frystyk 663: if (CORE_TRACE)
1.84 eric 664: HTTrace("StreamStack. No match found, dumping to local file\n");
1.65 frystyk 665: return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2 timbl 666: }
667:
668:
669: /* Find the cost of a filter stack
670: ** -------------------------------
671: **
672: ** Must return the cost of the same stack which StreamStack would set up.
673: **
674: ** On entry,
675: ** length The size of the data to be converted
676: */
1.77 frystyk 677: PUBLIC double HTStackValue (HTList * theseConversions,
678: HTFormat rep_in,
679: HTFormat rep_out,
680: double initial_value,
681: long int length)
1.2 timbl 682: {
1.14 timbl 683: int which_list;
684: HTList* conversion[2];
685:
1.87 ! frystyk 686: if (CORE_TRACE) {
1.84 eric 687: HTTrace("StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.65 frystyk 688: HTAtom_name(rep_in), initial_value,
689: HTAtom_name(rep_out));
690: }
1.2 timbl 691: if (rep_out == WWW_SOURCE ||
1.10 timbl 692: rep_out == rep_in) return 0.0;
1.2 timbl 693:
1.14 timbl 694: conversion[0] = theseConversions;
695: conversion[1] = HTConversions;
696:
697: for(which_list = 0; which_list<2; which_list++)
698: if (conversion[which_list]) {
1.15 luotonen 699: HTList * cur = conversion[which_list];
1.2 timbl 700: HTPresentation * pres;
1.15 luotonen 701: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
702: if (pres->rep == rep_in &&
1.17 luotonen 703: (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.59 frystyk 704: double value = initial_value * pres->quality;
1.2 timbl 705: if (HTMaxSecs != 0.0)
1.15 luotonen 706: value = value - (length*pres->secs_per_byte + pres->secs)
1.2 timbl 707: /HTMaxSecs;
708: return value;
709: }
710: }
711: }
1.63 frystyk 712: return NO_VALUE_FOUND; /* Really bad */
1.1 timbl 713: }
1.2 timbl 714:
1.87 ! frystyk 715: /* Create a new coder and insert it into stream chain
! 716: ** --------------------------------------------------
! 717: ** Creating the content decoding stack is not based on quality factors as
! 718: ** we don't have the freedom as with content types. Specify whether you
! 719: ** you want encoding or decoding using the BOOL "encoding" flag.
! 720: */
! 721: PUBLIC HTStream * HTCodingStack (HTEncoding coding,
! 722: HTStream * target,
! 723: HTRequest * request,
! 724: void * param,
! 725: BOOL encoding)
! 726: {
! 727: HTList * coders[2];
! 728: HTStream * top = target;
! 729: HTContentCoding * pres = NULL;
! 730: int cnt;
! 731: if (!coding || !request) {
! 732: if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
! 733: return target ? target : HTErrorStream();
! 734: }
! 735: coders[0] = request->encodings;
! 736: coders[1] = HTEncodings;
! 737: if (CORE_TRACE)
! 738: HTTrace("Codings..... Looking for %s\n", HTAtom_name(coding));
! 739: for (cnt=0; cnt < 2; cnt++) {
! 740: HTList * cur = coders[cnt];
! 741: while ((pres = (HTContentCoding *) HTList_nextObject(cur))) {
! 742: if (pres->coding == coding) {
! 743: if (CORE_TRACE) HTTrace("Codings..... Found...\n");
! 744: if (encoding) {
! 745: if (pres->encoder)
! 746: top = (*pres->encoder)(request, param, coding, top);
! 747: break;
! 748: } else if (pres->decoder) {
! 749: top = (*pres->decoder)(request, param, coding, top);
! 750: break;
! 751: }
! 752: }
! 753: }
! 754: }
! 755: return top;
! 756: }
1.10 timbl 757:
1.87 ! frystyk 758: /*
! 759: ** Here you can provide a complete list instead of a single token.
! 760: ** The list has to filled up in the order the _encodings_ are to be applied
! 761: */
! 762: PUBLIC HTStream * HTEncodingStack (HTList * encodings,
! 763: HTStream * target,
! 764: HTRequest * request,
! 765: void * param)
! 766: {
! 767: if (encodings) {
! 768: HTList * cur = encodings;
! 769: HTEncoding pres;
! 770: HTStream * top = target;
! 771: while ((pres = (HTEncoding) HTList_nextObject(cur)))
! 772: top = HTCodingStack(pres, top, request, param, YES);
! 773: return top;
! 774: }
! 775: return HTErrorStream();
! 776: }
! 777:
! 778: /*
! 779: ** Here you can provide a complete list instead of a single token.
! 780: ** The list has to be in the order the _encodings_ were applied - that
! 781: ** is, the same way that _encodings_ are to be applied. This is all consistent
! 782: ** with the order of the Content-Encoding header.
! 783: */
! 784: PUBLIC HTStream * HTDecodingStack (HTList * encodings,
! 785: HTStream * target,
! 786: HTRequest * request,
! 787: void * param)
! 788: {
! 789: if (encodings) {
! 790: HTEncoding pres;
! 791: int cnt = HTList_count(encodings);
! 792: HTStream * top = target;
! 793: while (cnt > 0) {
! 794: pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
! 795: top = HTCodingStack(pres, top, request, param, NO);
! 796: }
! 797: return top;
! 798: }
! 799: return HTErrorStream();
! 800: }
Webmaster