1 /**
2  * Copyright (C) 2001-2002 Artifex Software, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23 **/
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "ijs.h"
29 #include "ijs_server.h"
30 
31 #define BUF_SIZE 4096
32 
33 typedef struct _ExampleParamList ExampleParamList;
34 
35 struct _ExampleParamList {
36   ExampleParamList *next;
37   char *key;
38   char *value;
39   int value_size;
40 };
41 
42 static int
example_status_cb(void * status_cb_data,IjsServerCtx * ctx,IjsJobId job_id)43 example_status_cb (void *status_cb_data,
44 		  IjsServerCtx *ctx,
45 		  IjsJobId job_id)
46 {
47   return 0;
48 }
49 
50 static int
example_list_cb(void * list_cb_data,IjsServerCtx * ctx,IjsJobId job_id,char * val_buf,int val_size)51 example_list_cb (void *list_cb_data,
52 		 IjsServerCtx *ctx,
53 		 IjsJobId job_id,
54 		 char *val_buf,
55 		 int val_size)
56 {
57   const char *param_list = "OutputFile,DeviceManufacturer,DeviceModel,PageImageFormat,Dpi,Width,Height,BitsPerSample,ColorSpace,NumChan,PaperSize,PrintableArea,PrintableTopLeft,TopLeft";
58   int size = strlen (param_list);
59 
60   fprintf (stderr, "example_list_cb\n");
61 
62   if (size > val_size)
63     return IJS_EBUF;
64 
65   memcpy (val_buf, param_list, size);
66   return size;
67 }
68 
69 static int
example_enum_cb(void * enum_cb_data,IjsServerCtx * ctx,IjsJobId job_id,const char * key,char * val_buf,int val_size)70 example_enum_cb (void *enum_cb_data,
71 		 IjsServerCtx *ctx,
72 		 IjsJobId job_id,
73 		 const char *key,
74 		 char *val_buf,
75 		 int val_size)
76 {
77   const char *val = NULL;
78   if (!strcmp (key, "ColorSpace"))
79     val = "DeviceRGB,DeviceGray,DeviceCMYK";
80   else if (!strcmp (key, "DeviceManufacturer"))
81     val = "IJS Distribution";
82   else if (!strcmp (key, "DeviceModel"))
83     val = "ijs_server_example";
84   else if (!strcmp (key, "PageImageFormat"))
85     val = "Raster";
86 
87   if (val == NULL)
88     return IJS_EUNKPARAM;
89   else
90     {
91       int size = strlen (val);
92 
93       if (size > val_size)
94 	return IJS_EBUF;
95       memcpy (val_buf, val, size);
96       return size;
97     }
98 }
99 
100 /* A C implementation of /^(\d\.+\-eE)+x(\d\.+\-eE)+$/ */
101 static int
example_parse_wxh(const char * val,int size,double * pw,double * ph)102 example_parse_wxh (const char *val, int size,
103 		   double *pw, double *ph)
104 {
105   char buf[256];
106   char *tail;
107   int i;
108 
109   for (i = 0; i < size; i++)
110     if (val[i] == 'x')
111       break;
112 
113   if (i + 1 >= size)
114     return IJS_ESYNTAX;
115 
116   if (i >= sizeof(buf))
117     return IJS_EBUF;
118 
119   memcpy (buf, val, i);
120   buf[i] = 0;
121   *pw = strtod (buf, &tail);
122   if (tail == buf)
123     return IJS_ESYNTAX;
124 
125   if (size - i > sizeof(buf))
126     return IJS_EBUF;
127 
128   memcpy (buf, val + i + 1, size - i - 1);
129   buf[size - i - 1] = 0;
130   *ph = strtod (buf, &tail);
131   if (tail == buf)
132     return IJS_ESYNTAX;
133 
134   return 0;
135 }
136 
137 /**
138  * example_find_key: Search parameter list for key.
139  *
140  * @key: key to look up
141  *
142  * Return value: ExampleParamList entry matching @key, or NULL.
143  **/
144 static ExampleParamList *
example_find_key(ExampleParamList * pl,const char * key)145 example_find_key (ExampleParamList *pl, const char *key)
146 {
147   ExampleParamList *curs;
148 
149   for (curs = pl; curs != NULL; curs = curs->next)
150     {
151       if (!strcmp (curs->key, key))
152 	return curs;
153     }
154   return NULL;
155 }
156 
157 /**
158  * @printable: An array in which to store the printable area.
159  *
160  * On return, @printable = PrintableArea[0:1] + TopLeft[0:1]
161  **/
162 static int
example_compute_printable(ExampleParamList * pl,double printable[4])163 example_compute_printable (ExampleParamList *pl, double printable[4])
164 {
165   ExampleParamList *curs;
166   double width, height;
167   int code;
168   double margin = 0.5;
169 
170   curs = example_find_key (pl, "PaperSize");
171   if (curs == NULL)
172     return -1;
173   code = example_parse_wxh (curs->value, curs->value_size, &width, &height);
174 
175   if (code == 0)
176     {
177       printable[0] = width - 2 * margin;
178       printable[1] = height - 2 * margin;
179       printable[2] = margin;
180       printable[3] = margin;
181     }
182 
183   return code;
184 }
185 
186 static int
example_compute_offset(ExampleParamList * pl,IjsPageHeader * ph,double * px0,double * py0)187 example_compute_offset (ExampleParamList *pl, IjsPageHeader *ph,
188 			double *px0, double *py0)
189 {
190   ExampleParamList *curs;
191   double width, height;
192   double top, left;
193   int code;
194 
195   *px0 = 0;
196   *py0 = 0;
197 
198   curs = example_find_key (pl, "PaperSize");
199   if (curs == NULL)
200     return -1;
201 
202   code = example_parse_wxh (curs->value, curs->value_size, &width, &height);
203 
204   if (code == 0)
205     {
206       curs = example_find_key (pl, "TopLeft");
207       if (curs != NULL)
208 	{
209 	  code = example_parse_wxh (curs->value, curs->value_size,
210 				    &top, &left);
211 	}
212       else
213 	{
214 	  double printable[4];
215 
216 	  code = example_compute_printable (pl, printable);
217 	  if (code == 0)
218 	    {
219 	      top = printable[2];
220 	      left = printable[3];
221 	    }
222 	}
223     }
224 
225   if (code == 0)
226     {
227       *px0 = left;
228       *py0 = height - ph->height / ph->yres - top;
229     }
230 
231   return code;
232 }
233 
234 static int
example_get_cb(void * get_cb_data,IjsServerCtx * ctx,IjsJobId job_id,const char * key,char * val_buf,int val_size)235 example_get_cb (void *get_cb_data,
236 		 IjsServerCtx *ctx,
237 		 IjsJobId job_id,
238 		 const char *key,
239 		 char *val_buf,
240 		 int val_size)
241 {
242   ExampleParamList *pl = *(ExampleParamList **)get_cb_data;
243   ExampleParamList *curs;
244   const char *val;
245   char buf[256];
246   int code;
247 
248   fprintf (stderr, "example_get_cb: %s\n", key);
249   curs = example_find_key (pl, key);
250   if (curs != NULL)
251     {
252       if (curs->value_size > val_size)
253 	return IJS_EBUF;
254       memcpy (val_buf, curs->value, curs->value_size);
255       return curs->value_size;
256     }
257 
258   if (!strcmp (key, "PrintableArea") || !strcmp (key, "PrintableTopLeft"))
259     {
260       double printable[4];
261       int off = !strcmp (key, "PrintableArea") ? 0 : 2;
262 
263       code = example_compute_printable (pl, printable);
264       if (code == 0)
265 	{
266 	  sprintf (buf, "%gx%g", printable[off + 0], printable[off + 1]);
267 	  val = buf;
268 	}
269     }
270 
271   if (!strcmp (key, "DeviceManufacturer"))
272     val = "IJS Distribution";
273   else if (!strcmp (key, "DeviceModel"))
274     val = "ijs_server_example";
275   else if (!strcmp (key, "PageImageFormat"))
276     val = "Raster";
277 
278   if (val == NULL)
279     return IJS_EUNKPARAM;
280   else
281     {
282       int size = strlen (val);
283 
284       if (size > val_size)
285 	return IJS_EBUF;
286       memcpy (val_buf, val, size);
287       return size;
288     }
289 }
290 
291 static int
example_set_cb(void * set_cb_data,IjsServerCtx * ctx,IjsJobId job_id,const char * key,const char * value,int value_size)292 example_set_cb (void *set_cb_data, IjsServerCtx *ctx, IjsJobId job_id,
293 		const char *key, const char *value, int value_size)
294 {
295   ExampleParamList **ppl = (ExampleParamList **)set_cb_data;
296   ExampleParamList *pl;
297   int key_len = strlen (key);
298   int code;
299 
300   fprintf (stderr, "example_set_cb: %s=", key);
301 
302   if (!strcmp (key, "PaperSize"))
303     {
304       double width, height;
305 
306       code = example_parse_wxh (value, value_size, &width, &height);
307       if (code < 0)
308 	return code;
309     }
310 
311   fwrite (value, 1, value_size, stderr);
312   fputs ("\n", stderr);
313 
314   pl = example_find_key (*ppl, key);
315 
316   if (pl == NULL)
317     {
318       pl = (ExampleParamList *)malloc (sizeof (ExampleParamList));
319       pl->next = *ppl;
320       pl->key = malloc (key_len + 1);
321       memcpy (pl->key, key, key_len + 1);
322       *ppl = pl;
323     }
324   else
325     {
326       free (pl->value);
327     }
328 
329   pl->value = malloc (value_size);
330   memcpy (pl->value, value, value_size);
331   pl->value_size = value_size;
332   return 0;
333 }
334 
335 /**
336  * Finds a parameter in the param list, and allocates a null terminated
337  * string with the value.
338  **/
339 static char *
find_param(ExampleParamList * pl,const char * key)340 find_param (ExampleParamList *pl, const char *key)
341 {
342   ExampleParamList *curs;
343   char *result;
344 
345   curs = example_find_key (pl, key);
346   if (curs == NULL)
347     return NULL;
348 
349   result = malloc (curs->value_size + 1);
350   memcpy (result, curs->value, curs->value_size);
351   result[curs->value_size] = 0;
352   return result;
353 }
354 
355 static void
free_param_list(ExampleParamList * pl)356 free_param_list (ExampleParamList *pl)
357 {
358   ExampleParamList *next;
359 
360   for (; pl != NULL; pl = next)
361     {
362       next = pl->next;
363       free (pl->key);
364       free (pl->value);
365       free (pl);
366     }
367 }
368 
369 int
main(int argc,char ** argv)370 main (int argc, char **argv)
371 {
372   IjsServerCtx *ctx;
373   IjsPageHeader ph;
374   int status;
375   char buf[BUF_SIZE];
376   char hexbuf[BUF_SIZE * 3];
377   char *fn;
378   FILE *f = NULL;
379   double xscale, yscale;
380   double x0, y0;
381   ExampleParamList *pl = NULL;
382 
383   ctx = ijs_server_init ();
384   if (ctx == NULL)
385     return (1);
386   ijs_server_install_status_cb (ctx, example_status_cb, &pl);
387   ijs_server_install_list_cb (ctx, example_list_cb, &pl);
388   ijs_server_install_enum_cb (ctx, example_enum_cb, &pl);
389   ijs_server_install_set_cb (ctx, example_set_cb, &pl);
390   ijs_server_install_get_cb (ctx, example_get_cb, &pl);
391 
392   do
393     {
394       int total_bytes, bytes_left;
395       ExampleParamList *curs;
396 
397       status = ijs_server_get_page_header (ctx, &ph);
398       if (status) break;
399       fprintf (stderr, "got page header, %d x %d\n",
400 	      ph.width, ph.height);
401 
402       if (f == NULL)
403 	{
404 	  fn = find_param (pl, "OutputFile");
405 	  /* todo: check error! */
406 
407 	  if (fn == NULL)
408 	    {
409 	      fn = find_param (pl, "OutputFD");
410 	      if (fn != NULL)
411 		{
412 		  f = fdopen (atoi (fn), "w");
413 		}
414 	    }
415 	  else
416 	    {
417 	      f = fopen (fn, "w");
418 	    }
419 	  if (f == NULL)
420 	    {
421 	      fprintf (stderr, "can't open output file %s\n", fn);
422 	      fclose (stdin);
423 	      fclose (stdout);
424 	      break;
425 	    }
426 	  if (fn != NULL)
427 	    free (fn);
428 	}
429 
430       fprintf (f, "%%!PS-Adobe-2.0\n");
431 
432       example_compute_offset (pl, &ph, &x0, &y0);
433 
434       xscale = 72.0 / ph.xres;
435       yscale = 72.0 / ph.yres;
436 
437       fprintf (f, "%%%%BoundingBox: %d %d %d %d\n",
438 	       (int)(x0 * 72), (int)(y0 * 72),
439 	       (int)(x0 * 72 + xscale * ph.width + 0.999),
440 	       (int)(y0 * 72 + yscale * ph.height + 0.999));
441 
442       fprintf (f, "/rhex { currentfile exch readhexstring pop } bind def\n");
443       fprintf (f, "/picstr %d string def\n", ph.width);
444 
445       for (curs = pl; curs != NULL; curs = curs->next)
446 	{
447 	  fprintf (f, "%% IJS parameter: %s = ", curs->key);
448 	  fwrite (curs->value, 1, curs->value_size, f);
449 	  fputs ("\n", f);
450 	}
451 
452       fprintf (f,
453 	       "gsave\n"
454 	       "%f %f translate\n"
455 	       "%f %f scale\n"
456 	       "%d %d %d\n"
457 	       "[ %d 0 0 %d 0 %d ]\n",
458 	       x0 * 72, y0 * 72,
459 	       xscale * ph.width, yscale * ph.height,
460 	       ph.width, ph.height, ph.bps,
461 	       ph.width, -ph.height, ph.height);
462       if (ph.n_chan == 1)
463 	fprintf (f, "{ picstr rhex } image\n");
464       else
465 	{
466 	  fprintf (f, "{ picstr rhex }\n"
467 		   "false %d colorimage\n", ph.n_chan);
468 	}
469       total_bytes = ((ph.n_chan * ph.bps * ph.width + 7) >> 3) * ph.height;
470       bytes_left = total_bytes;
471       while (bytes_left)
472 	{
473 	  int n_bytes = bytes_left;
474 	  int i, j;
475 
476 	  if (n_bytes > sizeof(buf))
477 	    n_bytes = sizeof(buf);
478 #ifdef VERBOSE
479 	  fprintf (stderr, "%d bytes left, reading %d\n", bytes_left, n_bytes);
480 #endif
481 	  status = ijs_server_get_data (ctx, buf, n_bytes);
482 	  if (status)
483 	    {
484 	      fprintf (stderr, "page aborted!\n");
485 	      break;
486 	    }
487 	  j = 0;
488 	  for (i = 0; i < n_bytes; i++)
489 	    {
490 	      const char hex[16] = "0123456789AbCdEf";
491 	      unsigned char c = ((unsigned char *)buf)[i];
492 
493 	      hexbuf[j++] = hex[c >> 4];
494 	      hexbuf[j++] = hex[c & 0xf];
495 	      if ((i & 31) == 31)
496 		hexbuf[j++] = '\n';
497 	    }
498 	  if ((n_bytes & 31) != 0)
499 	    hexbuf[j++] = '\n';
500 	  fwrite (hexbuf, 1, j, f);
501 	  bytes_left -= n_bytes;
502 	}
503       fprintf (f, "grestore\nshowpage\n");
504     }
505   while (status == 0);
506 
507   if (status > 0) status = 0; /* normal exit */
508 
509   if (f)
510     fclose (f);
511   ijs_server_done (ctx);
512 
513   free_param_list (pl);
514 
515 #ifdef VERBOSE
516   fprintf (stderr, "server exiting with status %d\n", status);
517 #endif
518   return status;
519 }
520