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