Annotation of libwww/Library/src/HTFormat.c, revision 1.72
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.1 timbl 6: **
7: ** Bugs:
8: ** Assumes the incoming stream is ASCII, rather than a local file
9: ** format, and so ALWAYS converts from ASCII on non-ASCII machines.
10: ** Therefore, non-ASCII machines can't read local files.
1.2 timbl 11: **
1.45 duns 12: ** HISTORY:
1.52 frystyk 13: ** 8 Jul 94 FM Insulate free() from _free structure element.
14: ** 8 Nov 94 HFN Changed a lot to make reentrant
1.2 timbl 15: */
16:
1.58 frystyk 17: /* Library Include files */
18: #include "tcp.h"
1.52 frystyk 19: #include "HTUtils.h"
1.58 frystyk 20: #include "HTString.h"
1.52 frystyk 21: #include "HTTCP.h"
1.58 frystyk 22: #include "HTFWrite.h"
1.52 frystyk 23: #include "HTGuess.h"
1.68 frystyk 24: #include "HTNetMan.h"
1.52 frystyk 25: #include "HTError.h"
1.67 frystyk 26: #include "HTReqMan.h"
1.52 frystyk 27: #include "HTFormat.h" /* Implemented here */
1.2 timbl 28:
1.72 ! frystyk 29: #define NO_VALUE_FOUND -1e30 /* Stream Stack Value if none found */
1.63 frystyk 30:
1.72 ! frystyk 31: PRIVATE HTList * HTConversions = NULL;
! 32: PRIVATE HTList * HTCharsets = NULL;
! 33: PRIVATE HTList * HTEncodings = NULL;
! 34: PRIVATE HTList * HTLanguages = NULL;
1.63 frystyk 35:
36: PRIVATE double HTMaxSecs = 1e10; /* No effective limit */
1.17 luotonen 37:
1.60 frystyk 38: struct _HTStream {
39: CONST HTStreamClass * isa;
40: };
41:
1.52 frystyk 42: /* ------------------------------------------------------------------------- */
1.63 frystyk 43: /* ACCEPT LISTS OF CONVERSIONS, ENCODINGS, LANGUAGE, AND CHARSET */
1.61 frystyk 44: /* ------------------------------------------------------------------------- */
1.17 luotonen 45:
1.52 frystyk 46: /*
1.63 frystyk 47: ** For all `accept lists' there is a local list and a global list. The
48: ** local list is a part of the request structure and the global list is
49: ** internal to the HTFormat module. The global lists can be used when
50: ** specifying accept lists for ALL requests and the local list can be
51: ** used to add specific accept headers to the request.
52: */
53:
54: /*
55: ** Cleanup memory after the LOCAL list of converters, language,
56: ** charset, and encoding in the HTRequest structure. Note that
57: ** all these also have a global representation.
1.2 timbl 58: */
1.52 frystyk 59: PUBLIC void HTFormatDelete ARGS1(HTRequest *, request)
1.31 frystyk 60: {
1.63 frystyk 61: if (!request)
62: return;
63:
64: /* List of converters and presenters */
65: if (request->conversions) {
1.56 frystyk 66: HTList *cur = request->conversions;
67: HTPresentation *pres;
68: while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
69: FREE(pres->command); /* Leak fixed AL 6 Feb 1994 */
70: free(pres);
71: }
72: HTList_delete(request->conversions);
73: request->conversions = NULL;
1.31 frystyk 74: }
1.63 frystyk 75:
76: /* List of encoders (or decoders) */
77: if (request->encodings) {
78: HTList *cur = request->encodings;
79: HTAcceptNode *pres;
80: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
81: free(pres);
82: }
83: HTList_delete(request->encodings);
84: request->encodings = NULL;
85: }
86:
87: /* List of natural languages */
88: if (request->languages) {
89: HTList *cur = request->languages;
90: HTAcceptNode *pres;
91: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
92: free(pres);
93: }
94: HTList_delete(request->languages);
95: request->languages = NULL;
96: }
97:
98: /* List of charsets */
99: if (request->charsets) {
100: HTList *cur = request->charsets;
101: HTAcceptNode *pres;
102: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
103: free(pres);
104: }
105: HTList_delete(request->charsets);
106: request->charsets = NULL;
107: }
1.31 frystyk 108: }
109:
1.2 timbl 110:
1.61 frystyk 111: /*
1.63 frystyk 112: ** Cleanup memory after the GLOBAL list of converters, encodings,
113: ** languages, charsets etc. Note that there
1.61 frystyk 114: ** is also a LOCAL conversion list associated with each HTRequest
115: ** structure. Written by Eric Sink, eric@spyglass.com
116: */
117: PUBLIC void HTDisposeConversions NOARGS
118: {
1.63 frystyk 119: /* List of converters/preenters */
1.61 frystyk 120: if (HTConversions) {
121: HTList *cur = HTConversions;
122: HTPresentation *pres;
123: while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
124: FREE(pres->command);
125: free(pres);
126: }
127: HTList_delete(HTConversions);
128: HTConversions = NULL;
129: }
1.63 frystyk 130:
131: /* List of encoders */
132: if (HTEncodings) {
133: HTList *cur = HTEncodings;
134: HTAcceptNode *pres;
135: while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
136: free(pres);
137: }
138: HTList_delete(HTEncodings);
139: HTEncodings = NULL;
140: }
141:
142: /* List of Languages */
143: if (HTLanguages) {
144: HTList *cur = HTLanguages;
145: HTAcceptNode *pres;
146: while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
147: free(pres);
148: }
149: HTList_delete(HTLanguages);
150: HTLanguages = NULL;
151: }
152:
153: /* List of Charsets */
154: if (HTCharsets) {
155: HTList *cur = HTCharsets;
156: HTAcceptNode *pres;
157: while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
158: free(pres);
159: }
160: HTList_delete(HTCharsets);
161: HTCharsets = NULL;
162: }
1.61 frystyk 163: }
164:
165:
1.2 timbl 166: /* Define a presentation system command for a content-type
167: ** -------------------------------------------------------
1.52 frystyk 168: ** INPUT:
169: ** conversions: The list of conveters and presenters
170: ** representation: the MIME-style format name
171: ** command: the MAILCAP-style command template
172: ** quality: A degradation faction [0..1]
173: ** maxbytes: A limit on the length acceptable as input (0 infinite)
174: ** maxsecs: A limit on the time user will wait (0 for infinity)
1.2 timbl 175: */
1.72 ! frystyk 176: PUBLIC void HTPresentation_add (HTList * conversions,
! 177: CONST char * representation,
! 178: CONST char * command,
! 179: CONST char * test_command,
! 180: double quality,
! 181: double secs,
! 182: double secs_per_byte)
1.52 frystyk 183: {
1.63 frystyk 184: HTPresentation * pres = (HTPresentation *)calloc(1,sizeof(HTPresentation));
1.2 timbl 185: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
186:
187: pres->rep = HTAtom_for(representation);
188: pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
189: pres->converter = HTSaveAndExecute; /* Fixed for now ... */
190: pres->quality = quality;
191: pres->secs = secs;
192: pres->secs_per_byte = secs_per_byte;
193: pres->rep = HTAtom_for(representation);
1.49 howcome 194: pres->command = NULL;
1.2 timbl 195: StrAllocCopy(pres->command, command);
1.49 howcome 196: pres->test_command = NULL;
197: StrAllocCopy(pres->test_command, test_command);
1.12 timbl 198: HTList_addObject(conversions, pres);
1.2 timbl 199: }
200:
201:
202: /* Define a built-in function for a content-type
203: ** ---------------------------------------------
204: */
1.72 ! frystyk 205: PUBLIC void HTConversion_add (HTList * conversions,
! 206: CONST char * representation_in,
! 207: CONST char * representation_out,
! 208: HTConverter * converter,
! 209: double quality,
! 210: double secs,
! 211: double secs_per_byte)
1.52 frystyk 212: {
1.63 frystyk 213: HTPresentation * pres = (HTPresentation *)calloc(1,sizeof(HTPresentation));
1.2 timbl 214: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
215:
216: pres->rep = HTAtom_for(representation_in);
217: pres->rep_out = HTAtom_for(representation_out);
218: pres->converter = converter;
219: pres->command = NULL; /* Fixed */
1.49 howcome 220: pres->test_command = NULL;
1.2 timbl 221: pres->quality = quality;
222: pres->secs = secs;
223: pres->secs_per_byte = secs_per_byte;
1.12 timbl 224: HTList_addObject(conversions, pres);
1.56 frystyk 225: }
226:
1.72 ! frystyk 227: /*
! 228: ** Global Accept Format Types Conversions
! 229: ** list can be NULL
! 230: */
! 231: PUBLIC void HTFormat_setConversion (HTList *list)
! 232: {
! 233: HTConversions = list;
! 234: }
! 235:
! 236: PUBLIC HTList * HTFormat_conversion (void)
! 237: {
! 238: return HTConversions;
! 239: }
! 240:
! 241: /*
! 242: ** Global Accept Encodings
! 243: ** list can be NULL
! 244: */
! 245: PUBLIC void HTFormat_setEncoding (HTList *list)
! 246: {
! 247: HTEncodings = list;
! 248: }
! 249:
! 250: PUBLIC HTList * HTFormat_encoding (void)
! 251: {
! 252: return HTEncodings;
! 253: }
! 254:
! 255: /*
! 256: ** Global Accept Languages
! 257: ** list can be NULL
! 258: */
! 259: PUBLIC void HTFormat_setLanguage (HTList *list)
! 260: {
! 261: HTLanguages = list;
! 262: }
! 263:
! 264: PUBLIC HTList * HTFormat_language (void)
! 265: {
! 266: return HTLanguages;
! 267: }
! 268:
! 269: /*
! 270: ** Global Accept Charsets
! 271: ** list can be NULL
! 272: */
! 273: PUBLIC void HTFormat_setCharset (HTList *list)
! 274: {
! 275: HTCharsets = list;
! 276: }
! 277:
! 278: PUBLIC HTList * HTFormat_charset (void)
! 279: {
! 280: return HTCharsets;
! 281: }
1.56 frystyk 282:
1.17 luotonen 283: PUBLIC void HTAcceptEncoding ARGS3(HTList *, list,
1.63 frystyk 284: CONST char *,enc,
1.59 frystyk 285: double, quality)
1.17 luotonen 286: {
287: HTAcceptNode * node;
1.63 frystyk 288: if (!list || !enc || !*enc) {
1.71 frystyk 289: if (WWWTRACE)
1.63 frystyk 290: fprintf(TDEST, "Encodings... Bad argument\n");
291: return;
292: }
1.17 luotonen 293: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
294: if (!node) outofmem(__FILE__, "HTAcceptEncoding");
295: HTList_addObject(list, (void*)node);
296:
297: node->atom = HTAtom_for(enc);
298: node->quality = quality;
299: }
300:
301:
302: PUBLIC void HTAcceptLanguage ARGS3(HTList *, list,
1.63 frystyk 303: CONST char *,lang,
1.59 frystyk 304: double, quality)
1.17 luotonen 305: {
306: HTAcceptNode * node;
1.63 frystyk 307: if (!list || !lang || !*lang) {
1.71 frystyk 308: if (WWWTRACE)
1.63 frystyk 309: fprintf(TDEST, "Languages... Bad argument\n");
310: return;
311: }
312: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
313: if (!node) outofmem(__FILE__, "HTAcceptLanguage");
314:
315: HTList_addObject(list, (void*)node);
316: node->atom = HTAtom_for(lang);
317: node->quality = quality;
318: }
1.17 luotonen 319:
320:
1.63 frystyk 321: PUBLIC void HTAcceptCharset ARGS3(HTList *, list,
322: CONST char *, charset,
323: double, quality)
324: {
325: HTAcceptNode * node;
326: if (!list || !charset || !*charset) {
1.71 frystyk 327: if (WWWTRACE)
1.63 frystyk 328: fprintf(TDEST, "Charset..... Bad argument\n");
329: return;
330: }
1.17 luotonen 331: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
1.63 frystyk 332: if (!node) outofmem(__FILE__, "HTAcceptCharsetuage");
1.17 luotonen 333:
334: HTList_addObject(list, (void*)node);
1.63 frystyk 335: node->atom = HTAtom_for(charset);
1.17 luotonen 336: node->quality = quality;
337: }
338:
339:
1.63 frystyk 340: /* ------------------------------------------------------------------------- */
341: /* FORMAT NEGOTIATION */
342: /* ------------------------------------------------------------------------- */
343:
344: PRIVATE BOOL better_match ARGS2(HTFormat, f,
345: HTFormat, g)
346: {
347: CONST char *p, *q;
348:
349: if (f && g && (p = HTAtom_name(f)) && (q = HTAtom_name(g))) {
350: int i,j;
351: for(i=0 ; *p; p++) if (*p == '*') i++;
352: for(j=0 ; *q; q++) if (*q == '*') j++;
353: if (i < j) return YES;
354: }
355: return NO;
356: }
357:
358:
1.48 frystyk 359: PRIVATE BOOL wild_match ARGS2(HTAtom *, tmplate,
1.17 luotonen 360: HTAtom *, actual)
361: {
362: char *t, *a, *st, *sa;
363: BOOL match = NO;
364:
1.48 frystyk 365: if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22 luotonen 366: if (!strcmp(t, "*"))
367: return YES;
1.17 luotonen 368:
1.22 luotonen 369: if (strchr(t, '*') &&
370: (a = HTAtom_name(actual)) &&
371: (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17 luotonen 372:
1.22 luotonen 373: *sa = 0;
374: *st = 0;
375:
376: if ((*(st-1)=='*' &&
377: (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
378: (*(st+1)=='*' && !strcasecomp(t,a)))
379: match = YES;
380:
381: *sa = '/';
382: *st = '/';
383: }
384: }
1.23 luotonen 385: return match;
1.17 luotonen 386: }
387:
1.36 luotonen 388: /*
389: * Added by takada@seraph.ntt.jp (94/04/08)
390: */
1.48 frystyk 391: PRIVATE BOOL lang_match ARGS2(HTAtom *, tmplate,
1.36 luotonen 392: HTAtom *, actual)
393: {
394: char *t, *a, *st, *sa;
395: BOOL match = NO;
396:
1.48 frystyk 397: if (tmplate && actual &&
398: (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36 luotonen 399: st = strchr(t, '_');
400: sa = strchr(a, '_');
401: if ((st != NULL) && (sa != NULL)) {
402: if (!strcasecomp(t, a))
403: match = YES;
404: else
405: match = NO;
406: }
407: else {
408: if (st != NULL) *st = 0;
409: if (sa != NULL) *sa = 0;
410: if (!strcasecomp(t, a))
411: match = YES;
412: else
413: match = NO;
414: if (st != NULL) *st = '_';
415: if (sa != NULL) *sa = '_';
416: }
417: }
418: return match;
419: }
420: /* end of addition */
421:
422:
1.17 luotonen 423:
1.59 frystyk 424: PRIVATE double type_value ARGS2(HTAtom *, content_type,
1.17 luotonen 425: HTList *, accepted)
426: {
427: HTList * cur = accepted;
428: HTPresentation * pres;
429: HTPresentation * wild = NULL;
430:
431: if (!content_type || !accepted) return -1;
432:
433: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
434: if (pres->rep == content_type)
435: return pres->quality;
436: else if (wild_match(pres->rep, content_type))
437: wild = pres;
438: }
439: if (wild) return wild->quality;
440: else return -1;
441: }
442:
443:
1.59 frystyk 444: PRIVATE double lang_value ARGS2(HTAtom *, language,
1.17 luotonen 445: HTList *, accepted)
446: {
447: HTList * cur = accepted;
448: HTAcceptNode * node;
449: HTAcceptNode * wild = NULL;
450:
451: if (!language || !accepted || HTList_isEmpty(accepted)) {
452: return 0.1;
453: }
454:
455: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
456: if (node->atom == language) {
457: return node->quality;
458: }
1.36 luotonen 459: /*
460: * patch by takada@seraph.ntt.jp (94/04/08)
461: * the original line was
462: * else if (wild_match(node->atom, language)) {
463: * and the new line is
464: */
465: else if (lang_match(node->atom, language)) {
1.17 luotonen 466: wild = node;
467: }
468: }
469:
470: if (wild) {
471: return wild->quality;
472: }
473: else {
474: return 0.1;
475: }
476: }
477:
478:
1.59 frystyk 479: PRIVATE double encoding_value ARGS2(HTAtom *, encoding,
1.17 luotonen 480: HTList *, accepted)
481: {
482: HTList * cur = accepted;
483: HTAcceptNode * node;
484: HTAcceptNode * wild = NULL;
485: char * e;
486:
487: if (!encoding || !accepted || HTList_isEmpty(accepted))
488: return 1;
489:
490: e = HTAtom_name(encoding);
491: if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
492: return 1;
493:
494: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
495: if (node->atom == encoding)
496: return node->quality;
497: else if (wild_match(node->atom, encoding))
498: wild = node;
499: }
500: if (wild) return wild->quality;
501: else return 1;
502: }
503:
504:
505: PUBLIC BOOL HTRank ARGS4(HTList *, possibilities,
506: HTList *, accepted_content_types,
507: HTList *, accepted_languages,
508: HTList *, accepted_encodings)
509: {
510: int accepted_cnt = 0;
511: HTList * accepted;
512: HTList * sorted;
513: HTList * cur;
514: HTContentDescription * d;
515:
516: if (!possibilities) return NO;
517:
518: accepted = HTList_new();
519: cur = possibilities;
520: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
1.59 frystyk 521: double tv = type_value(d->content_type, accepted_content_types);
522: double lv = lang_value(d->content_language, accepted_languages);
523: double ev = encoding_value(d->content_encoding, accepted_encodings);
1.17 luotonen 524:
525: if (tv > 0) {
526: d->quality *= tv * lv * ev;
527: HTList_addObject(accepted, d);
528: accepted_cnt++;
529: }
1.18 luotonen 530: else {
531: if (d->filename) free(d->filename);
532: free(d);
533: }
1.17 luotonen 534: }
535:
1.58 frystyk 536: if (PROT_TRACE) fprintf(TDEST, "Ranking.....\n");
537: if (PROT_TRACE) fprintf(TDEST,
1.18 luotonen 538: "\nRANK QUALITY CONTENT-TYPE LANGUAGE ENCODING FILE\n");
1.17 luotonen 539:
540: sorted = HTList_new();
541: while (accepted_cnt-- > 0) {
542: HTContentDescription * worst = NULL;
543: cur = accepted;
544: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
545: if (!worst || d->quality < worst->quality)
546: worst = d;
547: }
548: if (worst) {
1.58 frystyk 549: if (PROT_TRACE)
550: fprintf(TDEST, "%d. %.4f %-20.20s %-8.8s %-10.10s %s\n",
551: accepted_cnt+1,
552: worst->quality,
553: (worst->content_type
1.17 luotonen 554: ? HTAtom_name(worst->content_type) : "-"),
1.58 frystyk 555: (worst->content_language
1.17 luotonen 556: ? HTAtom_name(worst->content_language) :"-"),
1.58 frystyk 557: (worst->content_encoding
1.17 luotonen 558: ? HTAtom_name(worst->content_encoding) :"-"),
1.58 frystyk 559: (worst->filename
1.17 luotonen 560: ? worst->filename :"-"));
561: HTList_removeObject(accepted, (void*)worst);
562: HTList_addObject(sorted, (void*)worst);
563: }
564: }
1.58 frystyk 565: if (PROT_TRACE) fprintf(TDEST, "\n");
1.17 luotonen 566: HTList_delete(accepted);
567: HTList_delete(possibilities->next);
568: possibilities->next = sorted->next;
569: sorted->next = NULL;
570: HTList_delete(sorted);
571:
572: if (!HTList_isEmpty(possibilities)) return YES;
573: else return NO;
574: }
575:
576:
1.2 timbl 577: /* Create a filter stack
578: ** ---------------------
579: **
1.7 secret 580: ** If a wildcard match is made, a temporary HTPresentation
1.2 timbl 581: ** structure is made to hold the destination format while the
582: ** new stack is generated. This is just to pass the out format to
583: ** MIME so far. Storing the format of a stream in the stream might
584: ** be a lot neater.
1.10 timbl 585: **
1.29 frystyk 586: ** The star/star format is special, in that if you can take
1.40 frystyk 587: ** that you can take anything.
1.2 timbl 588: */
1.52 frystyk 589: PUBLIC HTStream * HTStreamStack ARGS5(HTFormat, rep_in,
590: HTFormat, rep_out,
591: HTStream *, output_stream,
1.34 luotonen 592: HTRequest *, request,
593: BOOL, guess)
1.2 timbl 594: {
1.14 timbl 595: HTList * conversion[2];
596: int which_list;
1.59 frystyk 597: double best_quality = -1e30; /* Pretty bad! */
1.65 frystyk 598: HTPresentation *pres, *best_match=NULL;
1.14 timbl 599:
1.65 frystyk 600: if (STREAM_TRACE) {
601: fprintf(TDEST, "StreamStack. Constructing stream stack for %s to %s\n",
602: HTAtom_name(rep_in), HTAtom_name(rep_out));
603: }
1.34 luotonen 604: if (guess && rep_in == WWW_UNKNOWN) {
1.58 frystyk 605: if (PROT_TRACE) fprintf(TDEST, "Returning... guessing stream\n");
1.52 frystyk 606: return HTGuess_new(request, NULL, rep_in, rep_out, output_stream);
1.34 luotonen 607: }
608:
1.47 frystyk 609: if (rep_out == WWW_SOURCE || rep_out == rep_in) {
1.69 frystyk 610: return output_stream ? output_stream : HTBlackHole();
1.47 frystyk 611: }
1.2 timbl 612:
1.14 timbl 613: conversion[0] = request->conversions;
614: conversion[1] = HTConversions;
1.17 luotonen 615:
1.15 luotonen 616: for(which_list = 0; which_list<2; which_list++) {
617: HTList * cur = conversion[which_list];
618:
619: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.65 frystyk 620: if ((pres->rep==rep_in || wild_match(pres->rep, rep_in)) &&
621: (pres->rep_out==rep_out || wild_match(pres->rep_out,rep_out))){
622: if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33 luotonen 623: (!better_match(best_match->rep, pres->rep) &&
624: pres->quality > best_quality)) {
1.58 frystyk 625: #ifdef GOT_SYSTEM
1.65 frystyk 626: int result=0;
627: if (pres->test_command) {
628: result = system(pres->test_command);
629: if (STREAM_TRACE)
630: fprintf(TDEST, "StreamStack. system(%s) returns %d\n", pres->test_command, result);
631: }
632: if (!result) {
1.49 howcome 633: best_match = pres;
634: best_quality = pres->quality;
635: }
1.65 frystyk 636: #else
637: best_match = pres;
638: best_quality = pres->quality;
1.58 frystyk 639: #endif /* GOT_SYSTEM */
1.10 timbl 640: }
641: }
1.2 timbl 642: }
643: }
1.65 frystyk 644: if (best_match)
645: return (*best_match->converter)(request, best_match->command,
646: rep_in, rep_out, output_stream);
647: if (STREAM_TRACE)
648: fprintf(TDEST, "StreamStack. No match found, dumping to local file\n");
649: return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2 timbl 650: }
651:
652:
653: /* Find the cost of a filter stack
654: ** -------------------------------
655: **
656: ** Must return the cost of the same stack which StreamStack would set up.
657: **
658: ** On entry,
659: ** length The size of the data to be converted
660: */
1.59 frystyk 661: PUBLIC double HTStackValue ARGS5(
1.14 timbl 662: HTList *, theseConversions,
1.10 timbl 663: HTFormat, rep_in,
1.2 timbl 664: HTFormat, rep_out,
1.59 frystyk 665: double, initial_value,
1.2 timbl 666: long int, length)
667: {
1.14 timbl 668: int which_list;
669: HTList* conversion[2];
670:
1.65 frystyk 671: if (STREAM_TRACE) {
672: fprintf(TDEST, "StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
673: HTAtom_name(rep_in), initial_value,
674: HTAtom_name(rep_out));
675: }
1.2 timbl 676: if (rep_out == WWW_SOURCE ||
1.10 timbl 677: rep_out == rep_in) return 0.0;
1.2 timbl 678:
1.14 timbl 679: conversion[0] = theseConversions;
680: conversion[1] = HTConversions;
681:
682: for(which_list = 0; which_list<2; which_list++)
683: if (conversion[which_list]) {
1.15 luotonen 684: HTList * cur = conversion[which_list];
1.2 timbl 685: HTPresentation * pres;
1.15 luotonen 686: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
687: if (pres->rep == rep_in &&
1.17 luotonen 688: (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.59 frystyk 689: double value = initial_value * pres->quality;
1.2 timbl 690: if (HTMaxSecs != 0.0)
1.15 luotonen 691: value = value - (length*pres->secs_per_byte + pres->secs)
1.2 timbl 692: /HTMaxSecs;
693: return value;
694: }
695: }
696: }
1.63 frystyk 697: return NO_VALUE_FOUND; /* Really bad */
1.1 timbl 698: }
1.2 timbl 699:
1.10 timbl 700:
Webmaster