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