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