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