Annotation of libwww/Library/src/HTFormat.c, revision 1.21
1.7 secret 1:
1.1 timbl 2: /* Manage different file formats HTFormat.c
3: ** =============================
4: **
5: ** Bugs:
6: ** Not reentrant.
7: **
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: **
12: */
13:
1.10 timbl 14:
1.2 timbl 15: /* Implements:
1.1 timbl 16: */
1.2 timbl 17: #include "HTFormat.h"
18:
19: PUBLIC float HTMaxSecs = 1e10; /* No effective limit */
20: PUBLIC float HTMaxLength = 1e10; /* No effective limit */
21:
22: #ifdef unix
23: #ifdef NeXT
24: #define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n"
25: #else
26: #define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n"
27: /* Full pathname would be better! */
28: #endif
29: #endif
30:
1.1 timbl 31:
32: #include "HTUtils.h"
33: #include "tcp.h"
34:
35: #include "HTML.h"
1.12 timbl 36: #include "HTMLPDTD.h"
1.1 timbl 37: #include "HText.h"
1.2 timbl 38: #include "HTAlert.h"
39: #include "HTList.h"
40: #include "HTInit.h"
41: /* Streams and structured streams which we use:
42: */
43: #include "HTFWriter.h"
44: #include "HTPlain.h"
45: #include "SGML.h"
46: #include "HTML.h"
47: #include "HTMLGen.h"
48:
49: PUBLIC BOOL HTOutputSource = NO; /* Flag: shortcut parser to stdout */
50: extern BOOL interactive;
51:
1.10 timbl 52: #ifdef ORIGINAL
1.2 timbl 53: struct _HTStream {
54: CONST HTStreamClass* isa;
55: /* ... */
56: };
1.10 timbl 57: #endif
58:
59: /* this version used by the NetToText stream */
60: struct _HTStream {
61: CONST HTStreamClass * isa;
62: BOOL had_cr;
63: HTStream * sink;
64: };
1.2 timbl 65:
66:
1.17 luotonen 67: /*
68: ** Accept-Encoding and Accept-Language
69: */
70: typedef struct _HTAcceptNode {
71: HTAtom * atom;
72: float quality;
73: } HTAcceptNode;
74:
75:
76:
77:
1.2 timbl 78: /* Presentation methods
79: ** --------------------
80: */
81:
1.14 timbl 82: PUBLIC HTList * HTConversions = NULL;
1.2 timbl 83:
84:
85: /* Define a presentation system command for a content-type
86: ** -------------------------------------------------------
87: */
1.12 timbl 88: PUBLIC void HTSetPresentation ARGS6(
89: HTList *, conversions,
90: CONST char *, representation,
91: CONST char *, command,
92: float, quality,
93: float, secs,
94: float, secs_per_byte
1.2 timbl 95: ){
96:
97: HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
98: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
99:
100: pres->rep = HTAtom_for(representation);
101: pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
102: pres->converter = HTSaveAndExecute; /* Fixed for now ... */
103: pres->quality = quality;
104: pres->secs = secs;
105: pres->secs_per_byte = secs_per_byte;
106: pres->rep = HTAtom_for(representation);
107: pres->command = 0;
108: StrAllocCopy(pres->command, command);
109:
1.12 timbl 110: /* if (!HTPresentations) HTPresentations = HTList_new(); */
1.2 timbl 111:
1.15 luotonen 112: #ifdef OLD_CODE
113: if (strcmp(representation, "*")==0) {
1.2 timbl 114: if (default_presentation) free(default_presentation);
115: default_presentation = pres;
1.12 timbl 116: } else
117: #endif
118: HTList_addObject(conversions, pres);
1.2 timbl 119: }
120:
121:
122: /* Define a built-in function for a content-type
123: ** ---------------------------------------------
124: */
1.12 timbl 125: PUBLIC void HTSetConversion ARGS7(
126: HTList *, conversions,
127: CONST char *, representation_in,
128: CONST char *, representation_out,
1.6 timbl 129: HTConverter*, converter,
1.12 timbl 130: float, quality,
131: float, secs,
132: float, secs_per_byte
1.2 timbl 133: ){
1.1 timbl 134:
1.2 timbl 135: HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
136: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
137:
138: pres->rep = HTAtom_for(representation_in);
139: pres->rep_out = HTAtom_for(representation_out);
140: pres->converter = converter;
141: pres->command = NULL; /* Fixed */
142: pres->quality = quality;
143: pres->secs = secs;
144: pres->secs_per_byte = secs_per_byte;
145: pres->command = 0;
146:
1.12 timbl 147: /* if (!HTPresentations) HTPresentations = HTList_new(); */
1.2 timbl 148:
1.12 timbl 149: #ifdef OLD_CODE
1.2 timbl 150: if (strcmp(representation_in, "*")==0) {
151: if (default_presentation) free(default_presentation);
152: default_presentation = pres;
1.12 timbl 153: } else
154: #endif
155: HTList_addObject(conversions, pres);
1.2 timbl 156: }
1.1 timbl 157:
158:
159:
1.17 luotonen 160: PUBLIC void HTAcceptEncoding ARGS3(HTList *, list,
161: char *, enc,
162: float, quality)
163: {
164: HTAcceptNode * node;
165: char * cur;
166:
167: if (!list || !enc || !*enc) return;
168:
169: for(cur=enc; *cur; cur++) *cur=TOLOWER(*cur);
170:
171: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
172: if (!node) outofmem(__FILE__, "HTAcceptEncoding");
173: HTList_addObject(list, (void*)node);
174:
175: node->atom = HTAtom_for(enc);
176: node->quality = quality;
177: }
178:
179:
180: PUBLIC void HTAcceptLanguage ARGS3(HTList *, list,
181: char *, lang,
182: float, quality)
183: {
184: HTAcceptNode * node;
185:
186: if (!list || !lang || !*lang) return;
187:
188: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
189: if (!node) outofmem(__FILE__, "HTAcceptLanguage");
190:
191: HTList_addObject(list, (void*)node);
192: node->atom = HTAtom_for(lang);
193: node->quality = quality;
194: }
195:
196:
197: PRIVATE BOOL wild_match ARGS2(HTAtom *, template,
198: HTAtom *, actual)
199: {
200: char *t, *a, *st, *sa;
201: BOOL match = NO;
202:
203: if (template && actual &&
204: (t = HTAtom_name(template)) && strchr(t, '*') &&
205: (a = HTAtom_name(actual)) &&
206: (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.19 frystyk 207:
1.17 luotonen 208: *sa = 0;
209: *st = 0;
210:
211: if ((*(st-1)=='*' &&
212: (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
213: (*(st+1)=='*' && !strcasecomp(t,a)))
214: match = YES;
215:
216: *sa = '/';
217: *st = '/';
218: }
219: return match;
220: }
221:
222:
223: PRIVATE float type_value ARGS2(HTAtom *, content_type,
224: HTList *, accepted)
225: {
226: HTList * cur = accepted;
227: HTPresentation * pres;
228: HTPresentation * wild = NULL;
229:
230: if (!content_type || !accepted) return -1;
231:
232: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
233: if (pres->rep == content_type)
234: return pres->quality;
235: else if (wild_match(pres->rep, content_type))
236: wild = pres;
237: }
238: if (wild) return wild->quality;
239: else return -1;
240: }
241:
242:
243: PRIVATE float lang_value ARGS2(HTAtom *, language,
244: HTList *, accepted)
245: {
246: HTList * cur = accepted;
247: HTAcceptNode * node;
248: HTAcceptNode * wild = NULL;
249:
250: if (!language || !accepted || HTList_isEmpty(accepted)) {
251: return 0.1;
252: }
253:
254: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
255: if (node->atom == language) {
256: return node->quality;
257: }
258: else if (wild_match(node->atom, language)) {
259: wild = node;
260: }
261: }
262:
263: if (wild) {
264: return wild->quality;
265: }
266: else {
267: return 0.1;
268: }
269: }
270:
271:
272: PRIVATE float encoding_value ARGS2(HTAtom *, encoding,
273: HTList *, accepted)
274: {
275: HTList * cur = accepted;
276: HTAcceptNode * node;
277: HTAcceptNode * wild = NULL;
278: char * e;
279:
280: if (!encoding || !accepted || HTList_isEmpty(accepted))
281: return 1;
282:
283: e = HTAtom_name(encoding);
284: if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
285: return 1;
286:
287: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
288: if (node->atom == encoding)
289: return node->quality;
290: else if (wild_match(node->atom, encoding))
291: wild = node;
292: }
293: if (wild) return wild->quality;
294: else return 1;
295: }
296:
297:
298: PUBLIC BOOL HTRank ARGS4(HTList *, possibilities,
299: HTList *, accepted_content_types,
300: HTList *, accepted_languages,
301: HTList *, accepted_encodings)
302: {
303: int accepted_cnt = 0;
304: HTList * accepted;
305: HTList * sorted;
306: HTList * cur;
307: HTContentDescription * d;
308:
309: if (!possibilities) return NO;
310:
311: accepted = HTList_new();
312: cur = possibilities;
313: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
314: float tv = type_value(d->content_type, accepted_content_types);
315: float lv = lang_value(d->content_language, accepted_languages);
316: float ev = encoding_value(d->content_encoding, accepted_encodings);
317:
318: #ifdef ARI_DEBUG
319: CTRACE(stderr,
320: " ## FOR FILE \"%s\" (%.3f) VALUES type %.3f enc %.3f lang %.3f\n",
321: d->filename, d->quality, tv, ev, lv);
322: #endif
323:
324: if (tv > 0) {
325: d->quality *= tv * lv * ev;
326: HTList_addObject(accepted, d);
327: accepted_cnt++;
328: }
1.18 luotonen 329: else {
330: if (d->filename) free(d->filename);
331: free(d);
332: }
1.17 luotonen 333: }
334:
1.18 luotonen 335: CTRACE(stderr, "Ranking.....\n");
1.17 luotonen 336: CTRACE(stderr,
1.18 luotonen 337: "\nRANK QUALITY CONTENT-TYPE LANGUAGE ENCODING FILE\n");
1.17 luotonen 338:
339: sorted = HTList_new();
340: while (accepted_cnt-- > 0) {
341: HTContentDescription * worst = NULL;
342: cur = accepted;
343: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
344: if (!worst || d->quality < worst->quality)
345: worst = d;
346: }
347: if (worst) {
348: CTRACE(stderr, "%d. %.4f %-20.20s %-8.8s %-10.10s %s\n",
349: accepted_cnt+1,
350: worst->quality,
351: (worst->content_type
352: ? HTAtom_name(worst->content_type) : "-"),
353: (worst->content_language
354: ? HTAtom_name(worst->content_language) :"-"),
355: (worst->content_encoding
356: ? HTAtom_name(worst->content_encoding) :"-"),
357: (worst->filename
358: ? worst->filename :"-"));
359: HTList_removeObject(accepted, (void*)worst);
360: HTList_addObject(sorted, (void*)worst);
361: }
362: }
1.18 luotonen 363: CTRACE(stderr, "\n");
1.17 luotonen 364: HTList_delete(accepted);
365: HTList_delete(possibilities->next);
366: possibilities->next = sorted->next;
367: sorted->next = NULL;
368: HTList_delete(sorted);
369:
370: if (!HTList_isEmpty(possibilities)) return YES;
371: else return NO;
372: }
373:
374:
375:
376:
377:
1.13 timbl 378: /* Socket Input Buffering
379: ** ----------------------
1.1 timbl 380: **
1.13 timbl 381: ** This code is used because one cannot in general open a
382: ** file descriptor for a socket.
383: **
1.1 timbl 384: ** The input file is read using the macro which can read from
1.13 timbl 385: ** a socket or a file, but this should not be used for files
386: ** as fopen() etc is more portable of course.
387: **
1.1 timbl 388: ** The input buffer size, if large will give greater efficiency and
389: ** release the server faster, and if small will save space on PCs etc.
390: */
391:
392:
393: /* Set up the buffering
394: **
395: ** These routines are public because they are in fact needed by
396: ** many parsers, and on PCs and Macs we should not duplicate
397: ** the static buffer area.
398: */
1.13 timbl 399: PUBLIC HTInputSocket * HTInputSocket_new ARGS1 (int,file_number)
1.1 timbl 400: {
1.13 timbl 401: HTInputSocket *isoc = (HTInputSocket *)malloc(sizeof(*isoc));
402: if (!isoc) outofmem(__FILE__, "HTInputSocket_new");
403: isoc->input_file_number = file_number;
404: isoc->input_pointer = isoc->input_limit = isoc->input_buffer;
405: return isoc;
1.1 timbl 406: }
407:
408:
1.13 timbl 409: PUBLIC char HTInputSocket_getCharacter ARGS1(HTInputSocket*, isoc)
1.1 timbl 410: {
411: char ch;
412: do {
1.13 timbl 413: if (isoc-> input_pointer >= isoc->input_limit) {
1.1 timbl 414: int status = NETREAD(
1.13 timbl 415: isoc->input_file_number,
416: isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1 timbl 417: if (status <= 0) {
418: if (status == 0) return (char)EOF;
419: if (TRACE) fprintf(stderr,
420: "HTFormat: File read error %d\n", status);
421: return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
422: }
1.13 timbl 423: isoc-> input_pointer = isoc->input_buffer;
424: isoc->input_limit = isoc->input_buffer + status;
1.1 timbl 425: }
1.13 timbl 426: ch = *isoc-> input_pointer++;
1.1 timbl 427: } while (ch == (char) 13); /* Ignore ASCII carriage return */
428:
429: return FROMASCII(ch);
430: }
431:
1.17 luotonen 432: PUBLIC void HTInputSocket_free ARGS1(HTInputSocket *, me)
1.13 timbl 433: {
434: if (me) free(me);
435: }
436:
437:
1.16 luotonen 438: PUBLIC char * HTInputSocket_getBlock ARGS2(HTInputSocket*, isoc,
439: int *, len)
440: {
441: if (isoc->input_pointer >= isoc->input_limit) {
442: int status = NETREAD(isoc->input_file_number,
443: isoc->input_buffer,
444: ((*len < INPUT_BUFFER_SIZE) ?
445: *len : INPUT_BUFFER_SIZE));
446: if (status <= 0) {
447: isoc->input_limit = isoc->input_buffer;
448: if (status < 0)
449: CTRACE(stderr, "HTInputSocket: File read error %d\n", status);
450: *len = 0;
451: return NULL;
452: }
453: else {
454: *len = status;
455: return isoc->input_buffer;
456: }
457: }
458: else {
459: char * ret = isoc->input_pointer;
460: *len = isoc->input_limit - isoc->input_pointer;
461: isoc->input_pointer = isoc->input_limit;
462: return ret;
463: }
464: }
465:
466:
1.15 luotonen 467: PRIVATE int fill_in_buffer ARGS1(HTInputSocket *, isoc)
468: {
469: if (isoc) {
470: int status;
471:
472: isoc->input_pointer = isoc->input_buffer;
473: status = NETREAD(isoc->input_file_number,
474: isoc->input_buffer,
475: INPUT_BUFFER_SIZE);
476: if (status <= 0) {
477: isoc->input_limit = isoc->input_buffer;
478: if (status < 0)
479: if (TRACE) fprintf(stderr,
480: "HTInputSocket: File read error %d\n",
481: status);
482: }
483: else
484: isoc->input_limit = isoc->input_buffer + status;
485: return status;
486: }
487: return -1;
488: }
489:
490:
491: PRIVATE void ascii_cat ARGS3(char **, linep,
492: char *, start,
493: char *, end)
494: {
495: if (linep && start && end && start <= end) {
496: char *ptr;
497:
498: if (*linep) {
499: int len = strlen(*linep);
500: *linep = (char*)realloc(*linep, len + end-start + 1);
501: ptr = *linep + len;
502: }
503: else {
504: ptr = *linep = (char*)malloc(end-start + 1);
505: }
506:
507: while (start < end) {
508: *ptr = FROMASCII(*start);
509: ptr++;
510: start++;
511: }
512: *ptr = 0;
513: }
514: }
515:
516:
517: PRIVATE char * get_some_line ARGS2(HTInputSocket *, isoc,
518: BOOL, unfold)
519: {
520: if (!isoc)
521: return NULL;
522: else {
523: BOOL check_unfold = NO;
524: int prev_cr = 0;
525: char *start = isoc->input_pointer;
526: char *cur = isoc->input_pointer;
527: char * line = NULL;
528:
529: for(;;) {
530: /*
531: ** Get more if needed to complete line
532: */
533: if (cur >= isoc->input_limit) { /* Need more data */
534: ascii_cat(&line, start, cur);
535: if (fill_in_buffer(isoc) <= 0)
536: return line;
537: start = cur = isoc->input_pointer;
538: } /* if need more data */
539:
540: /*
541: ** Find a line feed if there is one
542: */
543: for(; cur < isoc->input_limit; cur++) {
544: char c = FROMASCII(*cur);
545: if (!c) {
1.18 luotonen 546: if (line) free(line); /* Leak fixed AL 6 Feb 94 */
1.15 luotonen 547: return NULL; /* Panic! read a 0! */
548: }
549: if (check_unfold && c != ' ' && c != '\t') {
550: return line; /* Note: didn't update isoc->input_pointer */
551: }
552: else {
553: check_unfold = NO;
554: }
555:
556: if (c=='\r') {
557: prev_cr = 1;
558: }
559: else {
560: if (c=='\n') { /* Found a line feed */
561: ascii_cat(&line, start, cur-prev_cr);
562: start = isoc->input_pointer = cur+1;
563:
564: if (line && strlen(line) > 0 && unfold) {
565: check_unfold = YES;
566: }
567: else {
568: return line;
569: }
570: } /* if NL */
571: /* else just a regular character */
572: prev_cr = 0;
573: } /* if not CR */
574: } /* while characters in buffer remain */
575: } /* until line read or end-of-file */
576: } /* valid parameters to function */
577: }
578:
579:
580: PUBLIC char * HTInputSocket_getLine ARGS1(HTInputSocket *, isoc)
581: {
582: return get_some_line(isoc, NO);
583: }
584:
585: PUBLIC char * HTInputSocket_getUnfoldedLine ARGS1(HTInputSocket *, isoc)
586: {
587: return get_some_line(isoc, YES);
588: }
589:
590:
591: /*
592: ** Read HTTP status line (if there is one).
593: **
594: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
595: ** First look at the stub in ASCII and check if it starts "HTTP/".
596: **
597: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
598: ** will be taken as a HTTP 1.0 server. Failure.
599: */
600: #define STUB_LENGTH 20
601: PUBLIC char * HTInputSocket_getStatusLine ARGS1(HTInputSocket *, isoc)
602: {
603: if (!isoc) {
604: return NULL;
605: }
606: else {
607: char buf[STUB_LENGTH + 1];
608: int i;
609: char server_version[STUB_LENGTH+1];
610: int server_status;
611:
612: /*
613: ** Read initial buffer
614: */
615: if (isoc->input_pointer >= isoc->input_limit &&
616: fill_in_buffer(isoc) <= 0) {
617: return NULL;
618: }
619:
620: for (i=0; i < STUB_LENGTH; i++)
621: buf[i] = FROMASCII(isoc->input_buffer[i]);
622: buf[STUB_LENGTH] = 0;
623:
624: if (0 != strncmp(buf, "HTTP/", 5) ||
625: sscanf(buf, "%20s%d", server_version, &server_status) < 2)
626: return NULL;
627: else
628: return get_some_line(isoc, NO);
629: }
630: }
631:
632:
633: /*
634: ** Do heuristic test to see if this is binary.
635: **
636: ** We check for characters above 128 in the first few bytes, and
637: ** if we find them we forget the html default.
638: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
639: **
640: ** Bugs: An HTTP 0.9 server returning a binary document with
641: ** characters < 128 will be read as ASCII.
642: */
643: PUBLIC BOOL HTInputSocket_seemsBinary ARGS1(HTInputSocket *, isoc)
644: {
645: if (isoc &&
646: (isoc->input_pointer < isoc->input_limit ||
647: fill_in_buffer(isoc) > 0)) {
648: char *p = isoc->input_buffer;
649: int i = STUB_LENGTH;
650:
651: for( ; i && p < isoc->input_limit; p++, i++)
652: if (((int)*p)&128)
653: return YES;
654: }
655: return NO;
656: }
657:
658:
659:
1.1 timbl 660: /* Stream the data to an ouput file as binary
661: */
1.13 timbl 662: PUBLIC int HTOutputBinary ARGS3( HTInputSocket *, isoc,
663: int, input,
664: FILE *, output)
1.1 timbl 665: {
666: do {
667: int status = NETREAD(
1.13 timbl 668: input, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1 timbl 669: if (status <= 0) {
670: if (status == 0) return 0;
671: if (TRACE) fprintf(stderr,
672: "HTFormat: File read error %d\n", status);
673: return 2; /* Error */
674: }
1.13 timbl 675: fwrite(isoc->input_buffer, sizeof(char), status, output);
1.1 timbl 676: } while (YES);
677: }
678:
679:
1.17 luotonen 680:
1.2 timbl 681: /* Create a filter stack
682: ** ---------------------
683: **
1.7 secret 684: ** If a wildcard match is made, a temporary HTPresentation
1.2 timbl 685: ** structure is made to hold the destination format while the
686: ** new stack is generated. This is just to pass the out format to
687: ** MIME so far. Storing the format of a stream in the stream might
688: ** be a lot neater.
1.10 timbl 689: **
690: ** The www/source format is special, in that if you can take
691: ** that you can take anything. However, we
1.2 timbl 692: */
1.12 timbl 693: PUBLIC HTStream * HTStreamStack ARGS2(
1.10 timbl 694: HTFormat, rep_in,
1.12 timbl 695: HTRequest *, request)
1.2 timbl 696: {
1.12 timbl 697: HTFormat rep_out = request->output_format; /* Could be a param */
1.14 timbl 698: HTList * conversion[2];
1.10 timbl 699: HTFormat source = WWW_SOURCE;
1.14 timbl 700: int which_list;
701: HTPresentation * pres, *match, *wildcard_match=0,
702: *source_match=0, *source_wildcard_match=0;
703:
1.2 timbl 704: if (TRACE) fprintf(stderr,
705: "HTFormat: Constructing stream stack for %s to %s\n",
1.10 timbl 706: HTAtom_name(rep_in),
1.2 timbl 707: HTAtom_name(rep_out));
708:
1.21 ! luotonen 709: if (rep_out == WWW_SOURCE || rep_out == rep_in)
! 710: return request->output_stream;
1.2 timbl 711:
1.14 timbl 712: conversion[0] = request->conversions;
713: conversion[1] = HTConversions;
1.17 luotonen 714:
1.15 luotonen 715: for(which_list = 0; which_list<2; which_list++) {
716: HTList * cur = conversion[which_list];
717:
718: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.17 luotonen 719: if (pres->rep == rep_in ||
720: wild_match(pres->rep, rep_in)) {
1.2 timbl 721: if (pres->rep_out == rep_out)
1.12 timbl 722: return (*pres->converter)(request, pres->command,
1.15 luotonen 723: rep_in, pres->rep_out,
724: request->output_stream);
1.17 luotonen 725: if (wild_match(pres->rep_out, rep_out)) {
1.10 timbl 726: wildcard_match = pres;
727: }
728: }
729: if (pres->rep == source) {
730: if (pres->rep_out == rep_out)
731: source_match = pres;
1.17 luotonen 732: if (wild_match(pres->rep_out, rep_out)) {
1.10 timbl 733: source_wildcard_match = pres;
1.2 timbl 734: }
735: }
736: }
737: }
1.14 timbl 738: match = wildcard_match ? wildcard_match :
739: source_match ? source_match :
740: source_wildcard_match;
741:
742: if (match) return (*match->converter)(
743: request, match->command, rep_in, rep_out,
744: request->output_stream);
1.10 timbl 745:
1.2 timbl 746: return NULL;
747: }
748:
749:
750: /* Find the cost of a filter stack
751: ** -------------------------------
752: **
753: ** Must return the cost of the same stack which StreamStack would set up.
754: **
755: ** On entry,
756: ** length The size of the data to be converted
757: */
1.12 timbl 758: PUBLIC float HTStackValue ARGS5(
1.14 timbl 759: HTList *, theseConversions,
1.10 timbl 760: HTFormat, rep_in,
1.2 timbl 761: HTFormat, rep_out,
762: float, initial_value,
763: long int, length)
764: {
1.14 timbl 765: int which_list;
766: HTList* conversion[2];
767:
1.2 timbl 768: if (TRACE) fprintf(stderr,
769: "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
1.10 timbl 770: HTAtom_name(rep_in), initial_value,
1.2 timbl 771: HTAtom_name(rep_out));
772:
773: if (rep_out == WWW_SOURCE ||
1.10 timbl 774: rep_out == rep_in) return 0.0;
1.2 timbl 775:
1.12 timbl 776: /* if (!HTPresentations) HTFormatInit(); set up the list */
1.2 timbl 777:
1.14 timbl 778: conversion[0] = theseConversions;
779: conversion[1] = HTConversions;
780:
781: for(which_list = 0; which_list<2; which_list++)
782: if (conversion[which_list]) {
1.15 luotonen 783: HTList * cur = conversion[which_list];
1.2 timbl 784: HTPresentation * pres;
1.15 luotonen 785: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
786: if (pres->rep == rep_in &&
1.17 luotonen 787: (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.2 timbl 788: float value = initial_value * pres->quality;
789: if (HTMaxSecs != 0.0)
1.15 luotonen 790: value = value - (length*pres->secs_per_byte + pres->secs)
1.2 timbl 791: /HTMaxSecs;
792: return value;
793: }
794: }
795: }
796:
797: return -1e30; /* Really bad */
1.17 luotonen 798: }
799:
800:
1.2 timbl 801:
1.1 timbl 802:
1.2 timbl 803: /* Push data from a socket down a stream
804: ** -------------------------------------
1.1 timbl 805: **
1.2 timbl 806: ** This routine is responsible for creating and PRESENTING any
1.1 timbl 807: ** graphic (or other) objects described by the file.
1.2 timbl 808: **
809: ** The file number given is assumed to be a TELNET stream ie containing
810: ** CRLF at the end of lines which need to be stripped to LF for unix
811: ** when the format is textual.
812: **
1.1 timbl 813: */
1.2 timbl 814: PUBLIC void HTCopy ARGS2(
815: int, file_number,
816: HTStream*, sink)
1.1 timbl 817: {
1.2 timbl 818: HTStreamClass targetClass;
1.13 timbl 819: HTInputSocket * isoc;
1.2 timbl 820:
1.5 timbl 821: /* Push the data down the stream
1.2 timbl 822: **
823: */
824: targetClass = *(sink->isa); /* Copy pointers to procedures */
1.13 timbl 825: isoc = HTInputSocket_new(file_number);
1.2 timbl 826:
827: /* Push binary from socket down sink
1.10 timbl 828: **
829: ** This operation could be put into a main event loop
1.2 timbl 830: */
831: for(;;) {
832: int status = NETREAD(
1.13 timbl 833: file_number, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.2 timbl 834: if (status <= 0) {
835: if (status == 0) break;
836: if (TRACE) fprintf(stderr,
1.20 frystyk 837: "HTFormat: Read error, read returns %d with errno=%d (%s)\n",
838: status, errno, strerror(errno));
1.2 timbl 839: break;
840: }
1.8 timbl 841:
842: #ifdef NOT_ASCII
843: {
844: char * p;
1.13 timbl 845: for(p = isoc->input_buffer; p < isoc->input_buffer+status; p++) {
1.8 timbl 846: *p = FROMASCII(*p);
847: }
848: }
849: #endif
850:
1.13 timbl 851: (*targetClass.put_block)(sink, isoc->input_buffer, status);
1.2 timbl 852: } /* next bufferload */
1.13 timbl 853: HTInputSocket_free(isoc);
1.2 timbl 854: }
855:
1.1 timbl 856:
1.7 secret 857:
858: /* Push data from a file pointer down a stream
859: ** -------------------------------------
860: **
861: ** This routine is responsible for creating and PRESENTING any
862: ** graphic (or other) objects described by the file.
863: **
864: **
865: */
866: PUBLIC void HTFileCopy ARGS2(
867: FILE *, fp,
868: HTStream*, sink)
869: {
870: HTStreamClass targetClass;
1.13 timbl 871: char input_buffer[INPUT_BUFFER_SIZE];
1.7 secret 872:
873: /* Push the data down the stream
874: **
875: */
876: targetClass = *(sink->isa); /* Copy pointers to procedures */
877:
878: /* Push binary from socket down sink
879: */
880: for(;;) {
881: int status = fread(
882: input_buffer, 1, INPUT_BUFFER_SIZE, fp);
883: if (status == 0) { /* EOF or error */
884: if (ferror(fp) == 0) break;
885: if (TRACE) fprintf(stderr,
886: "HTFormat: Read error, read returns %d\n", ferror(fp));
887: break;
888: }
889: (*targetClass.put_block)(sink, input_buffer, status);
1.13 timbl 890: } /* next bufferload */
1.7 secret 891: }
892:
893:
894:
895:
1.2 timbl 896: /* Push data from a socket down a stream STRIPPING CR
897: ** --------------------------------------------------
898: **
899: ** This routine is responsible for creating and PRESENTING any
1.8 timbl 900: ** graphic (or other) objects described by the socket.
1.2 timbl 901: **
902: ** The file number given is assumed to be a TELNET stream ie containing
903: ** CRLF at the end of lines which need to be stripped to LF for unix
904: ** when the format is textual.
905: **
1.1 timbl 906: */
1.2 timbl 907: PUBLIC void HTCopyNoCR ARGS2(
908: int, file_number,
909: HTStream*, sink)
910: {
1.13 timbl 911: HTStreamClass targetClass;
912: HTInputSocket * isoc;
1.1 timbl 913:
1.2 timbl 914: /* Push the data, ignoring CRLF, down the stream
915: **
916: */
917: targetClass = *(sink->isa); /* Copy pointers to procedures */
918:
919: /* Push text from telnet socket down sink
920: **
921: ** @@@@@ To push strings could be faster? (especially is we
922: ** cheat and don't ignore CR! :-}
923: */
1.13 timbl 924: isoc = HTInputSocket_new(file_number);
1.2 timbl 925: for(;;) {
926: char character;
1.13 timbl 927: character = HTInputSocket_getCharacter(isoc);
1.2 timbl 928: if (character == (char)EOF) break;
929: (*targetClass.put_character)(sink, character);
930: }
1.13 timbl 931: HTInputSocket_free(isoc);
1.2 timbl 932: }
1.1 timbl 933:
1.2 timbl 934:
1.7 secret 935:
1.2 timbl 936: /* Parse a socket given format and file number
937: **
938: ** This routine is responsible for creating and PRESENTING any
939: ** graphic (or other) objects described by the file.
940: **
941: ** The file number given is assumed to be a TELNET stream ie containing
942: ** CRLF at the end of lines which need to be stripped to LF for unix
943: ** when the format is textual.
944: **
945: */
1.14 timbl 946:
1.12 timbl 947: PUBLIC int HTParseSocket ARGS3(
1.10 timbl 948: HTFormat, rep_in,
1.2 timbl 949: int, file_number,
1.12 timbl 950: HTRequest *, request)
1.2 timbl 951: {
952: HTStream * stream;
953: HTStreamClass targetClass;
1.1 timbl 954:
1.12 timbl 955: stream = HTStreamStack(rep_in, request);
1.2 timbl 956:
957: if (!stream) {
958: char buffer[1024]; /* @@@@@@@@ */
959: sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12 timbl 960: HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.3 timbl 961: if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
1.16 luotonen 962: return HTLoadError(request, 501, buffer);
1.2 timbl 963: }
1.1 timbl 964:
1.3 timbl 965: /* Push the data, ignoring CRLF if necessary, down the stream
966: **
1.2 timbl 967: **
1.3 timbl 968: ** @@ Bug: This decision ought to be made based on "encoding"
1.9 timbl 969: ** rather than on format. @@@ When we handle encoding.
1.3 timbl 970: ** The current method smells anyway.
1.2 timbl 971: */
972: targetClass = *(stream->isa); /* Copy pointers to procedures */
1.10 timbl 973: if (rep_in == WWW_BINARY || HTOutputSource
974: || strstr(HTAtom_name(rep_in), "image/")
975: || strstr(HTAtom_name(rep_in), "video/")) { /* @@@@@@ */
1.2 timbl 976: HTCopy(file_number, stream);
977: } else { /* ascii text with CRLFs :-( */
978: HTCopyNoCR(file_number, stream);
979: }
1.7 secret 980: (*targetClass.free)(stream);
981:
982: return HT_LOADED;
983: }
984:
985:
986:
987: /* Parse a file given format and file pointer
988: **
989: ** This routine is responsible for creating and PRESENTING any
990: ** graphic (or other) objects described by the file.
991: **
992: ** The file number given is assumed to be a TELNET stream ie containing
1.10 timbl 993: ** CRLF at the end of lines which need to be stripped to \n for unix
1.7 secret 994: ** when the format is textual.
995: **
996: */
1.12 timbl 997: PUBLIC int HTParseFile ARGS3(
1.10 timbl 998: HTFormat, rep_in,
1.7 secret 999: FILE *, fp,
1.12 timbl 1000: HTRequest *, request)
1.7 secret 1001: {
1002: HTStream * stream;
1003: HTStreamClass targetClass;
1004:
1.12 timbl 1005: stream = HTStreamStack(rep_in, request);
1.7 secret 1006:
1007: if (!stream) {
1008: char buffer[1024]; /* @@@@@@@@ */
1009: sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12 timbl 1010: HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.7 secret 1011: if (TRACE) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
1.16 luotonen 1012: return HTLoadError(request, 501, buffer);
1.7 secret 1013: }
1014:
1.9 timbl 1015: /* Push the data down the stream
1.7 secret 1016: **
1017: **
1018: ** @@ Bug: This decision ought to be made based on "encoding"
1.10 timbl 1019: ** rather than on content-type. @@@ When we handle encoding.
1.7 secret 1020: ** The current method smells anyway.
1021: */
1022: targetClass = *(stream->isa); /* Copy pointers to procedures */
1023: HTFileCopy(fp, stream);
1.2 timbl 1024: (*targetClass.free)(stream);
1.1 timbl 1025:
1.2 timbl 1026: return HT_LOADED;
1.1 timbl 1027: }
1.2 timbl 1028:
1.10 timbl 1029:
1030: /* Converter stream: Network Telnet to internal character text
1031: ** -----------------------------------------------------------
1032: **
1033: ** The input is assumed to be in ASCII, with lines delimited
1034: ** by (13,10) pairs, These pairs are converted into (CR,LF)
1035: ** pairs in the local representation. The (CR,LF) sequence
1036: ** when found is changed to a '\n' character, the internal
1037: ** C representation of a new line.
1038: */
1039:
1040:
1.11 timbl 1041: PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
1.10 timbl 1042: {
1043: char c = FROMASCII(net_char);
1044: if (me->had_cr) {
1045: if (c==LF) {
1046: me->sink->isa->put_character(me->sink, '\n'); /* Newline */
1047: me->had_cr = NO;
1048: return;
1049: } else {
1050: me->sink->isa->put_character(me->sink, CR); /* leftover */
1051: }
1052: }
1053: me->had_cr = (c==CR);
1054: if (!me->had_cr)
1055: me->sink->isa->put_character(me->sink, c); /* normal */
1056: }
1057:
1.11 timbl 1058: PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
1.10 timbl 1059: {
1060: CONST char * p;
1061: for(p=s; *p; p++) NetToText_put_character(me, *p);
1062: }
1063:
1.11 timbl 1064: PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
1.10 timbl 1065: {
1066: CONST char * p;
1067: for(p=s; p<(s+l); p++) NetToText_put_character(me, *p);
1068: }
1069:
1070: PRIVATE void NetToText_free ARGS1(HTStream *, me)
1071: {
1072: me->sink->isa->free(me->sink); /* Close rest of pipe */
1073: free(me);
1074: }
1075:
1076: PRIVATE void NetToText_abort ARGS2(HTStream *, me, HTError, e)
1077: {
1078: me->sink->isa->abort(me->sink,e); /* Abort rest of pipe */
1079: free(me);
1080: }
1081:
1082: /* The class structure
1083: */
1084: PRIVATE HTStreamClass NetToTextClass = {
1085: "NetToText",
1086: NetToText_free,
1087: NetToText_abort,
1088: NetToText_put_character,
1089: NetToText_put_string,
1090: NetToText_put_block
1091: };
1092:
1093: /* The creation method
1094: */
1095: PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
1096: {
1097: HTStream* me = (HTStream*)malloc(sizeof(*me));
1098: if (me == NULL) outofmem(__FILE__, "NetToText");
1099: me->isa = &NetToTextClass;
1100:
1101: me->had_cr = NO;
1102: me->sink = sink;
1103: return me;
1104: }
1.2 timbl 1105:
1106:
Webmaster