Annotation of libwww/Library/src/HTFormat.c, revision 1.95
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.95 ! frystyk 6: ** @(#) $Id: HTFormat.c,v 1.94 1997/02/16 17:49:15 frystyk Exp $
1.1 timbl 7: **
8: ** Bugs:
9: ** Assumes the incoming stream is ASCII, rather than a local file
10: ** format, and so ALWAYS converts from ASCII on non-ASCII machines.
11: ** Therefore, non-ASCII machines can't read local files.
1.2 timbl 12: **
1.45 duns 13: ** HISTORY:
1.86 frystyk 14: ** 8 Jul 94 FM Insulate free from _free structure element.
1.52 frystyk 15: ** 8 Nov 94 HFN Changed a lot to make reentrant
1.2 timbl 16: */
17:
1.58 frystyk 18: /* Library Include files */
1.85 frystyk 19: #include "sysdep.h"
1.87 frystyk 20: #include "WWWUtil.h"
21: #include "HTStream.h"
1.93 frystyk 22: #include "HTWWWStr.h"
1.58 frystyk 23: #include "HTFWrite.h"
1.52 frystyk 24: #include "HTError.h"
25: #include "HTFormat.h" /* Implemented here */
1.2 timbl 26:
1.72 frystyk 27: #define NO_VALUE_FOUND -1e30 /* Stream Stack Value if none found */
1.63 frystyk 28:
1.87 frystyk 29: PRIVATE HTList * HTConversions = NULL; /* Content types */
1.88 frystyk 30: PRIVATE HTList * HTContentCoders = NULL; /* Content coders */
31: PRIVATE HTList * HTTransferCoders = NULL; /* Content transfer coders */
1.72 frystyk 32: PRIVATE HTList * HTCharsets = 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.88 frystyk 41: struct _HTCoding {
42: HTEncoding encoding;
43: HTCoder * encoder;
44: HTCoder * decoder;
1.87 frystyk 45: double quality;
46: };
47:
1.52 frystyk 48: /* ------------------------------------------------------------------------- */
1.87 frystyk 49: /* BASIC CONVERTERS */
50: /* ------------------------------------------------------------------------- */
51:
52: PUBLIC HTStream * HTBlackHoleConverter (HTRequest * request,
53: void * param,
54: HTFormat input_format,
55: HTFormat output_format,
56: HTStream * output_stream)
57: {
58: return HTBlackHole();
59: }
60: /* HTThroughLine
61: ** -------------
62: **
63: ** This function is a dummy function that returns the same output stream
64: ** as given as a parameter. Henrik 01/03-94
65: */
66: PUBLIC HTStream* HTThroughLine (HTRequest * request,
67: void * param,
68: HTFormat input_format,
69: HTFormat output_format,
70: HTStream * output_stream)
71: {
72: return output_stream;
73: }
74:
1.52 frystyk 75: /*
1.63 frystyk 76: ** For all `accept lists' there is a local list and a global list. The
77: ** local list is a part of the request structure and the global list is
78: ** internal to the HTFormat module. The global lists can be used when
79: ** specifying accept lists for ALL requests and the local list can be
80: ** used to add specific accept headers to the request.
81: */
82:
1.88 frystyk 83: /* ------------------------------------------------------------------------- */
84: /* CONTENT TYPES */
85: /* ------------------------------------------------------------------------- */
1.61 frystyk 86:
1.2 timbl 87: /* Define a presentation system command for a content-type
88: ** -------------------------------------------------------
1.52 frystyk 89: ** INPUT:
90: ** conversions: The list of conveters and presenters
91: ** representation: the MIME-style format name
92: ** command: the MAILCAP-style command template
93: ** quality: A degradation faction [0..1]
94: ** maxbytes: A limit on the length acceptable as input (0 infinite)
95: ** maxsecs: A limit on the time user will wait (0 for infinity)
1.2 timbl 96: */
1.72 frystyk 97: PUBLIC void HTPresentation_add (HTList * conversions,
1.85 frystyk 98: const char * representation,
99: const char * command,
100: const char * test_command,
1.72 frystyk 101: double quality,
102: double secs,
103: double secs_per_byte)
1.52 frystyk 104: {
1.83 frystyk 105: HTPresentation * pres;
106: if ((pres = (HTPresentation *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
107: HT_OUTOFMEM("HTSetPresentation");
1.2 timbl 108:
109: pres->rep = HTAtom_for(representation);
110: pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
111: pres->converter = HTSaveAndExecute; /* Fixed for now ... */
112: pres->quality = quality;
113: pres->secs = secs;
114: pres->secs_per_byte = secs_per_byte;
115: pres->rep = HTAtom_for(representation);
1.49 howcome 116: pres->command = NULL;
1.2 timbl 117: StrAllocCopy(pres->command, command);
1.49 howcome 118: pres->test_command = NULL;
119: StrAllocCopy(pres->test_command, test_command);
1.91 frystyk 120: if (CORE_TRACE)
121: HTTrace("Presentation Adding `%s\' with quality %.2f\n",
122: command, quality);
1.12 timbl 123: HTList_addObject(conversions, pres);
1.2 timbl 124: }
125:
1.73 frystyk 126: PUBLIC void HTPresentation_deleteAll (HTList * list)
127: {
128: if (list) {
129: HTList *cur = list;
130: HTPresentation *pres;
131: while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
1.83 frystyk 132: HT_FREE(pres->command);
133: HT_FREE(pres);
1.73 frystyk 134: }
135: HTList_delete(list);
136: }
137: }
1.2 timbl 138:
139: /* Define a built-in function for a content-type
140: ** ---------------------------------------------
141: */
1.72 frystyk 142: PUBLIC void HTConversion_add (HTList * conversions,
1.85 frystyk 143: const char * representation_in,
144: const char * representation_out,
1.72 frystyk 145: HTConverter * converter,
146: double quality,
147: double secs,
148: double secs_per_byte)
1.52 frystyk 149: {
1.83 frystyk 150: HTPresentation * pres;
1.87 frystyk 151: if ((pres = (HTPresentation*) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
1.83 frystyk 152: HT_OUTOFMEM("HTSetPresentation");
1.2 timbl 153: pres->rep = HTAtom_for(representation_in);
154: pres->rep_out = HTAtom_for(representation_out);
155: pres->converter = converter;
156: pres->command = NULL; /* Fixed */
1.49 howcome 157: pres->test_command = NULL;
1.2 timbl 158: pres->quality = quality;
159: pres->secs = secs;
160: pres->secs_per_byte = secs_per_byte;
1.91 frystyk 161: if (CORE_TRACE)
162: HTTrace("Conversions. Adding %p with quality %.2f\n",
163: converter, quality);
1.12 timbl 164: HTList_addObject(conversions, pres);
1.56 frystyk 165: }
166:
1.73 frystyk 167: PUBLIC void HTConversion_deleteAll (HTList * list)
168: {
169: HTPresentation_deleteAll(list);
170: }
171:
1.88 frystyk 172: /* ------------------------------------------------------------------------- */
173: /* CONTENT ENCODING AND CONTENT TRANSFER ENCODING */
174: /* ------------------------------------------------------------------------- */
175:
176: PUBLIC BOOL HTCoding_add (HTList * list,
177: const char * encoding,
178: HTCoder * encoder,
179: HTCoder * decoder,
180: double quality)
1.73 frystyk 181: {
1.88 frystyk 182: if (list && encoding && (encoder || decoder)) {
183: HTCoding * me;
184: if ((me = (HTCoding *) HT_CALLOC(1, sizeof(HTCoding))) == NULL)
185: HT_OUTOFMEM("HTCoding_add");
186: me->encoding = HTAtom_for(encoding);
1.87 frystyk 187: me->encoder = encoder;
188: me->decoder = decoder;
189: me->quality = quality;
190: if (CORE_TRACE)
191: HTTrace("Codings..... Adding %s with quality %.2f\n",
1.88 frystyk 192: encoding, quality);
1.87 frystyk 193: return HTList_addObject(list, (void *) me);
1.73 frystyk 194: }
1.87 frystyk 195: if (CORE_TRACE) HTTrace("Codings..... Bad argument\n");
196: return NO;
1.73 frystyk 197: }
198:
1.88 frystyk 199: PUBLIC void HTCoding_deleteAll (HTList * list)
1.73 frystyk 200: {
201: if (list) {
1.87 frystyk 202: HTList * cur = list;
1.88 frystyk 203: HTCoding * pres;
204: while ((pres = (HTCoding *) HTList_nextObject(cur)))
1.83 frystyk 205: HT_FREE(pres);
1.73 frystyk 206: HTList_delete(list);
207: }
208: }
209:
1.88 frystyk 210: PUBLIC const char * HTCoding_name (HTCoding * me)
1.87 frystyk 211: {
1.88 frystyk 212: return me ? HTAtom_name(me->encoding) : NULL;
1.95 ! frystyk 213: }
! 214:
! 215: PUBLIC double HTCoding_quality (HTCoding * me)
! 216: {
! 217: return me ? me->quality : 0.0;
1.87 frystyk 218: }
219:
1.88 frystyk 220: /* ------------------------------------------------------------------------- */
221: /* CONTENT LANGUAGE */
222: /* ------------------------------------------------------------------------- */
223:
1.73 frystyk 224: PUBLIC void HTLanguage_add (HTList * list,
1.85 frystyk 225: const char * lang,
1.73 frystyk 226: double quality)
227: {
228: HTAcceptNode * node;
229: if (!list || !lang || !*lang) {
1.87 frystyk 230: if (CORE_TRACE)
1.84 eric 231: HTTrace("Languages... Bad argument\n");
1.73 frystyk 232: return;
233: }
1.83 frystyk 234: if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
235: HT_OUTOFMEM("HTAcceptLanguage");
1.73 frystyk 236:
237: HTList_addObject(list, (void*)node);
238: node->atom = HTAtom_for(lang);
239: node->quality = quality;
240: }
241:
242: PUBLIC void HTLanguage_deleteAll (HTList * list)
243: {
1.87 frystyk 244: if (list) {
245: HTList *cur = list;
246: HTAcceptNode *pres;
247: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
248: HT_FREE(pres);
249: }
250: HTList_delete(list);
251: }
1.73 frystyk 252: }
253:
1.88 frystyk 254: /* ------------------------------------------------------------------------- */
255: /* CONTENT CHARSET */
256: /* ------------------------------------------------------------------------- */
257:
1.73 frystyk 258: PUBLIC void HTCharset_add (HTList * list,
1.85 frystyk 259: const char * charset,
1.73 frystyk 260: double quality)
261: {
262: HTAcceptNode * node;
263: if (!list || !charset || !*charset) {
1.87 frystyk 264: if (CORE_TRACE)
1.84 eric 265: HTTrace("Charset..... Bad argument\n");
1.73 frystyk 266: return;
267: }
1.83 frystyk 268: if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
269: HT_OUTOFMEM("HTAcceptCharsetuage");
1.73 frystyk 270:
271: HTList_addObject(list, (void*)node);
272: node->atom = HTAtom_for(charset);
273: node->quality = quality;
274: }
275:
276: PUBLIC void HTCharset_deleteAll (HTList * list)
277: {
1.87 frystyk 278: if (list) {
279: HTList *cur = list;
280: HTAcceptNode *pres;
281: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
282: HT_FREE(pres);
283: }
284: HTList_delete(list);
285: }
1.73 frystyk 286: }
287:
288: /* ------------------------------------------------------------------------- */
289: /* GLOBAL LIST OF CONVERTERS ETC. */
290: /* ------------------------------------------------------------------------- */
291:
1.72 frystyk 292: /*
293: ** Global Accept Format Types Conversions
294: ** list can be NULL
295: */
1.73 frystyk 296: PUBLIC void HTFormat_setConversion (HTList * list)
1.72 frystyk 297: {
298: HTConversions = list;
299: }
300:
301: PUBLIC HTList * HTFormat_conversion (void)
302: {
303: return HTConversions;
304: }
305:
1.92 frystyk 306: PUBLIC void HTFormat_addConversion (const char * input_format,
307: const char * output_format,
308: HTConverter * converter,
309: double quality,
310: double secs,
311: double secs_per_byte)
312: {
313: if (!HTConversions) HTConversions = HTList_new();
314: HTConversion_add(HTConversions, input_format, output_format,
315: converter, quality, secs, secs_per_byte);
316: }
317:
1.72 frystyk 318: /*
1.88 frystyk 319: ** Global list of Content Encodings
1.72 frystyk 320: ** list can be NULL
321: */
1.88 frystyk 322: PUBLIC void HTFormat_setContentCoding (HTList *list)
1.72 frystyk 323: {
1.88 frystyk 324: HTContentCoders = list;
1.72 frystyk 325: }
326:
1.88 frystyk 327: PUBLIC HTList * HTFormat_contentCoding (void)
1.72 frystyk 328: {
1.88 frystyk 329: return HTContentCoders;
1.72 frystyk 330: }
331:
1.92 frystyk 332: PUBLIC BOOL HTFormat_addCoding ( char * encoding,
333: HTCoder * encoder,
334: HTCoder * decoder,
335: double quality)
336: {
337: if (!HTContentCoders) HTContentCoders = HTList_new();
338: return HTCoding_add(HTContentCoders, encoding, encoder, decoder, quality);
339: }
340:
1.72 frystyk 341: /*
1.88 frystyk 342: ** Global list of Content Transfer Encodings
343: ** list can be NULL
344: */
345: PUBLIC void HTFormat_setTransferCoding (HTList *list)
346: {
347: HTTransferCoders = list;
348: }
349:
350: PUBLIC HTList * HTFormat_transferCoding (void)
351: {
352: return HTTransferCoders;
1.92 frystyk 353: }
354:
355: PUBLIC BOOL HTFormat_addTransferCoding ( char * encoding,
356: HTCoder * encoder,
357: HTCoder * decoder,
358: double quality)
359: {
360: if (!HTTransferCoders) HTTransferCoders = HTList_new();
361: return HTCoding_add(HTTransferCoders, encoding, encoder, decoder, quality);
1.88 frystyk 362: }
363:
364: /*
1.72 frystyk 365: ** Global Accept Languages
366: ** list can be NULL
367: */
368: PUBLIC void HTFormat_setLanguage (HTList *list)
369: {
370: HTLanguages = list;
371: }
372:
373: PUBLIC HTList * HTFormat_language (void)
374: {
375: return HTLanguages;
376: }
377:
378: /*
379: ** Global Accept Charsets
380: ** list can be NULL
381: */
382: PUBLIC void HTFormat_setCharset (HTList *list)
383: {
384: HTCharsets = list;
385: }
386:
387: PUBLIC HTList * HTFormat_charset (void)
388: {
389: return HTCharsets;
390: }
1.56 frystyk 391:
1.73 frystyk 392: /*
393: ** Convenience function to clean up
394: */
395: PUBLIC void HTFormat_deleteAll (void)
1.17 luotonen 396: {
1.73 frystyk 397: if (HTConversions) {
398: HTConversion_deleteAll(HTConversions);
399: HTConversions = NULL;
400: }
401: if (HTLanguages) {
402: HTLanguage_deleteAll(HTLanguages);
403: HTLanguages = NULL;
1.63 frystyk 404: }
1.88 frystyk 405: if (HTContentCoders) {
406: HTCoding_deleteAll(HTContentCoders);
407: HTContentCoders = NULL;
1.63 frystyk 408: }
1.88 frystyk 409: if (HTTransferCoders) {
410: HTCoding_deleteAll(HTTransferCoders);
411: HTTransferCoders = NULL;
412: }
1.73 frystyk 413: if (HTCharsets) {
414: HTCharset_deleteAll(HTCharsets);
415: HTCharsets = NULL;
1.63 frystyk 416: }
1.17 luotonen 417: }
418:
1.63 frystyk 419: /* ------------------------------------------------------------------------- */
1.90 frystyk 420: /* STREAM STACKS */
1.63 frystyk 421: /* ------------------------------------------------------------------------- */
422:
1.77 frystyk 423: PRIVATE BOOL better_match (HTFormat f, HTFormat g)
1.63 frystyk 424: {
1.85 frystyk 425: const char *p, *q;
1.63 frystyk 426:
427: if (f && g && (p = HTAtom_name(f)) && (q = HTAtom_name(g))) {
428: int i,j;
429: for(i=0 ; *p; p++) if (*p == '*') i++;
430: for(j=0 ; *q; q++) if (*q == '*') j++;
431: if (i < j) return YES;
432: }
433: return NO;
434: }
435:
1.87 frystyk 436: /* Create a Content Type filter stack
437: ** ----------------------------------
1.7 secret 438: ** If a wildcard match is made, a temporary HTPresentation
1.2 timbl 439: ** structure is made to hold the destination format while the
440: ** new stack is generated. This is just to pass the out format to
441: ** MIME so far. Storing the format of a stream in the stream might
442: ** be a lot neater.
1.10 timbl 443: **
1.29 frystyk 444: ** The star/star format is special, in that if you can take
1.40 frystyk 445: ** that you can take anything.
1.2 timbl 446: */
1.77 frystyk 447: PUBLIC HTStream * HTStreamStack (HTFormat rep_in,
448: HTFormat rep_out,
449: HTStream * output_stream,
450: HTRequest * request,
451: BOOL guess)
1.2 timbl 452: {
1.14 timbl 453: HTList * conversion[2];
454: int which_list;
1.59 frystyk 455: double best_quality = -1e30; /* Pretty bad! */
1.65 frystyk 456: HTPresentation *pres, *best_match=NULL;
1.80 frystyk 457: if (rep_out == WWW_RAW) {
1.87 frystyk 458: if (CORE_TRACE) HTTrace("StreamStack. Raw output...\n");
1.81 frystyk 459: return output_stream ? output_stream : HTErrorStream();
1.34 luotonen 460: }
1.79 frystyk 461:
1.80 frystyk 462: if (rep_out == rep_in) {
1.87 frystyk 463: if (CORE_TRACE)
1.84 eric 464: HTTrace("StreamStack. Identical input/output format (%s)\n",
1.80 frystyk 465: HTAtom_name(rep_out));
1.81 frystyk 466: return output_stream ? output_stream : HTErrorStream();
1.74 frystyk 467: }
1.87 frystyk 468: if (CORE_TRACE) {
1.89 eric 469: const char *p = HTAtom_name(rep_in);
470: const char *q = HTAtom_name(rep_out);
1.84 eric 471: HTTrace("StreamStack. Constructing stream stack for %s to %s\n",
1.82 frystyk 472: p ? p : "<NULL>", q ? q : "<NULL>");
1.47 frystyk 473: }
1.2 timbl 474:
1.88 frystyk 475: conversion[0] = HTRequest_conversion(request);
1.14 timbl 476: conversion[1] = HTConversions;
1.17 luotonen 477:
1.15 luotonen 478: for(which_list = 0; which_list<2; which_list++) {
479: HTList * cur = conversion[which_list];
480: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.93 frystyk 481: if ((pres->rep==rep_in || HTMIMEMatch(pres->rep, rep_in)) &&
482: (pres->rep_out==rep_out || HTMIMEMatch(pres->rep_out,rep_out))){
1.65 frystyk 483: if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33 luotonen 484: (!better_match(best_match->rep, pres->rep) &&
485: pres->quality > best_quality)) {
1.85 frystyk 486: #ifdef HAVE_SYSTEM
1.65 frystyk 487: int result=0;
488: if (pres->test_command) {
489: result = system(pres->test_command);
1.87 frystyk 490: if (CORE_TRACE)
1.84 eric 491: HTTrace("StreamStack. system(%s) returns %d\n", pres->test_command, result);
1.65 frystyk 492: }
493: if (!result) {
1.49 howcome 494: best_match = pres;
495: best_quality = pres->quality;
496: }
1.65 frystyk 497: #else
498: best_match = pres;
499: best_quality = pres->quality;
1.85 frystyk 500: #endif /* HAVE_SYSTEM */
1.10 timbl 501: }
502: }
1.2 timbl 503: }
504: }
1.80 frystyk 505:
506: if (best_match) {
507: if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
1.87 frystyk 508: if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81 frystyk 509: return output_stream ? output_stream : HTErrorStream();
1.80 frystyk 510: }
1.65 frystyk 511: return (*best_match->converter)(request, best_match->command,
512: rep_in, rep_out, output_stream);
1.80 frystyk 513: }
514: if (rep_out == WWW_SOURCE) {
1.87 frystyk 515: if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81 frystyk 516: return output_stream ? output_stream : HTErrorStream();
1.80 frystyk 517: }
518:
1.87 frystyk 519: if (CORE_TRACE)
1.84 eric 520: HTTrace("StreamStack. No match found, dumping to local file\n");
1.65 frystyk 521: return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2 timbl 522: }
523:
524:
525: /* Find the cost of a filter stack
526: ** -------------------------------
527: **
528: ** Must return the cost of the same stack which StreamStack would set up.
529: **
530: ** On entry,
531: ** length The size of the data to be converted
532: */
1.77 frystyk 533: PUBLIC double HTStackValue (HTList * theseConversions,
534: HTFormat rep_in,
535: HTFormat rep_out,
536: double initial_value,
537: long int length)
1.2 timbl 538: {
1.14 timbl 539: int which_list;
540: HTList* conversion[2];
541:
1.87 frystyk 542: if (CORE_TRACE) {
1.84 eric 543: HTTrace("StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.65 frystyk 544: HTAtom_name(rep_in), initial_value,
545: HTAtom_name(rep_out));
546: }
1.2 timbl 547: if (rep_out == WWW_SOURCE ||
1.10 timbl 548: rep_out == rep_in) return 0.0;
1.2 timbl 549:
1.14 timbl 550: conversion[0] = theseConversions;
551: conversion[1] = HTConversions;
552:
553: for(which_list = 0; which_list<2; which_list++)
554: if (conversion[which_list]) {
1.15 luotonen 555: HTList * cur = conversion[which_list];
1.2 timbl 556: HTPresentation * pres;
1.15 luotonen 557: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
558: if (pres->rep == rep_in &&
1.93 frystyk 559: (pres->rep_out == rep_out || HTMIMEMatch(pres->rep_out, rep_out))) {
1.59 frystyk 560: double value = initial_value * pres->quality;
1.2 timbl 561: if (HTMaxSecs != 0.0)
1.15 luotonen 562: value = value - (length*pres->secs_per_byte + pres->secs)
1.2 timbl 563: /HTMaxSecs;
564: return value;
565: }
566: }
567: }
1.63 frystyk 568: return NO_VALUE_FOUND; /* Really bad */
1.1 timbl 569: }
1.2 timbl 570:
1.87 frystyk 571: /* Create a new coder and insert it into stream chain
572: ** --------------------------------------------------
573: ** Creating the content decoding stack is not based on quality factors as
574: ** we don't have the freedom as with content types. Specify whether you
1.88 frystyk 575: ** you want encoding or decoding using the BOOL "encode" flag.
1.87 frystyk 576: */
1.88 frystyk 577: PUBLIC HTStream * HTContentCodingStack (HTEncoding encoding,
578: HTStream * target,
579: HTRequest * request,
580: void * param,
581: BOOL encode)
1.87 frystyk 582: {
583: HTList * coders[2];
584: HTStream * top = target;
1.88 frystyk 585: HTCoding * pres = NULL;
1.87 frystyk 586: int cnt;
1.88 frystyk 587: if (!encoding || !request) {
1.87 frystyk 588: if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
589: return target ? target : HTErrorStream();
590: }
1.88 frystyk 591: coders[0] = HTRequest_encoding(request);
592: coders[1] = HTContentCoders;
1.87 frystyk 593: if (CORE_TRACE)
1.94 frystyk 594: HTTrace("C-E......... Looking for `%s\'\n", HTAtom_name(encoding));
1.87 frystyk 595: for (cnt=0; cnt < 2; cnt++) {
596: HTList * cur = coders[cnt];
1.88 frystyk 597: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
598: if (pres->encoding == encoding) {
1.94 frystyk 599: if (CORE_TRACE) HTTrace("C-E......... Found...\n");
1.88 frystyk 600: if (encode) {
1.87 frystyk 601: if (pres->encoder)
1.88 frystyk 602: top = (*pres->encoder)(request, param, encoding, top);
1.87 frystyk 603: break;
604: } else if (pres->decoder) {
1.88 frystyk 605: top = (*pres->decoder)(request, param, encoding, top);
1.87 frystyk 606: break;
607: }
608: }
609: }
610: }
1.94 frystyk 611:
612: /*
613: ** If this is not a unity coding and we didn't find any coders
614: ** that could handle it then put in a local file save stream
615: ** instead of the stream that we got.
616: */
617: if (!HTFormat_isUnityContent(encoding) && target==top) {
618: if (encode) {
619: if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - removing encoding!\n");
620: HTAnchor_removeEncoding(HTRequest_anchor(request), encoding);
621: } else {
622: if (CORE_TRACE) HTTrace("C-E......... NOT FOUND - inserting save stream!\n");
623: (*top->isa->abort)(top, NULL);
624: top = HTSaveLocally(request, NULL, NULL,
625: HTRequest_outputFormat(request),
626: HTRequest_outputStream(request));
627: }
628: }
1.87 frystyk 629: return top;
630: }
1.10 timbl 631:
1.87 frystyk 632: /*
633: ** Here you can provide a complete list instead of a single token.
634: ** The list has to filled up in the order the _encodings_ are to be applied
635: */
1.88 frystyk 636: PUBLIC HTStream * HTContentEncodingStack (HTList * encodings,
637: HTStream * target,
638: HTRequest * request,
639: void * param)
1.87 frystyk 640: {
641: if (encodings) {
642: HTList * cur = encodings;
643: HTEncoding pres;
644: HTStream * top = target;
645: while ((pres = (HTEncoding) HTList_nextObject(cur)))
1.88 frystyk 646: top = HTContentCodingStack(pres, top, request, param, YES);
1.87 frystyk 647: return top;
648: }
649: return HTErrorStream();
650: }
651:
652: /*
653: ** Here you can provide a complete list instead of a single token.
654: ** The list has to be in the order the _encodings_ were applied - that
655: ** is, the same way that _encodings_ are to be applied. This is all consistent
656: ** with the order of the Content-Encoding header.
657: */
1.88 frystyk 658: PUBLIC HTStream * HTContentDecodingStack (HTList * encodings,
659: HTStream * target,
660: HTRequest * request,
661: void * param)
1.87 frystyk 662: {
663: if (encodings) {
664: HTEncoding pres;
665: int cnt = HTList_count(encodings);
666: HTStream * top = target;
667: while (cnt > 0) {
668: pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
1.88 frystyk 669: top = HTContentCodingStack(pres, top, request, param, NO);
1.87 frystyk 670: }
671: return top;
672: }
673: return HTErrorStream();
674: }
1.88 frystyk 675:
676: /* Create a new transfer coder and insert it into stream chain
677: ** -----------------------------------------------------------
678: ** Creating the content decoding stack is not based on quality factors as
679: ** we don't have the freedom as with content types. Specify whether you
680: ** you want encoding or decoding using the BOOL "encode" flag.
681: */
682: PUBLIC HTStream * HTTransferCodingStack (HTEncoding encoding,
683: HTStream * target,
684: HTRequest * request,
685: void * param,
686: BOOL encode)
687: {
688: HTList * coders[2];
689: HTStream * top = target;
690: HTCoding * pres = NULL;
691: int cnt;
692: if (!encoding || !request) {
693: if (CORE_TRACE) HTTrace("C-T-E..... Nothing applied...\n");
694: return target ? target : HTErrorStream();
695: }
696: coders[0] = HTRequest_transfer(request);
697: coders[1] = HTTransferCoders;
698: if (CORE_TRACE)
699: HTTrace("C-T-E....... Looking for %s\n", HTAtom_name(encoding));
700: for (cnt=0; cnt < 2; cnt++) {
701: HTList * cur = coders[cnt];
702: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
703: if (pres->encoding == encoding) {
704: if (CORE_TRACE) HTTrace("C-T-E....... Found...\n");
705: if (encode) {
706: if (pres->encoder)
707: top = (*pres->encoder)(request, param, encoding, top);
708: break;
709: } else if (pres->decoder) {
710: top = (*pres->decoder)(request, param, encoding, top);
711: break;
712: }
713: }
714: }
715: }
1.94 frystyk 716:
717: /*
718: ** If this is not a unity coding and we didn't find any coders
719: ** that could handle it then put in a local file save stream
720: ** instead of the stream that we got.
721: */
722: if (!HTFormat_isUnityTransfer(encoding) && target==top) {
723: if (encode) {
724: if (CORE_TRACE) HTTrace("C-T-E....... NOT FOUND - removing encoding!\n");
725: HTAnchor_setTransfer(HTRequest_anchor(request), NULL);
726: } else {
727: if (CORE_TRACE) HTTrace("C-T-E....... NOT FOUND - inserting save stream!\n");
728: (*top->isa->abort)(top, NULL);
729: top = HTSaveLocally(request, NULL, NULL,
730: HTRequest_outputFormat(request),
731: HTRequest_outputStream(request));
732: }
733: }
1.88 frystyk 734: return top;
735: }
736:
Webmaster