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