Annotation of libwww/Library/src/HTFormat.c, revision 1.2
1.1 timbl 1: /* Manage different file formats HTFormat.c
2: ** =============================
3: **
4: ** Bugs:
5: ** Not reentrant.
6: **
7: ** Assumes the incoming stream is ASCII, rather than a local file
8: ** format, and so ALWAYS converts from ASCII on non-ASCII machines.
9: ** Therefore, non-ASCII machines can't read local files.
1.2 ! timbl 10: **
! 11: ** Bugs: Big shakeup comming here
! 12: */
! 13:
! 14: /* Implements:
1.1 timbl 15: */
1.2 ! timbl 16: #include "HTFormat.h"
! 17:
! 18: PUBLIC float HTMaxSecs = 1e10; /* No effective limit */
! 19: PUBLIC float HTMaxLength = 1e10; /* No effective limit */
! 20:
! 21: #ifdef unix
! 22: #ifdef NeXT
! 23: #define PRESENT_POSTSCRIPT "open %s; /bin/rm -f %s\n"
! 24: #else
! 25: #define PRESENT_POSTSCRIPT "(ghostview %s ; /bin/rm -f %s)&\n"
! 26: /* Full pathname would be better! */
! 27: #endif
! 28: #endif
! 29:
1.1 timbl 30:
31: #include "HTUtils.h"
32: #include "tcp.h"
33:
34: #include "HTML.h"
1.2 ! timbl 35: #include "HTMLDTD.h"
1.1 timbl 36: #include "HText.h"
1.2 ! timbl 37: #include "HTAlert.h"
! 38: #include "HTList.h"
! 39: #include "HTInit.h"
! 40: /* Streams and structured streams which we use:
! 41: */
! 42: #include "HTFWriter.h"
! 43: #include "HTPlain.h"
! 44: #include "SGML.h"
! 45: #include "HTML.h"
! 46: #include "HTMLGen.h"
! 47:
! 48: PUBLIC BOOL HTOutputSource = NO; /* Flag: shortcut parser to stdout */
! 49: extern BOOL interactive;
! 50:
! 51: struct _HTStream {
! 52: CONST HTStreamClass* isa;
! 53: /* ... */
! 54: };
! 55:
! 56:
! 57: /* Presentation methods
! 58: ** --------------------
! 59: */
! 60:
! 61: PUBLIC HTList * HTPresentations = 0;
! 62: PUBLIC HTPresentation* default_presentation = 0;
! 63:
! 64:
! 65: /* Define a presentation system command for a content-type
! 66: ** -------------------------------------------------------
! 67: */
! 68: PUBLIC void HTSetPresentation ARGS5(
! 69: CONST char *, representation,
! 70: CONST char *, command,
! 71: float, quality,
! 72: float, secs,
! 73: float, secs_per_byte
! 74: ){
! 75:
! 76: HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
! 77: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
! 78:
! 79: pres->rep = HTAtom_for(representation);
! 80: pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
! 81: pres->converter = HTSaveAndExecute; /* Fixed for now ... */
! 82: pres->quality = quality;
! 83: pres->secs = secs;
! 84: pres->secs_per_byte = secs_per_byte;
! 85: pres->rep = HTAtom_for(representation);
! 86: pres->command = 0;
! 87: StrAllocCopy(pres->command, command);
! 88:
! 89: if (!HTPresentations) HTPresentations = HTList_new();
! 90:
! 91: if (strcmp(representation, "*")==0) {
! 92: if (default_presentation) free(default_presentation);
! 93: default_presentation = pres;
! 94: } else {
! 95: HTList_addObject(HTPresentations, pres);
! 96: }
! 97: }
! 98:
! 99:
! 100: /* Define a built-in function for a content-type
! 101: ** ---------------------------------------------
! 102: */
! 103: PUBLIC void HTSetConversion ARGS6(
! 104: CONST char *, representation_in,
! 105: CONST char *, representation_out,
! 106: HTConverter, converter,
! 107: float, quality,
! 108: float, secs,
! 109: float, secs_per_byte
! 110: ){
1.1 timbl 111:
1.2 ! timbl 112: HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
! 113: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
! 114:
! 115: pres->rep = HTAtom_for(representation_in);
! 116: pres->rep_out = HTAtom_for(representation_out);
! 117: pres->converter = converter;
! 118: pres->command = NULL; /* Fixed */
! 119: pres->quality = quality;
! 120: pres->secs = secs;
! 121: pres->secs_per_byte = secs_per_byte;
! 122: pres->command = 0;
! 123:
! 124: if (!HTPresentations) HTPresentations = HTList_new();
! 125:
! 126: if (strcmp(representation_in, "*")==0) {
! 127: if (default_presentation) free(default_presentation);
! 128: default_presentation = pres;
! 129: } else {
! 130: HTList_addObject(HTPresentations, pres);
! 131: }
! 132: }
1.1 timbl 133:
134:
135:
136: /* File buffering
137: ** --------------
138: **
139: ** The input file is read using the macro which can read from
140: ** a socket or a file.
141: ** The input buffer size, if large will give greater efficiency and
142: ** release the server faster, and if small will save space on PCs etc.
143: */
144: #define INPUT_BUFFER_SIZE 4096 /* Tradeoff */
145: PRIVATE char input_buffer[INPUT_BUFFER_SIZE];
146: PRIVATE char * input_pointer;
147: PRIVATE char * input_limit;
148: PRIVATE int input_file_number;
149:
150:
151: /* Set up the buffering
152: **
153: ** These routines are public because they are in fact needed by
154: ** many parsers, and on PCs and Macs we should not duplicate
155: ** the static buffer area.
156: */
157: PUBLIC void HTInitInput ARGS1 (int,file_number)
158: {
159: input_file_number = file_number;
160: input_pointer = input_limit = input_buffer;
161: }
162:
163:
164: PUBLIC char HTGetChararcter NOARGS
165: {
166: char ch;
167: do {
168: if (input_pointer >= input_limit) {
169: int status = NETREAD(
170: input_file_number, input_buffer, INPUT_BUFFER_SIZE);
171: if (status <= 0) {
172: if (status == 0) return (char)EOF;
173: if (TRACE) fprintf(stderr,
174: "HTFormat: File read error %d\n", status);
175: return (char)EOF; /* -1 is returned by UCX at end of HTTP link */
176: }
177: input_pointer = input_buffer;
178: input_limit = input_buffer + status;
179: }
180: ch = *input_pointer++;
181: } while (ch == (char) 13); /* Ignore ASCII carriage return */
182:
183: return FROMASCII(ch);
184: }
185:
186: /* Stream the data to an ouput file as binary
187: */
188: PUBLIC int HTOutputBinary ARGS2( int, input,
189: FILE *, output)
190: {
191: do {
192: int status = NETREAD(
193: input, input_buffer, INPUT_BUFFER_SIZE);
194: if (status <= 0) {
195: if (status == 0) return 0;
196: if (TRACE) fprintf(stderr,
197: "HTFormat: File read error %d\n", status);
198: return 2; /* Error */
199: }
200: fwrite(input_buffer, sizeof(char), status, output);
201: } while (YES);
202: }
203:
204:
1.2 ! timbl 205: /* Create a filter stack
! 206: ** ---------------------
! 207: **
! 208: ** If a widlcard match is made, a temporary HTPresentation
! 209: ** structure is made to hold the destination format while the
! 210: ** new stack is generated. This is just to pass the out format to
! 211: ** MIME so far. Storing the format of a stream in the stream might
! 212: ** be a lot neater.
! 213: */
! 214: PUBLIC HTStream * HTStreamStack ARGS4(
! 215: HTFormat, format_in,
! 216: HTFormat, rep_out,
! 217: HTStream*, sink,
! 218: HTParentAnchor*, anchor)
! 219: {
! 220: HTAtom * wildcard = HTAtom_for("*");
! 221: HTPresentation temp;
! 222: if (TRACE) fprintf(stderr,
! 223: "HTFormat: Constructing stream stack for %s to %s\n",
! 224: HTAtom_name(format_in),
! 225: HTAtom_name(rep_out));
! 226:
! 227: if (rep_out == WWW_SOURCE ||
! 228: rep_out == format_in) return sink;
! 229:
! 230: if (!HTPresentations) HTFormatInit(); /* set up the list */
! 231:
! 232: {
! 233: int n = HTList_count(HTPresentations);
! 234: int i;
! 235: HTPresentation * pres;
! 236: for(i=0; i<n; i++) {
! 237: pres = HTList_objectAt(HTPresentations, i);
! 238: if (pres->rep == format_in) {
! 239: if (pres->rep_out == rep_out)
! 240: return (*pres->converter)(pres, anchor, sink);
! 241: if (pres->rep_out == wildcard) {
! 242: temp = *pres;/* make temp conversion to needed fmt */
! 243: temp.rep_out = rep_out; /* yuk */
! 244: return (*pres->converter)(&temp, anchor, sink);
! 245: }
! 246: }
! 247: }
! 248: }
! 249:
! 250: /* if (HTConfirm("Save as temporary file?"))
! 251: return HTSaveAndExecute("ls -l %s", ".ps");
! 252: */
! 253: return NULL;
! 254:
! 255: }
! 256:
! 257:
! 258: /* Find the cost of a filter stack
! 259: ** -------------------------------
! 260: **
! 261: ** Must return the cost of the same stack which StreamStack would set up.
! 262: **
! 263: ** On entry,
! 264: ** length The size of the data to be converted
! 265: */
! 266: PUBLIC float HTStackValue ARGS4(
! 267: HTFormat, format_in,
! 268: HTFormat, rep_out,
! 269: float, initial_value,
! 270: long int, length)
! 271: {
! 272: HTAtom * wildcard = HTAtom_for("*");
! 273:
! 274: if (TRACE) fprintf(stderr,
! 275: "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
! 276: HTAtom_name(format_in), initial_value,
! 277: HTAtom_name(rep_out));
! 278:
! 279: if (rep_out == WWW_SOURCE ||
! 280: rep_out == format_in) return 0.0;
! 281:
! 282: if (!HTPresentations) HTFormatInit(); /* set up the list */
! 283:
! 284: {
! 285: int n = HTList_count(HTPresentations);
! 286: int i;
! 287: HTPresentation * pres;
! 288: for(i=0; i<n; i++) {
! 289: pres = HTList_objectAt(HTPresentations, i);
! 290: if (pres->rep == format_in && (
! 291: pres->rep_out == rep_out ||
! 292: pres->rep_out == wildcard)) {
! 293: float value = initial_value * pres->quality;
! 294: if (HTMaxSecs != 0.0)
! 295: value = value - (length*pres->secs_per_byte + pres->secs)
! 296: /HTMaxSecs;
! 297: return value;
! 298: }
! 299: }
! 300: }
! 301:
! 302: return -1e30; /* Really bad */
! 303:
! 304: }
! 305:
1.1 timbl 306:
1.2 ! timbl 307: /* Push data from a socket down a stream
! 308: ** -------------------------------------
1.1 timbl 309: **
1.2 ! timbl 310: ** This routine is responsible for creating and PRESENTING any
1.1 timbl 311: ** graphic (or other) objects described by the file.
1.2 ! timbl 312: **
! 313: ** The file number given is assumed to be a TELNET stream ie containing
! 314: ** CRLF at the end of lines which need to be stripped to LF for unix
! 315: ** when the format is textual.
! 316: **
1.1 timbl 317: */
1.2 ! timbl 318: PUBLIC void HTCopy ARGS2(
! 319: int, file_number,
! 320: HTStream*, sink)
1.1 timbl 321: {
1.2 ! timbl 322: HTStreamClass targetClass;
! 323:
! 324: /* Push the data, ignoring CRLF, down the stream
! 325: **
! 326: */
! 327: targetClass = *(sink->isa); /* Copy pointers to procedures */
! 328:
! 329: /* Push binary from socket down sink
! 330: */
! 331: for(;;) {
! 332: int status = NETREAD(
! 333: file_number, input_buffer, INPUT_BUFFER_SIZE);
! 334: if (status <= 0) {
! 335: if (status == 0) break;
! 336: if (TRACE) fprintf(stderr,
! 337: "HTFormat: Read error, read returns %d\n", status);
! 338: break;
! 339: }
! 340: (*targetClass.write)(sink, input_buffer, status);
! 341: } /* next bufferload */
! 342:
! 343: }
! 344:
1.1 timbl 345:
1.2 ! timbl 346: /* Push data from a socket down a stream STRIPPING CR
! 347: ** --------------------------------------------------
! 348: **
! 349: ** This routine is responsible for creating and PRESENTING any
! 350: ** graphic (or other) objects described by the file.
! 351: **
! 352: ** The file number given is assumed to be a TELNET stream ie containing
! 353: ** CRLF at the end of lines which need to be stripped to LF for unix
! 354: ** when the format is textual.
! 355: **
1.1 timbl 356: */
1.2 ! timbl 357: PUBLIC void HTCopyNoCR ARGS2(
! 358: int, file_number,
! 359: HTStream*, sink)
! 360: {
! 361: HTStreamClass targetClass;
1.1 timbl 362:
1.2 ! timbl 363: /* Push the data, ignoring CRLF, down the stream
! 364: **
! 365: */
! 366: targetClass = *(sink->isa); /* Copy pointers to procedures */
! 367:
! 368: /* Push text from telnet socket down sink
! 369: **
! 370: ** @@@@@ To push strings could be faster? (especially is we
! 371: ** cheat and don't ignore CR! :-}
! 372: */
1.1 timbl 373: HTInitInput(file_number);
1.2 ! timbl 374: for(;;) {
! 375: char character;
! 376: character = HTGetChararcter();
! 377: if (character == (char)EOF) break;
! 378: (*targetClass.put_character)(sink, character);
! 379: }
! 380: }
1.1 timbl 381:
1.2 ! timbl 382:
! 383: /* Parse a socket given format and file number
! 384: **
! 385: ** This routine is responsible for creating and PRESENTING any
! 386: ** graphic (or other) objects described by the file.
! 387: **
! 388: ** The file number given is assumed to be a TELNET stream ie containing
! 389: ** CRLF at the end of lines which need to be stripped to LF for unix
! 390: ** when the format is textual.
! 391: **
! 392: */
! 393: PUBLIC int HTParseSocket ARGS5(
! 394: HTFormat, format_in,
! 395: HTFormat, format_out,
! 396: HTParentAnchor *, anchor,
! 397: int, file_number,
! 398: HTStream*, sink)
! 399: {
! 400: HTStream * stream;
! 401: HTStreamClass targetClass;
1.1 timbl 402:
1.2 ! timbl 403: stream = HTStreamStack(format_in,
! 404: format_out,
! 405: sink , anchor);
! 406:
! 407: if (!stream) {
! 408: char buffer[1024]; /* @@@@@@@@ */
! 409: sprintf(buffer, "Sorry, can't convert from %s to %s.",
! 410: HTAtom_name(format_in), HTAtom_name(format_out));
! 411: fprintf(stderr, "HTFormat: %s", buffer);
! 412: return HTLoadError(sink, 501, buffer);
! 413: }
1.1 timbl 414:
1.2 ! timbl 415: /* Push the data, ignoring CRLF, down the stream
! 416: **
! 417: */
! 418: targetClass = *(stream->isa); /* Copy pointers to procedures */
! 419: if (format_in == WWW_BINARY || HTOutputSource) { /* @@@@@@ */
! 420: HTCopy(file_number, stream);
! 421: } else { /* ascii text with CRLFs :-( */
! 422: HTCopyNoCR(file_number, stream);
! 423: }
! 424: (*targetClass.end_document)(stream);
! 425: (*targetClass.free)(stream);
1.1 timbl 426:
1.2 ! timbl 427: return HT_LOADED;
1.1 timbl 428: }
1.2 ! timbl 429:
! 430:
! 431:
Webmaster