Annotation of libwww/Library/src/HTFormat.c, revision 1.16
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:
67: /* Presentation methods
68: ** --------------------
69: */
70:
1.14 timbl 71: PUBLIC HTList * HTConversions = NULL;
1.2 timbl 72:
73:
74: /* Define a presentation system command for a content-type
75: ** -------------------------------------------------------
76: */
1.12 timbl 77: PUBLIC void HTSetPresentation ARGS6(
78: HTList *, conversions,
79: CONST char *, representation,
80: CONST char *, command,
81: float, quality,
82: float, secs,
83: float, secs_per_byte
1.2 timbl 84: ){
85:
86: HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
87: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
88:
89: pres->rep = HTAtom_for(representation);
90: pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
91: pres->converter = HTSaveAndExecute; /* Fixed for now ... */
92: pres->quality = quality;
93: pres->secs = secs;
94: pres->secs_per_byte = secs_per_byte;
95: pres->rep = HTAtom_for(representation);
96: pres->command = 0;
97: StrAllocCopy(pres->command, command);
98:
1.12 timbl 99: /* if (!HTPresentations) HTPresentations = HTList_new(); */
1.2 timbl 100:
1.15 luotonen 101: #ifdef OLD_CODE
102: if (strcmp(representation, "*")==0) {
1.2 timbl 103: if (default_presentation) free(default_presentation);
104: default_presentation = pres;
1.12 timbl 105: } else
106: #endif
107: HTList_addObject(conversions, pres);
1.2 timbl 108: }
109:
110:
111: /* Define a built-in function for a content-type
112: ** ---------------------------------------------
113: */
1.12 timbl 114: PUBLIC void HTSetConversion ARGS7(
115: HTList *, conversions,
116: CONST char *, representation_in,
117: CONST char *, representation_out,
1.6 timbl 118: HTConverter*, converter,
1.12 timbl 119: float, quality,
120: float, secs,
121: float, secs_per_byte
1.2 timbl 122: ){
1.1 timbl 123:
1.2 timbl 124: HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
125: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
126:
127: pres->rep = HTAtom_for(representation_in);
128: pres->rep_out = HTAtom_for(representation_out);
129: pres->converter = converter;
130: pres->command = NULL; /* Fixed */
131: pres->quality = quality;
132: pres->secs = secs;
133: pres->secs_per_byte = secs_per_byte;
134: pres->command = 0;
135:
1.12 timbl 136: /* if (!HTPresentations) HTPresentations = HTList_new(); */
1.2 timbl 137:
1.12 timbl 138: #ifdef OLD_CODE
1.2 timbl 139: if (strcmp(representation_in, "*")==0) {
140: if (default_presentation) free(default_presentation);
141: default_presentation = pres;
1.12 timbl 142: } else
143: #endif
144: HTList_addObject(conversions, pres);
1.2 timbl 145: }
1.1 timbl 146:
147:
148:
1.13 timbl 149: /* Socket Input Buffering
150: ** ----------------------
1.1 timbl 151: **
1.13 timbl 152: ** This code is used because one cannot in general open a
153: ** file descriptor for a socket.
154: **
1.1 timbl 155: ** The input file is read using the macro which can read from
1.13 timbl 156: ** a socket or a file, but this should not be used for files
157: ** as fopen() etc is more portable of course.
158: **
1.1 timbl 159: ** The input buffer size, if large will give greater efficiency and
160: ** release the server faster, and if small will save space on PCs etc.
161: */
162:
163:
164: /* Set up the buffering
165: **
166: ** These routines are public because they are in fact needed by
167: ** many parsers, and on PCs and Macs we should not duplicate
168: ** the static buffer area.
169: */
1.13 timbl 170: PUBLIC HTInputSocket * HTInputSocket_new ARGS1 (int,file_number)
1.1 timbl 171: {
1.13 timbl 172: HTInputSocket *isoc = (HTInputSocket *)malloc(sizeof(*isoc));
173: if (!isoc) outofmem(__FILE__, "HTInputSocket_new");
174: isoc->input_file_number = file_number;
175: isoc->input_pointer = isoc->input_limit = isoc->input_buffer;
176: return isoc;
1.1 timbl 177: }
178:
179:
1.13 timbl 180: PUBLIC char HTInputSocket_getCharacter ARGS1(HTInputSocket*, isoc)
1.1 timbl 181: {
182: char ch;
183: do {
1.13 timbl 184: if (isoc-> input_pointer >= isoc->input_limit) {
1.1 timbl 185: int status = NETREAD(
1.13 timbl 186: isoc->input_file_number,
187: isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1 timbl 188: if (status <= 0) {
189: if (status == 0) return (char)EOF;
190: if (TRACE) fprintf(stderr,
191: "HTFormat: File read error %d\n", status);
192: return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
193: }
1.13 timbl 194: isoc-> input_pointer = isoc->input_buffer;
195: isoc->input_limit = isoc->input_buffer + status;
1.1 timbl 196: }
1.13 timbl 197: ch = *isoc-> input_pointer++;
1.1 timbl 198: } while (ch == (char) 13); /* Ignore ASCII carriage return */
199:
200: return FROMASCII(ch);
201: }
202:
1.13 timbl 203: PUBLIC void HTInputSocket_free(HTInputSocket * me)
204: {
205: if (me) free(me);
206: }
207:
208:
1.16 ! luotonen 209: PUBLIC char * HTInputSocket_getBlock ARGS2(HTInputSocket*, isoc,
! 210: int *, len)
! 211: {
! 212: if (isoc->input_pointer >= isoc->input_limit) {
! 213: int status = NETREAD(isoc->input_file_number,
! 214: isoc->input_buffer,
! 215: ((*len < INPUT_BUFFER_SIZE) ?
! 216: *len : INPUT_BUFFER_SIZE));
! 217: if (status <= 0) {
! 218: isoc->input_limit = isoc->input_buffer;
! 219: if (status < 0)
! 220: CTRACE(stderr, "HTInputSocket: File read error %d\n", status);
! 221: *len = 0;
! 222: return NULL;
! 223: }
! 224: else {
! 225: *len = status;
! 226: return isoc->input_buffer;
! 227: }
! 228: }
! 229: else {
! 230: char * ret = isoc->input_pointer;
! 231: *len = isoc->input_limit - isoc->input_pointer;
! 232: isoc->input_pointer = isoc->input_limit;
! 233: return ret;
! 234: }
! 235: }
! 236:
! 237:
1.15 luotonen 238: PRIVATE int fill_in_buffer ARGS1(HTInputSocket *, isoc)
239: {
240: if (isoc) {
241: int status;
242:
243: isoc->input_pointer = isoc->input_buffer;
244: status = NETREAD(isoc->input_file_number,
245: isoc->input_buffer,
246: INPUT_BUFFER_SIZE);
247: if (status <= 0) {
248: isoc->input_limit = isoc->input_buffer;
249: if (status < 0)
250: if (TRACE) fprintf(stderr,
251: "HTInputSocket: File read error %d\n",
252: status);
253: }
254: else
255: isoc->input_limit = isoc->input_buffer + status;
256: return status;
257: }
258: return -1;
259: }
260:
261:
262: PRIVATE void ascii_cat ARGS3(char **, linep,
263: char *, start,
264: char *, end)
265: {
266: if (linep && start && end && start <= end) {
267: char *ptr;
268:
269: if (*linep) {
270: int len = strlen(*linep);
271: *linep = (char*)realloc(*linep, len + end-start + 1);
272: ptr = *linep + len;
273: }
274: else {
275: ptr = *linep = (char*)malloc(end-start + 1);
276: }
277:
278: while (start < end) {
279: *ptr = FROMASCII(*start);
280: ptr++;
281: start++;
282: }
283: *ptr = 0;
284: }
285: }
286:
287:
288: PRIVATE char * get_some_line ARGS2(HTInputSocket *, isoc,
289: BOOL, unfold)
290: {
291: if (!isoc)
292: return NULL;
293: else {
294: BOOL check_unfold = NO;
295: int prev_cr = 0;
296: char *start = isoc->input_pointer;
297: char *cur = isoc->input_pointer;
298: char * line = NULL;
299:
300: for(;;) {
301: /*
302: ** Get more if needed to complete line
303: */
304: if (cur >= isoc->input_limit) { /* Need more data */
305: #if 0
306: if (TRACE) fprintf(stderr, "HTInputSocket: reading more data\n");
307: #endif
308: ascii_cat(&line, start, cur);
309: if (fill_in_buffer(isoc) <= 0)
310: return line;
311: start = cur = isoc->input_pointer;
312: } /* if need more data */
313:
314: /*
315: ** Find a line feed if there is one
316: */
317: #if 0
318: if (TRACE) fprintf(stderr, "HTInputSocket: processing read buffer\n");
319: #endif
320: for(; cur < isoc->input_limit; cur++) {
321: char c = FROMASCII(*cur);
322: if (!c) {
323: #if 0
324: if (TRACE) fprintf(stderr, "HTInputSocket: panic, read zero!\n");
325: #endif
326: return NULL; /* Panic! read a 0! */
327: }
328: if (check_unfold && c != ' ' && c != '\t') {
329: #if 0
330: if (TRACE) fprintf(stderr, "HTInputSocket: returning \"%s\"\n",
331: (line ? line : "(null)"));
332: #endif
333: return line; /* Note: didn't update isoc->input_pointer */
334: }
335: else {
336: check_unfold = NO;
337: }
338:
339: if (c=='\r') {
340: #if 0
341: if (TRACE) fprintf(stderr, "HTInputSocket: found linefeed\n");
342: #endif
343: prev_cr = 1;
344: }
345: else {
346: if (c=='\n') { /* Found a line feed */
347: #if 0
348: if (TRACE) fprintf(stderr, "HTInputSocket: found newline\n");
349: #endif
350: ascii_cat(&line, start, cur-prev_cr);
351: start = isoc->input_pointer = cur+1;
352:
353: if (line && strlen(line) > 0 && unfold) {
354: #if 0
355: if (TRACE) fprintf(stderr, "HTInputSocket: next time check unfolding\n");
356: #endif
357: check_unfold = YES;
358: }
359: else {
360: #if 0
361: if (TRACE) fprintf(stderr,
362: "HTInputSocket: no unfold check -- just return \"%s\"\n",
363: (line ? line : "(line)"));
364: #endif
365: return line;
366: }
367: } /* if NL */
368: /* else just a regular character */
369: prev_cr = 0;
370: } /* if not CR */
371: } /* while characters in buffer remain */
372: } /* until line read or end-of-file */
373: } /* valid parameters to function */
374: }
375:
376:
377: PUBLIC char * HTInputSocket_getLine ARGS1(HTInputSocket *, isoc)
378: {
379: return get_some_line(isoc, NO);
380: }
381:
382: PUBLIC char * HTInputSocket_getUnfoldedLine ARGS1(HTInputSocket *, isoc)
383: {
384: return get_some_line(isoc, YES);
385: }
386:
387:
388: /*
389: ** Read HTTP status line (if there is one).
390: **
391: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
392: ** First look at the stub in ASCII and check if it starts "HTTP/".
393: **
394: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
395: ** will be taken as a HTTP 1.0 server. Failure.
396: */
397: #define STUB_LENGTH 20
398: PUBLIC char * HTInputSocket_getStatusLine ARGS1(HTInputSocket *, isoc)
399: {
400: if (!isoc) {
401: return NULL;
402: }
403: else {
404: char buf[STUB_LENGTH + 1];
405: int i;
406: char server_version[STUB_LENGTH+1];
407: int server_status;
408:
409: /*
410: ** Read initial buffer
411: */
412: if (isoc->input_pointer >= isoc->input_limit &&
413: fill_in_buffer(isoc) <= 0) {
414: return NULL;
415: }
416:
417: for (i=0; i < STUB_LENGTH; i++)
418: buf[i] = FROMASCII(isoc->input_buffer[i]);
419: buf[STUB_LENGTH] = 0;
420:
421: if (0 != strncmp(buf, "HTTP/", 5) ||
422: sscanf(buf, "%20s%d", server_version, &server_status) < 2)
423: return NULL;
424: else
425: return get_some_line(isoc, NO);
426: }
427: }
428:
429:
430: /*
431: ** Do heuristic test to see if this is binary.
432: **
433: ** We check for characters above 128 in the first few bytes, and
434: ** if we find them we forget the html default.
435: ** Kludge to trap binary responses from illegal HTTP0.9 servers.
436: **
437: ** Bugs: An HTTP 0.9 server returning a binary document with
438: ** characters < 128 will be read as ASCII.
439: */
440: PUBLIC BOOL HTInputSocket_seemsBinary ARGS1(HTInputSocket *, isoc)
441: {
442: if (isoc &&
443: (isoc->input_pointer < isoc->input_limit ||
444: fill_in_buffer(isoc) > 0)) {
445: char *p = isoc->input_buffer;
446: int i = STUB_LENGTH;
447:
448: for( ; i && p < isoc->input_limit; p++, i++)
449: if (((int)*p)&128)
450: return YES;
451: }
452: return NO;
453: }
454:
455:
456:
1.1 timbl 457: /* Stream the data to an ouput file as binary
458: */
1.13 timbl 459: PUBLIC int HTOutputBinary ARGS3( HTInputSocket *, isoc,
460: int, input,
461: FILE *, output)
1.1 timbl 462: {
463: do {
464: int status = NETREAD(
1.13 timbl 465: input, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1 timbl 466: if (status <= 0) {
467: if (status == 0) return 0;
468: if (TRACE) fprintf(stderr,
469: "HTFormat: File read error %d\n", status);
470: return 2; /* Error */
471: }
1.13 timbl 472: fwrite(isoc->input_buffer, sizeof(char), status, output);
1.1 timbl 473: } while (YES);
474: }
475:
476:
1.2 timbl 477: /* Create a filter stack
478: ** ---------------------
479: **
1.7 secret 480: ** If a wildcard match is made, a temporary HTPresentation
1.2 timbl 481: ** structure is made to hold the destination format while the
482: ** new stack is generated. This is just to pass the out format to
483: ** MIME so far. Storing the format of a stream in the stream might
484: ** be a lot neater.
1.10 timbl 485: **
486: ** The www/source format is special, in that if you can take
487: ** that you can take anything. However, we
1.2 timbl 488: */
1.12 timbl 489: PUBLIC HTStream * HTStreamStack ARGS2(
1.10 timbl 490: HTFormat, rep_in,
1.12 timbl 491: HTRequest *, request)
1.2 timbl 492: {
1.12 timbl 493: HTFormat rep_out = request->output_format; /* Could be a param */
1.14 timbl 494: HTList * conversion[2];
1.2 timbl 495: HTAtom * wildcard = HTAtom_for("*");
1.10 timbl 496: HTFormat source = WWW_SOURCE;
1.14 timbl 497: int which_list;
498: HTPresentation * pres, *match, *wildcard_match=0,
499: *source_match=0, *source_wildcard_match=0;
500:
1.2 timbl 501: if (TRACE) fprintf(stderr,
502: "HTFormat: Constructing stream stack for %s to %s\n",
1.10 timbl 503: HTAtom_name(rep_in),
1.2 timbl 504: HTAtom_name(rep_out));
505:
1.14 timbl 506:
1.15 luotonen 507: #ifdef BUG_OUT /* by Lou Montulli 16 Aug 93, put in by AL 6 Dec 93 */
1.2 timbl 508: if (rep_out == WWW_SOURCE ||
1.12 timbl 509: rep_out == rep_in) return request->output_stream;
1.15 luotonen 510: #endif
511: if (rep_out == rep_in) return request->output_stream;
1.2 timbl 512:
1.14 timbl 513: conversion[0] = request->conversions;
514: conversion[1] = HTConversions;
1.2 timbl 515:
1.15 luotonen 516: for(which_list = 0; which_list<2; which_list++) {
517: HTList * cur = conversion[which_list];
518:
519: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.10 timbl 520: if (pres->rep == rep_in) {
1.2 timbl 521: if (pres->rep_out == rep_out)
1.12 timbl 522: return (*pres->converter)(request, pres->command,
1.15 luotonen 523: rep_in, pres->rep_out,
524: request->output_stream);
1.2 timbl 525: if (pres->rep_out == wildcard) {
1.10 timbl 526: wildcard_match = pres;
527: }
528: }
529: if (pres->rep == source) {
530: if (pres->rep_out == rep_out)
531: source_match = pres;
532: if (pres->rep_out == wildcard) {
533: source_wildcard_match = pres;
1.2 timbl 534: }
535: }
536: }
537: }
1.14 timbl 538: match = wildcard_match ? wildcard_match :
539: source_match ? source_match :
540: source_wildcard_match;
541:
542: if (match) return (*match->converter)(
543: request, match->command, rep_in, rep_out,
544: request->output_stream);
1.10 timbl 545:
1.2 timbl 546: return NULL;
547: }
548:
549:
550: /* Find the cost of a filter stack
551: ** -------------------------------
552: **
553: ** Must return the cost of the same stack which StreamStack would set up.
554: **
555: ** On entry,
556: ** length The size of the data to be converted
557: */
1.12 timbl 558: PUBLIC float HTStackValue ARGS5(
1.14 timbl 559: HTList *, theseConversions,
1.10 timbl 560: HTFormat, rep_in,
1.2 timbl 561: HTFormat, rep_out,
562: float, initial_value,
563: long int, length)
564: {
565: HTAtom * wildcard = HTAtom_for("*");
1.14 timbl 566: int which_list;
567: HTList* conversion[2];
568:
1.2 timbl 569: if (TRACE) fprintf(stderr,
570: "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
1.10 timbl 571: HTAtom_name(rep_in), initial_value,
1.2 timbl 572: HTAtom_name(rep_out));
573:
574: if (rep_out == WWW_SOURCE ||
1.10 timbl 575: rep_out == rep_in) return 0.0;
1.2 timbl 576:
1.12 timbl 577: /* if (!HTPresentations) HTFormatInit(); set up the list */
1.2 timbl 578:
1.14 timbl 579: conversion[0] = theseConversions;
580: conversion[1] = HTConversions;
581:
582: for(which_list = 0; which_list<2; which_list++)
583: if (conversion[which_list]) {
1.15 luotonen 584: HTList * cur = conversion[which_list];
1.2 timbl 585: HTPresentation * pres;
1.15 luotonen 586: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
587: if (pres->rep == rep_in &&
588: (pres->rep_out == rep_out || pres->rep_out == wildcard)) {
1.2 timbl 589: float value = initial_value * pres->quality;
590: if (HTMaxSecs != 0.0)
1.15 luotonen 591: value = value - (length*pres->secs_per_byte + pres->secs)
1.2 timbl 592: /HTMaxSecs;
593: return value;
594: }
595: }
596: }
597:
598: return -1e30; /* Really bad */
599:
600: }
601:
1.1 timbl 602:
1.2 timbl 603: /* Push data from a socket down a stream
604: ** -------------------------------------
1.1 timbl 605: **
1.2 timbl 606: ** This routine is responsible for creating and PRESENTING any
1.1 timbl 607: ** graphic (or other) objects described by the file.
1.2 timbl 608: **
609: ** The file number given is assumed to be a TELNET stream ie containing
610: ** CRLF at the end of lines which need to be stripped to LF for unix
611: ** when the format is textual.
612: **
1.1 timbl 613: */
1.2 timbl 614: PUBLIC void HTCopy ARGS2(
615: int, file_number,
616: HTStream*, sink)
1.1 timbl 617: {
1.2 timbl 618: HTStreamClass targetClass;
1.13 timbl 619: HTInputSocket * isoc;
1.2 timbl 620:
1.5 timbl 621: /* Push the data down the stream
1.2 timbl 622: **
623: */
624: targetClass = *(sink->isa); /* Copy pointers to procedures */
1.13 timbl 625: isoc = HTInputSocket_new(file_number);
1.2 timbl 626:
627: /* Push binary from socket down sink
1.10 timbl 628: **
629: ** This operation could be put into a main event loop
1.2 timbl 630: */
631: for(;;) {
632: int status = NETREAD(
1.13 timbl 633: file_number, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.2 timbl 634: if (status <= 0) {
635: if (status == 0) break;
636: if (TRACE) fprintf(stderr,
637: "HTFormat: Read error, read returns %d\n", status);
638: break;
639: }
1.8 timbl 640:
641: #ifdef NOT_ASCII
642: {
643: char * p;
1.13 timbl 644: for(p = isoc->input_buffer; p < isoc->input_buffer+status; p++) {
1.8 timbl 645: *p = FROMASCII(*p);
646: }
647: }
648: #endif
649:
1.13 timbl 650: (*targetClass.put_block)(sink, isoc->input_buffer, status);
1.2 timbl 651: } /* next bufferload */
1.13 timbl 652: HTInputSocket_free(isoc);
1.2 timbl 653: }
654:
1.1 timbl 655:
1.7 secret 656:
657: /* Push data from a file pointer down a stream
658: ** -------------------------------------
659: **
660: ** This routine is responsible for creating and PRESENTING any
661: ** graphic (or other) objects described by the file.
662: **
663: **
664: */
665: PUBLIC void HTFileCopy ARGS2(
666: FILE *, fp,
667: HTStream*, sink)
668: {
669: HTStreamClass targetClass;
1.13 timbl 670: char input_buffer[INPUT_BUFFER_SIZE];
1.7 secret 671:
672: /* Push the data down the stream
673: **
674: */
675: targetClass = *(sink->isa); /* Copy pointers to procedures */
676:
677: /* Push binary from socket down sink
678: */
679: for(;;) {
680: int status = fread(
681: input_buffer, 1, INPUT_BUFFER_SIZE, fp);
682: if (status == 0) { /* EOF or error */
683: if (ferror(fp) == 0) break;
684: if (TRACE) fprintf(stderr,
685: "HTFormat: Read error, read returns %d\n", ferror(fp));
686: break;
687: }
688: (*targetClass.put_block)(sink, input_buffer, status);
1.13 timbl 689: } /* next bufferload */
1.7 secret 690: }
691:
692:
693:
694:
1.2 timbl 695: /* Push data from a socket down a stream STRIPPING CR
696: ** --------------------------------------------------
697: **
698: ** This routine is responsible for creating and PRESENTING any
1.8 timbl 699: ** graphic (or other) objects described by the socket.
1.2 timbl 700: **
701: ** The file number given is assumed to be a TELNET stream ie containing
702: ** CRLF at the end of lines which need to be stripped to LF for unix
703: ** when the format is textual.
704: **
1.1 timbl 705: */
1.2 timbl 706: PUBLIC void HTCopyNoCR ARGS2(
707: int, file_number,
708: HTStream*, sink)
709: {
1.13 timbl 710: HTStreamClass targetClass;
711: HTInputSocket * isoc;
1.1 timbl 712:
1.2 timbl 713: /* Push the data, ignoring CRLF, down the stream
714: **
715: */
716: targetClass = *(sink->isa); /* Copy pointers to procedures */
717:
718: /* Push text from telnet socket down sink
719: **
720: ** @@@@@ To push strings could be faster? (especially is we
721: ** cheat and don't ignore CR! :-}
722: */
1.13 timbl 723: isoc = HTInputSocket_new(file_number);
1.2 timbl 724: for(;;) {
725: char character;
1.13 timbl 726: character = HTInputSocket_getCharacter(isoc);
1.2 timbl 727: if (character == (char)EOF) break;
728: (*targetClass.put_character)(sink, character);
729: }
1.13 timbl 730: HTInputSocket_free(isoc);
1.2 timbl 731: }
1.1 timbl 732:
1.2 timbl 733:
1.7 secret 734:
1.2 timbl 735: /* Parse a socket given format and file number
736: **
737: ** This routine is responsible for creating and PRESENTING any
738: ** graphic (or other) objects described by the file.
739: **
740: ** The file number given is assumed to be a TELNET stream ie containing
741: ** CRLF at the end of lines which need to be stripped to LF for unix
742: ** when the format is textual.
743: **
744: */
1.14 timbl 745:
1.12 timbl 746: PUBLIC int HTParseSocket ARGS3(
1.10 timbl 747: HTFormat, rep_in,
1.2 timbl 748: int, file_number,
1.12 timbl 749: HTRequest *, request)
1.2 timbl 750: {
751: HTStream * stream;
752: HTStreamClass targetClass;
1.1 timbl 753:
1.12 timbl 754: stream = HTStreamStack(rep_in, request);
1.2 timbl 755:
756: if (!stream) {
757: char buffer[1024]; /* @@@@@@@@ */
758: sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12 timbl 759: HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.3 timbl 760: if (TRACE) fprintf(stderr, "HTFormat: %s\n", buffer);
1.16 ! luotonen 761: return HTLoadError(request, 501, buffer);
1.2 timbl 762: }
1.1 timbl 763:
1.3 timbl 764: /* Push the data, ignoring CRLF if necessary, down the stream
765: **
1.2 timbl 766: **
1.3 timbl 767: ** @@ Bug: This decision ought to be made based on "encoding"
1.9 timbl 768: ** rather than on format. @@@ When we handle encoding.
1.3 timbl 769: ** The current method smells anyway.
1.2 timbl 770: */
771: targetClass = *(stream->isa); /* Copy pointers to procedures */
1.10 timbl 772: if (rep_in == WWW_BINARY || HTOutputSource
773: || strstr(HTAtom_name(rep_in), "image/")
774: || strstr(HTAtom_name(rep_in), "video/")) { /* @@@@@@ */
1.2 timbl 775: HTCopy(file_number, stream);
776: } else { /* ascii text with CRLFs :-( */
777: HTCopyNoCR(file_number, stream);
778: }
1.7 secret 779: (*targetClass.free)(stream);
780:
781: return HT_LOADED;
782: }
783:
784:
785:
786: /* Parse a file given format and file pointer
787: **
788: ** This routine is responsible for creating and PRESENTING any
789: ** graphic (or other) objects described by the file.
790: **
791: ** The file number given is assumed to be a TELNET stream ie containing
1.10 timbl 792: ** CRLF at the end of lines which need to be stripped to \n for unix
1.7 secret 793: ** when the format is textual.
794: **
795: */
1.12 timbl 796: PUBLIC int HTParseFile ARGS3(
1.10 timbl 797: HTFormat, rep_in,
1.7 secret 798: FILE *, fp,
1.12 timbl 799: HTRequest *, request)
1.7 secret 800: {
801: HTStream * stream;
802: HTStreamClass targetClass;
803:
1.12 timbl 804: stream = HTStreamStack(rep_in, request);
1.7 secret 805:
806: if (!stream) {
807: char buffer[1024]; /* @@@@@@@@ */
808: sprintf(buffer, "Sorry, can't convert from %s to %s.",
1.12 timbl 809: HTAtom_name(rep_in), HTAtom_name(request->output_format));
1.7 secret 810: if (TRACE) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
1.16 ! luotonen 811: return HTLoadError(request, 501, buffer);
1.7 secret 812: }
813:
1.9 timbl 814: /* Push the data down the stream
1.7 secret 815: **
816: **
817: ** @@ Bug: This decision ought to be made based on "encoding"
1.10 timbl 818: ** rather than on content-type. @@@ When we handle encoding.
1.7 secret 819: ** The current method smells anyway.
820: */
821: targetClass = *(stream->isa); /* Copy pointers to procedures */
822: HTFileCopy(fp, stream);
1.2 timbl 823: (*targetClass.free)(stream);
1.1 timbl 824:
1.2 timbl 825: return HT_LOADED;
1.1 timbl 826: }
1.2 timbl 827:
1.10 timbl 828:
829: /* Converter stream: Network Telnet to internal character text
830: ** -----------------------------------------------------------
831: **
832: ** The input is assumed to be in ASCII, with lines delimited
833: ** by (13,10) pairs, These pairs are converted into (CR,LF)
834: ** pairs in the local representation. The (CR,LF) sequence
835: ** when found is changed to a '\n' character, the internal
836: ** C representation of a new line.
837: */
838:
839:
1.11 timbl 840: PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, net_char)
1.10 timbl 841: {
842: char c = FROMASCII(net_char);
843: if (me->had_cr) {
844: if (c==LF) {
845: me->sink->isa->put_character(me->sink, '\n'); /* Newline */
846: me->had_cr = NO;
847: return;
848: } else {
849: me->sink->isa->put_character(me->sink, CR); /* leftover */
850: }
851: }
852: me->had_cr = (c==CR);
853: if (!me->had_cr)
854: me->sink->isa->put_character(me->sink, c); /* normal */
855: }
856:
1.11 timbl 857: PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
1.10 timbl 858: {
859: CONST char * p;
860: for(p=s; *p; p++) NetToText_put_character(me, *p);
861: }
862:
1.11 timbl 863: PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
1.10 timbl 864: {
865: CONST char * p;
866: for(p=s; p<(s+l); p++) NetToText_put_character(me, *p);
867: }
868:
869: PRIVATE void NetToText_free ARGS1(HTStream *, me)
870: {
871: me->sink->isa->free(me->sink); /* Close rest of pipe */
872: free(me);
873: }
874:
875: PRIVATE void NetToText_abort ARGS2(HTStream *, me, HTError, e)
876: {
877: me->sink->isa->abort(me->sink,e); /* Abort rest of pipe */
878: free(me);
879: }
880:
881: /* The class structure
882: */
883: PRIVATE HTStreamClass NetToTextClass = {
884: "NetToText",
885: NetToText_free,
886: NetToText_abort,
887: NetToText_put_character,
888: NetToText_put_string,
889: NetToText_put_block
890: };
891:
892: /* The creation method
893: */
894: PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
895: {
896: HTStream* me = (HTStream*)malloc(sizeof(*me));
897: if (me == NULL) outofmem(__FILE__, "NetToText");
898: me->isa = &NetToTextClass;
899:
900: me->had_cr = NO;
901: me->sink = sink;
902: return me;
903: }
1.2 timbl 904:
905:
Webmaster