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