1 /* alephbis.c: C routines to support external OCPs
2  * based on omegabis.c from the Omega project
3 
4 This file is part of the Aleph project
5 
6 Copyright (C) 1994--2001, 2014 John Plaice and Yannis Haralambous
7 Copyright (C) 2002 Behdad Esfahbod
8 Copyright (C) 2002, 2005, 2006 Roozbeh Pournader
9 Copyright (C) 2004 the Aleph team
10 
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Library General Public
13 License as published by the Free Software Foundation; either
14 version 2 of the License, or (at your option) any later version.
15 
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 Library General Public License for more details.
20 
21 You should have received a copy of the GNU Library General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
24 
25 #define EXTERN extern
26 #include "alephd.h"
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31 #undef read
32 
33 #if 1
34 
35 void
runexternalocp(string external_ocp_name)36 runexternalocp (string external_ocp_name)
37 {
38   char *in_file_name;
39   char *out_file_name;
40   FILE *in_file;
41   FILE *out_file;
42   char command_line[400];
43   int i;
44   unsigned c;
45   int c_in;
46 #ifdef WIN32
47   const char *tempenv;
48 
49 #define null_string(s) ((s == NULL) || (*s == '\0'))
50 
51   tempenv = getenv("TMPDIR");
52   if (null_string(tempenv))
53     tempenv = getenv("TEMP");
54   if (null_string(tempenv))
55     tempenv = getenv("TMP");
56   if (null_string(tempenv))
57     tempenv = "c:/tmp";	/* "/tmp" is not good if we are on a CD-ROM */
58   in_file_name = concat(tempenv, "/__aleph__in__XXXXXX");
59   mktemp(in_file_name);
60   in_file = fopen(in_file_name, FOPEN_WBIN_MODE);
61 #else
62 #if HAVE_MKSTEMP
63   int in_file_fd;
64   int out_file_fd;
65 
66   in_file_name = xstrdup("/tmp/__aleph__in__XXXXXX");
67   in_file_fd = mkstemp(in_file_name);
68   in_file = fdopen(in_file_fd, FOPEN_WBIN_MODE);
69 #else
70 #if HAVE_MKTEMP
71   in_file_name = xstrdup("/tmp/__aleph__in__XXXXXX");
72   mktemp(in_file_name);
73 #else
74   in_file_name = xstrdup(tmpnam(NULL));
75 #endif /* HAVE_MKTEMP */
76   in_file = fopen(in_file_name, FOPEN_WBIN_MODE);
77 #endif /* HAVE_MKSTEMP */
78 
79 #endif /* WIN32 */
80 
81   if (in_file == NULL)
82     fprintf(stderr, "aleph: error opening file: %s\n", strerror(errno));
83 
84   for (i=1; i<=otpinputend; i++) {
85       c = otpinputbuf[i];
86       if (c>0xffff) {
87           fprintf(stderr, "aleph: 31-bit chars not supported, goodbye.\n");
88           exit(1);
89       }
90       if (c<0x80) {
91           fputc(c & 0x7f, in_file);
92       } else if (c<0x800) {
93           fputc(0xc0 | ((c>>6) & 0x1f), in_file);
94           fputc(0x80 | (c & 0x3f), in_file);
95       } else if (c<0x10000) {
96           fputc(0xe0 | ((c>>12) & 0xf), in_file);
97           fputc(0x80 | ((c>>6) & 0x3f), in_file);
98           fputc(0x80 | (c & 0x3f), in_file);
99       } else if (c<0x200000) {
100           fputc(0xf0 | ((c>>18) & 0x7), in_file);
101           fputc(0x80 | ((c>>12) & 0x3f), in_file);
102           fputc(0x80 | ((c>>6) & 0x3f), in_file);
103           fputc(0x80 | (c & 0x3f), in_file);
104       } else if (c<0x4000000) {
105           fputc(0xf8 | ((c>>24) & 0x3), in_file);
106           fputc(0x80 | ((c>>18) & 0x3f), in_file);
107           fputc(0x80 | ((c>>12) & 0x3f), in_file);
108           fputc(0x80 | ((c>>6) & 0x3f), in_file);
109           fputc(0x80 | (c & 0x3f), in_file);
110       } else { /* c>=0x4000000 */
111           fputc(0xfc | ((c>>30) & 0x1), in_file);
112           fputc(0x80 | ((c>>24) & 0x3f), in_file);
113           fputc(0x80 | ((c>>18) & 0x3f), in_file);
114           fputc(0x80 | ((c>>12) & 0x3f), in_file);
115           fputc(0x80 | ((c>>6) & 0x3f), in_file);
116           fputc(0x80 | (c & 0x3f), in_file);
117       }
118   }
119   fclose(in_file);
120 
121 #define advance_cin do { if ((c_in = fgetc(out_file)) == -1) { \
122                          fprintf(stderr, "File contains bad char\n"); \
123                          goto end_of_while; \
124                     } } while (0)
125 
126 #ifdef WIN32
127   out_file_name = concat(tempenv, "/__aleph__out__XXXXXX");
128   mktemp(out_file_name);
129   out_file = fopen(out_file_name, FOPEN_RBIN_MODE);
130 #else
131 
132 #if HAVE_MKSTEMP
133   out_file_name = xstrdup("/tmp/__aleph__out__XXXXXX");
134   out_file_fd = mkstemp(out_file_name);
135   out_file = fdopen(out_file_fd, FOPEN_RBIN_MODE);
136 #else
137 #if HAVE_MKTEMP
138   out_file_name = xstrdup("/tmp/__aleph__out__XXXXXX");
139   mktemp(out_file_name);
140 #else
141   out_file_name = xstrdup(tmpnam(NULL));
142 #endif /* HAVE_MKTEMP */
143   out_file = fopen(out_file_name, FOPEN_RBIN_MODE);
144 #endif /* HAVE_MKSTEMP */
145 
146 #endif /* WIN32 */
147 
148   if (out_file == NULL)
149     fprintf(stderr, "aleph: error opening file: %s\n", strerror(errno));
150 
151   if (strlen(external_ocp_name+1) + strlen(in_file_name)
152       + strlen(out_file_name) + 15 > sizeof(command_line)) { /* random 15 */
153     fprintf(stderr, "aleph: command line would be too long (%d): %s %s %s\n",
154             (int) sizeof(command_line),
155             external_ocp_name+1, in_file_name, out_file_name);
156     exit(1);
157   }
158 
159   if (strchr(external_ocp_name+1, '\'')) {
160     fprintf(stderr, "aleph: single quote not allowed in ocp name: %s\n",
161             external_ocp_name+1);
162     exit(1);
163   }
164   if (strchr(in_file_name, '\'')) {
165     fprintf(stderr, "aleph: single quote not allowed in in file name: %s\n",
166             in_file_name);
167     exit(1);
168   }
169   if (strchr(out_file_name, '\'')) {
170     fprintf(stderr, "aleph: single quote not allowed in out file name: %s\n",
171             out_file_name);
172     exit(1);
173   }
174 
175   /* ok, we've done some basic safety checks. */
176   sprintf(command_line, "'%s' <'%s' >'%s'\n",
177           external_ocp_name+1, in_file_name, out_file_name);
178   system(command_line);
179   otpoutputend = 0;
180   otpoutputbuf[otpoutputend] = 0;
181   while ((c_in = fgetc(out_file)) != -1) {
182      if (c_in<0x80) {
183          c = c_in & 0x7f;
184      } else if (c_in<0xe0) {
185          c = (c_in & 0x1f) << 6;
186          advance_cin;
187          c |= c_in & 0x3f;
188      } else if (c_in<=0xf0) {
189          c = (c_in & 0xf) << 12;
190          advance_cin;
191          c |= (c_in & 0x3f) << 6;
192          advance_cin;
193          c |= c_in & 0x3f;
194      } else if (c_in<0xf8) {
195          c = (c_in & 0x7) << 18;
196          advance_cin;
197          c |= (c_in & 0x3f) << 12;
198          advance_cin;
199          c |= (c_in & 0x3f) << 6;
200          advance_cin;
201          c |= c_in & 0x3f;
202      } else if (c_in<0xfc) {
203          c = (c_in & 0x3) << 24;
204          advance_cin;
205          c |= (c_in & 0x3f) << 18;
206          advance_cin;
207          c |= (c_in & 0x3f) << 12;
208          advance_cin;
209          c |= (c_in & 0x3f) << 6;
210          advance_cin;
211          c |= c_in & 0x3f;
212      } else { /* c>=0xfc */
213          c = (c_in & 0x1)   << 30;
214          advance_cin;
215          c |= (c_in & 0x3f) << 24;
216          advance_cin;
217          c |= (c_in & 0x3f) << 18;
218          advance_cin;
219          c |= (c_in & 0x3f) << 12;
220          advance_cin;
221          c |= (c_in & 0x3f) << 6;
222          advance_cin;
223          c |= c_in & 0x3f;
224      }
225      otpoutputbuf[++otpoutputend] = c;
226   }
227 
228 end_of_while:
229   fclose(out_file);
230   remove(in_file_name);
231   remove(out_file_name);
232   free(in_file_name);
233   free(out_file_name);
234 }
235 
236 #else /* 0 */
237 
238 void
runexternalocp(string external_ocp_name)239 runexternalocp (string external_ocp_name)
240 {
241   int outpipes[2], inpipes[2];
242   char *outbuf;
243   char *inbuf;
244   int n;
245   int chars_read_in, chars_to_go_out;
246   int myerrno;
247 
248 #ifdef WIN32
249   STARTUPINFO si;
250   PROCESS_INFORMATION pi;
251   HANDLE hIn, hOut, hPipeIn, hPipeOut;
252   SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
253   DWORD ret = 0;
254 
255   /* Make pipes to send data from the parent to the child.  The parent
256      writes to outpipes[0], and the child reads from outpipes[1].  */
257   _pipe (outpipes, 0, _O_BINARY);
258   /* Make pipes to send data from the child to the parent.  The child
259      writes to inpipes[0], and the parent reads from inpipes[1].  */
260   _pipe (inpipes, 0, _O_BINARY);
261 
262   ZeroMemory( &si, sizeof(STARTUPINFO) );
263   si.cb = sizeof(STARTUPINFO);
264   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
265   si.wShowWindow = SW_SHOW;
266   si.hStdInput = _get_osfhandle(outpipes[0]);
267   si.hStdOutput = _get_osfhandle(inpipes[1]);
268   si.hStdError = _get_osfhandle(_fileno(stderr));
269 
270   /* Close unnecessary pipes.  */
271   close (outpipes[1]);
272   close (inpipes[0]);
273 
274   if (CreateProcess(external_ocp_name+1,
275 		    NULL, /* Use lpApplicationName */
276 		    NULL,
277 		    NULL,
278 		    TRUE, /* bInheritHandles */
279 		    0,
280 		    NULL,
281 		    NULL,
282 		    &si,
283 		    &pi) == 0) {
284     fprintf(stderr, "Failed to create process for %s (Error %d).\n", external_ocp_name+1, GetLastError());
285     return;
286   }
287 
288 #else /* ! WIN32 */
289 
290   /* Make pipes to send data from the parent to the child.  The parent
291      writes to outpipes[0], and the child reads from outpipes[1].  */
292   pipe (outpipes);
293   /* Make pipes to send data from the child to the parent.  The child
294      writes to inpipes[0], and the parent reads from inpipes[1].  */
295   pipe (inpipes);
296 
297   /* For a child process.  */
298   if (fork () == 0)
299     {
300       /* This part is executed by the child process.  It translates
301          lower case letters to upper case.  */
302 
303       char *prog = external_ocp_name+1;
304       char *args[] = {external_ocp_name+1, NULL};
305 
306       /* Close unnecessary pipes.  They are for the parent.  */
307       close (outpipes[1]);
308       close (inpipes[0]);
309 
310       /* Connect pipes to stdin and stdout.  */
311       dup2 (outpipes[0], 0);
312       dup2 (inpipes[1], 1);
313 
314       /* Overlays a new process image on an old process. */
315       execv (prog, args);
316 
317       /* We should never reach here. */
318     }
319   else
320     {
321       /* Close unnecessary pipes.  They are for the child.  */
322       close (outpipes[0]);
323       close (inpipes[1]);
324 
325 #endif /* WIN32 */
326 
327 /* Here is the interesting part */
328       outbuf = ((char *) otpinputbuf)+2;
329       inbuf = ((char *) otpoutputbuf)+2;
330       chars_to_go_out = 2*otpinputend;
331       chars_read_in = 0;
332       while ((n = write (outpipes[1], outbuf, chars_to_go_out))>0) {
333 fprintf(stderr, "Wrote (1) %d characters\n", n);
334         outbuf+=n;
335         chars_to_go_out-=n;
336         if (chars_to_go_out==0) goto done_writing;
337 /*
338         n = read (inpipes[0], inbuf, 1024);
339 fprintf(stderr, "Read (1) %d characters\n", n);
340         inbuf+=n;
341         chars_read_in+=n;
342 */
343       }
344 fprintf(stderr, "Wrote (2) %d characters\n", n);
345 
346 done_writing:
347       close (outpipes[1]);
348       while ((n = read (inpipes[0], inbuf, 1024)) > 0) {
349 fprintf(stderr, "Read (2) %d characters\n", n);
350         inbuf+=n;
351         chars_read_in+=n;
352       }
353 fprintf(stderr, "Read (3) %d characters\n", n);
354       otpoutputend = chars_read_in / 2;
355 
356       close (inpipes[0]);
357 #ifndef WIN32
358     }
359 #endif
360 }
361 
362 #endif /* 0 */
363