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