xref: /plan9/sys/src/cmd/gs/src/gdevupd.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997-2004 artofcode LLC. All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevupd.c,v 1.16 2004/08/04 19:36:12 stefan Exp $ */
18 /* gdevupd.c Revision: 1.88 */
19 /* "uniprint" -- Ugly Printer Driver by Gunther Hess (ghess@elmos.de) */
20 
21 /* Revision-History:
22    23-Mar-1997 -  1.43: First published version
23    24-Mar-1997 -  1.44: gs4.03 compatible version on the web
24    31-Mar-1997 -  1.53: First Version inside gs-fileset (limited)
25    28-Apr-1997 -  1.54: Version intended for public gs-release
26     4-May-1997 -  1.55: Deactivated an accidentially active Debug-Option
27    14-Jun-1997 -  1.56: Bug-Workaround for White on White Printing (gs5.0)
28    17-Jun-1997 -  1.57: More reasonable Fix for the above Bug
29    ...
30     7-Jul-1997 -  1.68: NULL-Param-BUG, HR's BJC, Pwidth/-height BUG, YFlip
31    25-Jul-1997 -  1.69: Bug-Fix: incomplete Change of PHEIGHT-Treatment
32     4-Aug-1997 -  1.70: Arrgh: still incomplete Change of PHEIGHT-Treatment
33    17-AUG-1997 -  1.71: Fix of BSD-sprintf bug. (returns char * there)
34    ...
35    28-Sep-1997 -  1.77: Fixed the byte<>char and casted-lvalue Problems
36    ...
37    12-Mar-1998 -  1.80: Some PJL-Functions, Map-Bug-Fix (by Wonder-Wolfgang)
38    21-Oct-1998 -  1.81: Added RGB2CMY[_]K Modi (Eric Domenjoud)
39    ...
40    27-Feb-2000 -  1.84: CMYKgenerate with forced K-Control [distributed]
41     2-Apr-2000 -        Unofficial modifications for Epson Stylus Color 300. GR
42     5-Apr-2000 -        GR fixed last row not filled bug in wrtescnm
43     7-May-2000 -  1.85: Always BOP/EOP-Massaging for RTL-Output (Dan Coby)
44   ...
45     7-May-2000 -  1.87: integrated stc300-code by Glenn Ramsey
46        "       -  1.88: reduced "cast discards `const'" warnings to 1
47 
48 */
49 
50 /* Canon BJC 610 additions from (hr)
51       Helmut Riegler <helmut-riegler@net4you.co.at>
52 
53    The BJC-4000 can be supported very easily, only by creating the right .upp
54    parameter file. If you have this printer and you are willing to do this,
55    contact me, I'll give you the technical details (ESC codes).
56 */
57 
58 /* Epson Stylus Color 300 (FMT_ESCNMY) additions 2-Apr-2000.
59    Glenn Ramsey <glennr@es.co.nz>
60 */
61 
62 /* ------------------------------------------------------------------- */
63 /* Compile-Time-Options                                                */
64 /* ------------------------------------------------------------------- */
65 
66 /**
67 There are two compile-time options for this driver:
68    1. UPD_SIGNAL   enables interrupt detection, that aborts printing and
69    2. UPD_MESSAGES controls the amount of messages generated by the driver
70 */
71 
72 #ifndef   UPD_SIGNAL
73 #ifdef      __unix__
74 #define       UPD_SIGNAL 1 /** Activated, if undefined, on UNIX-Systems */
75 #else  /*  !__unix__ */
76 #define       UPD_SIGNAL 0 /** Inactive on others, by default */
77 #endif /*  ?__unix__ */
78 #endif /* UPD_SIGNAL */
79 
80 #ifndef   UPD_MESSAGES
81 #define   UPD_MESSAGES UPD_M_ERROR /** Error-messages only, if not defined */
82 #endif /* UPD_MESSAGES */
83 
84 /* ------------------------------------------------------------------- */
85 /* Required Header-Files                                               */
86 /* ------------------------------------------------------------------- */
87 
88 #include "stdint_.h"
89 
90 #ifndef   hess_test_INCLUDED /* A private test-Option */
91 
92 #include "gdevprn.h" /** Printer-superclass header */
93 #include "gsparam.h" /** For the Parameter-Handling (optional) */
94 
95 #include <stdlib.h>  /** for rand */
96 #include <limits.h>  /** for INT_MIN */
97 #include <ctype.h>   /** for isupper */
98 
99 #endif /* hess_test_INCLUDED    A private test-Option */
100 
101 #if       UPD_SIGNAL
102 #include <signal.h> /** Only included, if UPD_SIGNAL is active (true) */
103 #endif /* UPD_SIGNAL */
104 
105 /* ------------------------------------------------------------------- */
106 /* Device-Structure (including an additional Structure-Pointer-Type)   */
107 /* ------------------------------------------------------------------- */
108 
109 typedef struct upd_s upd_t,*upd_p; /** Type & Pointer of device-specifics */
110 typedef const upd_t *upd_pc;       /** Pointer to constant device-specfics */
111 
112 typedef struct upd_device_s {      /** The driver must typedef ... */
113    gx_device_common;               /**    common fields for all devices */
114    gx_prn_device_common;           /**    common fields for printing-devices */
115    gs_param_string upd_version;    /**    Source-Code Version */
116    upd_p           upd;            /**    uniprint-specific extension */
117 } upd_device;                      /** some type usually  <name>_device> */
118 
119 /* ------------------------------------------------------------------- */
120 /* Major Driver-Functions                                              */
121 /* ------------------------------------------------------------------- */
122 
123 private dev_proc_print_page(upd_print_page); /** print a page (required) */
124 
125 private dev_proc_open_device(upd_open);      /** device-initialization (opt) */
126 private dev_proc_close_device(upd_close);    /** device-release (opt) */
127 
128 private dev_proc_get_params(upd_get_params); /** export parameters (opt) */
129 private dev_proc_put_params(upd_put_params); /** import parameters (opt) */
130 
131 /**
132 A `normal' Device-Driver wil only implement one of the following pairs
133 of functions for the colormapping. But "uniprint" is something special and
134 it really provides all four reasonable pairs and in addition to that
135 a fifth set of functions, that delivers better FS-Results with KCMY.
136 
137 The first pair is for the mapping into a single stored component, that
138 usually represents a grayscale. But nevertheless GHOSTSCRIPT deals with
139 RGB-Values, but promises to deal with R==G==B-Values when asking to map.
140 
141 The second pair deals with RGB-Values.
142 */
143 
144 private dev_proc_encode_color( upd_rgb_1color);  /** Gray-Gray->Index */
145 private dev_proc_decode_color( upd_1color_rgb);  /** Gray-Index->Gray */
146 
147 private dev_proc_encode_color( upd_rgb_3color);  /** RGB->RGB-Index */
148 private dev_proc_decode_color( upd_3color_rgb);  /** RGB-Index->RGB */
149 
150 /**
151 The third pair maps RGB-Values into four components, which one might
152 expect to be KCMY-Values, but they are not: "uniprint" considers this four
153 Values as White+RGB Values!
154 */
155 
156 private dev_proc_encode_color( upd_rgb_4color);  /** RGB->WRGB-Index */
157 private dev_proc_decode_color(upd_4color_rgb);   /** WRGB-Index->RGB */
158 
159 /**
160 The fourth pair deals with KCMY-Values. The Mapping-Function
161 is of a different type, due to the additional argument, but the
162 inverse-Function is of the same type, and expects RGB-Values to be
163 deliverd into the receiving 3-Component-Array!
164 */
165 
166 private dev_proc_encode_color(upd_cmyk_icolor); /** KCMY->KCMY-Index */
167 private dev_proc_decode_color( upd_icolor_rgb);  /** KCMY->RGB-Index */
168 
169 /**
170 The difference between the icolor-pair and the kcolor-pair is the enforced
171 black-generation in the forward-mapping. that is taken into account by the
172 reverse-mapping too.
173 */
174 
175 private dev_proc_encode_color(upd_cmyk_kcolor); /** adds black generation */
176 private dev_proc_decode_color( upd_kcolor_rgb);  /** watches black-gen */
177 
178 /**
179 "ovcolor" is CMYK with Black-Generation and Undercolor-Removal, which
180 is suitable for overprinting:
181    CMY' = (CMY-K')/(1-K')
182 with
183    K'   = min(C,M,Y)
184 */
185 
186 private dev_proc_encode_color(upd_rgb_ovcolor);  /** RGB->CMYK-Index */
187 #define upd_ovcolor_rgb upd_icolor_rgb            /** CMYK-Index->RGB */
188 
189 /**
190 "novcolor" is CMYK with Black-Generation and Undercolor-Removal, which
191 is suitable for CMY / K - Printing:
192    CMY' = CMY-K'
193 with
194    K'   = min(C,M,Y)
195 */
196 
197 private dev_proc_encode_color(upd_rgb_novcolor); /** RGB->CMYK-Index */
198 #define upd_novcolor_rgb upd_icolor_rgb           /** CMYK-Index->RGB */
199 
200 /**
201 For the sake of efficiency there is that bunch of functions and they
202 perform no validity checks, thus it has to be assured that they are
203 only active, if there is a valid device-structure for then.
204 upd_procs_map performs this task.
205 */
206 
207 private int             upd_procs_map( upd_device *udev);
208 
209 /* ------------------------------------------------------------------- */
210 /* Prototype of the Device-Structure (the only thing exported!)        */
211 /* ------------------------------------------------------------------- */
212 
213 /**
214 "uniprint" needs a procedure-table of its own, since it provides several
215 optional procedures. Simpler-Drivers (e.g. non-color-drivers) may use
216 prn_std_procs instead of defining their own procedure-table.
217 */
218 
219 #define upd_set_dev_proc(dev, p, proc) \
220    ((dev)->std_procs.p = (dev)->orig_procs.p = (proc))
221 
222 private gx_device_procs upd_procs = {  /** Table of procedures */
223    upd_open,                      /** open-function, upd-special */
224    gx_default_get_initial_matrix, /** retrieve matrix */
225    gx_default_sync_output,        /** sync display */
226    gdev_prn_output_page,          /** superclass-print (calls back) */
227    upd_close,                     /** close-function, upd-special */
228    gx_default_map_rgb_color,      /** RGB-mapping */
229    gx_default_map_color_rgb,      /** reverse mapping */
230    NULL,                          /** fill_rectangle */
231    NULL,                          /** tile_rectangle */
232    NULL,                          /** copy_mono */
233    NULL,                          /** copy_color */
234    NULL,                          /** draw_line */
235    gx_default_get_bits,           /** reads scanlines, e.g. for the driver */
236    upd_get_params,                /** Export parameters, upd-special */
237    upd_put_params,                /** Import parameters, upd-special */
238    gx_default_map_cmyk_color      /** KCMY-mapping */
239 };                                     /** */
240 
241 /**
242 The prototype-instance of the device-structure _must_ have the name
243 "gs_uniprint_device", where "uniprint" is the external name of the driver.
244 This notice is bluntly copied from drivers.txt, which a potential
245 driver-author should carefully read.
246 
247 Just to mention: this prototype is quite similar to the one, that
248 "prn_device" produces and it identifies "uniprint" as a monochrome 1Bit
249 device to GHOSTSCRIPT. But during the lifetime of a driver-instance
250 this might change.
251 
252 This is the end of the part of declarations, that are common for
253 color-drivers. The next sections address "uniprint"-specific data-types
254 and the reader might directly skip to the section titled
255 
256     upd_print_page: The main workhorse
257 */
258 
259 upd_device far_data gs_uniprint_device = { /** */
260    prn_device_body(upd_device, upd_procs,  /** The Type and Procedures */
261       "uniprint",                          /** External name of the Device */
262       DEFAULT_WIDTH_10THS,                 /** X-Size (1/10") */
263       DEFAULT_HEIGHT_10THS,                /** Y-Size (1/10") */
264       72, 72,                              /** X,Y-DpI */
265       0.0, 0.0, 0.0, 0.0,                  /** L,B,R,T-Margin */
266       1, /**  color_info.num_components 1/3/4 */
267       1, /**  color_info.depth         1/2/4/8/16/24/32 */
268       1, /**  color_info.max_gray      # of distinct gray levels -1 (255/1) */
269       0, /**  color_info.max_color     # of distinct color levels -1 (255/1/0)*/
270       2, /**  color_info.dither_grays  size of gray ramp for dithering (256/2) */
271       0, /**  color_info.dither_colors size of color cube ditto (256/2/0) */
272       upd_print_page),                     /** Print-procedure */
273       { NULL, 0, true },                   /** Driver-Version */
274       NULL                                 /** upd-field: Initially none */
275 };                                         /** */
276 
277 
278 /* ------------------------------------------------------------------- */
279 /* UPD-Data- and Prototypes                                            */
280 /* ------------------------------------------------------------------- */
281 
282 /*@ gdevupd.h < */
283 /* ------------------------------------------------------------------- */
284 /* External names of the UPD-Parameters                                */
285 /* ------------------------------------------------------------------- */
286 
287 /** UPD-Parameters
288 
289 "uniprint" supports a hole bunch of external parameters. This Parameters
290 fall into the following categories:
291 
292  0. special-string the upd_version, readonly          upd_version
293  1. choice         name-indices, stored in            upd->choice
294  2. boolean        single bits, stored in             upd->flags
295  3. integers       single numbers, stored in          upd->ints
296  4. integer-Arrays arrays of numbers, stored in       upd->int_a
297  5. string         device-commands, stored in         upd->strings
298  6. string-Arrays  arrayed device-commands, stored in upd->string_a
299  7. float-Arrays   arrays of floats, stored in        upd->float_a
300 
301 Currently there is no need for single floats, but they may be introduced in
302 future versions. Since "uniprint" somtimes manipulates the contents of the
303 array-variables it dynamically allocates storage for all this parameters.
304 
305 The following sections defines the names for this parameters in the order,
306 they are stored within the mentioned dynamic fields of the upd-structure.
307 A NULL-name means that the corresponding parameter is not externally visible.
308 Besides the name, there is always a symbolic index #defined, that MUST match
309 the Index-Number of the name.
310 Actually
311 */
312 
313 static const char *const upd_version = "upVersion"; /** Readonly Version */
314 
315 /** Names for the multiple-choice-Parameters
316 
317 Currently there are three Parameters, that are handled as named choices.
318 For each of them, there is an array of constant strings that consists of
319 
320 1.       the Parameter-Name
321 2. - n-1 the available choices.
322 n.       A terminating NULL
323 */
324 
325 static const char *const upd_mapper[] = { "upColorModel",
326 #define MAP_GRAY        1   /** Monochrome & Grayscale Devices */
327 "DeviceGray",               /** Monochrome & Grayscale Devices */
328 #define MAP_RGBW        2   /** RGB with White-Generation */
329 "DeviceRGBW",               /** RGB with White-Generation */
330 #define MAP_RGB         3   /** RGB-Mapping */
331 "DeviceRGB",                /** RGB-Mapping */
332 #define MAP_CMYK        4   /** CMYK-Mapping */
333 "DeviceCMYK",               /** CMYK-Mapping */
334 #define MAP_CMYKGEN     5   /** CMYK-Mapping with Black-Generation */
335 "DeviceCMYKgenerate",       /** CMYK-Mapping with Black-Generation */
336 #define MAP_RGBOV       6   /** RGB->CMYK with BG and UCR for CMYK */
337 "DeviceRGB2CMYK",           /** RGB->CMYK with BG and UCR for CMYK */
338 #define MAP_RGBNOV      7   /** RGB->CMYK with BG and UCR for CMY + K */
339 "DeviceRGB2CMY_K",          /** RGB->CMYK with BG and UCR for CMY + K */
340 NULL
341 };
342 
343 static const char *const upd_render[] = { "upRendering",
344 #define RND_FSCOMP      1   /** Componentwise Floyd-Steinberg */
345 "ErrorDiffusion",           /** Componentwise Floyd-Steinberg */
346 #define RND_FSCMYK      2   /** CMYK-specialized 32Bit Floyd-Steinberg */
347 "FSCMYK32",                 /** CMYK-specialized 32Bit Floyd-Steinberg */
348 #define RND_FSCMY_K     3   /** CMY_K Rendering */
349 "FSCMY_K",
350 NULL
351 };
352 
353 static const char *const upd_format[] = { "upOutputFormat",
354 #define FMT_RAS         1   /** Generates SUN-Rasterfiles */
355 "SunRaster",                /** Generates SUN-Rasterfiles */
356 #define FMT_EPSON       2   /** Generates X+Y-Weaved ESC/P-Output */
357 "Epson",                    /** Generates X+Y-Weaved ESC/P-Output */
358 #define FMT_ESCP2Y      3   /** Generates Y-Weaved ESC/P2-Output */
359 "EscP2",                    /** Generates Y-Weaved ESC/P2-Output */
360 #define FMT_ESCP2XY     4   /** Generates X+Y-Weaved ESC/P2-Output */
361 "EscP2XY",                  /** Generates X+Y-Weaved ESC/P2-Output */
362 #define FMT_RTL         5   /** Generates HP-PCL/RTL-Output */
363 "Pcl",                      /** Generates HP-PCL/RTL-Output */
364 #define FMT_CANON       6   /** Generates Output for Canon extended mode (hr) */
365 "Canon",                    /** Generates Output for Canon extended mode (hr) */
366 #define FMT_ESCNMY      7   /** Generates Output for Epson Stylus Color 300 (GR) */
367 "EscNozzleMap",             /** Generates Output for Epson Stylus Color 300 (GR) */
368 NULL
369 };
370 
371 static const char *const *const upd_choice[] = {
372 #define C_MAPPER        0   /** the selected Mapper */
373    upd_mapper,
374 #define C_RENDER        1   /** the selected Rendering */
375    upd_render,
376 #define C_FORMAT        2   /** the selected Choice */
377    upd_format
378 };
379 
380 /** Names for the flags (bool)
381 */
382 
383 static const char *const upd_flags[] = {      /** */
384 #define B_REVDIR            ((uint32_t) 1<<0)   /** FS-Dir-Flag */
385 "upFSReverseDirection",                       /** FS-Dir-Flag */
386 #define B_FIXDIR            ((uint32_t) 1<<1)   /** Do not alter FS-direction */
387 "upFSFixedDirection",                         /** Do not alter FS-direction */
388 #define B_FSWHITE           ((uint32_t) 1<<2)   /** Process white in FS */
389 "upFSProcessWhiteSpace",                      /** Process white in FS */
390 #define B_FSZERO            ((uint32_t) 1<<3)   /** Zero FS-Initialization */
391 "upFSZeroInit",                               /** Zero FS-Initialization */
392 
393 #define B_PAGEWIDTH         ((uint32_t) 1<<4)   /** Adjust Width in BOP */
394 "upAdjustPageWidthCommand",                   /** Adjust Page-Width in BOP */
395 #define B_PAGELENGTH        ((uint32_t) 1<<5)   /** Adjust Length in BOP */
396 "upAdjustPageLengthCommand",                  /** Adjust Page-Length in BOP */
397 #define B_TOPMARGIN         ((uint32_t) 1<<6)   /** Adjust Top-Margin in BOP */
398 "upAdjustTopMarginCommand",                   /** Adjust Top-Margin in BOP */
399 #define B_BOTTOMMARGIN      ((uint32_t) 1<<7)   /** Adjust Bottom-Margin in BOP */
400 "upAdjustBottomMarginCommand",                /** Adjust Bottom-Margin in BOP */
401 #define B_RESOLUTION        ((uint32_t) 1<<8)   /** Adjust Resolution in BOP */
402 "upAdjustResolutionCommand",                  /** Adjust Resolution in BOP */
403 #define B_MEDIASIZE         ((uint32_t) 1<<9)   /** Adjust Mediasize in BOP */
404 "upAdjustMediaSize",                          /** Adjust Mediasize in BOP */
405 
406 #define B_XABS              ((uint32_t) 1<<10)  /** Use Absolute X-Values */
407 "upFormatXabsolute",                          /** Use Absolute X-Values */
408 #define B_YABS              ((uint32_t) 1<<11)  /** Use Absolute Y-Values */
409 "upFormatYabsolute",                          /** Use Absolute Y-Values */
410 
411 #define B_MAP               ((uint32_t) 1<<12)  /** Mapping Initialized */
412 "upColorModelInitialized",                    /** Mapping Initialized */
413 #define B_BUF               ((uint32_t) 1<<13)  /** Raster-Buffer Initialized */
414 "upRasterBufferInitialized",                  /** Raster-Buffer Initialized */
415 #define B_RENDER            ((uint32_t) 1<<14)  /** Rendering Initialized */
416 "upRenderingInitialized",                     /** Rendering Initialized */
417 #define B_FORMAT            ((uint32_t) 1<<15)  /** Formatter Initialized */
418 "upOutputFormatInitialized",                  /** Formatter Initialized */
419 #define B_ABORT             ((uint32_t) 1<<16)  /** Abort on Interrupt */
420 "upOutputAborted",                            /** Abort on Interrupt */
421 #define B_ERROR             ((uint32_t) 1<<17)  /** Severe Error detected */
422 "upErrorDetected",                            /** Severe Error detected */
423 
424 #define B_OPEN              ((uint32_t) 1<<18)  /** Open-Command written */
425 "upWroteData",                                /** Open-Command written */
426 
427 #define B_YFLIP             ((uint32_t) 1<<19)  /** Mirrored printing (hr) */
428 "upYFlip",                                    /** Mirrored printing (hr) */
429 
430 #define B_REDUCEK           ((uint32_t) 1<<20)  /** CMY->Black Reduction */
431 "upFSReduceK"
432 
433 };
434 
435 /** B_OK4GO: Bits required to execute the print-loop */
436 
437 #define B_OK4GO  (B_MAP | B_BUF | B_RENDER | B_FORMAT)
438 
439 /** Names for the ints
440 */
441 
442 static const char *const upd_ints[] = {
443 #define I_PWIDTH            0                 /** Output-Width */
444 "upOutputWidth",
445 #define I_PHEIGHT           1                 /** Output-Height */
446 "upOutputHeight",
447 #define I_OCOMP             2                 /** Output-Components */
448 "upOutputComponents",
449 #define I_NSCNBUF           3                 /** Output-Buffers */
450 "upOutputBuffers",
451 #define I_XSTEP             4                 /** Unit-Step */
452 "upOutputXStep", /* > 0 -> divide Raster-X, < 0 muliply Raster-X */
453 #define I_XOFS              5                 /** abs. X-Offset */
454 "upOutputXOffset",
455 #define I_YSTEP             6                 /** Unit-Step */
456 "upOutputYStep", /* > 0 -> divide Raster-Y, < 0 muliply Raster-Y */
457 #define I_YOFS              7                 /** abs. Y-Offset */
458 "upOutputYOffset",
459 #define I_PINS2WRITE        8                 /** Number of Pins */
460 "upOutputPins",
461 
462 #define I_NXPASS            9                 /** X-Passes */
463 "upWeaveXPasses",
464 #define I_NYPASS           10                 /** Y-Passes */
465 "upWeaveYPasses",
466 #define I_NPASS            11                 /** Total # Passes */
467 "upWeavePasses",
468 #define I_BEG_Y            12                 /** Start of normal Weaving */
469 "upWeaveInitialScan",
470 #define I_END_Y            13                 /** End of normal Weaving */
471 "upWeaveFinalScan",
472 #define I_BEGSKIP          14                 /** A Scan-Offset */
473 "upWeaveYOffset",
474 #define I_ROWS             15                 /** Output rows per pass */
475 "upNozzleMapRowsPerPass",
476 #define I_PATRPT           16                 /** mask pattern repeat interval */
477 "upNozzleMapPatternRepeat"
478 };
479 
480 /** Names for the Integer-Arrays
481 */
482 
483 static const char *const upd_int_a[] = {      /** */
484 #define IA_COLOR_INFO       0                 /** external color_info */
485 "upColorInfo",                                /** external color_info */
486 
487 #define IA_COMPBITS         1                 /** Bits stored per Component */
488 "upComponentBits",                            /** Bits stored per Component */
489 #define IA_COMPSHIFT        2                 /** Shift for the stored Bits */
490 "upComponentShift",                           /** Shift for the stored Bits */
491 #define IA_COMPORDER        3                 /** Order of Output-Components */
492 "upOutputComponentOrder",                     /** Order of Output-Components */
493 
494 #define IA_STD_DY           4                 /** Standard-Weave Feeds */
495 "upWeaveYFeeds",                              /** Standard-Weave Feeds */
496 #define IA_STD_IX           5                 /** Standard-Weave X-Passes */
497 "upWeaveXStarts",                             /** Standard-Weave X-Start */
498 #define IA_BEG_DY           6                 /** Initial-Weave Feeds */
499 "upWeaveInitialYFeeds",                       /** Initial-Weave Feeds */
500 #define IA_BEG_IX           7                 /** Initial-Weave X-Start */
501 "upWeaveInitialXStarts",                      /** Initial-Weave X-Start */
502 #define IA_BEGBOT           8                 /** Initial-Weave #Pins */
503 "upWeaveInitialPins",                         /** Initial-Weave #Pins */
504 #define IA_END_DY           9                 /** Final-Weave Feeds */
505 "upWeaveFinalYFeeds",                         /** Final-Weave Feeds */
506 #define IA_END_IX          10                 /** Final-Weave X-Start */
507 "upWeaveFinalXStarts",                        /** Final-Weave X-Start */
508 #define IA_ENDTOP          11                 /** Final-Weave #Pins */
509 "upWeaveFinalPins",                           /** Final-Weave #Pins */
510 #define IA_ROWMASK         12                 /** The nozzle to row map */
511 "upNozzleMapRowMask",
512 #define IA_SCNOFS       13                 /** Mask to scan map */
513 "upNozzleMapMaskScanOffset"
514 };
515 
516 /** Names of the String-Parameters
517 */
518 
519 static const char *const upd_strings[] = { /** */
520 #define S_MODEL             0                 /** Name of the Printer-Model */
521 "upModel",                                    /** Name of the Printer-Model */
522 #define S_OPEN              1                 /** Printer-Begin-Job */
523 "upBeginJobCommand",                          /** Printer-Begin-Job */
524 #define S_CLOSE             2                 /** Printer-End-Job */
525 "upEndJobCommand",                            /** Printer-End-Job */
526 #define S_BEGIN             3                 /** Printer-Begin-Page */
527 "upBeginPageCommand",                         /** Printer-Begin-Page */
528 #define  S_END              4                 /** Printer-End-Page */
529 "upEndPageCommand",                           /** Printer-End-Page */
530 #define  S_ABORT            5                 /** Printer-Abort-Command */
531 "upAbortCommand",                             /** Printer-Abort-Command */
532 
533 #define S_XMOVE             6                 /** X-Positioning-Command */
534 "upXMoveCommand",                             /** X-Positioning-Command */
535 #define S_XSTEP             7                 /** X-Step Command (1<I_XSTEP) */
536 "upXStepCommand",                             /** X-Step Command (1<I_XSTEP) */
537 #define S_SETLF             8                 /** Set-Linefeed-Command */
538 "upSetLineFeedCommand",                       /** Set-Linefeed-Command */
539 #define S_YMOVE             9                 /** Y-Positioning-Command */
540 "upYMoveCommand",                             /** Y-Positioning-Command */
541 #define S_YSTEP            10                 /** Y-Step Command (1<I_YSTEP) */
542 "upYStepCommand"                              /** Y-Step Command (1<I_YSTEP) */
543 }; /** */
544 
545 /** Names for the String-Arrays
546 */
547 
548 static const char *const upd_string_a[] = {   /** */
549 #define SA_SETCOMP          0                 /** Select Components */
550 "upSelectComponentCommands",                  /** Select Components */
551 #define SA_WRITECOMP        1                 /** Write Component Comands */
552 "upWriteComponentCommands"                    /** Write Component Commands */
553 };                                            /** */
554 
555 /** Names for the float-Arrays
556 */
557 static const char *const upd_float_a[] = {    /** */
558 #define FA_WXFER            0                 /** White-Transfer */
559 "upWhiteTransfer",                            /** White-Transfer */
560 #define FA_RXFER            1                 /** Red-Transfer */
561 "upRedTransfer",                              /** Red-Transfer */
562 #define FA_GXFER            2                 /** Green-Transfer */
563 "upGreenTransfer",                            /** Green-Transfer */
564 #define FA_BXFER            3                 /** Blue-Transfer */
565 "upBlueTransfer",                             /** Blue-Transfer */
566 #define FA_KXFER            4                 /** Black-Transfer */
567 "upBlackTransfer",                            /** Black-Transfer */
568 #define FA_CXFER            5                 /** Cyan-Transfer */
569 "upCyanTransfer",                             /** Cyan-Transfer */
570 #define FA_MXFER            6                 /** Magenta-Transfer */
571 "upMagentaTransfer",                          /** Magenta-Transfer */
572 #define FA_YXFER            7                 /** Yellow-Transfer */
573 "upYellowTransfer",                           /** Yellow-Transfer */
574 #define FA_MARGINS          8                 /** private Margins */
575 "upMargins",                                  /** private Margins */
576 #define FA_MAP              9                 /** Color-Map       */
577 "upColorMap"                                  /** Color-Map       */
578 };                                            /** */
579 
580 /* ------------------------------------------------------------------- */
581 /* UPD-specific datatypes                                              */
582 /* ------------------------------------------------------------------- */
583 
584 /**
585 int32_t and uint32_t are 32Bit-Integer-Types used in the
586 Floyd-Steinberg Algorithm and instead of gx_color_index. The
587 8-Byte long's on some 64Bit-Machines are apparently useless,
588 since gdevprn.c does (currently) support only 32-Bit Rasterdata.
589 */
590 
591 #undef INT32_MIN
592 #undef INT32_MAX
593 #undef UINT32_MAX
594 
595 #if     arch_log2_sizeof_int < 2  /* int is too small */
596 #define                   INT32_MIN  LONG_MIN
597 #define                   INT32_MAX  LONG_MAX
598 #define                  UINT32_MAX ULONG_MAX
599 #else                             /* int is sufficient */
600 #define                   INT32_MIN   INT_MIN
601 #define                   INT32_MAX   INT_MAX
602 #define                  UINT32_MAX  UINT_MAX
603 #endif                            /* use int or long ? */
604 
605 /**
606 "updcmap" is used by the color-mapping functions of the driver.
607 there are four cmaps in the "uniprint"-structure, one for each component.
608 To be exact, it's not "4" but rather "UPD_CMAP_MAX", which is a synonym.
609 */
610 
611 typedef struct updcmap_s { /** */
612    gx_color_value      *code;      /** Values related to codes */
613    uint32_t               bitmsk;    /** Mask, right justified */
614    int                  bitshf;    /** Shift to right-justify */
615    int                  xfer;      /** Index to the Xfer-Array */
616    int                  bits;      /** # of Bits */
617    int                  comp;      /** Output-Number */
618    bool                 rise;      /* Rising/Falling Curve */
619 } updcmap_t, *updcmap_p;  /** */
620 typedef const updcmap_t *updcmap_pc;
621 
622 
623 /**
624 "updcomp" holds similar informations, but is used for the rendering
625 */
626 
627 typedef struct updcomp_s {  /* Parameters for Floyd-Steinberg */
628    int32_t                offset;    /* Offset added to scaled values */
629    int32_t                scale;     /* Scale for the raw values */
630    int32_t                threshold; /* Val must be larger than this to fire */
631    int32_t                spotsize;  /* subtracted from Val when fired */
632    uint32_t               bitmsk;    /* Mask */
633    int                  bitshf;    /* shift */
634    int                  bits;      /* # of Bits */
635    int                  cmap;      /* Index for the Parameter-name */
636 } updcomp_t, *updcomp_p;    /* Parameters for Floyd-Steinberg */
637 
638 /** updscan is the Element of the scan-buffer. */
639 
640 typedef struct updscan_s { /* Single Scanline (1 Bit/Pixel) */
641    byte   *bytes;      /* Buffer used w. 32-Bit Words */
642    int    *xbegin;     /* 1st  Pixel set (or nbytes<<3 if none) */
643    int    *xend;       /* last Pixel set (or -1, if none) */
644 } updscan_t, *updscan_p;   /* Single Scanline (1 Bit/Pixel) */
645 
646 
647 /** Main upd-Structure ***/
648 
649 #define UPD_CMAP_MAX     4 /** Number of Colormaps provided */
650 #define UPD_VALPTR_MAX  32 /** Number of valbuf-Pointers */
651 
652 #define upd_proc_pxlget(name) uint32_t name(upd_p upd)
653 #define upd_proc_render(name) int name(upd_p upd)
654 #define upd_proc_writer(name) int name(upd_p upd,FILE *out)
655 
656 struct upd_s { /* All upd-specific data */
657 
658    int                   *choice;     /** Named-Choices */
659    int                   *ints;       /** Integers */
660    gs_param_int_array    *int_a;      /** Integer-Arrays */
661    gs_param_string       *strings;    /** Strings */
662    gs_param_string_array *string_a;   /** String-Arrays */
663    gs_param_float_array  *float_a;    /** Float-Arrays */
664 
665    updcmap_t              cmap[UPD_CMAP_MAX]; /** Mapping-Data */
666 
667    byte                  *gsbuf;      /* Storage for GS-Rasterdata */
668    byte                  *gsscan;     /* Begin of GS-Rasterdata */
669 
670    byte                  *pxlptr;     /* Source for pxlget */
671    upd_proc_pxlget(     (*pxlget));   /* The Pixel-Reader */
672    upd_proc_render(     (*render));   /* Actual Rendering */
673    upd_proc_writer(     (*writer));
674 
675    updscan_p             *scnbuf;     /* Output-Values */
676    int32_t                 *valbuf;     /* Floyd-Steinberg-Buffer */
677    void                  *valptr[UPD_VALPTR_MAX];
678 
679    byte                  *outbuf;     /* Output-Buffer */
680    upd_proc_render(     (*start_render)); /* Setup for rendering */
681    upd_proc_writer(     (*start_writer)); /* Setup for writilg */
682 
683    uint32_t                 flags;      /** Some flags */
684    int                    pdwidth;    /** pdev-width upon open */
685    int                    pdheight;   /** pdev-height upon open */
686 
687    uint                   ngsbuf;     /* Size of gsbuf */
688    int                    gswidth;    /* Width in GS-Pixels */
689    int                    gsheight;   /* Height in GS-Pixels */
690 
691    int                    rwidth;     /* Rendering-Width */
692 
693    int                    pwidth;     /* Printing-Width */
694    int                    pheight;    /* # scanlines printed */
695 
696    int                    ncomp;      /* # Components in gsbuf */
697    int                    nmap;       /* # Entries in color-map */
698 
699    uint                   nvalbuf;    /* Size of valbuf */
700    int                    nscnbuf;    /* Number of entries in scnbuf. */
701 
702    int                    ocomp;      /* # Components written */
703    int                    nbytes;     /* Size of scnbuf[][].words */
704    int                    nlimits;    /* Size of scnbuf[][].xbegin/end */
705    int                    scnmsk;     /* Size of scanbuf - 1 */
706    uint                   noutbuf;    /* Size of the Output-Buffer */
707 
708    int                    ixpass;     /* Current X-pass (0 ... nxpass-1) */
709    int                    ipass;      /* Current pass (0 ... npass-1) */
710    int                    icomp;      /* Selected Component */
711    int                    lf;         /* Selected Line-Space */
712 
713    int                    xprinter;   /* Actual X-Position */
714 
715    int                    yscan;      /* Top-Scan (page-vari) */
716    int                    yprinter;   /* Actual Y-Position (page-vari) */
717    int                    yscnbuf;    /* Y not yet buffered */
718 };             /* All upd-specific data */
719 
720 
721 /* ------------------------------------------------------------------- */
722 /* Various Message-Levels                                              */
723 /* ------------------------------------------------------------------- */
724 
725 /**
726 UPD_MESSAGES, Is collection of Bits, that controls Messages
727 */
728 
729 #define UPD_M_NONE      0x0000 /** No Messages at all */
730 #define UPD_M_ERROR     0x0001 /** Errors */
731 #define UPD_M_WARNING   0x0002 /** Warnings */
732 #define UPD_M_TOPCALLS  0x0004 /** Log Calls to main Functions */
733 #define UPD_M_MAPCALLS  0x0008 /** Log Color-Mapping-Calls */
734 #define UPD_M_SETUP     0x0010 /** Log Setup-Activity */
735 #define UPD_M_FSBUF     0x0020 /** Error-Summary for valbuf */
736 #define UPD_M_FMTVARS   0x0040 /** (GR) Formatting variables */
737 
738 /* ------------------------------------------------------------------- */
739 /* The UPD-Routines                                                    */
740 /* ------------------------------------------------------------------- */
741 
742 /**
743 Besides the main routines required for the color-mapping, that were
744 declared near the beginning, there are some auxillary functions.
745 Most prominent are "upd_open_map" and "upd_close_map", which
746 do the proper actions when opening and closing the device.
747 */
748 
749 private int             upd_open_map( upd_device *udev);
750 private int             upd_close_map(upd_device *udev);
751 
752 /**
753 But "upd_truncate" and "upd_expand" are also mentionable. They are
754 the actual workhorses for the component-oriented mapping. When mapping
755 the 16Bit Component-Values to the indices, some truncation takes place
756 and this is what "upd_truncate" does, in the most general manner i can
757 think of and with O(log(n)) in time. "upd_expand" is required for the
758 reverse mapping-functions and is a constant-time `algorithm'.
759 */
760 private inline uint32_t   upd_truncate(upd_pc,int,gx_color_value);
761 
762 /* ------------------------------------------------------------------- */
763 /* Return the gx_color_value for a given component                     */
764 /* ------------------------------------------------------------------- */
765 private inline gx_color_value
upd_expand(upd_pc upd,int i,gx_color_index ci0)766 upd_expand(upd_pc upd,int i,gx_color_index ci0)
767 {
768    const updcmap_pc cmap = upd->cmap + i;    /* Writing-Shortcut */
769    uint32_t ci = (uint32_t)((ci0 >> cmap->bitshf) & cmap->bitmsk); /* Extract the component */
770 
771    if(!cmap->rise) ci = cmap->bitmsk - ci;   /* Invert, if necessary */
772 /* no Truncation/Expansion on full range */
773    if(gx_color_value_bits > cmap->bits) return cmap->code[ci];
774    else                                 return (gx_color_value) ci;
775 }
776 /* That's simple, isn't it? */
777 
778 /**
779 The next group of internal functions adresses the rendering. Besides
780 the main-functions "upd_open_render" and "upd_close_render", there
781 are groups of up to 3 Functions, for each algorithm available with
782 UPD. Two routines are invoked during open and close and the third
783 is called for each scanline. Actually a fourth function is provided,
784 that is invoked at the beginning of each page to be printed, but the
785 current algorithms do not need it.
786 */
787 private void            upd_open_render(   upd_device *udev);
788 private void            upd_close_render(  upd_device *udev);
789 
790 private void            upd_open_fscomp(   upd_device *udev);
791 private int             upd_fscomp(        upd_p upd);
792 private void            upd_close_fscomp(  upd_device *udev);
793 
794 private void            upd_open_fscmyk(   upd_device *udev);
795 private int             upd_fscmyk(        upd_p upd);
796 
797 private void            upd_open_fscmy_k(  upd_device *udev);
798 private int             upd_fscmy_k(       upd_p upd);
799 
800 /**
801 I hope that the formatting stuff can be kept simple and thus most
802 of the work is done inside the general open and close-functions.
803 During open, there is a call to a format-specific open-function, but
804 this is only for checking and determining the amount of of bytes required
805 for the output-buffer (and limit-values in the scan-buffer).
806 */
807 private int             upd_open_writer(   upd_device *udev);
808 private void            upd_close_writer(  upd_device *udev);
809 #if UPD_SIGNAL
810 private void            upd_signal_handler(int sig);
811 #endif
812 
813 /**
814 The first format are the uncompressed! SUN-Rasterfiles. The primary intention
815 of this format is testing, but it might turn out to be useful for other
816 purposes, even if the amount of generated data is huge. On the other hand
817 it is a violation of UPD's rules: the start-routine computes the Begin-Page
818 sequence (the Rasterfile header) since it would be a nuisance to provide
819 this code within each (test-)personalization in PostScript.
820 */
821 private int             upd_open_rascomp(   upd_device *udev);
822 private int             upd_start_rascomp(  upd_p upd, FILE *out);
823 private int             upd_rascomp(        upd_p upd, FILE *out);
824 
825 /**
826 The second format is ESC/P, the format introduced with the first Epson
827 impact printers. This format is used by a lot of other printers too.
828 It is also uncompressed. This formatter supports X- and Y-Weaving,
829 which makes it the most sophisticated one inside this driver.
830 */
831 
832 private void            upd_limits(        upd_p upd, bool check);
833 private int             upd_open_wrtescp(  upd_device *udev);
834 private int             upd_wrtescp(       upd_p upd, FILE *out);
835 
836 /**
837 The third format is ESC/P2, the format use by the newer Epson-Printers.
838 It allows runlength-Compression similar to the RTL/PCL-Family of Printers.
839 This formatter does not allow for X-Weaving.
840 
841 The fourth writer is a ESC/P2-Writer, that supports X-Weaving
842 */
843 private int             upd_rle(byte *out,const byte *in,int nbytes);
844 private int             upd_open_wrtescp2( upd_device *udev);
845 private int             upd_wrtescp2(      upd_p upd, FILE *out);
846 private int             upd_wrtescp2x(     upd_p upd, FILE *out);
847 
848 /**
849 The fifth writer is a HP-RTL/PCL-Writer
850 */
851 
852 private int             upd_open_wrtrtl(   upd_device *udev);
853 private int             upd_wrtrtl(        upd_p upd, FILE *out);
854 
855 /**
856 The sixth writer is for Canon Extended Mode (currently BJC610) (hr)
857 */
858 
859 private int             upd_open_wrtcanon( upd_device *udev);
860 private int             upd_wrtcanon(      upd_p upd, FILE *out);
861 
862 /**
863 The seventh writer is for ESC P/2 Nozzle Map Mode (currently Stylus Color 300) (GR)
864 */
865 
866 private int             upd_wrtescnm(      upd_p upd, FILE *out);
867 
868 
869 /**
870 Generalized Pixel Get & Read
871 */
872 private uint32_t upd_pxlfwd(upd_p upd);
873 private uint32_t upd_pxlrev(upd_p upd);
874 #define upd_pxlget(UPD) (*UPD->pxlget)(UPD)
875 
876 private void *upd_cast(const void *);
877 
878 /* ------------------------------------------------------------------- */
879 /* Macros to deal with the Parameter-Memory                            */
880 /* ------------------------------------------------------------------- */
881 
882 /**
883 Usually the creation of copies of external parameters is not necessary,
884 at least with gs-versions > 4.03. But uniprint writes to the parameters
885 in some cases or creates some by itself, thus to get a unified interface
886 all parameter-data are copied and thus it is legal to manipulate them.
887 
888 Here are several Macros, named "UPD_MM_*" to deal with that.
889 */
890 
891 /** UPD_MM_GET_ARRAY allocates & initializes an array of values */
892 #define UPD_MM_GET_ARRAY(mem, Which,Nelts)                                 \
893    Which = NULL;                                                      \
894    if(0 < (Nelts)) {                                                  \
895       byte *tmp = gs_malloc(mem, Nelts,sizeof(Which[0]),"uniprint/params");\
896       if(tmp) {                                                       \
897          memset(tmp,0,(Nelts)*sizeof(Which[0]));                      \
898          Which = (void *) tmp;                                        \
899       } else {                                                        \
900           return_error(gs_error_VMerror);                             \
901       }                                                               \
902    }
903 
904 /** UPD_MM_DEL_ARRAY frees an array of values */
905 #define UPD_MM_DEL_ARRAY(mem, Which,Nelts,Delete)                            \
906    if(Which && 0 < (Nelts)) {                                           \
907       uint ii;                                                          \
908       for(ii = 0; (Nelts) > ii; ++ii) Delete(mem, Which[ii]);                \
909       gs_free(mem, upd_cast(Which),Nelts,sizeof(Which[0]),"uniprint/params");\
910    }                                                                    \
911    Which = 0
912 
913 /** UPD_MM_DEL_VALUE deletes a value, does nothing */
914 #define UPD_MM_DEL_VALUE(mem, Which) /* */
915 
916 /** UPD_MM_DEL_PARAM deletes a single gs-array-parameter */
917 #define UPD_MM_DEL_PARAM(mem, Which)  {                                  \
918    if(Which.data && Which.size)                                     \
919       gs_free(mem, upd_cast(Which.data),Which.size,sizeof(Which.data[0]),\
920          "uniprint/params");                                        \
921 }
922 
923 /** UPD_MM_DEL_APARAM deletes a nested gs-array-parameter */
924 #define UPD_MM_DEL_APARAM(mem, Which) {                                  \
925    if(Which.data && Which.size) {                                   \
926       uint iii;                                                     \
927       for(iii = 0; iii < Which.size; ++iii)                         \
928          UPD_MM_DEL_PARAM(mem, Which.data[iii]);                         \
929       gs_free(mem, upd_cast(Which.data),Which.size,sizeof(Which.data[0]),\
930          "uniprint/params");                                        \
931    }                                                                \
932 }
933 
934 /** UPD_MM_CPY_ARRAY creates a new copy of an array of values */
935 #define UPD_MM_CPY_ARRAY(mem, To,From,Nelts,Copy)                \
936    UPD_MM_GET_ARRAY(mem, To,Nelts);                              \
937    if(To && From) {                                         \
938       uint ii;                                              \
939       for(ii = 0; (Nelts) > ii; ++ii) Copy(mem, To[ii],From[ii]);\
940    }
941 
942 /** UPD_MM_CPY_VALUE Copies a simple Value */
943 #define UPD_MM_CPY_VALUE(mem,To,From)  To = From
944 
945 #define UPD_MM_CPY_VALUE_3(mem,To,From)  To = From
946 
947 /** UPD_MM_CPY_PARAM Creates a copy of a gs-parameter */
948 #define UPD_MM_CPY_PARAM(mem, To, From)                                       \
949    if(From.data && From.size) {                                         \
950       UPD_MM_GET_ARRAY(mem, To.data,From.size);                              \
951       if(To.data) {                                                     \
952          To.size = From.size;                                           \
953          memcpy(upd_cast(To.data),From.data,To.size*sizeof(To.data[0]));\
954       }                                                                 \
955    }
956 
957 /** UPD_MM_CPY_APARAM Creates a copy of a nested gs-parameter */
958 #define UPD_MM_CPY_APARAM(mem, To,From)                                     \
959    if(From.data && From.size) {                                        \
960        UPD_MM_GET_ARRAY(mem, To.data,From.size);			       \
961       if(To.data) {                                                    \
962          gs_param_string *tmp2 = (gs_param_string *) upd_cast(To.data);\
963          uint iii;                                                     \
964          To.size = From.size;                                          \
965          for(iii = 0; To.size > iii; ++iii)                            \
966 	     UPD_MM_CPY_PARAM(mem, tmp2[iii],From.data[iii]);	       \
967       }                                                                \
968    }
969 
970 /* ------------------------------------------------------------------- */
971 /* UPD-Initialized-Data                                                */
972 /* ------------------------------------------------------------------- */
973 
974 /** Version-String */
975 
976 static const char rcsid[] = "$Revision: 1.16 $";
977 
978 /** Default-Transfer-curve */
979 
980 static const float upd_data_xfer[2] = { 0.0, 1.0 };
981 
982 /*@ > */
983 
984 /* ------------------------------------------------------------------- */
985 /* upd_cast: keeps some compilers more happy [dangerous]               */
986 /* ------------------------------------------------------------------- */
987 
988 private void *
upd_cast(const void * data)989 upd_cast(const void *data)
990 {
991   return (void *) data;
992 }
993 
994 /* ------------------------------------------------------------------- */
995 /* upd_signal_handler: Catch interrupts                                */
996 /* ------------------------------------------------------------------- */
997 
998 #if UPD_SIGNAL
999 static upd_p sigupd = NULL;
1000 private void
upd_signal_handler(int sig)1001 upd_signal_handler(int sig)
1002 {
1003   if(sigupd) sigupd->flags |= B_ABORT;
1004 }
1005 #endif
1006 
1007 
1008 /* ------------------------------------------------------------------- */
1009 /* upd_print_page: The main workhorse                                  */
1010 /* ------------------------------------------------------------------- */
1011 
1012 /**
1013 Function: upd_print_page
1014 
1015 This is the top-level printing routine. It works through this
1016 steps:
1017 
1018  1. Once for each generated file, the "device-open-sequence" is written.
1019  2. The "page-begin-sequence" is written.
1020 
1021  3. The data are generated and written:
1022     3.1: Data are converted into a "printer-family"-specific format.
1023          This step includes the halftoning, if selected.
1024     3.2: Data are written with a printer-specific function.
1025          There is not much code-compression inside theese functions,
1026          since i observed to improvments in print-speed. Other
1027          drivers do a better job in this.
1028 
1029  4. The "page-end-sequence" is written.
1030  5. If a one-page-per-file mode is selected, the "device-close-sequence"
1031     is added to the output. For multi-page files, this writing is
1032     performed in "upd_close", the drivers close-function.
1033 
1034 The routine is quite short, since all the allocation and checking
1035 occur in upd_open and upd_putparams. The only test, that upd_print_page
1036 does, is the verification wether the device is in a sane state. This
1037 must be done here, since during the initialisation, the device is
1038 usually opened several times, before obtaining a valid state.
1039 */
1040 
1041 private int
upd_print_page(gx_device_printer * pdev,FILE * out)1042 upd_print_page(gx_device_printer *pdev, FILE *out)
1043 {
1044    upd_device *const udev  = (upd_device *) pdev;
1045    const upd_p       upd   = udev->upd;
1046    const int *const  ints  = upd ? upd->ints : NULL;
1047    int error,need,yfill;
1048 
1049 #if UPD_SIGNAL /* variables required for signal-handling only */
1050    void (*oldint )(int) = NULL;
1051    void (*oldterm)(int) = NULL;
1052    upd_p  oldupd            = sigupd;
1053 #endif         /* variables required for signal-handling only */
1054 
1055 /*
1056  * Refuse to work, if not explicitly enabled during open
1057  * (some/lot of allocated memory is required)
1058  */
1059    if(!upd || B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR))) {
1060 #if UPD_MESSAGES & (UPD_M_ERROR | UPD_M_TOPCALLS)
1061          errprintf("CALL-REJECTED upd_print_page(0x%05lx,0x%05lx)\n",
1062              (long) udev,(long) out);
1063 #endif
1064       return gs_error_undefined;
1065    }
1066 
1067 #if UPD_MESSAGES & UPD_M_TOPCALLS
1068    errprintf("CALL: upd_print_page(0x%05lx,0x%05lx)\n",
1069       (long) udev,(long) out);
1070 #endif
1071 
1072 #if UPD_SIGNAL /* Setup of signal-handling */
1073    sigupd  = upd;
1074    oldint  = signal(SIGINT, upd_signal_handler);
1075    oldterm = signal(SIGTERM,upd_signal_handler);
1076 #endif         /* Setup of signal-handling */
1077 
1078 /*
1079  * If the OutputFile was just opened, transfer the Open-Sequence to it.
1080  */
1081    if(!(upd->flags & B_OPEN)) {
1082 
1083       if(0   <  upd->strings[S_OPEN].size)
1084          fwrite(upd->strings[S_OPEN].data,1,upd->strings[S_OPEN].size,out);
1085       upd->flags |= B_OPEN;
1086    }
1087 /*
1088  * Always write the the Page-begin-sequence
1089  */
1090    if(0  <   upd->strings[S_BEGIN].size)
1091       fwrite(upd->strings[S_BEGIN].data,1,upd->strings[S_BEGIN].size,out);
1092 /*
1093  * Establish page-variables
1094  */
1095 
1096 /* Positions */
1097    upd->xprinter  = 0;
1098    upd->yscan     = 0; /* Position we are processing */
1099    upd->yprinter  = 0; /* Actual Printer-Positions */
1100    upd->yscnbuf   = 0; /* Next free scnbuf-Line */
1101 
1102 /* Rendering & Writing Setup, if available */
1103    if(upd->start_render) (*upd->start_render)(upd);
1104    if(upd->start_writer) (*upd->start_writer)(upd,out);
1105 
1106 /* How many scanlines do we need ? */
1107    need = ints[I_NYPASS] * ints[I_PINS2WRITE];
1108    if(0 >= need) need = 1;
1109 
1110 /* The Weave-counters */
1111    upd->ipass  =  0;
1112    upd->ixpass =  0;
1113    upd->icomp  = -1; /* Enforces initial selection */
1114    upd->lf     = -1; /* Enforces initial selection */
1115 /*
1116  * Main Loop
1117  */
1118    while(upd->pheight > upd->yscan) { /* Main-Loop */
1119 
1120 /*
1121  *    Load as much data into the scan-buffer as possible
1122  *    (this is done in scan-sequence, the printing not necessarily.)
1123  */
1124       if(ints[I_BEGSKIP] > upd->yscan) yfill = 0;
1125       else                             yfill = upd->yscan - ints[I_BEGSKIP];
1126 
1127       for(yfill += upd->nscnbuf; upd->yscnbuf < yfill; upd->yscnbuf++) {
1128 
1129          if(upd->gsheight > upd->yscnbuf)  {
1130 
1131             if(0 > (*dev_proc(udev,get_bits))((gx_device *) udev,
1132                                    upd->yscnbuf,upd->gsbuf,&upd->gsscan)) {
1133 #if UPD_MESSAGES & UPD_M_WARNING
1134                errprintf("get_bits aborted with error, yscnbuf = %4d\n",
1135                   upd->yscnbuf);
1136 #endif
1137                break;
1138             }
1139          } else {
1140 
1141             memset(upd->gsscan = upd->gsbuf,0,upd->ngsbuf);
1142 
1143          }
1144 
1145          if(0 > (*upd->render)(upd)) {
1146 #if UPD_MESSAGES & UPD_M_WARNING
1147             errprintf("Rendering aborted with error, yscnbuf = %4d\n",
1148                upd->yscnbuf);
1149 #endif
1150             break;
1151          }
1152 
1153       }
1154 /*
1155  *    Did the buffering loop take an error exit ?
1156  */
1157       if((upd->yscnbuf ^ yfill) & upd->scnmsk) break;
1158 /*
1159  *    Print as much as possible
1160  */
1161       while((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) {
1162 
1163 /*        first write the scan(s) */
1164           (*upd->writer)(upd,out);
1165 
1166 /*        Check for termination */
1167           if(upd->yscan >= upd->pheight) break;
1168           if(upd->flags  & B_ABORT ) {
1169 #if UPD_MESSAGES & UPD_M_WARNING
1170              errprintf("Printing aborted upon interrupt, yscan = %4d\n",
1171                 upd->yscan);
1172 #endif
1173              break;
1174           }
1175       }
1176 /*
1177  *    Did the print-Loop take an error exit ?
1178  */
1179       if((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) break;
1180    }                                  /* Main-Loop */
1181 
1182 /*
1183  * If we aborted for some reason, use the dedicated sequence
1184  */
1185 
1186    if((upd->pheight > upd->yscan) &&
1187       (0  <  upd->strings[S_ABORT].size)) { /* Only This! */
1188       fwrite(upd->strings[S_ABORT].data,1,upd->strings[S_ABORT].size,out);
1189 
1190       upd->flags &= ~B_OPEN; /* Inhibit Close-Sequence ! */
1191 /*
1192  * If there is no special sequence, or we came to normal end,
1193  * write the normal sequence, if any
1194  */
1195 
1196    } else if(0  <   upd->strings[S_END].size) {
1197       fwrite(upd->strings[S_END].data,1,upd->strings[S_END].size,out);
1198    }
1199 /*
1200  * If necessary, write the close-sequence
1201  */
1202    if((NULL != udev->fname  ) && strchr(udev->fname,'%')) {
1203 
1204       if(0  <   upd->strings[S_CLOSE].size)
1205          fwrite(upd->strings[S_CLOSE].data,1,upd->strings[S_CLOSE].size,out);
1206 
1207       upd->flags &= ~B_OPEN;
1208    }
1209 
1210 /*
1211  * clean up, and return status
1212  */
1213 
1214    fflush(out); /* just to prepare for ferror */
1215 
1216    if(upd->pheight > upd->yscan) error = gs_error_interrupt;
1217    else if(ferror(out))          error = gs_error_ioerror;
1218    else                          error = 0;
1219 
1220 #if UPD_MESSAGES & UPD_M_TOPCALLS
1221    errprintf("RETURN: %d = upd_print_page(0x%05lx,0x%05lx)\n",
1222       error,(long) udev,(long)out);
1223 #endif
1224 
1225 #if UPD_SIGNAL /* Restore Interrupt-state */
1226       sigupd = oldupd;
1227       (void) signal(SIGINT ,oldint);
1228       (void) signal(SIGTERM,oldterm);
1229 #endif         /* Restore Interrupt-state */
1230 
1231    return error;
1232 }
1233 
1234 /* ------------------------------------------------------------------- */
1235 /* upd_open: Initialize everything for printing                        */
1236 /* ------------------------------------------------------------------- */
1237 /**
1238 "upd_open" is -through the specified table of procedures- called instead
1239 of the normal open-procedures for printer-devices, that performs quite
1240 a complex job. Thus it is necessary to call this  `superclass-open�
1241 here.
1242 
1243 Besides that, this routine does quite a complex job too, in initializes
1244 everything required to print a page. This might be time-consuming, the
1245 alternative would be "upd_print_page", but i often print 100 pages or
1246 more, but i never experienced more than 5-6 open-calls.
1247 */
1248 
1249 private int
upd_open(gx_device * pdev)1250 upd_open(gx_device *pdev)
1251 {
1252    upd_device *const udev    =  (upd_device *) pdev;
1253    const upd_p       upd     =  udev->upd;
1254    int              error;
1255 
1256 #if UPD_MESSAGES & UPD_M_TOPCALLS
1257       errprintf("CALL: upd_open(0x%05lx)\n",(long) pdev);
1258 #endif
1259 
1260 /** enforce the UPD-Margins */
1261 
1262    if((NULL != upd) &&
1263       (NULL != upd->float_a[FA_MARGINS].data) &&
1264       (4    == upd->float_a[FA_MARGINS].size)    ) {
1265       static float m[4];
1266       m[1] = upd->float_a[FA_MARGINS].data[1] / 72.0;
1267       m[3] = upd->float_a[FA_MARGINS].data[3] / 72.0;
1268       if(B_YFLIP & upd->flags) {
1269          m[0] = upd->float_a[FA_MARGINS].data[2] / 72.0;
1270          m[2] = upd->float_a[FA_MARGINS].data[0] / 72.0;
1271       } else {
1272          m[0] = upd->float_a[FA_MARGINS].data[0] / 72.0;
1273          m[2] = upd->float_a[FA_MARGINS].data[2] / 72.0;
1274       }
1275       gx_device_set_margins((gx_device *) udev, m, true);
1276    }
1277 
1278 /** call the super-class open **/
1279    error = gdev_prn_open(pdev);
1280 
1281 /** invoke the subroutines, if an upd is present. */
1282 
1283    if(upd) {
1284 
1285       upd->flags &= ~B_OK4GO;
1286 
1287 /**
1288 The following initializations are run, even in case of an error in
1289 the super-class open, just to bring our upd into a sane state.
1290 */
1291       if(0 > error) upd->flags |= B_ERROR;
1292 
1293       if(gs_error_VMerror == upd_open_map(udev)) error = gs_error_VMerror;
1294 
1295 /**
1296 The following piece of code is here for demonstration-purposes:
1297 It determines the size of the printed image and allocates the
1298 buffer for the raw raster-data
1299 */
1300       upd->gswidth  = udev->width -
1301          (int)((dev_l_margin(udev)+dev_r_margin(udev))*udev->x_pixels_per_inch);
1302 
1303       upd->gsheight = udev->height -
1304          (int)((dev_t_margin(udev)+dev_b_margin(udev))*udev->y_pixels_per_inch);
1305 
1306       upd->ngsbuf = 0;    /* Ensure sane values */
1307       upd->gsbuf  = NULL; /* Ensure sane values */
1308 
1309       if(B_MAP & upd->flags) { /* Only if prerequisites were met */
1310          uint want  = gx_device_raster(pdev,true);
1311          upd->gsbuf = gs_malloc(pdev->memory, want,1,"upd/gsbuf");
1312 
1313          if(upd->gsbuf) {
1314             upd->ngsbuf = want;
1315             upd->flags |= B_BUF;  /* Signal Success */
1316          } else {
1317             error = gs_error_VMerror; /* Signal Error */
1318             upd->flags |= B_ERROR;
1319          }
1320 
1321       }                            /* Only if prerequisites were met */
1322 
1323       upd_open_render(udev);  /* First subloop in printing */
1324 
1325       if(gs_error_VMerror == upd_open_writer(udev)) error = gs_error_VMerror;
1326 
1327       udev->upd->pdwidth  = udev->width;
1328       udev->upd->pdheight = udev->height;
1329 
1330 #if UPD_MESSAGES & UPD_M_SETUP
1331       if((upd->flags & (B_OK4GO | B_ERROR)) == B_OK4GO) {
1332         int i,j,l,ln,lv;
1333         errprintf("\nupd->flags    = 0x%05lx\n",(unsigned long)upd->flags);
1334         errprintf(  "upd->pdwidth  = %5d\n",upd->pdwidth);
1335         errprintf(  "upd->pdheight = %5d\n",upd->pdheight);
1336         errprintf(  "upd->ngsbuf   = %5u\n",upd->ngsbuf);
1337         errprintf(  "upd->gswidth  = %5d\n",upd->gswidth);
1338         errprintf(  "upd->gsheight = %5d\n",upd->gsheight);
1339         errprintf(  "upd->rwidth   = %5d\n",upd->rwidth);
1340         errprintf(  "upd->pwidth   = %5d\n",upd->pwidth);
1341         errprintf(  "upd->pheight  = %5d\n",upd->pheight);
1342         errprintf(  "upd->nvalbuf  = %5u\n",upd->nvalbuf);
1343         errprintf(  "upd->nscnbuf  = %5d\n",upd->nscnbuf);
1344         errprintf(  "upd->ncomp    = %5d\n",upd->ncomp);
1345         errprintf(  "upd->ocomp    = %5d\n",upd->ocomp);
1346         errprintf(  "upd->nbytes   = %5d\n",upd->nbytes);
1347         errprintf(  "upd->nlimits  = %5d\n",upd->nlimits);
1348         errprintf(  "upd->scnmsk   = %5d\n",upd->scnmsk);
1349         errprintf(  "upd->noutbuf  = %5u\n",upd->noutbuf);
1350         errprintf(  "upd->ixpass   = %5d\n",upd->ixpass);
1351         errprintf(  "upd->ipass    = %5d\n",upd->ipass);
1352         errprintf(  "upd->icomp    = %5d\n",upd->icomp);
1353         errprintf(  "upd->lf       = %5d\n",upd->lf);
1354         errprintf(  "upd->xprinter = %5d\n",upd->xprinter);
1355         errprintf(  "upd->yscan    = %5d\n",upd->yscan);
1356         errprintf(  "upd->yprinter = %5d\n",upd->yprinter);
1357         errprintf(  "upd->yscnbuf  = %5d\n",upd->yscnbuf);
1358 
1359         ln = 13;
1360         lv = 5;
1361         for(i = 0; countof(upd_choice) > i; ++i) {
1362           if(!upd_choice[i]) continue;
1363           l = strlen(upd_choice[i][0]);
1364           if(ln < l) ln = l;
1365           for(j = 1; upd_choice[i][j]; ++j) {
1366             l = strlen(upd_choice[i][j]);
1367             if(lv < l) lv = l;
1368           }
1369         }
1370 
1371         for(i = 0; countof(upd_flags) > i; ++i) {
1372           if(upd_flags[i]) {
1373             l = strlen(upd_flags[i]);
1374             if(ln < l) ln = l;
1375           }
1376         }
1377 
1378         for(i = 0; countof(upd_ints) > i; ++i) {
1379           if(upd_ints[i]) {
1380             l = strlen(upd_ints[i]);
1381             if(ln < l) ln = l;
1382           }
1383         }
1384 
1385         for(i = 0; countof(upd_int_a) > i; ++i) {
1386           if(upd_int_a[i]) {
1387             l = strlen(upd_int_a[i]);
1388             if(ln < l) ln = l;
1389           }
1390         }
1391 
1392         for(i = 0; countof(upd_strings) > i; ++i) {
1393           if(upd_strings[i]) {
1394             l = strlen(upd_strings[i]);
1395             if(ln < l) ln = l;
1396           }
1397         }
1398 
1399         for(i = 0; countof(upd_string_a) > i; ++i) {
1400           if(upd_string_a[i]) {
1401             l = strlen(upd_string_a[i]);
1402             if(ln < l) ln = l;
1403           }
1404         }
1405 
1406         for(i = 0; countof(upd_float_a) > i; ++i) {
1407           if(upd_float_a[i]) {
1408             l = strlen(upd_float_a[i]);
1409             if(ln < l) ln = l;
1410           }
1411         }
1412 
1413         for(i = 0; countof(upd_choice) > i; ++i) {
1414           if(upd_choice[i]) {
1415             errprintf("%*s = %-*s (%2d)\n",ln,upd_choice[i][0],
1416                lv,upd_choice[i][upd->choice[i]],upd->choice[i]);
1417           } else {
1418             errprintf("%*s[%2d] = %2d\n",ln-4,"upd_choice",i,
1419                upd->choice[i]);
1420           }
1421         }
1422 
1423         for(i = 0; countof(upd_flags) > i; ++i) {
1424           if(upd_flags[i]) {
1425             errprintf("%*s = %s\n",ln,upd_flags[i],
1426                ((uint32_t) 1 << i) & upd->flags ? "true" : "false");
1427           } else {
1428             errprintf("%*s[%2d] = %s\n",ln-4,"upd_flags",i,
1429                ((uint32_t) 1 << i) & upd->flags ? "true" : "false");
1430 
1431           }
1432         }
1433 
1434         for(i = 0; countof(upd_ints) > i; ++i) {
1435           if(upd_ints[i]) {
1436             errprintf("%*s = %5d\n",ln,upd_ints[i],upd->ints[i]);
1437           } else {
1438             errprintf("%*s[%2d] = %5d\n",ln-4,"upd_ints",i,upd->ints[i]);
1439           }
1440         }
1441 
1442       }
1443 
1444 
1445       errprintf("\n%sready to print\n\n",
1446          B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR)) ?
1447          "NOT " : "");
1448 #endif
1449 
1450    }
1451 
1452 #if UPD_MESSAGES & UPD_M_TOPCALLS
1453       errprintf("RETURN: %d = upd_open(0x%05lx)\n",
1454          error,(long) pdev);
1455 #endif
1456 
1457    return error;
1458 }
1459 
1460 /* ------------------------------------------------------------------- */
1461 /* upd_close: Release everything allocated in upd_open                 */
1462 /* ------------------------------------------------------------------- */
1463 
1464 private int
upd_close(gx_device * pdev)1465 upd_close(gx_device *pdev)
1466 {
1467    upd_device *const udev    =  (upd_device *) pdev;
1468    const upd_p       upd     =  udev->upd;
1469    int         error = 0;
1470    int         code;
1471 
1472 #if UPD_MESSAGES & UPD_M_TOPCALLS
1473    errprintf("CALL: upd_close(0x%05lx)\n",(long)pdev);
1474 #endif
1475 
1476 /** If necessary, write the close-sequence **/
1477 
1478    if( upd && (( B_OPEN | B_OK4GO) ==
1479                ((B_OPEN | B_OK4GO | B_ERROR) & upd->flags))) {
1480 
1481       if(udev->file && upd->strings && 0 < upd->strings[S_CLOSE].size)
1482          fwrite(upd->strings[S_CLOSE].data,1,
1483                 upd->strings[S_CLOSE].size,udev->file);
1484 
1485       upd->flags &= ~B_OPEN;
1486    }
1487 
1488 /** Then release the open-allocated memory */
1489    if(upd) {
1490 
1491       upd_close_writer(udev);
1492 
1493       if(upd->gsbuf)
1494          gs_free(pdev->memory, upd->gsbuf,upd->ngsbuf,1,"uniprint/gsbuf");
1495       upd->gsbuf  = NULL;
1496       upd->ngsbuf = 0;
1497       upd->flags &= ~B_BUF;
1498 
1499       upd_close_render(udev);
1500       upd_close_map(udev);
1501 
1502       UPD_MM_DEL_ARRAY(pdev->memory, upd->choice,  countof(upd_choice),  UPD_MM_DEL_VALUE);
1503       UPD_MM_DEL_ARRAY(pdev->memory, upd->ints,    countof(upd_ints),    UPD_MM_DEL_VALUE);
1504       UPD_MM_DEL_ARRAY(pdev->memory, upd->int_a,   countof(upd_int_a),   UPD_MM_DEL_PARAM);
1505       UPD_MM_DEL_ARRAY(pdev->memory, upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
1506       UPD_MM_DEL_ARRAY(pdev->memory, upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
1507       UPD_MM_DEL_ARRAY(pdev->memory, upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
1508 
1509       gs_free(pdev->memory, upd,sizeof(upd[0]),1,"uniprint");
1510 
1511       udev->upd = NULL;
1512    }
1513 
1514 /** Then call the superclass close **/
1515    code = gdev_prn_close(pdev);
1516    error = error > code ? code : error;
1517 
1518 
1519 #if UPD_MESSAGES & UPD_M_TOPCALLS
1520       errprintf("RETURN: %d = upd_close(0x%05lx)\n",
1521          error,(long) pdev);
1522 #endif
1523 
1524    return error;
1525 }
1526 
1527 /* ------------------------------------------------------------------- */
1528 /* upd_get_params: Export Parameters to the Interpreter                */
1529 /* ------------------------------------------------------------------- */
1530 
1531 #if UPD_MESSAGES & UPD_M_TOPCALLS
1532 #define UPD_EXIT_GET(Err,Dev,List)                                      \
1533    if(0 > Err) {                                                        \
1534       errprintf("RETURN-%d: %d upd_get_params(0x%05lx,0x%05lx)\n", \
1535          __LINE__,Err,(long) Dev,(long) List);                          \
1536       return_error(Err);                                                \
1537    }
1538 #else
1539 #define UPD_EXIT_GET(Err,Dev,List) if(0 > Err) return_error(Err);
1540 #endif
1541 
1542 private int
upd_get_params(gx_device * pdev,gs_param_list * plist)1543 upd_get_params(gx_device *pdev, gs_param_list *plist)
1544 {
1545    upd_device *const udev    =  (upd_device *) pdev;
1546    const upd_p       upd     =  udev->upd;
1547    int               error,i;
1548 
1549 #if UPD_MESSAGES & UPD_M_TOPCALLS
1550       errprintf("CALL: upd_get_params(0x%05lx,0x%05lx)\n",
1551          (long) udev,(long) plist);
1552 #endif
1553 
1554 /** Call the SuperClass-get_params at the beginning */
1555    error = gdev_prn_get_params((gx_device *)udev,plist);
1556    UPD_EXIT_GET(error,udev,plist);
1557 
1558 /** Export the version */
1559    if(upd_version) { /* Version-Export enabled */
1560       udev->upd_version.data       = (const byte *) rcsid;
1561       udev->upd_version.size       = strlen(rcsid);
1562       udev->upd_version.persistent = true;
1563       error = param_write_string(plist,upd_version,&udev->upd_version);
1564       UPD_EXIT_GET(error,udev,plist);
1565    }                 /* Version-Export enabled */
1566 
1567 /** Export the Named choices */
1568    for(i = 0; i < countof(upd_choice); ++i) {
1569       if(!upd_choice[i]) continue; /* Choice-Export disabled */
1570       if(upd && upd->choice && upd->choice[i]) {
1571          gs_param_string name;
1572          name.data       = (const byte *) upd_choice[i][upd->choice[i]];
1573          name.size       = strlen((const char *) name.data);
1574          name.persistent = true;
1575          error = param_write_name(plist,upd_choice[i][0],&name);
1576       } else {
1577          error = param_write_null(plist,upd_choice[i][0]);
1578       }
1579       UPD_EXIT_GET(error,udev,plist);
1580    }
1581 
1582 /** Export the flags (bool) */
1583    for(i = 0; i < countof(upd_flags); ++i) {
1584       if(!upd_flags[i]) continue; /* Flag-Export disabled */
1585       if(upd) {
1586          bool value = upd->flags & ((uint32_t) 1 << i);
1587          error = param_write_bool(plist,upd_flags[i],&value);
1588       } else {
1589          error = param_write_null(plist,upd_flags[i]);
1590       }
1591       UPD_EXIT_GET(error,udev,plist);
1592    }
1593 
1594 /** Export the ints */
1595    for(i = 0; i < countof(upd_ints); ++i) {
1596       if(!upd_ints[i]) continue; /* int-Export disabled */
1597       if(upd && upd->ints && upd->ints[i]) {
1598          int value = upd->ints[i];
1599          error = param_write_int( plist,upd_ints[i],&value);
1600       } else {
1601          error = param_write_null(plist,upd_ints[i]);
1602       }
1603       UPD_EXIT_GET(error,udev,plist);
1604    }
1605 
1606 /** Export the int-arrays */
1607    for(i = 0; i < countof(upd_int_a); ++i) {
1608       if(!upd_int_a[i]) continue; /* int-Array-Export disabled */
1609       if(upd && upd->int_a && upd->int_a[i].size) {
1610          error = param_write_int_array( plist,upd_int_a[i],(upd->int_a+i));
1611       } else {
1612          error = param_write_null(plist,upd_int_a[i]);
1613       }
1614       UPD_EXIT_GET(error,udev,plist);
1615    }
1616 
1617 /** Export the strings */
1618    for(i = 0; i < countof(upd_strings); ++i) {
1619       if(!upd_strings[i]) continue; /* String-Export disabled */
1620       if(upd && upd->strings && upd->strings[i].size) {
1621          error = param_write_string( plist,upd_strings[i],(upd->strings+i));
1622       } else {
1623          error = param_write_null(plist,upd_strings[i]);
1624       }
1625       UPD_EXIT_GET(error,udev,plist);
1626    }
1627 
1628 /** Export the string-Arrays */
1629    for(i = 0; i < countof(upd_string_a); ++i) {
1630       if(!upd_string_a[i]) continue; /* String-Array-Export disabled */
1631       if(upd && upd->string_a && upd->string_a[i].size) {
1632          error =
1633             param_write_string_array( plist,upd_string_a[i],(upd->string_a+i));
1634       } else {
1635          error = param_write_null(plist,upd_string_a[i]);
1636       }
1637       UPD_EXIT_GET(error,udev,plist);
1638    }
1639 
1640 /** Export the float-Arrays */
1641    for(i = 0; i < countof(upd_float_a); ++i) {
1642       if(!upd_float_a[i]) continue; /* Float-Array-Export disabled */
1643       if(upd && upd->float_a && upd->float_a[i].size) {
1644          error =
1645             param_write_float_array( plist,upd_float_a[i],(upd->float_a+i));
1646       } else {
1647          error = param_write_null(plist,upd_float_a[i]);
1648       }
1649       UPD_EXIT_GET(error,udev,plist);
1650    }
1651 
1652 #if UPD_MESSAGES & UPD_M_TOPCALLS
1653    errprintf("RETURN: %d = upd_get_params(0x%05lx,0x%05lx)\n",
1654        error,(long) udev,(long) plist);
1655 #endif
1656 
1657    return error;
1658 }
1659 
1660 #undef UPD_EXIT_GET
1661 
1662 /* ------------------------------------------------------------------- */
1663 /* upd_put_params: Load Parameters into the device-structure           */
1664 /* ------------------------------------------------------------------- */
1665 
1666 private int
upd_put_params(gx_device * pdev,gs_param_list * plist)1667 upd_put_params(gx_device *pdev, gs_param_list *plist)
1668 {
1669    upd_device *const      udev       = (upd_device *) pdev;
1670    upd_p                  upd        = udev->upd;
1671    int                    error      = 0, code,i;
1672 
1673    float                  MarginsHWResolution[2],Margins[2];
1674    gx_device_color_info   color_info;
1675    uint32_t                 flags      = 0;
1676    int                   *choice     = NULL;
1677    int                   *ints       = NULL;
1678    gs_param_int_array    *int_a      = NULL;
1679    gs_param_string       *strings    = NULL;
1680    gs_param_string_array *string_a   = NULL;
1681    gs_param_float_array  *float_a    = NULL, mfa;
1682 
1683 /**
1684 Error is used for two purposes: either it holds a negative error
1685 code or it is used as a bitfield, that tells, which parameters
1686 were actually loaded.  If any of the important parameters changed
1687 upd_put_params closes the device, since the real parameter-evaluation
1688 is carried out by upd_open.
1689 */
1690 
1691 #define UPD_PUT_FLAGS       0x0002
1692 #define UPD_PUT_CHOICE      0x0004
1693 #define UPD_PUT_INTS        0x0008
1694 #define UPD_PUT_INT_A       0x0010
1695 #define UPD_PUT_STRINGS     0x0020
1696 #define UPD_PUT_STRING_A    0x0040
1697 #define UPD_PUT_FLOAT_A     0x0080
1698 #define UPD_PUT_CHANGEDSIZE 0x0100
1699 
1700 #if UPD_MESSAGES & UPD_M_TOPCALLS
1701       errprintf("CALL: upd_put_params(0x%05lx,0x%05lx)\n",
1702          (long)udev,(long)plist);
1703 #endif
1704 
1705 
1706 /**
1707 I consider the following part of upd_put_params a bad-nasty-hack-hack
1708 and i am uncertain, wether it really works in the intended way. I provide it
1709 just for the case someone is performing nasty-parameter-changes on the
1710 active device, especially switching the OutputFile. If this happens in
1711 a situation, where data were written to the file, but the termination
1712 sequence is required, the driver does it now. (If you want to know, why
1713 i am writing bad-nasty-hack-hack, visit http://www.zark.com )
1714 */
1715    if(upd && (B_OPEN & udev->upd->flags) && (NULL != udev->file)) {
1716 
1717       gs_param_string fname = { NULL, 0, false };
1718 
1719       code = param_read_string(plist,"OutputFile",&fname);
1720       if((1 != code) && (0 != code)) {
1721          code = param_read_null(plist,"OutputFile");
1722          if(0 == code) {
1723             fname.data = (const byte *) "";
1724             fname.size = 0;
1725          }
1726       }
1727 
1728       if((0 == code) &&
1729          strncmp((const char *)fname.data,udev->fname,fname.size)) {
1730          if(upd->strings && 0 < udev->upd->strings[S_CLOSE].size)
1731             fwrite(upd->strings[S_CLOSE].data,1,
1732                    upd->strings[S_CLOSE].size,udev->file);
1733 
1734          upd->flags &= ~B_OPEN;
1735       }
1736    }
1737 /* Done with the bad-nasty-hack-hack */
1738 
1739 /**
1740 The next thing "upd_put_params" does, is a little strange too. It imports
1741 a readonly-parameter, the version-string. I do not know wether it is still
1742 required, but some versions of GHOSTSCRIPT disliked it very much, if an
1743 existing parameter was not touched by the put-operation.
1744 
1745 On the other hand it is the right time to show the basic-outline of the
1746 parameter-importing flow. Basically the proper "param_read"-procedure
1747 is called. If it indicated, that the parameter was present, but of the
1748 wrong type, a read for the null-type is attempted, which is by convention
1749 somehow an reset to default. This sequence is applied to all the parameters
1750 and in case of the array-parameters, a succesful null-read is marked by
1751 setting data and size to 0.
1752 */
1753 #if UPD_MESSAGES & UPD_M_SETUP
1754 #define UPD_PARAM_READ(Param_read,Name,Object)       \
1755    code = Param_read(plist,Name,&Object);            \
1756    if(0 > code) {                                    \
1757       code = param_read_null(plist,Name);            \
1758       if(0 == code) memset(&Object,0,sizeof(Object));\
1759    }                                                 \
1760    if(!code) errprintf(                         \
1761       "upd_put_params: retrieved parameter \"%s\"\n",\
1762       Name);                                         \
1763    if(0 > code) {                                    \
1764       param_signal_error(plist,Name,code);           \
1765       if(error > code) error = code;                 \
1766    }
1767 #else
1768 #define UPD_PARAM_READ(Param_read,Name,Object)       \
1769    code = Param_read(plist,Name,&Object);            \
1770    if(0 > code) {                                    \
1771       code = param_read_null(plist,Name);            \
1772       if(0 == code) memset(&Object,0,sizeof(Object));\
1773    }                                                 \
1774    if(0 > code) {                                    \
1775       param_signal_error(plist,Name,code);           \
1776       if(error > code) error = code;                 \
1777    }
1778 #endif
1779 
1780    UPD_PARAM_READ(param_read_string,upd_version,udev->upd_version)
1781 
1782 
1783 /**
1784 upd_put_params begins it's normal work by creating a copy, of
1785 the data, that it might change, except for color_info that might
1786 be changed in the device-structure, all manipulations are carried
1787 out on this copies.
1788 */
1789    MarginsHWResolution[0] = udev->MarginsHWResolution[0];
1790    MarginsHWResolution[1] = udev->MarginsHWResolution[1];
1791                Margins[0] = udev->Margins[0];
1792                Margins[1] = udev->Margins[1];
1793 
1794    color_info = udev->color_info;
1795    if(upd) {
1796      flags = upd->flags;
1797      UPD_MM_CPY_ARRAY(udev->memory, choice,  upd->choice,  countof(upd_choice),
1798         UPD_MM_CPY_VALUE);
1799      UPD_MM_CPY_ARRAY(udev->memory, ints,    upd->ints,    countof(upd_ints),
1800         UPD_MM_CPY_VALUE);
1801      UPD_MM_CPY_ARRAY(udev->memory, int_a,   upd->int_a,   countof(upd_int_a),
1802         UPD_MM_CPY_PARAM);
1803      UPD_MM_CPY_ARRAY(udev->memory, strings, upd->strings, countof(upd_strings),
1804         UPD_MM_CPY_PARAM);
1805      UPD_MM_CPY_ARRAY(udev->memory, string_a,upd->string_a,countof(upd_string_a),
1806         UPD_MM_CPY_APARAM);
1807      UPD_MM_CPY_ARRAY(udev->memory, float_a, upd->float_a, countof(upd_float_a),
1808         UPD_MM_CPY_PARAM);
1809    } else {
1810      flags = 0;
1811      UPD_MM_GET_ARRAY(udev->memory, choice,  countof(upd_choice));
1812      UPD_MM_GET_ARRAY(udev->memory, ints,    countof(upd_ints));
1813      UPD_MM_GET_ARRAY(udev->memory, int_a,   countof(upd_int_a));
1814      UPD_MM_GET_ARRAY(udev->memory, strings, countof(upd_strings));
1815      UPD_MM_GET_ARRAY(udev->memory, string_a,countof(upd_string_a));
1816      UPD_MM_GET_ARRAY(udev->memory, float_a, countof(upd_float_a));
1817    }
1818 
1819 /** Import the Multiple-Choices */
1820    for(i = 0; countof(upd_choice) > i; ++i) {
1821       gs_param_string value = { NULL, 0, false};
1822       if(!upd_choice[i][0]) continue;
1823       UPD_PARAM_READ(param_read_name,upd_choice[i][0],value);
1824       if(0 == code) {
1825          if(0 <= error) error |= UPD_PUT_CHOICE;
1826          choice[i] = 0;
1827          if(0 < value.size) {
1828             int j;
1829             for(j = 1; upd_choice[i][j]; ++j) {
1830                if((strlen(upd_choice[i][j]) == value.size) &&
1831                   (0 == strncmp(upd_choice[i][j],
1832                             (const char *) value.data,value.size))) {
1833                   choice[i] = j;
1834                   break;
1835                }
1836             }
1837          }
1838       }
1839    }
1840 
1841 /** Import the Boolean Values */
1842    for(i = 0; countof(upd_flags) > i; ++i) {
1843       uint32_t bit  = (uint32_t) 1 << i;
1844       bool   flag = flags & bit ? true : false;
1845       if(!upd_flags[i]) continue;
1846       UPD_PARAM_READ(param_read_bool,upd_flags[i],flag);
1847       if(0 == code) {
1848          if(0 <= error) error |= UPD_PUT_FLAGS;
1849          if(flag) flags |=  bit;
1850          else     flags &= ~bit;
1851       }
1852    }
1853 
1854 /** Import the Integer Values */
1855    for(i = 0; countof(upd_ints) > i; ++i) {
1856       int value = ints[i];
1857       if(!upd_ints[i]) continue;
1858       UPD_PARAM_READ(param_read_int,upd_ints[i],value);
1859       if(0 == code) {
1860          if(0 <= error) error |= UPD_PUT_INTS;
1861          ints[i] = value;
1862       }
1863    }
1864 
1865 /** Import the Integer Arrays */
1866    for(i = 0; countof(upd_int_a) > i; ++i) {
1867       gs_param_int_array value = int_a[i];
1868       if(!upd_int_a[i]) continue;
1869       UPD_PARAM_READ(param_read_int_array,upd_int_a[i],value);
1870       if(0 == code) {
1871          if(0 <= error) error |= UPD_PUT_INT_A;
1872          UPD_MM_DEL_PARAM(udev->memory, int_a[i]);
1873          if(!value.size) {
1874             value.data = NULL;
1875             int_a[i]   = value;
1876          } else {
1877             UPD_MM_CPY_PARAM(udev->memory, int_a[i],value);
1878          }
1879       }
1880    }
1881 
1882 /** Import the Strings */
1883    for(i = 0; countof(upd_strings) > i; ++i) {
1884       gs_param_string value = strings[i];
1885       if(!upd_strings[i]) continue;
1886       UPD_PARAM_READ(param_read_string,upd_strings[i],value);
1887       if(0 == code) {
1888          if(0 <= error) error |= UPD_PUT_STRINGS;
1889          UPD_MM_DEL_PARAM(udev->memory, strings[i]);
1890          if(!value.size) {
1891             value.data = NULL;
1892             strings[i]   = value;
1893          } else {
1894             UPD_MM_CPY_PARAM(udev->memory, strings[i],value);
1895          }
1896       }
1897    }
1898 
1899 /** Import the String Arrays */
1900    for(i = 0; countof(upd_string_a) > i; ++i) {
1901       gs_param_string_array value = string_a[i];
1902       if(!upd_string_a[i]) continue;
1903       UPD_PARAM_READ(param_read_string_array,upd_string_a[i],value);
1904       if(0 == code) {
1905          if(0 <= error) error |= UPD_PUT_STRING_A;
1906          UPD_MM_DEL_APARAM(udev->memory, string_a[i]);
1907          if(!value.size) {
1908             value.data  = NULL;
1909             string_a[i] = value;
1910          } else {
1911             UPD_MM_CPY_APARAM(udev->memory, string_a[i],value);
1912          }
1913       }
1914    }
1915 
1916 /** Import the Float Arrays */
1917    for(i = 0; countof(upd_float_a) > i; ++i) {
1918       gs_param_float_array value = float_a[i];
1919       if(!upd_float_a[i]) continue;
1920       UPD_PARAM_READ(param_read_float_array,upd_float_a[i],value);
1921       if(0 == code) {
1922          if(0 <= error) error |= UPD_PUT_FLOAT_A;
1923          UPD_MM_DEL_PARAM(udev->memory, float_a[i]);
1924          if(!value.size) {
1925             value.data = NULL;
1926             float_a[i] = value;
1927          } else {
1928             UPD_MM_CPY_PARAM(udev->memory, float_a[i],value);
1929          }
1930       }
1931    }
1932 
1933 /**
1934 Prior to the call to the superclass-put_params, the memory-layout and
1935 the color-model needs adjustment. This is performed here, if any parameters
1936 were set.
1937 In addition to that, Resolution & Margin-Parameters are tested & adjusted.
1938 */
1939    if(0 < error) {
1940 
1941       int *ip,*ip2,ncomp,nbits;
1942 
1943       if(6 > int_a[IA_COLOR_INFO].size) {
1944          UPD_MM_DEL_PARAM(udev->memory, int_a[IA_COLOR_INFO]);
1945          UPD_MM_GET_ARRAY(udev->memory, int_a[IA_COLOR_INFO].data,6);
1946          int_a[IA_COLOR_INFO].size = 6;
1947       }
1948       ip = (int *) upd_cast(int_a[IA_COLOR_INFO].data);
1949 
1950       if(0 == ip[0]) { /* Try to obtain num_components */
1951          switch(choice[C_MAPPER]) {
1952             case MAP_GRAY:     ip[0] = 1; break;
1953             case MAP_RGBW:     ip[0] = 3; break;
1954             case MAP_RGB:      ip[0] = 3; break;
1955             case MAP_CMYK:     ip[0] = 4; break;
1956             case MAP_CMYKGEN:  ip[0] = 4; break;
1957             case MAP_RGBOV:    ip[0] = 3; break;
1958             case MAP_RGBNOV:   ip[0] = 3; break;
1959             default:           ip[0] = color_info.num_components; break;
1960          }
1961       }                /* Try to obtain num_components */
1962 
1963       switch(choice[C_MAPPER]) {
1964          case MAP_GRAY:     ncomp = 1; break;
1965          case MAP_RGBW:     ncomp = 4; break;
1966          case MAP_RGB:      ncomp = 3; break;
1967          case MAP_CMYK:     ncomp = 4; break;
1968          case MAP_CMYKGEN:  ncomp = 4; break;
1969          case MAP_RGBOV:    ncomp = 4; break;
1970          case MAP_RGBNOV:   ncomp = 4; break;
1971          default:           ncomp = ip[0]; break;
1972       }
1973       if(UPD_CMAP_MAX < ncomp) ncomp = UPD_CMAP_MAX;
1974 
1975       if(ncomp > int_a[IA_COMPBITS].size) { /* Default ComponentBits */
1976          UPD_MM_GET_ARRAY(udev->memory, ip2,ncomp);
1977          nbits = 32 / ncomp;
1978          if(8 < nbits) nbits = 8;
1979          for(i = 0; i < ncomp; ++i) ip2[i] = nbits;
1980          UPD_MM_DEL_PARAM(udev->memory, int_a[IA_COMPBITS]);
1981          int_a[IA_COMPBITS].data = ip2;
1982          int_a[IA_COMPBITS].size = ncomp;
1983       }                                     /* Default ComponentBits */
1984 
1985       if(ncomp > int_a[IA_COMPSHIFT].size) {  /* Default ComponentShift */
1986          nbits = 0;
1987          for(i = 0; i < ncomp; ++i) nbits += int_a[IA_COMPBITS].data[i];
1988          UPD_MM_GET_ARRAY(udev->memory, ip2,ncomp);
1989          for(i = 0; i < ncomp; ++i) {
1990             ip2[i] = nbits - int_a[IA_COMPBITS].data[i];
1991             nbits -= int_a[IA_COMPBITS].data[i];
1992          }
1993          UPD_MM_DEL_PARAM(udev->memory, int_a[IA_COMPSHIFT]);
1994          int_a[IA_COMPSHIFT].data = ip2;
1995          int_a[IA_COMPSHIFT].size = ncomp;
1996       }                                       /* Default ComponentShift */
1997 
1998       if(0 == ip[1]) { /* Try to compute the depth */
1999          nbits = 0;
2000          for(i = 0; i < ncomp; ++i) {
2001             if(nbits < (int_a[IA_COMPBITS].data[i] +
2002                         int_a[IA_COMPSHIFT].data[i]))
2003                nbits =  int_a[IA_COMPBITS].data[i] +
2004                         int_a[IA_COMPSHIFT].data[i];
2005          }
2006          if(      1 >= nbits) nbits =  1;
2007          else if( 2 >= nbits) nbits =  2;
2008          else if( 4 >= nbits) nbits =  4;
2009          else if( 8 >= nbits) nbits =  8;
2010          else if(16 >= nbits) nbits = 16;
2011          else if(24 >= nbits) nbits = 24;
2012          else                 nbits = 32;
2013 
2014          ip[1] = nbits;
2015 
2016       }                /* Try to compute the depth */
2017 
2018       if(0 == ip[2]) { /* Number of Gray-Levels */
2019          nbits = 0;
2020          for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
2021             nbits = int_a[IA_COMPBITS].data[i];
2022          if(nbits > 8) nbits = 8;
2023          ip[2] = (1 << nbits) - 1;
2024       }                /* Number of Gray-Levels */
2025 
2026       if(0 == ip[3] && 1 < ip[0]) { /* Number of Colors */
2027          nbits = 0;
2028          for(i = 0; i < ip[0]; ++i) nbits += int_a[IA_COMPBITS].data[i];
2029          if(nbits > 8) nbits = 8;
2030          ip[3] = (1 << nbits) - 1;
2031       }                             /* Number of Colors */
2032 
2033       if(0 == ip[4]) { /* Gray-Ramp */
2034          nbits = 0;
2035          for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
2036             nbits = int_a[IA_COMPBITS].data[i];
2037          if(2 < nbits) ip[4] = 256;
2038          else          ip[4] = 2;
2039       }                /* Gray-Ramp */
2040 
2041       if(0 == ip[5] && 1 < ip[0]) { /* Color-Ramp */
2042          nbits = 0;
2043          for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
2044             nbits = int_a[IA_COMPBITS].data[i];
2045          if(2 < nbits) ip[5] = 256;
2046          else          ip[5] = 2;
2047       }                             /* Color-Ramp */
2048 
2049       udev->color_info.num_components = ip[0];
2050       udev->color_info.depth          = ip[1];
2051       udev->color_info.max_gray       = (gx_color_value) ip[2];
2052       udev->color_info.max_color      = (gx_color_value) ip[3];
2053       udev->color_info.dither_grays   = (gx_color_value) ip[4];
2054       udev->color_info.dither_colors  = (gx_color_value) ip[5];
2055 
2056 /*
2057  * Now we're dealing with the Resolution- & Margin-Stuff
2058  * (This is close to be a bad-nasty-hack-hack)
2059  */
2060       if((0 == param_read_float_array(plist,"HWResolution",&mfa)) &&
2061          (2 == mfa.size) && (0 != mfa.data)) {
2062          udev->MarginsHWResolution[0] = mfa.data[0];
2063          udev->MarginsHWResolution[1] = mfa.data[1];
2064       } else {
2065          udev->MarginsHWResolution[0] = udev->HWResolution[0];
2066          udev->MarginsHWResolution[1] = udev->HWResolution[1];
2067       }
2068 
2069       if((0 == param_read_float_array(plist,".HWMargins",&mfa)) &&
2070          (4 == mfa.size) && (0 != mfa.data)) {
2071          udev->Margins[0] = -mfa.data[0] * udev->MarginsHWResolution[0] / 72.0;
2072          udev->Margins[1] = -mfa.data[3] * udev->MarginsHWResolution[1] / 72.0;
2073       }
2074    }                                       /* Change the color-Info */
2075 
2076 /* Call the superclass-put_params now */
2077    code = gdev_prn_put_params((gx_device *)udev,plist);
2078    if(0 > code) error = code;
2079 
2080 /**
2081 If the superclass-"put_params" went o.k. too, then the new parameters are
2082 transferred into the device-structure. In the case of "uniprint", this may
2083 
2084  1. Close the device, which might fail.
2085  2. Allocate new memory for the upd-specific structure, that might fail too.
2086 
2087 */
2088 /* *HGS* recognize a changed device geometry */
2089    if( udev->upd &&                              /* HGS */
2090       ((udev->width  != udev->upd->pdwidth) ||   /* HGS */
2091       (udev->height != udev->upd->pdheight)  ))  /* HGS */
2092         error |= UPD_PUT_CHANGEDSIZE;            /* HGS */
2093 
2094    if(0 < error && udev->is_open) {
2095       code = gs_closedevice((gx_device *)udev);
2096       if(0 > code) error = code;
2097    }
2098 
2099    if(0 < error) { /* Actually something loaded without error */
2100 
2101       if(!(upd = udev->upd)) {
2102         UPD_MM_GET_ARRAY(udev->memory, udev->upd,1);
2103         upd = udev->upd;
2104       } else {
2105         UPD_MM_DEL_ARRAY(udev->memory, upd->choice,  countof(upd_choice),  UPD_MM_DEL_VALUE);
2106         UPD_MM_DEL_ARRAY(udev->memory, upd->ints,    countof(upd_ints),    UPD_MM_DEL_VALUE);
2107         UPD_MM_DEL_ARRAY(udev->memory, upd->int_a,   countof(upd_int_a),   UPD_MM_DEL_PARAM);
2108         UPD_MM_DEL_ARRAY(udev->memory, upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
2109         UPD_MM_DEL_ARRAY(udev->memory, upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
2110         UPD_MM_DEL_ARRAY(udev->memory, upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
2111       }
2112 
2113       upd->choice   = choice;
2114       upd->flags    = flags;
2115       upd->ints     = ints;
2116       upd->int_a    = int_a;
2117       upd->strings  = strings;
2118       upd->string_a = string_a;
2119       upd->float_a  = float_a;
2120 
2121       if(0 < error) error = 0;
2122 
2123    } else {
2124 
2125                   udev->Margins[0] =             Margins[0];
2126                   udev->Margins[1] =             Margins[1];
2127       udev->MarginsHWResolution[0] = MarginsHWResolution[0];
2128       udev->MarginsHWResolution[1] = MarginsHWResolution[1];
2129 
2130       udev->color_info = color_info;
2131       UPD_MM_DEL_ARRAY(udev->memory, choice,  countof(upd_choice),  UPD_MM_DEL_VALUE);
2132       UPD_MM_DEL_ARRAY(udev->memory, ints,    countof(upd_ints),    UPD_MM_DEL_VALUE);
2133       UPD_MM_DEL_ARRAY(udev->memory, int_a,   countof(upd_int_a),   UPD_MM_DEL_PARAM);
2134       UPD_MM_DEL_ARRAY(udev->memory, strings, countof(upd_strings), UPD_MM_DEL_PARAM);
2135       UPD_MM_DEL_ARRAY(udev->memory, string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
2136       UPD_MM_DEL_ARRAY(udev->memory, float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
2137 
2138    }
2139 
2140 /*
2141  * upd_put_params keeps the Procedures upd to date
2142  */
2143 
2144    upd_procs_map(udev);
2145 
2146 
2147 #if UPD_MESSAGES & UPD_M_TOPCALLS
2148       errprintf("RETURN: %d = upd_put_params(0x%05lx,0x%05lx)\n",
2149          error,(long) udev, (long) plist);
2150 #endif
2151 
2152    return error;
2153 }
2154 
2155 /* ------------------------------------------------------------------- */
2156 /* upd_cmyk_icolor: KCMY->KCMY-Index Mapping                           */
2157 /* ------------------------------------------------------------------- */
2158 /**
2159 The next Routines, that follow, are the color-mapping routines.
2160 GHOSTSCRIPT talks about "gx_color_values" and the driver has
2161 to merge the 1, 3 or four values into up to 32 Bits, that means
2162 it is necessary to do some truncation and shifting. For the truncation
2163 "uniprint" uses the internal function "upd_truncate" and "upd_expand"
2164 reverses this in the reverse-mapping procedures.
2165 */
2166 
2167 private gx_color_index
upd_cmyk_icolor(gx_device * pdev,const gx_color_value cv[])2168 upd_cmyk_icolor(gx_device *pdev, const gx_color_value cv[])
2169 {
2170    const upd_p     upd = ((upd_device *)pdev)->upd;
2171    gx_color_index  rv;
2172    gx_color_value c, m, y, k;
2173    c = cv[0]; m = cv[1]; y = cv[2]; k = cv[3];
2174 
2175 /**
2176 All 4-Component-Modi have to deal with the Problem, that a value
2177 with all bits set can be produced, which is treated as an error-return
2178 from the mapping-functions. But with RGBW or KCMY, there is a neat
2179 trick: Grayscale are transferred as RGB/CMY=0 and holding Data only
2180 in the W- or K-Component.
2181 */
2182 
2183    if((c == m) && (m == y)) {
2184 
2185       rv = upd_truncate(upd,0,(gx_color_value)(c > k ? c : k));
2186 
2187    } else {
2188 
2189       rv  = upd_truncate(upd,0,k) | upd_truncate(upd,1,c)
2190           | upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
2191 
2192 
2193 /* It might still become a "gx_no_color_value" due to truncation, thus: */
2194 
2195       if(rv == gx_no_color_index) rv ^= 1;
2196    }
2197 
2198 
2199 #if UPD_MESSAGES & UPD_M_MAPCALLS
2200   errprintf(
2201 "cmyk_icolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
2202    255.0 * (double) c / (double) gx_max_color_value,
2203    255.0 * (double) m / (double) gx_max_color_value,
2204    255.0 * (double) y / (double) gx_max_color_value,
2205    255.0 * (double) k / (double) gx_max_color_value,
2206    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2207                  / (double) upd->cmap[1].bitmsk,
2208    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2209                  / (double) upd->cmap[2].bitmsk,
2210    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2211                  / (double) upd->cmap[3].bitmsk,
2212    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2213                  / (double) upd->cmap[0].bitmsk,
2214    (pdev->color_info.depth + 3)>>2,rv);
2215 #endif
2216 
2217    return rv;
2218 }
2219 
2220 /* ------------------------------------------------------------------- */
2221 /* upd_icolor_rgb: Stored KCMY back to a RGB                           */
2222 /* ------------------------------------------------------------------- */
2223 
2224 private int
upd_icolor_rgb(gx_device * pdev,gx_color_index color,gx_color_value prgb[3])2225 upd_icolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
2226 {
2227    const upd_p     upd = ((upd_device *)pdev)->upd;
2228    gx_color_value c,m,y,k;
2229 
2230 /*
2231  * Expand to the Component-Values
2232  */
2233    k = upd_expand(upd,0,color);
2234    c = upd_expand(upd,1,color);
2235    m = upd_expand(upd,2,color);
2236    y = upd_expand(upd,3,color);
2237 
2238 /*
2239  * Then Invert and subtract K from the colors
2240  */
2241    prgb[0] = gx_max_color_value - c;
2242    if(prgb[0] > k) prgb[0] -= k;
2243    else            prgb[0]  = 0;
2244 
2245    prgb[1] = gx_max_color_value - m;
2246    if(prgb[1] > k) prgb[1] -= k;
2247    else            prgb[1]  = 0;
2248 
2249    prgb[2] = gx_max_color_value - y;
2250    if(prgb[2] > k) prgb[2] -= k;
2251    else            prgb[2]  = 0;
2252 
2253 
2254 #if UPD_MESSAGES & UPD_M_MAPCALLS
2255    errprintf(
2256     "icolor_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
2257     (pdev->color_info.depth + 3)>>2,color,
2258     255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2259                      / (double) upd->cmap[1].bitmsk,
2260     255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2261                      / (double) upd->cmap[2].bitmsk,
2262     255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2263                      / (double) upd->cmap[3].bitmsk,
2264     255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2265                      / (double) upd->cmap[0].bitmsk,
2266     255.0 * (double)   c     / (double) gx_max_color_value,
2267     255.0 * (double)   m     / (double) gx_max_color_value,
2268     255.0 * (double)   y     / (double) gx_max_color_value,
2269     255.0 * (double)   k     / (double) gx_max_color_value,
2270     255.0 * (double) prgb[0] / (double) gx_max_color_value,
2271     255.0 * (double) prgb[1] / (double) gx_max_color_value,
2272     255.0 * (double) prgb[2] / (double) gx_max_color_value);
2273 #endif
2274 
2275    return 0;
2276 }
2277 
2278 /* ------------------------------------------------------------------- */
2279 /* upd_rgb_1color: Grayscale->Grayscale-index-Mapping              */
2280 /* ------------------------------------------------------------------- */
2281 
2282 private gx_color_index
upd_rgb_1color(gx_device * pdev,const gx_color_value cv[])2283 upd_rgb_1color(gx_device *pdev, const gx_color_value cv[])
2284 {
2285    const upd_p     upd = ((upd_device *)pdev)->upd;
2286    gx_color_index  rv;
2287    gx_color_value g;
2288 
2289    g = cv[0];
2290    rv = upd_truncate(upd,0,g);
2291 
2292 #if UPD_MESSAGES & UPD_M_MAPCALLS
2293    errprintf(
2294       "rgb_1color: (%5.1f) : (%5.1f) : 0x%0*lx\n",
2295       255.0 * (double) g  / (double) gx_max_color_value,
2296       255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2297                     / (double) upd->cmap[0].bitmsk,
2298       (pdev->color_info.depth + 3)>>2,rv);
2299 #endif
2300 
2301    return rv;
2302 }
2303 
2304 /* ------------------------------------------------------------------- */
2305 /* upd_1color_rgb: reversal of the above                               */
2306 /* ------------------------------------------------------------------- */
2307 
2308 private int
upd_1color_rgb(gx_device * pdev,gx_color_index color,gx_color_value cv[1])2309 upd_1color_rgb(gx_device *pdev, gx_color_index color, gx_color_value cv[1])
2310 {
2311    const upd_p     upd = ((upd_device *)pdev)->upd;
2312 /*
2313  * Actual task: expand to full range of gx_color_value
2314  */
2315    cv[0] = upd_expand(upd,0,color);
2316 
2317 #if UPD_MESSAGES & UPD_M_MAPCALLS
2318    errprintf("1color_rgb: 0x%0*lx -> %5.1f -> (%5.1f,%5.1f,%5.1f)\n",
2319       (pdev->color_info.depth + 3)>>2,color,
2320       255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2321                        / (double) upd->cmap[0].bitmsk,
2322       255.0 * (double) prgb[0] / (double) gx_max_color_value,
2323       255.0 * (double) prgb[0] / (double) gx_max_color_value,
2324       255.0 * (double) prgb[0] / (double) gx_max_color_value);
2325 #endif
2326 
2327    return 0;
2328 }
2329 
2330 /* ------------------------------------------------------------------- */
2331 /* upd_rgb_3color: component-wise RGB->RGB-Mapping                     */
2332 /* ------------------------------------------------------------------- */
2333 
2334 private gx_color_index
upd_rgb_3color(gx_device * pdev,const gx_color_value cv[])2335 upd_rgb_3color(gx_device *pdev, const gx_color_value cv[])
2336 {
2337    const upd_p     upd = ((upd_device *)pdev)->upd;
2338    gx_color_index  rv;
2339    gx_color_value r, g, b;
2340    r = cv[0]; g = cv[1]; b = cv[2];
2341 
2342    rv = upd_truncate(upd,0,r) | upd_truncate(upd,1,g) | upd_truncate(upd,2,b);
2343    if(rv == gx_no_color_index) rv ^= 1;
2344 
2345 #if UPD_MESSAGES & UPD_M_MAPCALLS
2346   errprintf(
2347    "rgb_3color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
2348    255.0 * (double) r / (double) gx_max_color_value,
2349    255.0 * (double) g / (double) gx_max_color_value,
2350    255.0 * (double) b / (double) gx_max_color_value,
2351    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2352                  / (double) upd->cmap[0].bitmsk,
2353    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2354                  / (double) upd->cmap[1].bitmsk,
2355    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2356                  / (double) upd->cmap[2].bitmsk,
2357    (pdev->color_info.depth + 3)>>2,rv);
2358 #endif
2359 
2360    return rv;
2361 }
2362 
2363 /* ------------------------------------------------------------------- */
2364 /* upd_3color_rgb: reversal of the above                               */
2365 /* ------------------------------------------------------------------- */
2366 
2367 private int
upd_3color_rgb(gx_device * pdev,gx_color_index color,gx_color_value prgb[3])2368 upd_3color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
2369 {
2370    const upd_p     upd = ((upd_device *)pdev)->upd;
2371 
2372    prgb[0] = upd_expand(upd,0,color);
2373    prgb[1] = upd_expand(upd,1,color);
2374    prgb[2] = upd_expand(upd,2,color);
2375 
2376 #if UPD_MESSAGES & UPD_M_MAPCALLS
2377    errprintf(
2378      "3color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
2379       (pdev->color_info.depth + 3)>>2,color,
2380       255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2381                        / (double) upd->cmap[0].bitmsk,
2382       255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2383                        / (double) upd->cmap[1].bitmsk,
2384       255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2385                        / (double) upd->cmap[2].bitmsk,
2386 
2387       255.0 * (double) prgb[0] / (double) gx_max_color_value,
2388       255.0 * (double) prgb[1] / (double) gx_max_color_value,
2389       255.0 * (double) prgb[2] / (double) gx_max_color_value);
2390 #endif
2391 
2392    return 0;
2393 }
2394 
2395 /* ------------------------------------------------------------------- */
2396 /* upd_rgb_4color: Create an WRGB-Index from RGB                       */
2397 /* ------------------------------------------------------------------- */
2398 
2399 private gx_color_index
upd_rgb_4color(gx_device * pdev,const gx_color_value cv[])2400 upd_rgb_4color(gx_device *pdev, const gx_color_value cv[])
2401 {
2402    const upd_p     upd = ((upd_device *)pdev)->upd;
2403    gx_color_index  rv;
2404    gx_color_value r, g, b;
2405 
2406    r = cv[0]; g = cv[1]; b = cv[2];
2407 
2408    if((r == g) && (g == b)) {
2409 
2410       rv = upd_truncate(upd,0,r);
2411 
2412    } else {
2413 
2414       gx_color_value w = g < r ? g : r; w = w < b ? w : b; /* Minimum */
2415 
2416       rv = upd_truncate(upd,0,w) | upd_truncate(upd,1,r) |
2417            upd_truncate(upd,2,g) | upd_truncate(upd,3,b);
2418 
2419 /* It might still become a "gx_no_color_value" due to truncation, thus: */
2420 
2421       if(rv == gx_no_color_index) rv ^= 1;
2422    }
2423 
2424 #if UPD_MESSAGES & UPD_M_MAPCALLS
2425   errprintf(
2426    "rgb_4color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
2427    255.0 * (double) r / (double) gx_max_color_value,
2428    255.0 * (double) g / (double) gx_max_color_value,
2429    255.0 * (double) b / (double) gx_max_color_value,
2430    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2431                  / (double) upd->cmap[1].bitmsk,
2432    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2433                  / (double) upd->cmap[2].bitmsk,
2434    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2435                  / (double) upd->cmap[3].bitmsk,
2436    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2437                  / (double) upd->cmap[0].bitmsk,
2438    (pdev->color_info.depth + 3)>>2,rv);
2439 #endif
2440 
2441    return rv;
2442 }
2443 
2444 /* ------------------------------------------------------------------- */
2445 /* upd_4color_rgb: Stored WRGB-Index back to a RGB                     */
2446 /* ------------------------------------------------------------------- */
2447 
2448 private int
upd_4color_rgb(gx_device * pdev,gx_color_index color,gx_color_value prgb[3])2449 upd_4color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
2450 {
2451    const upd_p     upd = ((upd_device *)pdev)->upd;
2452 
2453 /*
2454  * Expand to the Component-Values
2455  */
2456    prgb[0] = upd_expand(upd,1,color);
2457    prgb[1] = upd_expand(upd,2,color);
2458    prgb[2] = upd_expand(upd,3,color);
2459 
2460 /* Revert our Grayscale-Trick: */
2461    if(!(prgb[0] || prgb[1] || prgb[2]))
2462       prgb[0] = prgb[1] = prgb[2] = upd_expand(upd,0,color);
2463 
2464 
2465 #if UPD_MESSAGES & UPD_M_MAPCALLS
2466    errprintf(
2467     "4color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
2468     (pdev->color_info.depth + 3)>>2,color,
2469     255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2470                      / (double) upd->cmap[1].bitmsk,
2471     255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2472                      / (double) upd->cmap[2].bitmsk,
2473     255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2474                      / (double) upd->cmap[3].bitmsk,
2475     255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2476                      / (double) upd->cmap[0].bitmsk,
2477     255.0 * (double) prgb[0] / (double) gx_max_color_value,
2478     255.0 * (double) prgb[1] / (double) gx_max_color_value,
2479     255.0 * (double) prgb[2] / (double) gx_max_color_value);
2480 #endif
2481 
2482    return 0;
2483 }
2484 
2485 /* ------------------------------------------------------------------- */
2486 /* upd_cmyk_kcolor: KCMY->KCMY-Index Mapping with Black Generation     */
2487 /* ------------------------------------------------------------------- */
2488 
2489 private gx_color_index
upd_cmyk_kcolor(gx_device * pdev,const gx_color_value cv[])2490 upd_cmyk_kcolor(gx_device *pdev, const gx_color_value cv[])
2491 {
2492    const upd_p     upd = ((upd_device *)pdev)->upd;
2493    gx_color_index  rv;
2494    gx_color_value  black;
2495 
2496    gx_color_value c, m, y, k;
2497    c = cv[0]; m = cv[1]; y = cv[2]; k = cv[3];
2498 
2499    if((c == m) && (m == y)) {
2500 
2501       black = c > k ? c : k;
2502       rv = upd_truncate(upd,0,black);
2503 
2504    } else {
2505 
2506       if(k && !(c | m | y)) {
2507          black = k;
2508       } else {
2509          black = c     < m ? c     : m;
2510          black = black < y ? black : y;
2511       }
2512 
2513       rv  = upd_truncate(upd,0,black) | upd_truncate(upd,1,c)
2514           | upd_truncate(upd,2,m)     | upd_truncate(upd,3,y);
2515 
2516 /* It might still become a "gx_no_color_value" due to truncation, thus: */
2517 
2518       if(rv == gx_no_color_index) rv ^= 1;
2519    }
2520 
2521 
2522 #if UPD_MESSAGES & UPD_M_MAPCALLS
2523   errprintf(
2524 "cmyk_kcolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
2525    255.0 * (double) c / (double) gx_max_color_value,
2526    255.0 * (double) m / (double) gx_max_color_value,
2527    255.0 * (double) y / (double) gx_max_color_value,
2528    255.0 * (double) k / (double) gx_max_color_value,
2529    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2530                  / (double) upd->cmap[1].bitmsk,
2531    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2532                  / (double) upd->cmap[2].bitmsk,
2533    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2534                  / (double) upd->cmap[3].bitmsk,
2535    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2536                  / (double) upd->cmap[0].bitmsk,
2537    (pdev->color_info.depth + 3)>>2,rv);
2538 #endif
2539 
2540    return rv;
2541 }
2542 
2543 /* ------------------------------------------------------------------- */
2544 /* upd_kcolor_rgb: Stored CMY+generated K back to a RGB                */
2545 /* ------------------------------------------------------------------- */
2546 
2547 private int
upd_kcolor_rgb(gx_device * pdev,gx_color_index color,gx_color_value prgb[3])2548 upd_kcolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
2549 {
2550    const upd_p     upd = ((upd_device *)pdev)->upd;
2551    gx_color_value c,m,y,k;
2552 
2553 /*
2554  * Expand to the Component-Values
2555  */
2556    k = upd_expand(upd,0,color);
2557    c = upd_expand(upd,1,color);
2558    m = upd_expand(upd,2,color);
2559    y = upd_expand(upd,3,color);
2560 
2561 /*
2562  * Check for plain Gray-Values
2563  */
2564    if(!(c | m | y )) {
2565 
2566       prgb[2] = prgb[1] = prgb[0] = gx_max_color_value - k;
2567 
2568    } else {
2569       prgb[0] = gx_max_color_value - c;
2570       prgb[1] = gx_max_color_value - m;
2571       prgb[2] = gx_max_color_value - y;
2572    }
2573 
2574 #if UPD_MESSAGES & UPD_M_MAPCALLS
2575    errprintf(
2576     "kcolor_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
2577     (pdev->color_info.depth + 3)>>2,color,
2578     255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2579                      / (double) upd->cmap[1].bitmsk,
2580     255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2581                      / (double) upd->cmap[2].bitmsk,
2582     255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2583                      / (double) upd->cmap[3].bitmsk,
2584     255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2585                      / (double) upd->cmap[0].bitmsk,
2586     255.0 * (double)   c     / (double) gx_max_color_value,
2587     255.0 * (double)   m     / (double) gx_max_color_value,
2588     255.0 * (double)   y     / (double) gx_max_color_value,
2589     255.0 * (double)   k     / (double) gx_max_color_value,
2590     255.0 * (double) prgb[0] / (double) gx_max_color_value,
2591     255.0 * (double) prgb[1] / (double) gx_max_color_value,
2592     255.0 * (double) prgb[2] / (double) gx_max_color_value);
2593 #endif
2594 
2595    return 0;
2596 }
2597 
2598 /* ------------------------------------------------------------------- */
2599 /* upd_rgb_ovcolor: Create an KCMY-Index from RGB                      */
2600 /* ------------------------------------------------------------------- */
2601 
2602 private gx_color_index
upd_rgb_ovcolor(gx_device * pdev,const gx_color_value cv[])2603 upd_rgb_ovcolor(gx_device *pdev, const gx_color_value cv[])
2604 {
2605    const upd_p     upd = ((upd_device *)pdev)->upd;
2606    gx_color_index  rv;
2607    gx_color_value  c,m,y,black;
2608    gx_color_value r, g, b;
2609    r = cv[0]; g = cv[1]; b = cv[2];
2610    if((r == g) && (g == b)) {
2611 
2612       black  = gx_max_color_value - r;
2613       rv     = upd_truncate(upd,0,black);
2614       c = m = y = 0;
2615 
2616    } else {
2617 
2618       c = gx_max_color_value - r;
2619       m = gx_max_color_value - g;
2620       y = gx_max_color_value - b;
2621 
2622       black = c     < m ? c     : m;
2623       black = black < y ? black : y;
2624 
2625       if(black != gx_max_color_value) {
2626         float tmp,d;
2627 
2628         d   = (float)(gx_max_color_value - black);
2629 
2630         tmp = (float) (c-black) / d;
2631         if(      0.0 > tmp) tmp = 0.0;
2632         else if( 1.0 < tmp) tmp = 1.0;
2633         c   = (gx_color_value)(tmp * gx_max_color_value + 0.499);
2634 
2635         tmp = (float) (m-black) / d;
2636         if(      0.0 > tmp) tmp = 0.0;
2637         else if( 1.0 < tmp) tmp = 1.0;
2638         m   = (gx_color_value)(tmp * gx_max_color_value + 0.499);
2639 
2640         tmp = (float) (y-black) / d;
2641         if(      0.0 > tmp) tmp = 0.0;
2642         else if( 1.0 < tmp) tmp = 1.0;
2643         y   = (gx_color_value)(tmp * gx_max_color_value + 0.499);
2644 
2645       } else {
2646 
2647         c = m = y = gx_max_color_value;
2648 
2649       }
2650 
2651       rv = upd_truncate(upd,0,black) | upd_truncate(upd,1,c) |
2652            upd_truncate(upd,2,m)     | upd_truncate(upd,3,y);
2653 
2654 /* It might still become a "gx_no_color_value" due to truncation, thus: */
2655 
2656       if(rv == gx_no_color_index) rv ^= 1;
2657    }
2658 
2659 #if UPD_MESSAGES & UPD_M_MAPCALLS
2660   errprintf(
2661    "rgb_ovcolor: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
2662    255.0 * (double) r / (double) gx_max_color_value,
2663    255.0 * (double) g / (double) gx_max_color_value,
2664    255.0 * (double) b / (double) gx_max_color_value,
2665    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2666                  / (double) upd->cmap[1].bitmsk,
2667    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2668                  / (double) upd->cmap[2].bitmsk,
2669    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2670                  / (double) upd->cmap[3].bitmsk,
2671    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2672                  / (double) upd->cmap[0].bitmsk,
2673    (pdev->color_info.depth + 3)>>2,rv);
2674 #endif
2675 
2676    return rv;
2677 }
2678 
2679 /* ------------------------------------------------------------------- */
2680 /* upd_rgb_novcolor: Create an KCMY-Index from RGB                      */
2681 /* ------------------------------------------------------------------- */
2682 
2683 private gx_color_index
upd_rgb_novcolor(gx_device * pdev,const gx_color_value cv[])2684 upd_rgb_novcolor(gx_device *pdev, const gx_color_value cv[])
2685 {
2686    const upd_p     upd = ((upd_device *)pdev)->upd;
2687    gx_color_index  rv;
2688    gx_color_value  c,m,y,black;
2689    gx_color_value r, g, b;
2690    r = cv[0]; g = cv[1]; b = cv[2];
2691 
2692    if((r == g) && (g == b)) {
2693 
2694       black  = gx_max_color_value - r;
2695       rv     = upd_truncate(upd,0,black);
2696       c = m = y = 0;
2697 
2698    } else {
2699 
2700       c = gx_max_color_value - r;
2701       m = gx_max_color_value - g;
2702       y = gx_max_color_value - b;
2703 
2704       black = c     < m ? c     : m;
2705       black = black < y ? black : y;
2706       c     = c - black;
2707       m     = m - black;
2708       y     = y - black;
2709 
2710       rv = upd_truncate(upd,0,black) | upd_truncate(upd,1,c) |
2711            upd_truncate(upd,2,m)     | upd_truncate(upd,3,y);
2712 
2713 /* It might still become a "gx_no_color_value" due to truncation, thus: */
2714 
2715       if(rv == gx_no_color_index) rv ^= 1;
2716    }
2717 
2718 #if UPD_MESSAGES & UPD_M_MAPCALLS
2719   errprintf(
2720    "rgb_ovcolor: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
2721    255.0 * (double) r / (double) gx_max_color_value,
2722    255.0 * (double) g / (double) gx_max_color_value,
2723    255.0 * (double) b / (double) gx_max_color_value,
2724    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
2725                  / (double) upd->cmap[1].bitmsk,
2726    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
2727                  / (double) upd->cmap[2].bitmsk,
2728    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
2729                  / (double) upd->cmap[3].bitmsk,
2730    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
2731                  / (double) upd->cmap[0].bitmsk,
2732    (pdev->color_info.depth + 3)>>2,rv);
2733 #endif
2734 
2735    return rv;
2736 }
2737 
2738 /* ------------------------------------------------------------------- */
2739 /* NOTE: Beyond this point only "uniprint"-special-items.              */
2740 /* ------------------------------------------------------------------- */
2741 
2742 /* ------------------------------------------------------------------- */
2743 /* Truncate a gx_color_value to the desired number of bits.            */
2744 /* ------------------------------------------------------------------- */
2745 
2746 private uint32_t
upd_truncate(upd_pc upd,int i,gx_color_value v)2747 upd_truncate(upd_pc upd,int i,gx_color_value v) {
2748    const updcmap_pc cmap = upd->cmap + i;
2749    int32_t           s; /* step size */
2750    gx_color_value *p; /* value-pointer */
2751 
2752    if(0 == cmap->bits) {                          /* trivial case */
2753 
2754       v = 0;
2755 
2756    } else if(gx_color_value_bits > cmap->bits) { /* really truncate ? */
2757 
2758       p = cmap->code + ((cmap->bitmsk + 1) >> 1);
2759       s =              ((cmap->bitmsk + 1) >> 2);
2760 /*
2761  * Perform search in monotonic code-array
2762  */
2763       while(s > 0) {
2764          if(v > *p) {           /* we're below */
2765             p += s;
2766          } else if(v < p[-1]) { /* we're ahead for sure */
2767             p -= s;
2768          } else {
2769 /* years ago, i knew what this was good for */
2770             if((v-p[-1]) < (p[0]-v)) p -= 1;
2771             break;
2772          }
2773          s >>= 1;
2774       }
2775       if((v-p[-1]) < (p[0]-v)) p -= 1;
2776       v = p - cmap->code;
2777    }
2778 
2779    if(!cmap->rise) v = cmap->bitmsk - v; /* Again reverse, if necessary */
2780 
2781    return ((uint32_t) v) << cmap->bitshf;
2782 }
2783 
2784 /* ------------------------------------------------------------------- */
2785 /* upd_open_map: install the color-mapping                             */
2786 /* ------------------------------------------------------------------- */
2787 
2788 private int
upd_open_map(upd_device * udev)2789 upd_open_map(upd_device *udev)
2790 {
2791    const upd_p      upd   = udev->upd;
2792    int imap;
2793 
2794 /** _always_ initialize crucial Values! */
2795    for(imap = 0; UPD_CMAP_MAX > imap; ++imap) upd->cmap[imap].code   = NULL;
2796    upd->ncomp = 0;
2797 
2798 /** There should not be an error yet */
2799    if(B_ERROR & upd->flags)    imap = 0;
2800 
2801 /** Establish the xfer-Indices */
2802    if(imap) {
2803       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
2804          upd->cmap[imap].xfer = -1;
2805          upd->cmap[imap].bits =  0;
2806       }
2807       switch(upd->choice[C_MAPPER]) {
2808          case MAP_GRAY:
2809             upd->cmap[0].xfer = FA_WXFER;
2810          break;
2811          case MAP_RGBW:
2812             upd->cmap[0].xfer = FA_WXFER;
2813             upd->cmap[1].xfer = FA_RXFER;
2814             upd->cmap[2].xfer = FA_GXFER;
2815             upd->cmap[3].xfer = FA_BXFER;
2816          break;
2817          case MAP_RGB:
2818             upd->cmap[0].xfer = FA_RXFER;
2819             upd->cmap[1].xfer = FA_GXFER;
2820             upd->cmap[2].xfer = FA_BXFER;
2821          break;
2822          case MAP_CMYK:
2823             upd->cmap[0].xfer = FA_KXFER;
2824             upd->cmap[1].xfer = FA_CXFER;
2825             upd->cmap[2].xfer = FA_MXFER;
2826             upd->cmap[3].xfer = FA_YXFER;
2827          break;
2828          case MAP_CMYKGEN:
2829             upd->cmap[0].xfer = FA_KXFER;
2830             upd->cmap[1].xfer = FA_CXFER;
2831             upd->cmap[2].xfer = FA_MXFER;
2832             upd->cmap[3].xfer = FA_YXFER;
2833          break;
2834          case MAP_RGBOV:
2835             upd->cmap[0].xfer = FA_KXFER;
2836             upd->cmap[1].xfer = FA_CXFER;
2837             upd->cmap[2].xfer = FA_MXFER;
2838             upd->cmap[3].xfer = FA_YXFER;
2839          break;
2840          case MAP_RGBNOV:
2841             upd->cmap[0].xfer = FA_KXFER;
2842             upd->cmap[1].xfer = FA_CXFER;
2843             upd->cmap[2].xfer = FA_MXFER;
2844             upd->cmap[3].xfer = FA_YXFER;
2845          break;
2846          default:
2847 #if         UPD_MESSAGES & UPD_M_WARNING
2848                if(upd_choice[C_MAPPER][0])
2849                   errprintf(
2850                      "upd_open_map: unsupported %s=%d\n",
2851                      upd_choice[C_MAPPER][0],upd->choice[C_MAPPER]);
2852                else
2853                   errprintf(
2854                      "upd_open_map: unsupported choce[%d]=%d\n",
2855                      C_MAPPER,upd->choice[C_MAPPER]);
2856 #endif
2857             imap = 0;
2858          break;
2859       }
2860    }
2861 
2862 
2863 /** The bit number sould be positive & fit into the storage */
2864 
2865    if(imap) { /* Check number of Bits & Shifts */
2866 
2867 #if      UPD_MESSAGES & UPD_M_WARNING
2868       uint32_t used = 0,bitmsk;
2869 #endif
2870       bool success = true;
2871 
2872       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
2873          if(0 > upd->cmap[imap].xfer) continue;
2874 
2875          if((0                     > upd->int_a[IA_COMPBITS].data[imap])  ||
2876             (gx_color_value_bits   < upd->int_a[IA_COMPBITS].data[imap])  ||
2877             (0                     > upd->int_a[IA_COMPSHIFT].data[imap]) ||
2878             (upd->int_a[IA_COMPBITS].data[imap] >
2879              (udev->color_info.depth - upd->int_a[IA_COMPSHIFT].data[imap]))) {
2880 #if         UPD_MESSAGES & UPD_M_WARNING
2881                errprintf(
2882                   "upd_open_map: %d Bits << %d is illegal for %d. Component\n",
2883                   upd->int_a[IA_COMPBITS].data[imap],
2884                   upd->int_a[IA_COMPSHIFT].data[imap],imap+1);
2885 #endif
2886 
2887             success = false;
2888 
2889 
2890          } else {
2891 
2892             int         n;
2893             const float *now;
2894             float       last;
2895 
2896             if((NULL == upd->float_a[upd->cmap[imap].xfer].data) ||
2897                (2    >  upd->float_a[upd->cmap[imap].xfer].size)   ) {
2898                float *fp;
2899                UPD_MM_DEL_PARAM(udev->memory, upd->float_a[upd->cmap[imap].xfer]);
2900                UPD_MM_GET_ARRAY(udev->memory, fp,2);
2901                fp[0] = 0.0;
2902                fp[1] = 1.0;
2903                upd->float_a[upd->cmap[imap].xfer].data = fp;
2904                upd->float_a[upd->cmap[imap].xfer].size = 2;
2905             }
2906             n    = upd->float_a[upd->cmap[imap].xfer].size-1;
2907             now  = upd->float_a[upd->cmap[imap].xfer].data;
2908             last = now[n];
2909 
2910             if(     *now < last) { /* Rising */
2911                last = *now++;
2912                while(n--) {
2913                  if(last >= *now) break;
2914                  last = *now++;
2915                }
2916             } else if(*now > last) { /* Falling */
2917                last = *now++;
2918                while(n--) {
2919                  if(last <= *now) break;
2920                  last = *now++;
2921                }
2922             }                      /* Monotony-check */
2923 
2924             if(0 <= n) {
2925 #if            UPD_MESSAGES & UPD_M_WARNING
2926                errprintf(
2927                   "upd_open_map: %d. Component has non monoton Xfer\n",imap+1);
2928 #endif
2929                success = false;
2930 
2931             } else {
2932 
2933 #if            UPD_MESSAGES & UPD_M_WARNING
2934 
2935                bitmsk   = ((uint32_t) 1 << upd->int_a[IA_COMPBITS].data[imap]) -1;
2936                bitmsk <<= upd->int_a[IA_COMPSHIFT].data[imap];
2937 
2938                if(used & bitmsk) errprintf(
2939                   "upd_open_map: %d. Component overlaps with others\n",imap+1);
2940 
2941                used |= bitmsk;
2942 #endif
2943             }
2944          }
2945       }
2946 
2947       if(!success) imap = 0;
2948 
2949    }             /* Check number of Bits */
2950 
2951 /** Do the allocation */
2952 
2953    if(imap) {
2954 
2955       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
2956          if(0 > upd->cmap[imap].xfer) continue;
2957 
2958          upd->cmap[imap].bits     = upd->int_a[IA_COMPBITS].data[imap];
2959          upd->cmap[imap].bitshf   = upd->int_a[IA_COMPSHIFT].data[imap];
2960          upd->cmap[imap].bitmsk   = 1;
2961          upd->cmap[imap].bitmsk <<= upd->cmap[imap].bits;
2962          upd->cmap[imap].bitmsk  -= 1;
2963          upd->cmap[imap].rise     =
2964             upd->float_a[upd->cmap[imap].xfer].data[0] <
2965             upd->float_a[upd->cmap[imap].xfer].data[
2966                upd->float_a[upd->cmap[imap].xfer].size-1] ?
2967             true : false;
2968          upd->cmap[imap].code     = gs_malloc(udev->memory, upd->cmap[imap].bitmsk+1,
2969              sizeof(upd->cmap[imap].code[0]),"upd/code");
2970          if(!upd->cmap[imap].code) break;
2971       }
2972 
2973       if(UPD_CMAP_MAX > imap) {
2974 
2975          imap = 0;
2976 
2977 #if      UPD_MESSAGES & UPD_M_ERROR
2978             errprintf("upd_open_map: could not allocate code-arrays\n");
2979 #        endif
2980 
2981       }
2982    }
2983 
2984 /** then fill the code-arrays */
2985 
2986    if(imap) {
2987 /*
2988  * Try making things easier: (than with stcolor)
2989  *     normalize values to 0.0/1.0-Range
2990  *     X-Axis:   Color-Values (implied)
2991  *     Y-Values: Indices      (given)
2992  */
2993 
2994       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
2995 
2996          const updcmap_p cmap = upd->cmap + imap;
2997          uint32_t ly,iy;
2998          float ystep,xstep,fx,fy;
2999 
3000 /*       Variables & Macro for Range-Normalization */
3001          double offset,scale;
3002 #define  XFVAL(I) ((upd->float_a[cmap->xfer].data[I]-offset)*scale)
3003 
3004          if(0 > cmap->xfer) continue;
3005 
3006          cmap->code[cmap->bitmsk] = gx_max_color_value;
3007 
3008          if(!cmap->bits) continue;
3009 
3010          offset = upd->float_a[cmap->xfer].data[0];
3011          if(     0.0 > offset) offset = 0.0;
3012          else if(1.0 < offset) offset = 1.0;
3013 
3014          scale  = upd->float_a[cmap->xfer].data[upd->float_a[cmap->xfer].size-1];
3015          if(     0.0 > scale ) scale  = 0.0;
3016          else if(1.0 < scale ) scale  = 1.0;
3017 
3018          if(scale != offset) scale = 1.0 / (scale - offset);
3019          else                scale = 0.0;
3020 
3021 /*       interpolate */
3022          ystep = (float) 1.0 / (float) cmap->bitmsk;
3023          xstep = (float) 1.0 / (float)(upd->float_a[cmap->xfer].size - 1);
3024 
3025          iy = 0;
3026          for(ly = 0; ly <= cmap->bitmsk; ++ly) {
3027 
3028             fy = ystep * ly; /* Target-Value */
3029 
3030             while(((iy+2) < upd->float_a[cmap->xfer].size) &&
3031                   (fy > XFVAL(iy+1))) ++iy;
3032 
3033             fx  = iy + (fy - XFVAL(iy))/(XFVAL(iy+1) - XFVAL(iy));
3034 
3035             fx *= xstep * gx_max_color_value;
3036 
3037             fx  = fx < 0.0 ? 0.0 :
3038                  (fx > gx_max_color_value ? gx_max_color_value : fx);
3039 
3040             cmap->code[ly] = (gx_color_value)fx;
3041             if((fx - cmap->code[ly]) >= 0.5) cmap->code[ly] += 1;
3042          }
3043 
3044 #undef   XFVAL
3045 
3046       }
3047    }
3048 
3049 /** If we're ok, massage upd->ncomp */
3050 
3051    if(imap) {
3052       switch(upd->choice[C_MAPPER]) {
3053          case MAP_GRAY:
3054            if(1 > imap) imap = 0;
3055            upd->ncomp = 1;
3056          break;
3057          case MAP_RGBW: /* RGB->RGBW */
3058            if(4 > imap) imap = 0;
3059            upd->ncomp = 4;
3060          break;
3061          case MAP_RGB: /* Plain RGB */
3062            if(3 > imap) imap = 0;
3063            upd->ncomp = 3;
3064          break;
3065          case MAP_CMYK: /* Plain KCMY */
3066            if(4 > imap) imap = 0;
3067             upd->ncomp = 4;
3068          break;
3069          case MAP_CMYKGEN: /* KCMY with black-generation */
3070            if(4 > imap) imap = 0;
3071            upd->ncomp = 4;
3072          break;
3073          case MAP_RGBOV: /* RGB->KCMY with black-generation */
3074            if(4 > imap) imap = 0;
3075            upd->ncomp = 4;
3076          break;
3077          case MAP_RGBNOV: /* RGB->KCMY with black-generation */
3078            if(4 > imap) imap = 0;
3079            upd->ncomp = 4;
3080          break;
3081 
3082          default:
3083            imap = 0;
3084 #if        UPD_MESSAGES & UPD_M_WARNING
3085               errprintf(
3086                  "upd_open: Mapping %d unknown\n",upd->choice[C_MAPPER]);
3087 #endif
3088 
3089          break;
3090       }
3091    }
3092 
3093 
3094 /** If unsuccesful, install the default routines */
3095 
3096    if(!imap) {
3097       upd_close_map(udev);
3098    } else {
3099       upd->flags |= B_MAP;
3100       upd_procs_map(udev);
3101    }
3102 
3103    return imap ? 1 : -1;
3104 }
3105 
3106 /* ------------------------------------------------------------------- */
3107 /* upd_procs_map: (de-) install the color-mapping-procedures           */
3108 /* ------------------------------------------------------------------- */
3109 
3110 private int
upd_procs_map(upd_device * udev)3111 upd_procs_map(upd_device *udev)
3112 {
3113    int imap;
3114 
3115    if( udev->upd &&
3116       (udev->upd->flags & B_MAP)) imap = udev->upd->choice[C_MAPPER];
3117    else                           imap = 0;
3118 
3119    switch(imap) {
3120      case MAP_GRAY: /* Grayscale -> Grayscale */
3121        set_dev_proc(udev,encode_color, upd_rgb_1color);
3122        set_dev_proc(udev,decode_color, upd_1color_rgb);
3123        set_dev_proc(udev,map_rgb_color, upd_rgb_1color);
3124        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
3125        set_dev_proc(udev,map_color_rgb, upd_1color_rgb);
3126      break;
3127      case MAP_RGBW: /* RGB->RGBW */
3128        set_dev_proc(udev,encode_color, upd_rgb_4color);
3129        set_dev_proc(udev,decode_color, upd_4color_rgb);
3130        set_dev_proc(udev,map_rgb_color, upd_rgb_4color);
3131        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
3132        set_dev_proc(udev,map_color_rgb, upd_4color_rgb);
3133      break;
3134      case MAP_RGB: /* Plain RGB */
3135        set_dev_proc(udev,encode_color, upd_rgb_3color);
3136        set_dev_proc(udev,decode_color, upd_3color_rgb);
3137        set_dev_proc(udev,map_rgb_color, upd_rgb_3color);
3138        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
3139        set_dev_proc(udev,map_color_rgb, upd_3color_rgb);
3140      break;
3141      case MAP_CMYK: /* Plain KCMY */
3142        set_dev_proc(udev,encode_color, upd_cmyk_icolor);
3143        set_dev_proc(udev,decode_color, upd_icolor_rgb);
3144        set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
3145        set_dev_proc(udev,map_cmyk_color,upd_cmyk_icolor);
3146        set_dev_proc(udev,map_color_rgb, upd_icolor_rgb);
3147      break;
3148      case MAP_CMYKGEN: /* KCMY with black-generation */
3149        set_dev_proc(udev,encode_color, upd_cmyk_kcolor);
3150        set_dev_proc(udev,decode_color, upd_kcolor_rgb);
3151        set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
3152        set_dev_proc(udev,map_cmyk_color,upd_cmyk_kcolor);
3153        set_dev_proc(udev,map_color_rgb, upd_kcolor_rgb);
3154      break;
3155      case MAP_RGBOV: /* RGB -> KCMY with BG and UCR for CMYK-Output */
3156        set_dev_proc(udev,encode_color, upd_rgb_ovcolor);
3157        set_dev_proc(udev,decode_color, upd_ovcolor_rgb);
3158        set_dev_proc(udev,map_rgb_color, upd_rgb_ovcolor);
3159        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
3160        set_dev_proc(udev,map_color_rgb, upd_ovcolor_rgb);
3161      break;
3162      case MAP_RGBNOV: /* RGB -> KCMY with BG and UCR for CMY+K-Output */
3163        set_dev_proc(udev,encode_color, upd_rgb_novcolor);
3164        set_dev_proc(udev,decode_color, upd_novcolor_rgb);
3165        set_dev_proc(udev,map_rgb_color, upd_rgb_novcolor);
3166        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
3167        set_dev_proc(udev,map_color_rgb, upd_novcolor_rgb);
3168      break;
3169 
3170      default:
3171        set_dev_proc(udev,encode_color, gx_default_map_rgb_color);
3172        set_dev_proc(udev,decode_color, gx_default_map_color_rgb);
3173        set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
3174        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
3175        set_dev_proc(udev,map_color_rgb, gx_default_map_color_rgb);
3176      break;
3177   }
3178   return 0;
3179 
3180 }
3181 
3182 /* ------------------------------------------------------------------- */
3183 /* upd_close_map: remove color mapping                                 */
3184 /* ------------------------------------------------------------------- */
3185 
3186 private int
upd_close_map(upd_device * udev)3187 upd_close_map(upd_device *udev)
3188 {
3189    const upd_p      upd   = udev->upd;
3190    int imap;
3191 
3192    if(upd) {
3193 
3194       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
3195 
3196          if(upd->cmap[imap].code)
3197             gs_free(udev->memory, upd->cmap[imap].code,sizeof(upd->cmap[imap].code[0]),
3198                 upd->cmap[imap].bitmsk+1,"upd/code");
3199          upd->cmap[imap].code   = NULL;
3200 
3201          upd->cmap[imap].bitmsk = 0;
3202          upd->cmap[imap].bitshf = 0;
3203          upd->cmap[imap].bits   = 0;
3204          upd->cmap[imap].rise   = false;
3205       }
3206       upd->flags &= ~B_MAP;
3207    }
3208 
3209    upd_procs_map(udev);
3210 
3211    return 0;
3212 }
3213 
3214 /* ------------------------------------------------------------------- */
3215 /* Functions for the rendering of data                                 */
3216 /* ------------------------------------------------------------------- */
3217 
3218 /**
3219 Inside the main-upd-type are a "valbuf" and some unidentified
3220 pointers. This stuff is used in conjunction with the rendering,
3221 which is the process of converting gx_color_indices into something
3222 suitable for the device.
3223 
3224 */
3225 
3226 /* ------------------------------------------------------------------- */
3227 /* upd_open_render: Initialize rendering                               */
3228 /* ------------------------------------------------------------------- */
3229 
3230 private void
upd_open_render(upd_device * udev)3231 upd_open_render(upd_device *udev)
3232 {
3233    const upd_p upd = udev->upd;
3234    int  icomp;
3235 
3236 /** Reset everything related to rendering */
3237    upd->flags       &= ~B_RENDER;
3238    upd->valbuf       = NULL;
3239    upd->nvalbuf      = 0;
3240    upd->render       = NULL;
3241    upd->start_render = NULL;
3242    for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
3243 
3244    if( (B_BUF | B_MAP) ==
3245       ((B_BUF | B_MAP | B_ERROR) & upd->flags)) {
3246 
3247 /** Establish the renderingwidth in upd */
3248       upd->rwidth = upd->gswidth;
3249       if((0            < upd->ints[I_PWIDTH]) &&
3250          (upd->gswidth > upd->ints[I_PWIDTH])   )
3251           upd->rwidth  = upd->ints[I_PWIDTH];
3252 
3253 /** Call the Render-specific Open-Function */
3254       switch(upd->choice[C_RENDER]) {
3255          case RND_FSCOMP:
3256             upd_open_fscomp(udev);
3257          break;
3258          case RND_FSCMYK:
3259             upd_open_fscmyk(udev);
3260          break;
3261          case RND_FSCMY_K:
3262             upd_open_fscmy_k(udev);
3263          break;
3264          default:
3265 #if UPD_MESSAGES & UPD_M_WARNING
3266             errprintf("upd_open_render: Unknown rendering type %d\n",
3267                 upd->choice[C_RENDER]);
3268 #endif
3269          break;
3270       }
3271    }
3272 
3273    if(B_RENDER != ((B_ERROR | B_RENDER) & upd->flags))
3274       upd_close_render(udev);
3275 
3276    return;
3277 }
3278 
3279 
3280 /* ------------------------------------------------------------------- */
3281 /* upd_close_render: Deinitialize rendering                            */
3282 /* ------------------------------------------------------------------- */
3283 
3284 private void
upd_close_render(upd_device * udev)3285 upd_close_render(upd_device *udev)
3286 {
3287    const upd_p upd = udev->upd;
3288 
3289    if(upd) {
3290       int icomp;
3291 
3292       if((upd->render == upd_fscomp) ||
3293          (upd->render == upd_fscmyk)   )  upd_close_fscomp(udev);
3294 
3295       if((0 < upd->nvalbuf) && upd->valbuf)
3296          gs_free(udev->memory, upd->valbuf,upd->nvalbuf,sizeof(upd->valbuf[0]),"upd/valbuf");
3297       upd->valbuf  = NULL;
3298       upd->nvalbuf = 0;
3299 
3300       upd->flags       &= ~B_RENDER;
3301       upd->render       = NULL;
3302       upd->start_render = NULL;
3303       for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
3304 
3305    }
3306    return;
3307 }
3308 
3309 /* ------------------------------------------------------------------- */
3310 /* upd_open_fscomp: Initialize Component-Floyd-Steinberg               */
3311 /* ------------------------------------------------------------------- */
3312 #if UPD_MESSAGES & UPD_M_FSBUF
3313 static int32_t fs_emin[UPD_VALPTR_MAX],fs_emax[UPD_VALPTR_MAX];
3314 #endif
3315 private void
upd_open_fscomp(upd_device * udev)3316 upd_open_fscomp(upd_device *udev)
3317 {
3318    const upd_p upd = udev->upd;
3319    int icomp,order[UPD_CMAP_MAX];
3320 
3321 #if UPD_MESSAGES & UPD_M_FSBUF
3322    for(icomp = 0; UPD_VALPTR_MAX < icomp; ++icomp)
3323       fs_emin[icomp] = fs_emax[icomp] = 0;
3324 #endif
3325 
3326    icomp = upd->ncomp;
3327 
3328    if((0              >= icomp) ||
3329       (UPD_VALPTR_MAX <  icomp) ||
3330       (UPD_CMAP_MAX   <  icomp)   ) icomp      = 0;
3331 
3332 /**
3333 This Version of the FS-algorithm works on the mapped components, but
3334 the printing-order might be different from the order dictated by the
3335 mapping-routines. The optional COMPORDER-Array is used for that. The
3336 initial test checks it's integrity.
3337 */
3338    if(icomp) {
3339       if(upd->ncomp <= upd->int_a[IA_COMPORDER].size) { /* Reordering */
3340          bool success = true;
3341          for(icomp = 0; upd->ncomp > icomp; ++icomp) {
3342             order[icomp] = upd->int_a[IA_COMPORDER].data[icomp];
3343             if((0            >  order[icomp]) ||
3344                (UPD_CMAP_MAX <= order[icomp])   ) {
3345                success = false;
3346 #if UPD_MESSAGES & UPD_M_WARNING
3347                   errprintf(
3348                    "upd_open_fscomp: %d is illegal component-index\n",
3349                    order[icomp]);
3350 #endif
3351             }
3352          }
3353          if(!success) icomp = 0;
3354       } else {                                          /* Default-Ordering */
3355          for(icomp = 0; UPD_CMAP_MAX > icomp; ++icomp) order[icomp] = icomp;
3356       }                                                 /* Ordering defined */
3357    }
3358 
3359 /**
3360 If anything was ok. up to now, memory get's allocated.
3361 */
3362    if(icomp) {
3363 
3364       for(icomp = 0; upd->ncomp > icomp; ++icomp) {
3365          upd->valptr[icomp] = gs_malloc(udev->memory, 1,sizeof(updcomp_t),"upd/fscomp");
3366          if(NULL == upd->valptr[icomp]) {
3367 #if UPD_MESSAGES & UPD_M_ERROR
3368             errprintf(
3369                "upd_open_fscomp: could not allocate %d. updcomp\n",
3370                icomp);
3371 #endif
3372             icomp = 0;
3373             break;
3374          }
3375       }
3376    }
3377 
3378    if(icomp) {
3379       uint need;
3380 
3381       need  = (2 + upd->rwidth) * upd->ncomp;
3382       upd->valbuf = gs_malloc(udev->memory, need,sizeof(upd->valbuf[0]),"upd/valbuf");
3383 
3384       if(upd->valbuf) {
3385          upd->nvalbuf = need;
3386          memset(upd->valbuf,0,need*sizeof(upd->valbuf[0]));
3387       } else {
3388 #if UPD_MESSAGES & UPD_M_ERROR
3389          errprintf(
3390             "upd_open_fscomp: could not allocate %u words for valbuf\n",need);
3391 #endif
3392          icomp = 0;
3393       }
3394    }
3395 
3396 /* Still happy? then compute component-values */
3397 
3398    if(icomp) {
3399       for(icomp = 0; upd->ncomp > icomp; ++icomp) {
3400 
3401          const updcomp_p comp   = upd->valptr[icomp];
3402          const int32_t     nsteps = upd->cmap[order[icomp]].bitmsk;
3403          float ymin,ymax;
3404          int32_t highmod,highval;
3405          int i;
3406 
3407          comp->threshold = nsteps;
3408          comp->spotsize  = nsteps;
3409          comp->offset    = 0;
3410          comp->scale     = 1;
3411          comp->cmap      = order[icomp];
3412          upd->cmap[comp->cmap].comp = icomp;
3413          comp->bits      = upd->cmap[comp->cmap].bits;
3414          comp->bitshf    = upd->cmap[comp->cmap].bitshf;
3415          comp->bitmsk    = upd->cmap[comp->cmap].bitmsk;
3416 
3417          if(!nsteps) continue; /* A 0-Bit component is legal! */
3418 
3419          if(upd->cmap[comp->cmap].rise) {
3420             ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
3421             ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[
3422                       upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
3423          } else {
3424             ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
3425             ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[
3426                       upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
3427          }
3428 
3429          if(0.0 > ymin) {
3430             ymin = 0.0;
3431             if(0.0 > ymax) ymax = 1.0 / (float) (nsteps+1);
3432          }
3433          if(1.0 < ymax) ymax = 1.0;
3434 
3435          comp->spotsize = ((int32_t) 1 << 28) - 1;
3436 
3437          for(i = 0; i < 32; ++i) { /* Attempt Ideal */
3438 
3439             highval = (int32_t)((ymax-ymin) * (double) comp->spotsize + 0.5);
3440 
3441             if(!(highmod = highval % nsteps)) break; /* Gotcha */
3442 
3443             highval += nsteps - highmod;
3444             comp->spotsize = (int32_t)((double) highval / (ymax-ymin) + 0.5);
3445 
3446             if(!(comp->spotsize % 2)) comp->spotsize++;
3447 
3448          }                         /* Attempt Ideal */
3449 
3450          comp->offset    = (int32_t)(ymin * (double) comp->spotsize + (double) 0.5);
3451          comp->scale     = highval / nsteps;
3452          comp->threshold = comp->spotsize / 2;
3453 
3454 #if UPD_MESSAGES & UPD_M_SETUP
3455          errprintf(
3456              "Values for %d. Component after %d iterations\n",comp->cmap+1,i);
3457          errprintf(
3458              "steps:     %10ld, Bits: %d\n",(long) comp->bitmsk,comp->bits);
3459          errprintf(
3460              "xfer:      %10d Points, %s\n",
3461              upd->float_a[upd->cmap[comp->cmap].xfer].size,
3462              upd->cmap[comp->cmap].rise ? "rising" : "falling");
3463          errprintf(
3464              "offset:    %10d 0x%08x\n",comp->offset,comp->offset);
3465          errprintf(
3466              "scale:     %10d 0x%08x\n",comp->scale,comp->scale);
3467          errprintf(
3468              "threshold: %10d 0x%08x\n",comp->threshold,comp->threshold);
3469          errprintf(
3470              "spotsize:  %10d 0x%08x\n",comp->spotsize,comp->spotsize);
3471 #endif
3472       }
3473    }
3474 /**
3475 Optional Random Initialization of the value-Buffer
3476 */
3477    if(icomp && !(B_FSZERO & upd->flags)) {
3478       for(icomp = 0; icomp < upd->ncomp; ++icomp) {
3479          const updcomp_p comp = upd->valptr[icomp];
3480          int i;
3481          int32_t lv = INT32_MAX, hv = INT32_MIN, v;
3482          float scale;
3483          for(i = icomp; i < upd->nvalbuf; i += upd->ncomp) {
3484             v = rand();
3485             if(lv > v) lv = v;
3486             if(hv < v) hv = v;
3487             upd->valbuf[i] = v;
3488          }
3489          scale = (float) comp->threshold / (float) (hv - lv);
3490          lv   += (int32_t)(comp->threshold / (2*scale));
3491          for(i = icomp; i < upd->nvalbuf; i += upd->ncomp)
3492             upd->valbuf[i] = (int32_t)(scale * (upd->valbuf[i] - lv));
3493       }
3494    }
3495 
3496 /**
3497 The render-Routine acts as an indicator, which render-close is to use!
3498 */
3499    upd->render = upd_fscomp;
3500 
3501    if(icomp) upd->flags |=  B_RENDER;
3502    else      upd->flags &= ~B_RENDER;
3503 
3504    return;
3505 }
3506 
3507 /* ------------------------------------------------------------------- */
3508 /* upd_close_fscomp: Deinitialize Component-Floyd-Steinberg            */
3509 /* ------------------------------------------------------------------- */
3510 
3511 private void
upd_close_fscomp(upd_device * udev)3512 upd_close_fscomp(upd_device *udev)
3513 {
3514    const upd_p upd = udev->upd;
3515    int icomp;
3516 
3517 #if UPD_MESSAGES & UPD_M_FSBUF
3518    if(upd && (upd->flags & B_RENDER)) {
3519 
3520       for(icomp = 0; icomp < upd->ncomp; ++icomp) {
3521          updcomp_p comp = upd->valptr[icomp];
3522          if(!comp) continue;
3523          if(!comp->spotsize) continue;
3524          errprintf("%d. Component: %6.3f <= error <= %6.3f\n",
3525              icomp+1,
3526              (double) fs_emin[icomp] / (double) comp->spotsize,
3527              (double) fs_emax[icomp] / (double) comp->spotsize);
3528       }
3529 
3530    }
3531 #endif
3532 
3533    for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) {
3534       if(!upd->valptr[icomp]) continue;
3535       gs_free(udev->memory, upd->valptr[icomp],1,sizeof(updcomp_t),"upd/fscomp");
3536       upd->valptr[icomp] = NULL;
3537    }
3538 }
3539 
3540 /* ------------------------------------------------------------------- */
3541 /* upd_fscomp: Apply Floyd-Steinberg to each component                 */
3542 /* ------------------------------------------------------------------- */
3543 
3544 /**
3545    With UPD_M_FSBUF Max/Min-Values for the Errors are computed
3546 */
3547 #if   UPD_MESSAGES & UPD_M_FSBUF
3548 #define FS_M_ROWERR(I)                                        \
3549            if(fs_emin[I] > rowerr[I]) fs_emin[I] = rowerr[I]; \
3550            if(fs_emax[I] < rowerr[I]) fs_emax[I] = rowerr[I];
3551 #else
3552 #define FS_M_ROWERR(I) ;
3553 #endif
3554 /**
3555    FS_GOAL computes the desired Pixel-Value
3556 */
3557 #define FS_GOAL(Raw,I)                                                     \
3558    pixel[I] = (int32_t)(Raw) * comp[I]->scale +    comp[I]->offset           \
3559             + rowerr[I]  + colerr[I] -       ((colerr[I]+4)>>3);           \
3560    if(         pixel[I] < 0)                    pixel[I] = 0;              \
3561    else if(    pixel[I] >    comp[I]->spotsize) pixel[I] = comp[I]->spotsize;
3562 
3563 /*
3564  *    Distribute the error:   prev  now   next
3565  *                                   X    7/16 Y
3566  *                            3/16  5/16  1/16 Y+1
3567  */
3568 #define FS_DIST(I)                                                    \
3569    if(!first) rowerr[I-dir] += ((3*pixel[I]+8)>>4); /* 3/16 */        \
3570               rowerr[I    ]  = ((5*pixel[I]  )>>4)  /* 5/16 */        \
3571                              + (( colerr[I]+4)>>3); /* 1/16 (rest) */ \
3572               colerr[I    ]  = pixel[I]             /* 8/16 (neu) */  \
3573                              - ((5*pixel[I]  )>>4)                    \
3574                              - ((3*pixel[I]+8)>>4);
3575 /**
3576    S_FSTEP   adjusts the Indices (rowerr, bit and iword)
3577 */
3578 #define S_FSTEP                                \
3579    rowerr += dir;                              \
3580    first   = false;                            \
3581    if(0 > dir) { /* Reverse */                 \
3582       if(!(bit <<= 1)) { bit = 0x01; ibyte--; }\
3583    } else {      /* Forward */                 \
3584       if(!(bit >>= 1)) { bit = 0x80; ibyte++; }\
3585    }             /* Inc/Dec Bit */
3586 
3587 private int
upd_fscomp(upd_p upd)3588 upd_fscomp(upd_p upd)
3589 {
3590    const updscan_p  scan    = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
3591    const updcomp_p *comp    = (updcomp_p *) upd->valptr;
3592    int32_t *const     pixel  = upd->valbuf;
3593    int32_t *const     colerr = pixel  + upd->ncomp;
3594    int32_t           *rowerr = colerr + upd->ncomp;
3595    int              pwidth = upd->rwidth;
3596    int              dir,ibyte;
3597    int              iblack,bblack,pxlset;
3598    uint32_t       ci;
3599    byte         bit;
3600    bool         first = true;
3601 /*
3602  * Erase the component-Data
3603  */
3604    switch(upd->ncomp) {
3605      case 4:  memset(scan[3].bytes,0,upd->nbytes);
3606      case 3:  memset(scan[2].bytes,0,upd->nbytes);
3607               memset(scan[1].bytes,0,upd->nbytes);
3608      default: memset(scan[0].bytes,0,upd->nbytes);
3609    }
3610 /*
3611  * determine the direction
3612  */
3613    if(upd->flags &   B_REVDIR) { /* This one reverse */
3614 
3615       if(upd->flags & B_YFLIP) {
3616          dir     = upd->ncomp;
3617          bit     = 0x80;
3618          ibyte   = 0;
3619       } else {
3620          dir     =  -upd->ncomp;
3621          rowerr +=   upd->ncomp * (pwidth-1);
3622          bit     =   0x80 >>     ((pwidth-1) & 7);
3623          ibyte   =                (pwidth-1) >> 3;
3624       }
3625 
3626       if(!(upd->flags & B_FSWHITE)) {
3627          upd_pxlfwd(upd);
3628          while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
3629       }
3630 
3631       upd_pxlrev(upd);
3632 
3633    } else {                       /* This one forward */
3634 
3635       if(upd->flags & B_YFLIP) {
3636          dir     =  -upd->ncomp;
3637          rowerr +=   upd->ncomp * (pwidth-1);
3638          bit     =   0x80 >>     ((pwidth-1) & 7);
3639          ibyte   =                (pwidth-1) >> 3;
3640       } else {
3641          dir     = upd->ncomp;
3642          bit     = 0x80;
3643          ibyte   = 0;
3644       }
3645 
3646       if(!(upd->flags & B_FSWHITE)) {
3647          upd_pxlrev(upd);
3648          while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
3649       }
3650 
3651       upd_pxlfwd(upd);
3652 
3653    }                              /* reverse or forward */
3654 /*
3655  * Toggle Direction, if not fixed
3656  */
3657    if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
3658 /*
3659  * Skip over leading white-space
3660  */
3661    if(!(upd->flags & B_FSWHITE)) {
3662       upd_proc_pxlget((*fun)) = upd->pxlget;
3663       byte             *ptr   = upd->pxlptr;
3664       while((0 < pwidth) && !upd_pxlget(upd)) {
3665          pwidth--;
3666          fun = upd->pxlget;
3667          ptr = upd->pxlptr;
3668          S_FSTEP
3669       }
3670       upd->pxlget = fun;
3671       upd->pxlptr = ptr;
3672    }
3673 /*
3674  * Set iblack, if black-reduction is active
3675  */
3676   iblack = -1;
3677   bblack =  0;
3678   if((4 == upd->ncomp) && (B_REDUCEK & upd->flags)) {
3679     iblack = upd->cmap[0].comp;
3680     bblack = 1<<iblack;
3681   }
3682 /*
3683  * Process all Pixels
3684  */
3685    first = true;
3686    while(0 < pwidth--) {
3687 /*
3688  *    Execute FS-Algorithm for each active component
3689  */
3690       pxlset = 0;
3691       ci = upd_pxlget(upd);
3692       switch(upd->ncomp) {
3693          case 4:  FS_M_ROWERR(3)
3694                   FS_GOAL(comp[3]->bitmsk & (ci >> comp[3]->bitshf),3)
3695                   if(pixel[3] >  comp[3]->threshold) { /* "Fire" */
3696                      pixel[3] -= comp[3]->spotsize;
3697                       scan[3].bytes[ibyte] |= bit;
3698                       pxlset  |= 8;
3699                   }                                    /* "Fire" */
3700                   FS_DIST(3)
3701 
3702          case 3:  FS_M_ROWERR(2)
3703                   FS_GOAL(comp[2]->bitmsk & (ci >> comp[2]->bitshf),2)
3704                   if(pixel[2] >  comp[2]->threshold) { /* "Fire" */
3705                      pixel[2] -= comp[2]->spotsize;
3706                       scan[2].bytes[ibyte] |= bit;
3707                       pxlset  |= 4;
3708                   }                                    /* "Fire" */
3709                   FS_DIST(2)
3710 
3711                   FS_M_ROWERR(1)
3712                   FS_GOAL(comp[1]->bitmsk & (ci >> comp[1]->bitshf),1)
3713                   if(pixel[1] >  comp[1]->threshold) { /* "Fire" */
3714                      pixel[1] -= comp[1]->spotsize;
3715                       scan[1].bytes[ibyte] |= bit;
3716                       pxlset  |= 2;
3717                   }                                    /* "Fire" */
3718                   FS_DIST(1)
3719 
3720          default: FS_M_ROWERR(0)
3721                   FS_GOAL(comp[0]->bitmsk & (ci >> comp[0]->bitshf),0)
3722                   if(pixel[0] >  comp[0]->threshold) { /* "Fire" */
3723                      pixel[0] -= comp[0]->spotsize;
3724                       scan[0].bytes[ibyte] |= bit;
3725                       pxlset  |= 1;
3726                   }                                    /* "Fire" */
3727                   FS_DIST(0)
3728       }
3729 /*
3730  *    Black-Reduction
3731  */
3732       if(bblack) {
3733         if(pxlset & bblack) pxlset |= 15;
3734         switch(pxlset) {
3735           case  0:
3736           case  1:
3737           case  2:
3738           case  4:
3739           case  8:
3740           case  3:
3741           case  5:
3742           case  9:
3743           case  6:
3744           case 10:
3745           case 12:
3746             break;
3747           default:
3748             scan[0].bytes[ibyte]      &= ~bit;
3749             scan[1].bytes[ibyte]      &= ~bit;
3750             scan[2].bytes[ibyte]      &= ~bit;
3751             scan[3].bytes[ibyte]      &= ~bit;
3752             scan[iblack].bytes[ibyte] |=  bit;
3753           break;
3754         }
3755       }
3756 /*
3757  *    Adjust rowerr, bit & iword, depending on direction
3758  */
3759       S_FSTEP
3760    }
3761 /*
3762  * Finally call the limits-Routine
3763  */
3764    if(0 < upd->nlimits) upd_limits(upd,true);
3765    return 0;
3766 }
3767 
3768 /* ------------------------------------------------------------------- */
3769 /* upd_open_fscmyk: Initialize Component-Floyd-Steinberg               */
3770 /* ------------------------------------------------------------------- */
3771 
3772 private void
upd_open_fscmyk(upd_device * udev)3773 upd_open_fscmyk(upd_device *udev)
3774 {
3775    const upd_p upd = udev->upd;
3776 
3777    upd_open_fscomp(udev);
3778 
3779    if((B_RENDER & upd->flags) &&
3780       (4 == upd->ncomp) &&
3781       (8 <= upd->cmap[0].bits) && (24 == upd->cmap[0].bitshf) &&
3782       (8 <= upd->cmap[1].bits) && (16 == upd->cmap[1].bitshf) &&
3783       (8 <= upd->cmap[2].bits) && ( 8 == upd->cmap[2].bitshf) &&
3784       (8 <= upd->cmap[3].bits) && ( 0 == upd->cmap[3].bitshf)   ) {
3785       upd->render = upd_fscmyk;
3786    } else {
3787       upd->flags &= ~B_RENDER;
3788    }
3789 
3790 }
3791 
3792 /* ------------------------------------------------------------------- */
3793 /* upd_fscmyk: 32 Bit, K-CMY-Order Dithering                           */
3794 /* ------------------------------------------------------------------- */
3795 
3796 private int
upd_fscmyk(upd_p upd)3797 upd_fscmyk(upd_p upd)
3798 {
3799    const updscan_p  scan   = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
3800    int32_t *const     pixel  = upd->valbuf;
3801    const updcomp_p *comp   = (updcomp_p *) upd->valptr;
3802    int32_t *const     colerr = pixel  + 4;
3803    int32_t           *rowerr = colerr + 4;
3804    int32_t            pwidth = upd->rwidth;
3805    int              dir,ibyte;
3806    byte             bit,*data;
3807    bool             first = false;
3808 /*
3809  * Erase the component-Data
3810  */
3811    memset(scan[0].bytes,0,upd->nbytes);
3812    memset(scan[1].bytes,0,upd->nbytes);
3813    memset(scan[2].bytes,0,upd->nbytes);
3814    memset(scan[3].bytes,0,upd->nbytes);
3815 
3816 /*
3817  * determine the direction
3818  */
3819    if(upd->flags &   B_REVDIR) { /* This one reverse */
3820 
3821       if(!(upd->flags & B_FSWHITE)) {
3822          data = upd->gsscan;
3823          while(0 < pwidth && !*(uint32_t *)data) pwidth--, data += 4;
3824          if(0 >= pwidth) {
3825             if(0 < upd->nlimits) upd_limits(upd,false);
3826             return 0;
3827          }
3828       }
3829 
3830       data        = upd->gsscan + 4 * (upd->rwidth-1);
3831 
3832    } else {                          /* This one forward */
3833 
3834       if(!(upd->flags & B_FSWHITE)) {
3835          data = upd->gsscan + 4 * (upd->rwidth-1);
3836          while(0 < pwidth && !*(uint32_t *)data) pwidth--, data -= 4;
3837          if(0 >= pwidth) {
3838             if(0 < upd->nlimits) upd_limits(upd,false);
3839             return 0;
3840          }
3841       }
3842 
3843       data        = upd->gsscan;
3844 
3845    }                              /* reverse or forward */
3846 /*
3847  * Bits depend on FLIP & Direction
3848  */
3849    if(!(B_REVDIR & upd->flags) == !(B_YFLIP  & upd->flags)) {
3850       dir         = 4;
3851       bit         = 0x80;
3852       ibyte       = 0;
3853    } else {
3854       dir         =  -4;
3855       rowerr     +=   4 *             (upd->rwidth-1);
3856       bit         =   0x80 >>        ((upd->rwidth-1) & 7);
3857       ibyte       =                   (upd->rwidth-1) >> 3;
3858    }
3859 
3860 /*
3861  * Toggle Direction, if not fixed
3862  */
3863    if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
3864 /*
3865  * Skip over leading white-space
3866  */
3867    if(!(upd->flags & B_FSWHITE)) {
3868       while(0 < pwidth && !*((uint32_t *)data)) {
3869          pwidth--;
3870          if(B_YFLIP  & upd->flags) data -= dir;
3871          else                      data += dir;
3872          S_FSTEP
3873       }
3874    }
3875 /*
3876  * Process all Pixels
3877  */
3878    first = true;
3879    while(0 < pwidth--) {
3880 /*
3881  *    Compute the Black-Value first
3882  */
3883       FS_M_ROWERR(upd->cmap[0].comp) FS_GOAL(data[0],upd->cmap[0].comp);
3884 
3885 /*
3886  *    Decide wether this is a color value
3887  */
3888       if(data[1] || data[2] || data[3]) {
3889 
3890          FS_M_ROWERR(upd->cmap[1].comp) FS_GOAL(data[1],upd->cmap[1].comp)
3891          FS_M_ROWERR(upd->cmap[2].comp) FS_GOAL(data[2],upd->cmap[2].comp)
3892          FS_M_ROWERR(upd->cmap[3].comp) FS_GOAL(data[3],upd->cmap[3].comp)
3893 /*
3894  *       if black fires, then all other components fire logically too
3895  */
3896          if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
3897 
3898             pixel[0] -= comp[0]->spotsize;
3899             pixel[1] -= comp[1]->spotsize;
3900             pixel[2] -= comp[2]->spotsize;
3901             pixel[3] -= comp[3]->spotsize;
3902             scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
3903 
3904 /*
3905  *       if black is below threshold, only components with larger data-values
3906  *       are allowed to fire
3907  */
3908          } else {                                 /* Restricted firing */
3909 
3910             if(( data[0] < data[1]) &&
3911                (pixel[upd->cmap[1].comp] >
3912                  comp[upd->cmap[1].comp]->threshold)) { /* "Fire" */
3913                 pixel[upd->cmap[1].comp] -= comp[upd->cmap[1].comp]->spotsize;
3914                  scan[upd->cmap[1].comp].bytes[ibyte] |= bit;
3915             }                                           /* "Fire" */
3916 
3917             if(( data[0] < data[2]) &&
3918                (pixel[upd->cmap[2].comp] >
3919                  comp[upd->cmap[2].comp]->threshold)) { /* "Fire" */
3920                 pixel[upd->cmap[2].comp] -= comp[upd->cmap[2].comp]->spotsize;
3921                  scan[upd->cmap[2].comp].bytes[ibyte] |= bit;
3922             }                                           /* "Fire" */
3923 
3924             if(( data[0] < data[3]) &&
3925                (pixel[upd->cmap[3].comp] >
3926                  comp[upd->cmap[3].comp]->threshold)) { /* "Fire" */
3927                 pixel[upd->cmap[3].comp] -= comp[upd->cmap[3].comp]->spotsize;
3928                  scan[upd->cmap[3].comp].bytes[ibyte] |= bit;
3929             }                                           /* "Fire" */
3930 
3931          }                                        /* Fire-Mode */
3932 
3933 /*
3934  * Handle Color-Errors
3935  */
3936          FS_DIST(upd->cmap[3].comp)
3937          FS_DIST(upd->cmap[2].comp)
3938          FS_DIST(upd->cmap[1].comp)
3939 
3940       } else if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
3941                  scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
3942                 pixel[upd->cmap[0].comp] -= comp[upd->cmap[0].comp]->spotsize;
3943       }
3944 
3945       FS_DIST(upd->cmap[0].comp)
3946 /*
3947  *    Adjust bit & iword, depending on direction
3948  */
3949       S_FSTEP
3950       if(upd->flags & B_YFLIP) data -= dir;
3951       else                     data += dir;
3952    }
3953 /*
3954  * Finally call the limits-Routine
3955  */
3956    if(0 < upd->nlimits) upd_limits(upd,true);
3957    return 0;
3958 }
3959 
3960 /* ------------------------------------------------------------------- */
3961 /* upd_open_fscmy_k: Initialize for CMY_K Printing                     */
3962 /* ------------------------------------------------------------------- */
3963 
3964 private void
upd_open_fscmy_k(upd_device * udev)3965 upd_open_fscmy_k(upd_device *udev)
3966 {
3967    const upd_p upd = udev->upd;
3968 
3969    upd_open_fscomp(udev);
3970 
3971    if((B_RENDER & upd->flags) &&
3972       (4 == upd->ncomp)) {
3973       upd->render = upd_fscmy_k;
3974    } else {
3975       upd->flags &= ~B_RENDER;
3976    }
3977 
3978 }
3979 
3980 /* ------------------------------------------------------------------- */
3981 /* upd_fscmy_k: CMY_K rendering                                        */
3982 /* ------------------------------------------------------------------- */
3983 
3984 private int
upd_fscmy_k(upd_p upd)3985 upd_fscmy_k(upd_p upd)
3986 {
3987    const updscan_p  scan    = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
3988    const updcomp_p *comp    = (updcomp_p *) upd->valptr;
3989    int32_t *const     pixel  = upd->valbuf;
3990    int32_t *const     colerr = pixel  + upd->ncomp;
3991    int32_t           *rowerr = colerr + upd->ncomp;
3992    int              pwidth = upd->rwidth;
3993    int              dir,ibyte;
3994    uint32_t       ci;
3995    byte         bit;
3996    bool         first = true;
3997 /*
3998  * Erase the component-Data
3999  */
4000    memset(scan[3].bytes,0,upd->nbytes);
4001    memset(scan[2].bytes,0,upd->nbytes);
4002    memset(scan[1].bytes,0,upd->nbytes);
4003    memset(scan[0].bytes,0,upd->nbytes);
4004 /*
4005  * determine the direction
4006  */
4007    if(upd->flags &   B_REVDIR) { /* This one reverse */
4008 
4009       if(upd->flags & B_YFLIP) {
4010          dir     = 4;
4011          bit     = 0x80;
4012          ibyte   = 0;
4013       } else {
4014          dir     =  -4;
4015          rowerr +=   4 * (pwidth-1);
4016          bit     =   0x80 >>     ((pwidth-1) & 7);
4017          ibyte   =                (pwidth-1) >> 3;
4018       }
4019 
4020       if(!(upd->flags & B_FSWHITE)) {
4021          upd_pxlfwd(upd);
4022          while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
4023       }
4024 
4025       upd_pxlrev(upd);
4026 
4027    } else {                       /* This one forward */
4028 
4029       if(upd->flags & B_YFLIP) {
4030          dir     =  -4;
4031          rowerr +=   4          * (pwidth-1);
4032          bit     =   0x80 >>     ((pwidth-1) & 7);
4033          ibyte   =                (pwidth-1) >> 3;
4034       } else {
4035          dir     = 4;
4036          bit     = 0x80;
4037          ibyte   = 0;
4038       }
4039 
4040       if(!(upd->flags & B_FSWHITE)) {
4041          upd_pxlrev(upd);
4042          while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
4043       }
4044 
4045       upd_pxlfwd(upd);
4046 
4047    }                              /* reverse or forward */
4048 /*
4049  * Toggle Direction, if not fixed
4050  */
4051    if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
4052 /*
4053  * Skip over leading white-space
4054  */
4055    if(!(upd->flags & B_FSWHITE)) {
4056       upd_proc_pxlget((*fun)) = upd->pxlget;
4057       byte             *ptr   = upd->pxlptr;
4058       while((0 < pwidth) && !upd_pxlget(upd)) {
4059          pwidth--;
4060          fun = upd->pxlget;
4061          ptr = upd->pxlptr;
4062          S_FSTEP
4063       }
4064       upd->pxlget = fun;
4065       upd->pxlptr = ptr;
4066    }
4067 /*
4068  * Process all Pixels
4069  */
4070    first = true;
4071    while(0 < pwidth--) {
4072 
4073 /*    get the Pixel-Value */
4074 
4075       ci = upd_pxlget(upd);
4076 
4077 /*    process all components */
4078 
4079       FS_M_ROWERR(0) FS_GOAL(comp[0]->bitmsk & (ci >> comp[0]->bitshf),0)
4080       FS_M_ROWERR(1) FS_GOAL(comp[1]->bitmsk & (ci >> comp[1]->bitshf),1)
4081       FS_M_ROWERR(2) FS_GOAL(comp[2]->bitmsk & (ci >> comp[2]->bitshf),2)
4082       FS_M_ROWERR(3) FS_GOAL(comp[3]->bitmsk & (ci >> comp[3]->bitshf),3)
4083 
4084       if(pixel[0] >  comp[0]->threshold) { /* Black fires */
4085 
4086         pixel[0]             -= comp[0]->spotsize;
4087         scan[0].bytes[ibyte] |= bit;
4088 
4089       } else {                             /* Colors may fire */
4090 
4091          if((pixel[1] <= comp[1]->threshold) ||
4092             (pixel[2] <= comp[2]->threshold) ||
4093             (pixel[3] <= comp[3]->threshold)   ) { /* Really a Color */
4094 
4095             if(pixel[1] >               comp[1]->threshold) {
4096                pixel[1]              -= comp[1]->spotsize;
4097                 scan[1].bytes[ibyte] |= bit;
4098             }
4099 
4100             if(pixel[2] >               comp[2]->threshold) {
4101                pixel[2]              -= comp[2]->spotsize;
4102                 scan[2].bytes[ibyte] |= bit;
4103             }
4104 
4105             if(pixel[3] >               comp[3]->threshold) {
4106                pixel[3]              -= comp[3]->spotsize;
4107                 scan[3].bytes[ibyte] |= bit;
4108             }
4109 
4110          } else {
4111             pixel[1]              -= comp[1]->spotsize;
4112             pixel[2]              -= comp[2]->spotsize;
4113             pixel[3]              -= comp[3]->spotsize;
4114             scan[0].bytes[ibyte] |= bit;
4115          }
4116       }
4117 
4118       FS_DIST(0)
4119       FS_DIST(1)
4120       FS_DIST(2)
4121       FS_DIST(3)
4122 
4123 /*
4124  *    Adjust rowerr, bit & iword, depending on direction
4125  */
4126       S_FSTEP
4127    }
4128 /*
4129  * Finally call the limits-Routine
4130  */
4131    if(0 < upd->nlimits) upd_limits(upd,true);
4132    return 0;
4133 }
4134 
4135 /* ------------------------------------------------------------------- */
4136 /* upd_open_writer: Initialize rendering                               */
4137 /* ------------------------------------------------------------------- */
4138 
4139 private int
upd_open_writer(upd_device * udev)4140 upd_open_writer(upd_device *udev)
4141 {
4142    const upd_p upd                 = udev->upd;
4143    bool        success             = true;
4144 
4145 
4146 /** Reset the crucial values */
4147    upd->start_writer = NULL;
4148    upd->writer       = NULL;
4149    upd->scnbuf       = NULL;
4150    upd->nscnbuf      = 0;
4151    upd->nbytes       = 0;
4152    upd->nlimits      = 0;
4153    upd->outbuf       = NULL;
4154    upd->noutbuf      = 0;
4155 
4156 /** Rendering should be succesfully initialized */
4157    if(B_RENDER != ((B_RENDER | B_ERROR) & upd->flags))
4158       success = false;
4159 
4160 /** Create number of components */
4161    upd->ocomp = upd->ncomp;
4162    if(0 < upd->ints[I_OCOMP]) upd->ocomp = upd->ints[I_OCOMP];
4163 
4164 /** Massage some Parameters */
4165    if(success) {
4166 
4167 /*    Make sure, that Pass & Pin-Numbers are at least 1 */
4168       if(1 >  upd->ints[I_NYPASS]) upd->ints[I_NYPASS] = 1;
4169       if(1 >  upd->ints[I_NXPASS]) upd->ints[I_NXPASS] = 1;
4170       if(1 >  upd->ints[I_PINS2WRITE]) upd->ints[I_PINS2WRITE] = 1;
4171 
4172       if((upd->ints[I_NXPASS] * upd->ints[I_NYPASS]) > upd->ints[I_NPASS])
4173          upd->ints[I_NPASS] = upd->ints[I_NXPASS] * upd->ints[I_NYPASS];
4174 
4175 /*    Create Default noWeave-Feeds */
4176 
4177       if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
4178          int ix,iy,*ip;
4179          UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_STD_DY]);
4180          UPD_MM_GET_ARRAY(udev->memory, ip,upd->ints[I_NPASS]);
4181          upd->int_a[IA_STD_DY].data = ip;
4182          upd->int_a[IA_STD_DY].size = upd->ints[I_NPASS];
4183 
4184          for(iy = 1; iy < upd->ints[I_NYPASS]; ++iy) {
4185             for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
4186             *ip++ = 1;
4187          }
4188          for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
4189          *ip = upd->ints[I_NYPASS] * upd->ints[I_PINS2WRITE]
4190              - upd->ints[I_NYPASS] + 1;
4191 
4192          upd->ints[I_BEG_Y] = 0;
4193          upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ?
4194                               upd->ints[I_PHEIGHT] : upd->gsheight;
4195       }
4196 
4197 /*    Adjust BEG_Y */
4198       if(0 >= upd->ints[I_BEG_Y]) {
4199          if(0 <  upd->int_a[IA_BEG_DY].size) {
4200             int i,sum = 0;
4201             for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
4202                sum +=  upd->int_a[IA_BEG_DY].data[i];
4203             upd->ints[I_BEG_Y] = sum;
4204          } else {
4205             upd->ints[I_BEG_Y] = 0;
4206          }
4207       }
4208 
4209 /*    Adjust END_Y */
4210 /*    Arrgh, I knew, why I refused to provide defaults for crucial */
4211 /*    parameters in uniprint. But o.k. it's nice for size-changing */
4212 /*    PostScript-Code. Nevertheless, it's still not perfect.       */
4213 
4214       if(0 >= upd->int_a[IA_ENDTOP].size ||
4215          0 >= upd->int_a[IA_END_DY].size   ) upd->ints[I_END_Y] =
4216          upd->ints[I_PHEIGHT] ? upd->ints[I_PHEIGHT] : upd->gsheight;
4217 
4218       if(0 >= upd->ints[I_END_Y]) upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ?
4219         upd->ints[I_PHEIGHT] : upd->gsheight;
4220 
4221 
4222 /*    Create Default X-Passes */
4223 
4224       if(0 >= upd->int_a[IA_STD_IX].size) {
4225          int ix,i,*ip;
4226          UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_STD_IX]);
4227          UPD_MM_GET_ARRAY(udev->memory, ip,upd->int_a[IA_STD_DY].size);
4228          upd->int_a[IA_STD_IX].data = ip;
4229          upd->int_a[IA_STD_IX].size = upd->int_a[IA_STD_DY].size;
4230 
4231          for(i = 0, ix = 0; i < upd->int_a[IA_STD_IX].size; ++i) {
4232             *ip++ = ix++;
4233             if(ix == upd->ints[I_NXPASS]) ix = 0;
4234          }
4235       }
4236 
4237       if((0 >= upd->int_a[IA_BEG_IX].size) &&
4238          (0 <  upd->int_a[IA_BEG_DY].size)   ) {
4239          int ix,i,*ip;
4240          UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_BEG_IX]);
4241          UPD_MM_GET_ARRAY(udev->memory, ip,upd->int_a[IA_BEG_DY].size);
4242          upd->int_a[IA_BEG_IX].data = ip;
4243          upd->int_a[IA_BEG_IX].size = upd->int_a[IA_BEG_DY].size;
4244 
4245          for(i = 0, ix = 0; i < upd->int_a[IA_BEG_IX].size; ++i) {
4246             *ip++ = ix++;
4247             if(ix == upd->ints[I_NXPASS]) ix = 0;
4248          }
4249       }
4250 
4251       if((0 >= upd->int_a[IA_END_IX].size) &&
4252          (0 <  upd->int_a[IA_END_DY].size)   ) {
4253          int ix,i,*ip;
4254          UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_END_IX]);
4255          UPD_MM_GET_ARRAY(udev->memory, ip,upd->int_a[IA_END_DY].size);
4256          upd->int_a[IA_END_IX].data = ip;
4257          upd->int_a[IA_END_IX].size = upd->int_a[IA_END_DY].size;
4258 
4259          for(i = 0, ix = 0; i < upd->int_a[IA_END_IX].size; ++i) {
4260             *ip++ = ix++;
4261             if(ix == upd->ints[I_NXPASS]) ix = 0;
4262          }
4263       }
4264    }
4265 
4266    if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
4267 #if UPD_MESSAGES & UPD_M_WARNING
4268       errprintf(
4269         "upd_open_writer: Only %d instead of %d normal Feeds\n",
4270         (int) upd->int_a[IA_STD_DY].size,upd->ints[I_NPASS]);
4271 #endif
4272       success = false;
4273 
4274    } else if(upd->int_a[IA_STD_IX].size < upd->int_a[IA_STD_DY].size) {
4275 #if UPD_MESSAGES & UPD_M_WARNING
4276       errprintf(
4277         "upd_open_writer: Only %d instead of %d normal Xstarts\n",
4278         (int) upd->int_a[IA_STD_IX].size,
4279         (int) upd->int_a[IA_STD_DY].size);
4280 #endif
4281       success = false;
4282    }
4283 
4284 /** The sum of Values in STD_DY should equal NYPASS * PINS2WRITE (diagnostic) */
4285 
4286 #if UPD_MESSAGES & UPD_M_WARNING
4287    if(success) {
4288       int i,sum = 0;
4289       for(i = 0; upd->ints[I_NPASS] > i; ++i)
4290          sum += upd->int_a[IA_STD_DY].data[i];
4291       if((upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]) != sum)
4292          errprintf(
4293          "upd_open_writer: Sum of normal Feeds is %d rather than %d\n",
4294          sum,upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]);
4295    }
4296 #endif
4297 
4298    if(upd->int_a[IA_BEG_IX].size < upd->int_a[IA_BEG_DY].size) {
4299 #if UPD_MESSAGES & UPD_M_WARNING
4300       errprintf(
4301         "upd_open_writer: Only %d instead of %d initial Xstarts\n",
4302         (int) upd->int_a[IA_BEG_IX].size,
4303         (int) upd->int_a[IA_BEG_DY].size);
4304 #endif
4305       success = false;
4306    }
4307 
4308    if(upd->int_a[IA_BEGBOT].size < upd->int_a[IA_BEG_DY].size) {
4309 #if UPD_MESSAGES & UPD_M_WARNING
4310       errprintf(
4311         "upd_open_writer: Only %d instead of %d initial Pins\n",
4312         (int) upd->int_a[IA_BEGBOT].size,
4313         (int) upd->int_a[IA_BEG_DY].size);
4314 #endif
4315       success = false;
4316 
4317    } else {
4318 
4319       int i;
4320       for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
4321          if((upd->int_a[IA_BEGBOT].data[i] > upd->ints[I_PINS2WRITE]) ||
4322             (upd->int_a[IA_BEGBOT].data[i] < 0                      )   ) break;
4323 
4324       if(i < upd->int_a[IA_BEG_DY].size) {
4325 #if UPD_MESSAGES & UPD_M_WARNING
4326          errprintf(
4327            "upd_open_writer: Only %d is invalid initial Pins\n",
4328            upd->int_a[IA_BEGBOT].data[i]);
4329 #endif
4330          success = false;
4331       }
4332    }
4333 
4334 
4335 /** The sum of Values in BEG_DY should equal BEG_Y */
4336 
4337 #if UPD_MESSAGES & UPD_M_WARNING
4338    if(success) {
4339       int i,sum = 0;
4340       for(i = 0;  upd->int_a[IA_BEG_DY].size > i; ++i)
4341          sum += upd->int_a[IA_BEG_DY].data[i];
4342       if(upd->ints[I_BEG_Y] != sum)
4343          errprintf(
4344          "upd_open_writer: Sum of initial Feeds is %d rather than %d\n",
4345          sum,upd->ints[I_BEG_Y]);
4346    }
4347 #endif
4348 
4349    if(upd->int_a[IA_END_IX].size < upd->int_a[IA_END_DY].size) {
4350 #if UPD_MESSAGES & UPD_M_WARNING
4351       errprintf(
4352         "upd_open_writer: Only %d instead of %d final Xstarts\n",
4353         (int) upd->int_a[IA_END_IX].size,
4354         (int) upd->int_a[IA_END_DY].size);
4355 #endif
4356       success = false;
4357    }
4358 
4359    if(upd->int_a[IA_ENDTOP].size < upd->int_a[IA_END_DY].size) {
4360 #if UPD_MESSAGES & UPD_M_WARNING
4361       errprintf(
4362         "upd_open_writer: Only %d instead of %d Final Pins\n",
4363         (int) upd->int_a[IA_ENDTOP].size,
4364         (int) upd->int_a[IA_END_DY].size);
4365 #endif
4366       success = false;
4367 
4368    } else {
4369 
4370       int i;
4371       for(i = 0; i < upd->int_a[IA_END_DY].size; ++i)
4372          if((upd->int_a[IA_ENDTOP].data[i] > upd->ints[I_PINS2WRITE]) ||
4373             (upd->int_a[IA_ENDTOP].data[i] < 0                      )   ) break;
4374 
4375       if(i < upd->int_a[IA_END_DY].size) {
4376 #if UPD_MESSAGES & UPD_M_WARNING
4377          errprintf(
4378            "upd_open_writer: Only %d is invalid initial Pins\n",
4379            upd->int_a[IA_ENDTOP].data[i]);
4380 #endif
4381          success = false;
4382       }
4383    }
4384 
4385 /** SA_SETCOMP must be valid, if present */
4386    if((0 < upd->string_a[SA_SETCOMP].size) &&
4387       (upd->ocomp > upd->string_a[SA_SETCOMP].size)) {
4388 #if UPD_MESSAGES & UPD_M_WARNING
4389       errprintf(
4390          "upd_open_writer: Only %d SETCOMP-Commands (%d required)\n",
4391          (int) upd->string_a[SA_SETCOMP].size,upd->ocomp);
4392 #endif
4393       success = false;
4394    }
4395 
4396 /** Determine required number of scan-Buffers */
4397 
4398    if(success) { /* Compute nscnbuf */
4399       int32_t want,use;
4400 
4401       want  = upd->ints[I_NYPASS];
4402       want *= upd->ints[I_PINS2WRITE];
4403 
4404       if(upd->ints[I_NSCNBUF] > want) want = upd->ints[I_NSCNBUF];
4405 
4406       if(1 > want)                         want = 1;
4407 
4408       for(use = 1; 0 < use; use <<= 1) if(use > want) break;
4409 
4410       if(use <= INT_MAX) upd->nscnbuf = upd->ints[I_NSCNBUF] = use;
4411       else               success      = false;
4412 
4413    }                /* Compute nscnbuf */
4414 
4415 /** Determine number of words in scan-buffers */
4416 
4417    if(success) { /* Compute pwidth, scnmsk, nbytes, pheight */
4418 
4419       if(0 < upd->ints[I_PWIDTH]) upd->pwidth = upd->ints[I_PWIDTH];
4420       else                        upd->pwidth = upd->gswidth;
4421 
4422       upd->nbytes  = (upd->pwidth+CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]) - 1)
4423             /                   (CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]));
4424 
4425       upd->scnmsk  = upd->nscnbuf - 1;
4426 
4427       if(0 < upd->ints[I_PHEIGHT]) upd->pheight = upd->ints[I_PHEIGHT];
4428       else                         upd->pheight = upd->gsheight;
4429 
4430    }             /* Compute pwidth, scnmsk, nbytes */
4431 
4432 /** Call the writer-specific open-function */
4433 
4434    if(success) { /* Determine sizes */
4435       switch(upd->choice[C_FORMAT]) {
4436          case FMT_RAS:
4437             if(0 > upd_open_rascomp(udev)) success = false;
4438          break;
4439          case FMT_EPSON:
4440             if(0 > upd_open_wrtescp(udev)) success = false;
4441          break;
4442          case FMT_ESCP2Y:
4443          case FMT_ESCP2XY:
4444          case FMT_ESCNMY: /* (GR) */
4445             if(0 > upd_open_wrtescp2(udev)) success = false;
4446          break;
4447          case FMT_RTL:
4448             if(0 > upd_open_wrtrtl(udev))   success = false;
4449          break;
4450          case FMT_CANON: /* (hr) */
4451             if(0 > upd_open_wrtcanon(udev)) success = false;
4452          break;
4453          default:
4454             success = false;
4455 #if UPD_MESSAGES & UPD_M_WARNING
4456             errprintf("upd_open_writer: Unknown writer-type %d\n",
4457                 upd->choice[C_FORMAT]);
4458 #endif
4459          break;
4460       }
4461    }             /* Determine sizes*/
4462 
4463 /** Allocate the Outputbuffer */
4464    if(success && (0 < upd->noutbuf)) { /* Allocate outbuf */
4465       upd->outbuf = gs_malloc(udev->memory, upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
4466       if(!upd->outbuf) success = false;
4467    }                                   /* Allocate outbuf */
4468 
4469 /** Allocate the desired scan-buffer-pointers */
4470    if(success) {
4471       upd->scnbuf = gs_malloc(udev->memory, upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
4472       if(NULL == upd->scnbuf) {
4473          success = false;
4474       } else {
4475          int ibuf;
4476          for(ibuf = 0; ibuf < upd->nscnbuf; ++ibuf) {
4477             if(success) upd->scnbuf[ibuf] =
4478                gs_malloc(udev->memory, upd->ocomp,sizeof(upd->scnbuf[0][0]),"upd/scnbuf[]");
4479             else upd->scnbuf[ibuf] = NULL;
4480 
4481             if(!upd->scnbuf[ibuf]) {
4482                success = false;
4483             } else {
4484                int icomp;
4485                for(icomp = 0; icomp < upd->ocomp; ++icomp) {
4486                   if(success) upd->scnbuf[ibuf][icomp].bytes =
4487                     gs_malloc(udev->memory, upd->nbytes,sizeof(upd->scnbuf[0][0].bytes[0]),
4488                     "upd/bytes");
4489                   else        upd->scnbuf[ibuf][icomp].bytes = NULL;
4490                   if(!upd->scnbuf[ibuf][icomp].bytes) success = false;
4491 
4492                   if(0 < upd->nlimits) {
4493 
4494                      upd->scnbuf[ibuf][icomp].xbegin = gs_malloc(udev->memory, upd->nlimits,
4495                         sizeof(upd->scnbuf[0][0].xbegin[0]),"upd/xbegin");
4496                      if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
4497 
4498                      upd->scnbuf[ibuf][icomp].xend   = gs_malloc(udev->memory, upd->nlimits,
4499                         sizeof(upd->scnbuf[0][0].xend[0]),"upd/xend");
4500                      if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
4501 
4502                   } else {
4503 
4504                      upd->scnbuf[ibuf][icomp].xbegin = NULL;
4505                      upd->scnbuf[ibuf][icomp].xend   = NULL;
4506 
4507                   }
4508                }
4509             }
4510          }
4511       }
4512    }
4513 
4514    if(success) upd->flags |= B_FORMAT;
4515    else        upd_close_writer(udev);
4516 
4517    return success ? 1 : -1;
4518 }
4519 
4520 /* ------------------------------------------------------------------- */
4521 /* upd_close_writer: Deinitialize rendering                            */
4522 /* ------------------------------------------------------------------- */
4523 
4524 private void
upd_close_writer(upd_device * udev)4525 upd_close_writer(upd_device *udev)
4526 {
4527    const upd_p upd = udev->upd;
4528 
4529    if(upd) {
4530       int ibuf,icomp;
4531 
4532       if((0 < upd->noutbuf) && upd->outbuf)
4533          gs_free(udev->memory, upd->outbuf,upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
4534       upd->noutbuf = 0;
4535       upd->outbuf  = NULL;
4536 
4537       if((0 < upd->nscnbuf) && upd->scnbuf) {
4538          for(ibuf = 0; upd->nscnbuf > ibuf; ++ibuf) {
4539 
4540             if(!upd->scnbuf[ibuf]) continue;
4541 
4542             for(icomp = 0; icomp < upd->ocomp; ++icomp) {
4543 
4544                if((0 < upd->nbytes) && upd->scnbuf[ibuf][icomp].bytes)
4545                   gs_free(udev->memory, upd->scnbuf[ibuf][icomp].bytes,upd->nbytes,
4546                      sizeof(upd->scnbuf[ibuf][icomp].words[0]),"upd/bytes");
4547                upd->scnbuf[ibuf][icomp].bytes = NULL;
4548 
4549                if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xbegin)
4550                   gs_free(udev->memory, upd->scnbuf[ibuf][icomp].xbegin,upd->nlimits,
4551                      sizeof(upd->scnbuf[ibuf][icomp].xbegin[0]),"upd/xbegin");
4552                upd->scnbuf[ibuf][icomp].xbegin = NULL;
4553 
4554                if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xend)
4555                   gs_free(udev->memory, upd->scnbuf[ibuf][icomp].xend,upd->nlimits,
4556                      sizeof(upd->scnbuf[ibuf][icomp].xend[0]),"upd/xend");
4557                upd->scnbuf[ibuf][icomp].xend = NULL;
4558             }
4559 
4560             if(icomp)
4561                gs_free(udev->memory, upd->scnbuf[ibuf],upd->ocomp,sizeof(upd->scnbuf[0][0]),
4562                   "upd/scnbuf[]");
4563             upd->scnbuf[ibuf] = NULL;
4564 
4565          }
4566          gs_free(udev->memory, upd->scnbuf,upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
4567       }
4568 
4569 
4570       upd->flags &= ~B_FORMAT;
4571    }
4572 }
4573 
4574 
4575 /* ------------------------------------------------------------------- */
4576 /* upd_limits: Establish passwise limits, after rendering              */
4577 /* ------------------------------------------------------------------- */
4578 
4579 private void
upd_limits(upd_p upd,bool check)4580 upd_limits(upd_p upd, bool check)
4581 {
4582    updscan_p  scans = upd->scnbuf[upd->yscnbuf & upd->scnmsk], scan;
4583    int   xs,x,xe,icomp,pass;
4584    byte *bytes,bit;
4585 
4586    for(icomp = 0; icomp < upd->ocomp; ++icomp) {
4587       scan = scans + icomp;
4588       for(pass = 0; pass < upd->nlimits; ++pass) {
4589          scan->xbegin[pass] = upd->pwidth;
4590          scan->xend[  pass] = -1;
4591       }
4592    }
4593 
4594    if(check) { /* Really check */
4595       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Check Components */
4596          scan  = scans + icomp;
4597          bytes = scan->bytes;
4598 
4599          for(xs = 0; xs < upd->nbytes  && !bytes[xs];   ++xs);
4600 
4601          if(xs < upd->nbytes) { /* Has Data */
4602             for(xe = upd->nbytes; xs < xe && !bytes[xe-1]; --xe);
4603 
4604             for(pass = 0; pass < upd->nlimits; ++pass) { /* limit (pass) loop */
4605 
4606                x = ((xs<<3)/upd->nlimits)*upd->nlimits + pass;
4607                while((x >> 3) < xs) x += upd->nlimits;
4608 
4609                bit = 0x80 >> (x & 7);
4610                while(x < scan->xbegin[pass]) {
4611                   if(bytes[x>>3] & bit) scan->xbegin[pass] = x;
4612                   x  += upd->nlimits;
4613                   bit = 0x80 >> (x & 7);
4614                }
4615 
4616                x = (((xe<<3)|7)/upd->nlimits)*upd->nlimits + pass;
4617 
4618                while((x >> 3) < xe) x += upd->nlimits;
4619                while((x >> 3) > xe) x -= upd->nlimits;
4620 
4621                bit = 0x80 >> (xs & 7);
4622                while(x > scan->xend[pass]) {
4623                   if(bytes[x>>3] & bit) scan->xend[pass] = x;
4624                   x -= upd->nlimits;
4625                   bit = 0x80 >> (x & 7);
4626                }
4627 
4628             }                                            /* limit (pass) loop */
4629 
4630          }                      /* Has Data */
4631 
4632       }                                             /* Check Components */
4633 
4634    }           /* Really check */
4635 
4636 }
4637 
4638 /* ------------------------------------------------------------------- */
4639 /* upd_open_rascomp: ncomp * 1Bit Raster-Writer                        */
4640 /* ------------------------------------------------------------------- */
4641 
4642 private int
upd_open_rascomp(upd_device * udev)4643 upd_open_rascomp(upd_device *udev)
4644 {
4645    const upd_p upd = udev->upd;
4646    int32_t noutbuf;
4647    int error = 0;
4648 
4649    noutbuf = upd->pwidth;
4650 
4651    if(1 < upd->ncomp) noutbuf *= 8; /* ??? upd->ocomp */
4652 
4653    noutbuf = ((noutbuf+15)>>4)<<1;
4654 
4655    if(INT_MAX >= noutbuf) {
4656       upd->noutbuf = noutbuf;
4657       upd->start_writer = upd_start_rascomp;
4658       upd->writer       = upd_rascomp;
4659    } else {
4660       error = -1;
4661    }
4662 
4663    return error;
4664 }
4665 
4666 /* ------------------------------------------------------------------- */
4667 /* upd_start_rascomp: write appropiate raster-header                   */
4668 /* ------------------------------------------------------------------- */
4669 #if arch_is_big_endian
4670 #define put32(I32,Out)       \
4671    fwrite(&I32,1,4,Out)
4672 #else
4673 #define put32(I32,Out)       \
4674    putc(((I32)>>24)&255,Out),\
4675    putc(((I32)>>16)&255,Out),\
4676    putc(((I32)>> 8)&255,Out),\
4677    putc( (I32)     &255,Out)
4678 #endif
4679 
4680 private int
upd_start_rascomp(upd_p upd,FILE * out)4681 upd_start_rascomp(upd_p upd, FILE *out) {
4682 
4683 /** if no begin-sequence externally set */
4684    if(0 == upd->strings[S_BEGIN].size) {
4685       int32_t val;
4686 
4687 /**   ras_magic */
4688       val = 0x59a66a95;
4689       put32(val,out);
4690 
4691 /**   ras_width */
4692       val = upd->pwidth;
4693       put32(val,out);
4694 
4695 /**   ras_height */
4696       val = upd->pheight;
4697       put32(val,out);
4698 
4699 /**   ras_depth */
4700       if(1 < upd->ncomp) val = 8; /* ??? upd->ocomp */
4701       else               val = 1;
4702       put32(val,out);
4703 
4704 /**   ras_length */
4705       val *= upd->pwidth;
4706       val = ((val+15)>>4)<<1;
4707       val *= upd->pheight;
4708       put32(val,out);
4709 
4710 /**   ras_type */
4711       val = 1;
4712       put32(val,out);
4713 
4714 /**   ras_maptype */
4715       val = 1;
4716       put32(val,out);
4717 
4718 /**   ras_maplength */
4719       val = 3 * (1 << upd->ncomp); /* ??? upd->ocomp */
4720       put32(val,out);
4721 
4722 /**   R,G,B-Map */
4723       if(1 == upd->ncomp) { /* ??? upd->ocomp */
4724          const updcomp_p comp = upd->valptr[0];
4725 
4726          if(upd->cmap[comp->cmap].rise) {
4727             putc((char) 0x00,out); putc((char) 0xff,out);
4728             putc((char) 0x00,out); putc((char) 0xff,out);
4729             putc((char) 0x00,out); putc((char) 0xff,out);
4730          } else {
4731             putc((char) 0xff,out); putc((char) 0x00,out);
4732             putc((char) 0xff,out); putc((char) 0x00,out);
4733             putc((char) 0xff,out); putc((char) 0x00,out);
4734          }
4735 
4736       } else if(3 == upd->ncomp) { /* ??? upd->ocomp */
4737          int rgb;
4738 
4739          for( rgb = 0; rgb < 3; ++rgb) {
4740             int entry;
4741             for(entry = 0; entry < 8; ++entry) {
4742                byte xval = upd->cmap[rgb].rise ? 0x00 : 0xff;
4743                if(entry & (1<<upd->cmap[rgb].comp)) xval ^= 0xff;
4744                putc(xval,out);
4745             }
4746          }
4747       } else { /* we have 4 components */
4748          int rgb;
4749 
4750          for(rgb = 16; 0 <= rgb; rgb -= 8) {
4751             int entry;
4752             for(entry = 0; entry < 16; ++entry) {
4753                uint32_t rgbval = 0;
4754 
4755                if(entry & (1<<upd->cmap[0].comp)) {
4756 
4757                   rgbval = 0xffffff;
4758 
4759                } else {
4760 
4761                   if(entry & (1<<upd->cmap[1].comp)) rgbval |= 0xff0000;
4762                   if(entry & (1<<upd->cmap[2].comp)) rgbval |= 0x00ff00;
4763                   if(entry & (1<<upd->cmap[3].comp)) rgbval |= 0x0000ff;
4764                }
4765 
4766                if(!upd->cmap[1].rise) rgbval ^= 0xff0000;
4767                if(!upd->cmap[2].rise) rgbval ^= 0x00ff00;
4768                if(!upd->cmap[3].rise) rgbval ^= 0x0000ff;
4769 
4770                if(!(upd->choice[C_MAPPER] == MAP_RGBW)) rgbval ^= 0xffffff;
4771 
4772                putc((rgbval>>rgb)&255,out);
4773             }
4774          }
4775       }
4776    }
4777    memset(upd->outbuf,0,upd->noutbuf);
4778 
4779    return 0;
4780 }
4781 
4782 /* ------------------------------------------------------------------- */
4783 /* upd_rascomp: assemble & write a scanline                            */
4784 /* ------------------------------------------------------------------- */
4785 private int
upd_rascomp(upd_p upd,FILE * out)4786 upd_rascomp(upd_p upd, FILE *out) {
4787    updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
4788    uint bits = upd->pwidth;
4789 
4790    if(1 == upd->ncomp) { /* ??? upd->ocomp */
4791       uint nbytes;
4792 
4793       nbytes = (bits+7)>>3;
4794       memcpy(upd->outbuf,scan->bytes,nbytes);
4795       if((bits &= 7)) upd->outbuf[nbytes-1] &= ((byte) 0xff) << (8-bits);
4796 
4797    } else {
4798 
4799       byte  *buf   = upd->outbuf, bit = 0x80;
4800       int    ibyte = 0;
4801 
4802       while(0 < bits--) {
4803          byte val = 0;
4804          switch(upd->ncomp) { /* ??? upd->ocomp */
4805             case 4:  if(scan[3].bytes[ibyte] & bit) val |= 8;
4806             case 3:  if(scan[2].bytes[ibyte] & bit) val |= 4;
4807                      if(scan[1].bytes[ibyte] & bit) val |= 2;
4808             case 1:  if(scan[0].bytes[ibyte] & bit) val |= 1;
4809          }
4810          *buf++ = val;
4811          if(!(bit >>= 1)) {
4812             bit    = 0x80;
4813             ibyte += 1;
4814          }
4815       }
4816    }
4817 
4818    fwrite(upd->outbuf,1,upd->noutbuf,out);
4819    upd->yscan += 1;
4820 
4821    return 0;
4822 }
4823 
4824 /* ------------------------------------------------------------------- */
4825 /* upd_open_wrtescp: ESC/P Writer intended for ESC * m commands        */
4826 /* ------------------------------------------------------------------- */
4827 
4828 private int
upd_open_wrtescp(upd_device * udev)4829 upd_open_wrtescp(upd_device *udev)
4830 {
4831    const upd_p      upd  = udev->upd;
4832    int              error = 0;
4833 
4834 /** Adjust the PageLength, If Requested */
4835    if((B_PAGELENGTH & upd->flags) &&
4836       (0 < upd->strings[S_BEGIN].size)) { /* BOP-Checker */
4837      int   i,state = 0,value = 0;
4838      byte *bp = (byte *) upd_cast(upd->strings[S_BEGIN].data);
4839      for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
4840         switch(state) {
4841            case  0:
4842               if(0x1b == bp[i]) state = 1;
4843            break;
4844            case  1:
4845               if('C'  == bp[i]) state = 2;
4846               else              state = 0;
4847            break;
4848            case  2:
4849               if(bp[i]) {
4850                  value = (int)(0.5 + udev->height * (float) bp[i]
4851                                / udev->y_pixels_per_inch);
4852                  if(       0 >= value) bp[i] = 1;
4853                  else if(128 >  value) bp[i] = value;
4854                  else                  bp[i] = 127;
4855                  state = 0;
4856               } else {
4857                  state = 3;
4858               }
4859            break;
4860            case  3:
4861               value = (int)(0.5 + udev->height / udev->y_pixels_per_inch);
4862               if(       0 >= value) bp[i] = 1;
4863               else if( 22 >  value) bp[i] = value;
4864               else                  bp[i] = 22;
4865               state = 0;
4866            break;
4867         }
4868      }
4869    }                                    /* BOP-Checker */
4870 
4871 
4872 /** Either SETLF or YMOVE must be set */
4873    if((0 == upd->strings[S_SETLF].size) &&
4874       (0 == upd->strings[S_YMOVE].size)   ) {
4875 #if UPD_MESSAGES & UPD_M_WARNING
4876       errprintf(
4877         "ESC/P-Open: Either SETLF- or YMOVE-Command must be present\n");
4878 #endif
4879       error = -1;
4880    }
4881 
4882 /** X-Positioning must be set too */
4883    if(((1 <  upd->ints[I_XSTEP]        ) &&
4884        (0 == upd->strings[S_XSTEP].size)   ) ||
4885       ((1 < upd->ints[I_NXPASS]        ) &&
4886        (0 == upd->strings[S_XMOVE].size) &&
4887        (0 == upd->strings[S_XSTEP].size)   )   ) {
4888 #if UPD_MESSAGES & UPD_M_WARNING
4889       errprintf(
4890          "ESC/P-Open: Missing XSTEP- and/or XMOVE-Command\n");
4891 #endif
4892       error = -1;
4893    }
4894 
4895 /** SA_WRITECOMP must be valid */
4896    if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) { /* ??? upd->ocomp */
4897 #if UPD_MESSAGES & UPD_M_WARNING
4898       errprintf(
4899          "ESC/P-Open: WRITECOMP-Commands must be given\n");
4900 #endif
4901       error = -1;
4902    }
4903 
4904 /**
4905 If all this is correct, it's time to coumput the size of the output-buffer.
4906 It must hold:
4907   1. Y-Positioning
4908   2. X-Positioning
4909   3. Component-Selection
4910   4. The Raster-Command
4911   5. The Data
4912 */
4913    if(0 <= error) {
4914       int32_t i,noutbuf,need;
4915 
4916       if(0 < upd->strings[S_YMOVE].size) {
4917          noutbuf = upd->strings[S_YMOVE].size + 2;
4918       } else {
4919          int nmax = upd->pheight;
4920          if(      1 < upd->ints[I_YSTEP]) nmax /=  upd->ints[I_YSTEP];
4921          else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
4922          noutbuf  = 2 * upd->strings[S_SETLF].size + 2;
4923          noutbuf += nmax/255 + 1;
4924       }
4925 
4926       if(1 < upd->ints[I_YSTEP])
4927          noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
4928 
4929       noutbuf +=  upd->strings[S_XMOVE].size + 2;
4930 
4931       if(1 < upd->ints[I_XSTEP])
4932          noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
4933 
4934       if(0 < upd->string_a[SA_SETCOMP].size) {
4935          need = 0;
4936          for(i = 0; i < upd->ocomp; ++i)
4937             if(need < upd->string_a[SA_SETCOMP].data[i].size)
4938                need = upd->string_a[SA_SETCOMP].data[i].size;
4939          noutbuf += need;
4940       }
4941 
4942       need = 0;
4943       for(i = 0; i < upd->ocomp; ++i)
4944          if(need < upd->string_a[SA_WRITECOMP].data[i].size)
4945             need = upd->string_a[SA_WRITECOMP].data[i].size;
4946       noutbuf += need + 2;
4947 
4948       noutbuf += ((upd->ints[I_PINS2WRITE] + 7) / 8)
4949                * ((upd->pwidth + upd->ints[I_NXPASS] - 1)/upd->ints[I_NXPASS]);
4950 
4951       if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
4952          upd->noutbuf      = noutbuf;
4953          upd->writer       = upd_wrtescp;
4954          upd->nlimits      = upd->ints[I_NXPASS];
4955          error             = 1;
4956       } else {
4957          error = -1;
4958 #if      UPD_MESSAGES & UPD_M_WARNING
4959             errprintf(
4960               "ESC/P-Open: %ld is unreasonable size of Outputbuffer\n",
4961               (long) noutbuf);
4962 #endif
4963       }
4964    }
4965 
4966    return error;
4967 }
4968 
4969 /* ------------------------------------------------------------------- */
4970 /* upd_wrtescp: Write a pass                                           */
4971 /* ------------------------------------------------------------------- */
4972 
4973 private int
upd_wrtescp(upd_p upd,FILE * out)4974 upd_wrtescp(upd_p upd, FILE *out)
4975 {
4976    int  pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
4977    byte *obytes,bit;
4978    updscan_p scan;
4979 
4980 /** Determine the number of pins to write */
4981 
4982    if(upd->yscan < upd->ints[I_BEG_Y]) {
4983       ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
4984       pintop = 0;
4985       pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
4986    } else if(upd->yscan >= upd->ints[I_END_Y]) {
4987       ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
4988       pinbot = upd->ints[I_PINS2WRITE];
4989       pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
4990    } else {
4991       ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
4992       pintop = 0;
4993       pinbot = upd->ints[I_PINS2WRITE];
4994    }
4995 
4996    ybegin =  pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
4997    yend   =  pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
4998 
4999 /** Determine Width of this scan */
5000 
5001    xbegin = upd->pwidth;
5002    xend   = -1;
5003 
5004    for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
5005 
5006       if(0 > y) continue; /* Inserted Scanlines */
5007 
5008       scan = upd->scnbuf[y & upd->scnmsk];
5009 
5010       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
5011          if(xbegin > scan[icomp].xbegin[ixpass])
5012             xbegin = scan[icomp].xbegin[ixpass];
5013          if(xend   < scan[icomp].xend[  ixpass])
5014             xend   = scan[icomp].xend[  ixpass];
5015       }                                             /* Compwise test */
5016 
5017    }                                                     /* Pin-testloop */
5018 
5019    if(xbegin <= xend) { /* Some data to write */
5020 
5021       ioutbuf = 0;
5022 
5023       if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
5024 
5025 /*
5026  *    Adjust the Printers Y-Position
5027  */
5028       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
5029          if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
5030          else                    y = upd->yscan - upd->yprinter;
5031 
5032          if(      1 < upd->ints[I_YSTEP]) {
5033             n      =  y / upd->ints[I_YSTEP];  /* Major-Steps */
5034             y     -=  n * upd->ints[I_YSTEP];  /* Minor-Steps */
5035          } else if(-1 > upd->ints[I_YSTEP]) {
5036             n      = y * -upd->ints[I_YSTEP];  /* May this work? */
5037             y      = 0;
5038          } else {
5039             n      = y;
5040             y      = 0;
5041          }
5042 
5043          if(n) { /* Coarse Positioning */
5044             if(0 < upd->strings[S_YMOVE].size) {
5045 
5046                memcpy(upd->outbuf+ioutbuf,
5047                           upd->strings[S_YMOVE].data,
5048                           upd->strings[S_YMOVE].size);
5049                ioutbuf += upd->strings[S_YMOVE].size;
5050 
5051                upd->outbuf[ioutbuf++] =  n     & 0xff;
5052                upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
5053 
5054             } else {
5055 
5056                while(n) {
5057                   int n2do = n > 255 ? 255 : n;
5058                   if(upd->lf != n2do) {
5059                      memcpy(upd->outbuf+ioutbuf,
5060                                 upd->strings[S_SETLF].data,
5061                                 upd->strings[S_SETLF].size);
5062                      ioutbuf += upd->strings[S_SETLF].size;
5063                      upd->outbuf[ioutbuf++] = n2do;
5064                      upd->lf                = n2do;
5065                   }
5066                   upd->outbuf[ioutbuf++] = '\n';
5067                   n -= n2do;
5068                }
5069             }
5070          }       /* Coarse Positioning */
5071 
5072          if(0 < upd->strings[S_YSTEP].size) {
5073             while(y--) {
5074                memcpy(upd->outbuf+ioutbuf,
5075                           upd->strings[S_YSTEP].data,
5076                           upd->strings[S_YSTEP].size);
5077                ioutbuf += upd->strings[S_YSTEP].size;
5078             }
5079          }
5080 
5081          upd->yprinter = upd->yscan;
5082       }                                 /* Adjust Y-Position */
5083 
5084 /*
5085  * Now write the required components
5086  */
5087       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
5088 /*
5089  *       First check, wether this Component needs printing
5090  */
5091          for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
5092             if(0 > y) continue;
5093             scan = upd->scnbuf[y & upd->scnmsk]+icomp;
5094             if(0 <= scan->xend[ixpass]) break;
5095          }                                                     /* Comp-Test */
5096          if(y >= yend) continue; /* Component not required */
5097 /*
5098  *       Select the Component
5099  */
5100          if((0 < upd->string_a[SA_SETCOMP].size) &&
5101             (upd->icomp != icomp               )   ) { /* Selection enabled */
5102             upd->icomp = icomp;
5103             if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
5104                memcpy(upd->outbuf+ioutbuf,
5105                           upd->string_a[SA_SETCOMP].data[icomp].data,
5106                           upd->string_a[SA_SETCOMP].data[icomp].size);
5107                ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
5108             }
5109          }                                      /* Selection enabled */
5110 /*
5111  *       Establish the X-Position
5112  */
5113          if(xbegin != upd->xprinter) {
5114 
5115             if(0 == upd->strings[S_XMOVE].size) {
5116 
5117                upd->outbuf[ioutbuf++] = '\r';
5118                upd->xprinter          =  0;
5119                n = 0;
5120                x = ixpass;
5121 
5122             } else {
5123 
5124                if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
5125                else                    n = x = xbegin - upd->xprinter;
5126 
5127                if(        1 < upd->ints[I_XSTEP]) {
5128                   if(0 > n) {
5129                      n  -= upd->ints[I_XSTEP];
5130                      x  -= n;
5131                   }
5132                   if(n) n  /= upd->ints[I_XSTEP]; /* Major-Steps */
5133                   if(x) x  %= upd->ints[I_XSTEP]; /* Minor-Steps */
5134 
5135                } else if(-1 > upd->ints[I_XSTEP]) {
5136                   n *= -upd->ints[I_XSTEP]; /* May this work? */
5137                   x  = 0;
5138                }
5139 
5140                if(n) { /* Adjust X-Position */
5141 
5142                  memcpy(upd->outbuf+ioutbuf,
5143                              upd->strings[S_XMOVE].data,
5144                              upd->strings[S_XMOVE].size);
5145                   ioutbuf += upd->strings[S_XMOVE].size;
5146 
5147                   upd->outbuf[ioutbuf++] =  n     & 0xff;
5148                   upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
5149 
5150                }       /* Adjust X-Position */
5151 
5152             }
5153 
5154             if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
5155                while(x--) {
5156                   memcpy(upd->outbuf+ioutbuf,
5157                              upd->strings[S_XSTEP].data,
5158                              upd->strings[S_XSTEP].size);
5159                   ioutbuf += upd->strings[S_XSTEP].size;
5160                }
5161             }                                         /* Fine-Adjust X */
5162          }
5163          upd->xprinter = xend+1;
5164 /*
5165  *       Send the Write-Command
5166  */
5167          if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
5168             memcpy(upd->outbuf+ioutbuf,
5169                        upd->string_a[SA_WRITECOMP].data[icomp].data,
5170                        upd->string_a[SA_WRITECOMP].data[icomp].size);
5171             ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
5172          }
5173          n = (xend - xbegin) / upd->ints[I_NXPASS] + 1;;
5174          upd->outbuf[ioutbuf++] =  n     & 255;
5175          upd->outbuf[ioutbuf++] = (n>>8) & 255;
5176 /*
5177  *       Clear the data-Part
5178  */
5179          obytes   =  upd->outbuf+ioutbuf;
5180          n       *= (upd->ints[I_PINS2WRITE]+7)>>3;
5181          memset(obytes,0,n);
5182          ioutbuf += n;
5183 /*
5184  *       Set the Pixels
5185  */
5186          for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
5187 
5188             bit     = 0x80 >> (pintop & 7);
5189             obytes += pintop>>3;
5190 
5191             for(pin = pintop, y = ybegin; pin < pinbot;
5192                 pin++,        y += upd->ints[I_NYPASS]) {
5193                if(0 <= y) {
5194                   scan = upd->scnbuf[y & upd->scnmsk]+icomp;
5195                   if(scan->bytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
5196                }
5197                if(!(bit >>= 1)) { obytes++; bit = 0x80; }
5198             }
5199 
5200             obytes += (upd->ints[I_PINS2WRITE]-pinbot+7)>>3;
5201          }
5202 /*
5203  *       Send this Component to the Printer
5204  */
5205          fwrite(upd->outbuf,1,ioutbuf,out);
5206          ioutbuf = 0;
5207       }                                             /* Component-Print */
5208    }                    /* Some data to write */
5209 
5210 /** Advance counters in upd, change modi */
5211 
5212    if(upd->yscan < upd->ints[I_BEG_Y]) {
5213       upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
5214       if(     upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
5215       else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
5216    } else if(upd->yscan >= upd->ints[I_END_Y]) {
5217       upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
5218       if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
5219    } else {
5220       upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
5221       if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
5222       if(upd->yscan >= upd->ints[I_END_Y])         upd->ipass = 0;
5223    }
5224 
5225    return 0;
5226 }
5227 
5228 /* ------------------------------------------------------------------- */
5229 /* upd_open_wrtescp2: ESC/P2 Writer intended for ESC . 1  commands     */
5230 /* ------------------------------------------------------------------- */
5231 
5232 private int
upd_open_wrtescp2(upd_device * udev)5233 upd_open_wrtescp2(upd_device *udev)
5234 {
5235    const upd_p      upd             = udev->upd;
5236    int              error           = 0;
5237    float            pixels_per_inch = 360.0;
5238 
5239 /** Analyze (and optionally adjust) the BOP-Sequence */
5240    if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
5241      int   i,state = 0,value = 0;
5242      byte *bp = (byte *) upd_cast(upd->strings[S_BEGIN].data);
5243      for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
5244         switch(state) {
5245            case  0:
5246               if(0x1b == bp[i]) state = 1;
5247            break;
5248            case  1:
5249               if('('  == bp[i]) state = 2;
5250               else              state = 0;
5251            break;
5252            case  2:
5253               switch(bp[i]) {
5254                  case 'U': state =  3; break; /* Printer-Resolution */
5255                  case 'C': state =  6; break; /* Page-Length */
5256                  case 'c': state = 10; break; /* Top/Bottom Margin */
5257                  default:  state =  0; break;
5258               }
5259            break;
5260            case  3:
5261               if(1 == bp[i]) state = 4;
5262               else           state = 0;
5263            break;
5264            case  4:
5265               if(0 == bp[i]) state = 5;
5266               else           state = 0;
5267            break;
5268            case  5:
5269               pixels_per_inch = 3600.0 / (float) bp[i];
5270               state = 0;
5271            break;
5272            case  6:
5273               if(2 == bp[i]) state = 7;
5274               else           state = 0;
5275            break;
5276            case  7:
5277               if(0 == bp[i]) state = 8;
5278               else           state = 0;
5279            break;
5280            case  8:
5281               if(B_PAGELENGTH & upd->flags) {
5282                  value = (int)(0.5 + udev->height
5283                                * pixels_per_inch / udev->y_pixels_per_inch);
5284                  bp[i] =  value     & 0xff;
5285               }
5286               state = 9;
5287            break;
5288            case  9:
5289               if(B_PAGELENGTH & upd->flags) {
5290                  bp[i] = (value>>8) & 0xff;
5291               }
5292               state = 0;
5293            break;
5294            case 10:
5295               if(4 == bp[i]) state = 11;
5296               else           state =  0;
5297            break;
5298            case 11:
5299               if(0 == bp[i]) state = 12;
5300               else           state =  0;
5301            break;
5302            case  12:
5303               if(B_TOPMARGIN & upd->flags) {
5304                  value =  (int)(dev_t_margin(udev) * pixels_per_inch);
5305                  bp[i] =  value     & 0xff;
5306               }
5307               state = 13;
5308            break;
5309            case  13:
5310               if(B_TOPMARGIN & upd->flags) {
5311                  bp[i] = (value>>8) & 0xff;
5312               }
5313               state = 14;
5314            break;
5315            case  14:
5316               if(B_BOTTOMMARGIN & upd->flags) {
5317                  value = (int)(0.5 + udev->height
5318                                * pixels_per_inch / udev->y_pixels_per_inch
5319                        - dev_b_margin(udev) * pixels_per_inch);
5320                  bp[i] =  value     & 0xff;
5321               }
5322               state = 15;
5323            break;
5324            case  15:
5325               if(B_BOTTOMMARGIN & upd->flags) {
5326                  bp[i] = (value>>8) & 0xff;
5327               }
5328               state =  0;
5329            break;
5330         }
5331      }
5332    }                                    /* BOP-Checker */
5333 
5334 /** Create Y-Move-Command, if not given */
5335    if(0 == upd->strings[S_YMOVE].size) {
5336       byte *bp;
5337       UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_YMOVE]);
5338       UPD_MM_GET_ARRAY(udev->memory, bp,5);
5339       upd->strings[S_YMOVE].data = bp;
5340       upd->strings[S_YMOVE].size = 5;
5341       *bp++ = 0x1b; /* ESC */
5342       *bp++ = '(';
5343       *bp++ = upd->flags & B_YABS ? 'V' : 'v';
5344       *bp++ =  2;
5345       *bp++ =  0;
5346    }
5347 
5348 /** X-Positioning must be set too, sometimes */
5349    if((1 < upd->ints[I_XSTEP]) && (0 == upd->strings[S_XSTEP].size)) {
5350 
5351 #if UPD_MESSAGES & UPD_M_WARNING
5352       errprintf(
5353          "ESC/P2-Open: XSTEP-Command required for XSTEP=%d\n",
5354          upd->ints[I_XSTEP]);
5355 #endif
5356       error = -1;
5357 
5358    } else if((1 <  upd->ints[I_NXPASS]       ) &&
5359              (0 == upd->strings[S_XMOVE].size) &&
5360              (0 == upd->strings[S_XSTEP].size)   ) {
5361       byte *bp;
5362       int ratio;
5363 
5364       ratio = (int)((udev->y_pixels_per_inch + 0.5) / udev->x_pixels_per_inch);
5365 
5366       if(0 == upd->ints[I_XSTEP]) { /* Adjust scale-factor too! */
5367          if(ratio > 1) upd->ints[I_XSTEP] = -ratio;
5368       } else {                     /* Adjust scale-factor too! */
5369          ratio = -upd->ints[I_XSTEP];
5370       }
5371 
5372       if(2 == upd->ints[I_NXPASS]) { /* Use a relative Step */
5373 
5374          UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_XSTEP]);
5375          UPD_MM_GET_ARRAY(udev->memory, bp,4);
5376          upd->strings[S_XSTEP].size = 4;
5377          upd->strings[S_XSTEP].data = bp;
5378          *bp++ = 0x1b;
5379          *bp++ = '\\';
5380          *bp++ =  ratio     & 0xff;
5381          *bp++ = (ratio>>8) & 0xff;
5382 
5383       } else {                      /* Use relative or absolute Move */
5384 
5385          UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_XMOVE]);
5386          UPD_MM_GET_ARRAY(udev->memory, bp,2);
5387          upd->strings[S_XMOVE].size = 2;
5388          upd->strings[S_XMOVE].data = bp;
5389          *bp++  = 0x1b;
5390          *bp++  = upd->flags & B_XABS ? '$' : '\\';
5391 
5392       }
5393    }
5394 
5395    /* Check the Nozzle Map parameters and set some defaults */
5396    /* Used a switch construct in case FMT_ESCNMXY is added later */
5397    switch(upd->choice[C_FORMAT]){
5398       case FMT_ESCNMY:
5399          /* RowsPerPass */
5400          if( 0 == upd->ints[I_ROWS] ){
5401             upd->ints[I_ROWS] = 1;
5402          }
5403          /* PatternRepeat */
5404          if( 0 == upd->ints[I_PATRPT] ){
5405             upd->ints[I_PATRPT] = 1;
5406          }
5407          /* RowMask - default is all 1's */
5408          if( upd->ints[I_PATRPT] != upd->int_a[IA_ROWMASK].size ) {
5409             int i, *bp;
5410             UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_ROWMASK]);
5411             UPD_MM_GET_ARRAY(udev->memory, bp,upd->ints[I_PATRPT]);
5412             upd->int_a[IA_ROWMASK].size = upd->ints[I_PATRPT];
5413             upd->int_a[IA_ROWMASK].data = bp;
5414             for (i = 0 ; i < upd->ints[I_PATRPT] ; i++){
5415                *bp++  = 1; /* black */
5416             }
5417          }
5418          /* MaskScanOffset - default is 0-patternRepeat */
5419          if( upd->ints[I_PATRPT] != upd->int_a[IA_SCNOFS].size ) {
5420             int i, *bp;
5421             UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_SCNOFS]);
5422             UPD_MM_GET_ARRAY(udev->memory, bp,upd->ints[I_PATRPT]);
5423             upd->int_a[IA_SCNOFS].size = upd->ints[I_PATRPT];
5424             upd->int_a[IA_SCNOFS].data = bp;
5425             for (i = 0 ; i < upd->ints[I_PATRPT] ; i++){
5426                *bp++  = i;
5427             }
5428          }
5429       break;
5430       case FMT_ESCP2Y:
5431       case FMT_ESCP2XY:
5432          /* Nozzle map parameters are not valid for these formats
5433             so ignore them*/
5434       break;
5435    }
5436 
5437 
5438 /** If there is neither a writecomp nor a setcomp-command, generate both */
5439    if((0 == upd->string_a[SA_WRITECOMP].size) &&
5440       (0 == upd->string_a[SA_SETCOMP].size  )   ) { /* Default-commands */
5441       byte *bp;
5442       gs_param_string *ap;
5443       int   i;
5444 
5445       if(4 == upd->ocomp) { /* Establish Component-Selection */
5446          UPD_MM_DEL_APARAM(udev->memory, upd->string_a[SA_SETCOMP]);
5447          UPD_MM_GET_ARRAY(udev->memory, ap,4);
5448          upd->string_a[SA_SETCOMP].data = ap;
5449          upd->string_a[SA_SETCOMP].size = 4;
5450          for(i = 0; i < 4; ++i) {
5451             UPD_MM_GET_ARRAY(udev->memory, bp,3);
5452             ap[i].size = 3;
5453             ap[i].data = bp;
5454             *bp++ = 0x1b;
5455             *bp++ = 'r';
5456             switch(((updcomp_p)upd->valptr[i])->cmap) { /* use COMPORDER! */
5457                case 0: *bp++ = 0; break; /* Black */
5458                case 1: *bp++ = 2; break; /* Cyan */
5459                case 2: *bp++ = 1; break; /* Magenta */
5460                case 3: *bp++ = 4; break; /* Yellow */
5461             }                                           /* use COMPORDER! */
5462          }
5463       }                     /* Establish Component-Selection */
5464 
5465       UPD_MM_DEL_APARAM(udev->memory, upd->string_a[SA_WRITECOMP]);
5466       UPD_MM_GET_ARRAY(udev->memory, ap,upd->ocomp);
5467       upd->string_a[SA_WRITECOMP].data = ap;
5468       upd->string_a[SA_WRITECOMP].size = upd->ncomp;
5469       for(i = 0; i < upd->ocomp; ++i) {
5470          UPD_MM_GET_ARRAY(udev->memory, bp,6);
5471          ap[i].size = 6;
5472          ap[i].data = bp;
5473          *bp++ = 0x1b;
5474          *bp++ = '.';
5475          *bp++ =  1;  /* RLE */
5476          switch(upd->choice[C_FORMAT]){
5477             case FMT_ESCP2Y:
5478             case FMT_ESCP2XY:
5479                *bp++ = (byte)(3600.0 * upd->ints[I_NYPASS] /
5480                                  udev->y_pixels_per_inch + 0.5);
5481                *bp++ = (byte)(3600.0 * upd->ints[I_NXPASS] /
5482                                  udev->x_pixels_per_inch + 0.5);
5483                *bp++ = upd->ints[I_PINS2WRITE];
5484             break;
5485             case FMT_ESCNMY:
5486                /*
5487                *bp++ = 3600.0 / udev->y_pixels_per_inch + 0.5;
5488                *bp++ = 3600.0 / udev->x_pixels_per_inch + 0.5;
5489                */
5490                *bp++ = 10; /* needs to always be this for esc300 */
5491                *bp++ = 10;
5492                *bp++ = upd->ints[I_ROWS];
5493             break;
5494          }
5495       }
5496    }                                                /* Default-commands */
5497 
5498 /** SA_WRITECOMP must be valid */
5499    if(upd->ocomp > upd->string_a[SA_WRITECOMP].size) {
5500 #if UPD_MESSAGES & UPD_M_WARNING
5501       errprintf(
5502          "ESC/P2-Open: WRITECOMP-Commands must be given\n");
5503 #endif
5504       error = -1;
5505    }
5506 
5507 /** Check Validity of X-Pass */
5508    switch(upd->choice[C_FORMAT]) {
5509       case FMT_ESCP2Y:
5510          if(1 < upd->ints[I_NXPASS]) {
5511 #if         UPD_MESSAGES & UPD_M_WARNING
5512                errprintf(
5513                   "ESC/P2-Open: FMT_ESCP2Y cannot handle multiple X-Passes\n");
5514 #endif
5515             error = -1;
5516          } else {
5517             upd->writer = upd_wrtescp2;
5518          }
5519       break;
5520       case FMT_ESCP2XY:
5521          upd->writer  = upd_wrtescp2x;
5522          upd->nlimits = upd->ints[I_NXPASS];
5523 #if      UPD_MESSAGES & UPD_M_WARNING
5524             if(1 == upd->ints[I_NXPASS])
5525                errprintf(
5526                   "ESC/P2-Open: FMT_ESCP2XY should not be used with 1X-Pass\n");
5527 #endif
5528       break;
5529       case FMT_ESCNMY:
5530          if(1 < upd->ints[I_NXPASS]) {
5531 #if         UPD_MESSAGES & UPD_M_WARNING
5532                errprintf(
5533                   "ESC/P2-Open: FMT_ESCNMY cannot handle multiple X-Passes\n");
5534 #endif
5535             error = -1;
5536          } else {
5537             upd->writer = upd_wrtescnm;
5538          }
5539       break;
5540       default:
5541 #if      UPD_MESSAGES & UPD_M_WARNING
5542             errprintf(
5543                "ESC/P2-Open: %d is not a ESC/P2-Format\n",
5544                upd->choice[C_FORMAT]);
5545 #endif
5546          error = - 1;
5547       break;
5548    }
5549 
5550 
5551 /**
5552 If all this is correct, it's time to compute the size of the output-buffer.
5553 It must hold:
5554   1. Y-Positioning
5555   2. X-Positioning
5556   3. Component-Selection
5557   4. The Raster-Command
5558   5. The Data
5559 */
5560    if(0 <= error) {
5561       int32_t i,noutbuf,need;
5562       /* Y-Positioning */
5563       if(0 < upd->strings[S_YMOVE].size) {
5564          noutbuf = upd->strings[S_YMOVE].size + 2;
5565       } else {
5566          int nmax = upd->pheight;
5567          if(      1 < upd->ints[I_YSTEP]) nmax /=  upd->ints[I_YSTEP];
5568          else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
5569          noutbuf  = 2 * upd->strings[S_SETLF].size + 2;
5570          noutbuf += nmax/255 + 1;
5571       }
5572 
5573       if(1 < upd->ints[I_YSTEP])
5574          noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
5575 
5576       /* X-Positioning */
5577       if(0 == upd->strings[S_XMOVE].size) {
5578          noutbuf += 1; /* The CR */
5579          noutbuf += (upd->ints[I_NXPASS]-1) * upd->strings[S_XSTEP].size;
5580       } else {
5581          noutbuf +=  upd->strings[S_XMOVE].size + 2;
5582 
5583          if(1 < upd->ints[I_XSTEP])
5584             noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
5585       }
5586 
5587       /* Component-Selection */
5588       if(0 < upd->string_a[SA_SETCOMP].size) {
5589           need = 0;
5590           for(i = 0; i < upd->ocomp; ++i)
5591              if(need < upd->string_a[SA_SETCOMP].data[i].size)
5592                 need = upd->string_a[SA_SETCOMP].data[i].size;
5593           noutbuf += need;
5594       }
5595 
5596       /* The Raster-Command */
5597       need = 0;
5598       for(i = 0; i < upd->ocomp; ++i)
5599          if(need < upd->string_a[SA_WRITECOMP].data[i].size)
5600             need = upd->string_a[SA_WRITECOMP].data[i].size;
5601       noutbuf += need + 2;
5602 
5603       /* The Data */
5604       noutbuf += 2*upd->nbytes + (upd->nbytes + 127) / 128;
5605 
5606       upd->noutbuf      = noutbuf;
5607       error             = 1;
5608    }
5609 
5610    return error;
5611 }
5612 
5613 /* ------------------------------------------------------------------- */
5614 /* upd_wrtescp2: Write a pass                                          */
5615 /* ------------------------------------------------------------------- */
5616 
5617 private int
upd_wrtescp2(upd_p upd,FILE * out)5618 upd_wrtescp2(upd_p upd, FILE *out)
5619 {
5620    int  pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n;
5621    byte *obytes;
5622    updscan_p scan;
5623 
5624 /** Determine the number of pins to write */
5625 
5626    if(upd->yscan < upd->ints[I_BEG_Y]) {
5627       pintop = 0;
5628       pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
5629    } else if(upd->yscan >= upd->ints[I_END_Y]) {
5630       pinbot = upd->ints[I_PINS2WRITE];
5631       pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
5632    } else {
5633       pintop = 0;
5634       pinbot = upd->ints[I_PINS2WRITE];
5635    }
5636 
5637    ybegin =  pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
5638    yend   =  pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
5639 
5640 /** Determine Width of this scan */
5641 
5642    xbegin = upd->nbytes;
5643    xend   = -1;
5644 
5645    for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
5646 
5647       if(0 > y) continue; /* Inserted Scanlines */
5648 
5649       scan = upd->scnbuf[y & upd->scnmsk];
5650 
5651       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
5652          obytes = scan[icomp].bytes;
5653 
5654          for(x = 0; x < xbegin && !obytes[x]; x++);
5655          if(x < xbegin) xbegin = x;
5656 
5657          if(x < upd->nbytes) {
5658             for(x = upd->nbytes-1; x > xend && !obytes[x]; x--);
5659             if(x > xend) xend = x;
5660          }
5661       }                                             /* Compwise test */
5662 
5663    }                                                     /* Pin-testloop */
5664 
5665    if(xbegin <= xend) { /* Some data to write */
5666 
5667       ioutbuf = 0;
5668 
5669       if(0 == upd->strings[S_XMOVE].size) xbegin = 0;
5670 
5671 /*
5672  *    Adjust the Printers Y-Position
5673  */
5674       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
5675          if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
5676          else                    y = upd->yscan - upd->yprinter;
5677 
5678          if(      1 < upd->ints[I_YSTEP]) {
5679             n      =  y / upd->ints[I_YSTEP];  /* Major-Steps */
5680             y     -=  n * upd->ints[I_YSTEP];  /* Minor-Steps */
5681          } else if(-1 > upd->ints[I_YSTEP]) {
5682             n      = y * -upd->ints[I_YSTEP];  /* May this work? */
5683             y      = 0;
5684          } else {
5685             n      = y;
5686             y      = 0;
5687          }
5688 
5689          if(n) { /* Coarse Positioning */
5690             memcpy(upd->outbuf+ioutbuf,
5691                        upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
5692             ioutbuf += upd->strings[S_YMOVE].size;
5693 
5694             upd->outbuf[ioutbuf++] =  n     & 0xff;
5695             upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
5696 
5697          }       /* Coarse Positioning */
5698 
5699          if(0 < upd->strings[S_YSTEP].size) {
5700             while(y--) {
5701                memcpy(upd->outbuf+ioutbuf,
5702                           upd->strings[S_YSTEP].data,
5703                           upd->strings[S_YSTEP].size);
5704                ioutbuf += upd->strings[S_YSTEP].size;
5705             }
5706          }
5707 
5708          upd->yprinter = upd->yscan;
5709       }                                 /* Adjust Y-Position */
5710 /*
5711  * Now write the required components
5712  */
5713       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
5714 /*
5715  *       First check, wether this Component needs printing
5716  */
5717          for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
5718             if(0 > y) continue;
5719             obytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
5720             for(x = xbegin; x <= xend && !obytes[x]; ++x);
5721             if(             x <= xend) break;
5722          }                                                     /* Comp-Test */
5723          if(y >= yend) continue; /* Component not required */
5724 /*
5725  *       Select the Component
5726  */
5727          if((0 < upd->string_a[SA_SETCOMP].size) &&
5728             (upd->icomp != icomp               )   ) { /* Selection enabled */
5729             upd->icomp = icomp;
5730             if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
5731                memcpy(upd->outbuf+ioutbuf,
5732                           upd->string_a[SA_SETCOMP].data[icomp].data,
5733                           upd->string_a[SA_SETCOMP].data[icomp].size);
5734                ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
5735             }
5736          }                                      /* Selection enabled */
5737 /*
5738  *       Establish the X-Position
5739  */
5740          if(xbegin != upd->xprinter) {
5741 
5742             if(0 == upd->strings[S_XMOVE].size) {
5743 
5744                upd->outbuf[ioutbuf++] = '\r';
5745                upd->xprinter          =  0;
5746                n = 0;
5747                x = 0;
5748 
5749             } else {
5750 
5751                if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
5752                else                    n = x = xbegin - upd->xprinter;
5753 
5754                if(        1 < upd->ints[I_XSTEP]) {
5755                   if(0 > n) {
5756                      n  -= upd->ints[I_XSTEP];
5757                      x  -= n;
5758                   }
5759                   if(n) n  /= upd->ints[I_XSTEP]; /* Major-Steps */
5760                   if(x) x  %= upd->ints[I_XSTEP]; /* Minor-Steps */
5761 
5762                } else if(-1 > upd->ints[I_XSTEP]) {
5763                   n *= -upd->ints[I_XSTEP]; /* May this work? */
5764                   x  = 0;
5765                }
5766 
5767                if(n) { /* Adjust X-Position */
5768 
5769                  memcpy(upd->outbuf+ioutbuf,
5770                              upd->strings[S_XMOVE].data,
5771                              upd->strings[S_XMOVE].size);
5772                   ioutbuf += upd->strings[S_XMOVE].size;
5773 
5774                   upd->outbuf[ioutbuf++] =  n     & 0xff;
5775                   upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
5776 
5777                }       /* Adjust X-Position */
5778 
5779             }
5780 
5781             if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
5782                while(x--) {
5783                   memcpy(upd->outbuf+ioutbuf,
5784                              upd->strings[S_XSTEP].data,
5785                              upd->strings[S_XSTEP].size);
5786                   ioutbuf += upd->strings[S_XSTEP].size;
5787                }
5788             }                                         /* Fine-Adjust X */
5789          }
5790          upd->xprinter = xend+1;
5791 
5792 /*
5793  *       Send the Write-Command
5794  */
5795          if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
5796             memcpy(upd->outbuf+ioutbuf,
5797                        upd->string_a[SA_WRITECOMP].data[icomp].data,
5798                        upd->string_a[SA_WRITECOMP].data[icomp].size);
5799             ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
5800          }
5801          n = xend + 1 - xbegin;
5802          upd->outbuf[ioutbuf++] = (n<<3) & 255;
5803          upd->outbuf[ioutbuf++] = (n>>5) & 255;
5804 /*
5805  *       Set the Pixels
5806  */
5807          for(pin = 0; pin < pintop; ++pin) {
5808             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
5809             fwrite(upd->outbuf,1,ioutbuf,out);
5810             ioutbuf = 0;
5811          }
5812 
5813          for(y = ybegin; 0 > y;    y += upd->ints[I_NYPASS]) {
5814             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
5815             fwrite(upd->outbuf,1,ioutbuf,out);
5816             ioutbuf = 0;
5817          }
5818 
5819          for(; y < yend; y += upd->ints[I_NYPASS]) {
5820             ioutbuf += upd_rle(upd->outbuf+ioutbuf,
5821                upd->scnbuf[y & upd->scnmsk][icomp].bytes+xbegin,n);
5822             fwrite(upd->outbuf,1,ioutbuf,out);
5823             ioutbuf = 0;
5824          }
5825 
5826          for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
5827             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
5828             fwrite(upd->outbuf,1,ioutbuf,out);
5829             ioutbuf = 0;
5830          }
5831       }                                             /* Component-Print */
5832    }                    /* Some data to write */
5833 
5834 /** Advance counters in upd, change modi */
5835    if(upd->yscan < upd->ints[I_BEG_Y]) {
5836       upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
5837       if(     upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
5838       else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
5839    } else if(upd->yscan >= upd->ints[I_END_Y]) {
5840       upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
5841       if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
5842    } else {
5843       upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
5844       if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
5845       if(upd->yscan >= upd->ints[I_END_Y])         upd->ipass = 0;
5846    }
5847 
5848    return 0;
5849 }
5850 
5851 /* ------------------------------------------------------------------- */
5852 /* upd_wrtescnm: Write a pass                                          */
5853 /* ------------------------------------------------------------------- */
5854 
5855 /*GR copied from upd_wrtescp2 and modified */
5856 
5857 private int
upd_wrtescnm(upd_p upd,FILE * out)5858 upd_wrtescnm(upd_p upd, FILE *out)
5859 {
5860    int  pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n;
5861    int  irow,imask,iyofs;
5862    byte *obytes;
5863    updscan_p scan;
5864 
5865 /** Determine the number of pins to write */
5866 
5867    if(upd->yscan < upd->ints[I_BEG_Y]) {
5868       pintop = 0;
5869       pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
5870    } else if(upd->yscan >= upd->ints[I_END_Y]) {
5871       pinbot = upd->ints[I_PINS2WRITE];
5872       pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
5873    } else {
5874       pintop = 0;
5875       pinbot = upd->ints[I_PINS2WRITE];
5876    }
5877 
5878    ybegin =  pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
5879    yend   =  pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
5880 
5881 /** Determine Width of this scan */
5882 
5883    xbegin = upd->nbytes;
5884    xend   = -1;
5885 
5886    for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
5887 
5888       if(0 > y) continue; /* Inserted Scanlines */
5889 
5890       scan = upd->scnbuf[y & upd->scnmsk];
5891 
5892       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
5893          obytes = scan[icomp].bytes;
5894 
5895          for(x = 0; x < xbegin && !obytes[x]; x++);
5896          if(x < xbegin) xbegin = x;
5897 
5898          if(x < upd->nbytes) {
5899             for(x = upd->nbytes-1; x > xend && !obytes[x]; x--);
5900             if(x > xend) xend = x;
5901          }
5902       }                                             /* Compwise test */
5903    }                                                     /* Pin-testloop */
5904 
5905    if(xbegin <= xend) { /* Some data to write */
5906 
5907       ioutbuf = 0;
5908 
5909       if(0 == upd->strings[S_XMOVE].size) xbegin = 0;
5910 
5911 /*
5912  *    Adjust the Printers Y-Position
5913  */
5914       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
5915          if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
5916          else                    y = upd->yscan - upd->yprinter;
5917 
5918          if(      1 < upd->ints[I_YSTEP]) {
5919             n      =  y / upd->ints[I_YSTEP];  /* Major-Steps */
5920             y     -=  n * upd->ints[I_YSTEP];  /* Minor-Steps */
5921          } else if(-1 > upd->ints[I_YSTEP]) {
5922             n      = y * -upd->ints[I_YSTEP];  /* May this work? */
5923             y      = 0;
5924          } else {
5925             n      = y;
5926             y      = 0;
5927          }
5928 
5929          if(n) { /* Coarse Positioning */
5930             memcpy(upd->outbuf+ioutbuf,
5931                        upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
5932             ioutbuf += upd->strings[S_YMOVE].size;
5933 
5934             upd->outbuf[ioutbuf++] =  n     & 0xff;
5935             upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
5936 
5937          }       /* Coarse Positioning */
5938 
5939          if(0 < upd->strings[S_YSTEP].size) {
5940             while(y--) {
5941                memcpy(upd->outbuf+ioutbuf,
5942                           upd->strings[S_YSTEP].data,
5943                           upd->strings[S_YSTEP].size);
5944                ioutbuf += upd->strings[S_YSTEP].size;
5945             }
5946          }
5947 
5948          upd->yprinter = upd->yscan;
5949       }                                 /* Adjust Y-Position */
5950 /*
5951  * Now write the required components
5952  */
5953 
5954 /*
5955 *     Select the Component
5956 *
5957 *     Always issue an ESC 'r' 0 - don't know why - that
5958 *     is just what the windows driver does.
5959 */
5960       icomp=0;
5961       if((0 < upd->string_a[SA_SETCOMP].size) /* &&
5962          (upd->icomp != icomp               )   */) { /* Selection enabled */
5963          upd->icomp = icomp;
5964          if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
5965             memcpy(upd->outbuf+ioutbuf,
5966                        upd->string_a[SA_SETCOMP].data[icomp].data,
5967                        upd->string_a[SA_SETCOMP].data[icomp].size);
5968             ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
5969          }
5970       }                                      /* Selection enabled */
5971 /*
5972 *     Establish the X-Position
5973 */
5974       if(xbegin != upd->xprinter) {
5975 
5976          if(0 == upd->strings[S_XMOVE].size) {
5977 
5978             upd->outbuf[ioutbuf++] = '\r';
5979             upd->xprinter          =  0;
5980             n = 0;
5981             x = 0;
5982 
5983          } else {
5984 
5985             if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
5986             else                    n = x = xbegin - upd->xprinter;
5987 
5988             if(        1 < upd->ints[I_XSTEP]) {
5989                if(0 > n) {
5990                   n  -= upd->ints[I_XSTEP];
5991                   x  -= n;
5992                }
5993                if(n) n  /= upd->ints[I_XSTEP]; /* Major-Steps */
5994                if(x) x  %= upd->ints[I_XSTEP]; /* Minor-Steps */
5995 
5996             } else if(-1 > upd->ints[I_XSTEP]) {
5997                n *= -upd->ints[I_XSTEP]; /* May this work? */
5998                x  = 0;
5999             }
6000 
6001             if(n) { /* Adjust X-Position */
6002 
6003               memcpy(upd->outbuf+ioutbuf,
6004                           upd->strings[S_XMOVE].data,
6005                           upd->strings[S_XMOVE].size);
6006                ioutbuf += upd->strings[S_XMOVE].size;
6007 
6008                upd->outbuf[ioutbuf++] =  n     & 0xff;
6009                upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
6010 
6011             }       /* Adjust X-Position */
6012 
6013          }
6014 
6015          if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
6016             while(x--) {
6017                memcpy(upd->outbuf+ioutbuf,
6018                           upd->strings[S_XSTEP].data,
6019                           upd->strings[S_XSTEP].size);
6020                ioutbuf += upd->strings[S_XSTEP].size;
6021             }
6022          }                                         /* Fine-Adjust X */
6023       }
6024       upd->xprinter = xend+1;
6025 
6026 /*
6027 *     Send the Write-Command - the default is ESC '.' 1
6028 */
6029       if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
6030          memcpy(upd->outbuf+ioutbuf,
6031                     upd->string_a[SA_WRITECOMP].data[icomp].data,
6032                     upd->string_a[SA_WRITECOMP].data[icomp].size);
6033          ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
6034       }
6035       n = xend + 1 - xbegin;
6036       upd->outbuf[ioutbuf++] = (n<<3) & 255;
6037       upd->outbuf[ioutbuf++] = (n>>5) & 255;
6038 /*
6039 *       Set the Pixels
6040 */
6041       irow=0; /* row counter for output data */
6042 
6043       /*  pins at the top of the head that don't print */
6044       for(pin = 0; pin < pintop; ++pin) {
6045          int i;
6046          for(i=0 ; i < upd->ints[I_PATRPT]; i++){
6047             if(irow >= upd->ints[I_ROWS]) break;
6048             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6049             fwrite(upd->outbuf,1,ioutbuf,out);
6050             irow++;
6051             ioutbuf = 0;
6052          }
6053       }
6054 
6055       /*  I'm not really sure what this does */
6056       /* it looks like we're filling in empty rows */
6057       for(y = ybegin; 0 > y;    y += upd->ints[I_NYPASS]) {
6058 
6059          int i;
6060          for(i=0 ; i < upd->ints[I_PATRPT]; i++){
6061             if(irow >= upd->ints[I_ROWS]) break;
6062             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6063             fwrite(upd->outbuf,1,ioutbuf,out);
6064             ioutbuf = 0;
6065             irow++;
6066          }
6067       }
6068 
6069       for(; y < yend; y += upd->ints[I_NYPASS]) {
6070 
6071          int i,masklen=upd->ints[I_PATRPT],yinc=0;
6072 
6073          for(i=0 ; (i < upd->ints[I_PATRPT]); i++){
6074             if(irow >= upd->ints[I_ROWS]) break;
6075             imask = irow%masklen;
6076             icomp = upd->int_a[IA_ROWMASK].data[imask];
6077             if(icomp == 0) {
6078                ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6079             } else {
6080                --icomp;
6081                iyofs = upd->int_a[IA_SCNOFS].data[imask];
6082                ioutbuf += upd_rle(upd->outbuf+ioutbuf,
6083                upd->scnbuf[(y+iyofs) & upd->scnmsk][icomp].bytes+xbegin,n);
6084                yinc+=upd->ints[I_NYPASS];
6085             }
6086             fwrite(upd->outbuf,1,ioutbuf,out);
6087             ioutbuf = 0;
6088             irow++;
6089          }
6090 
6091          if (upd->ints[I_NYPASS] < upd->ints[I_PATRPT]) {
6092             y+=yinc;
6093             if (y > 0)
6094                y-=upd->ints[I_NYPASS];
6095          }
6096       }
6097 
6098       /*  I think this is the pins at the bottom of the head that don't print */
6099       for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
6100          int i;
6101          for(i=0 ; i < upd->ints[I_PATRPT]; i++){
6102             if(irow >= upd->ints[I_ROWS]) break;
6103             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6104             fwrite(upd->outbuf,1,ioutbuf,out);
6105             ioutbuf = 0;
6106             irow++;
6107          }
6108       }
6109 
6110       /* pad empty rows that haven't been filled yet*/
6111        if (irow < upd->ints[I_ROWS]) {
6112          for( ; irow < upd->ints[I_ROWS]; irow++){
6113             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6114             fwrite(upd->outbuf,1,ioutbuf,out);
6115             ioutbuf = 0;
6116          }
6117       }
6118 
6119    }              /* Some data to write */
6120 
6121 /** Advance counters in upd, change modi */
6122    if(upd->yscan < upd->ints[I_BEG_Y]) {
6123       upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
6124       if(     upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
6125       else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
6126    } else if(upd->yscan >= upd->ints[I_END_Y]) {
6127       upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
6128       if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
6129    } else {
6130       upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
6131       if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
6132       if(upd->yscan >= upd->ints[I_END_Y])         upd->ipass = 0;
6133    }
6134 
6135    return 0;
6136 }
6137 
6138 
6139 /* ------------------------------------------------------------------- */
6140 /* upd_wrtescp2x: Write an ESC/P2-pass with X-Weaving                  */
6141 /* ------------------------------------------------------------------- */
6142 
6143 private int
upd_wrtescp2x(upd_p upd,FILE * out)6144 upd_wrtescp2x(upd_p upd, FILE *out)
6145 {
6146    int  pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
6147    byte *obytes,bit;
6148    updscan_p scan;
6149 
6150 /** Determine the number of pins to write */
6151 
6152    if(upd->yscan < upd->ints[I_BEG_Y]) {
6153       ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
6154       pintop = 0;
6155       pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
6156    } else if(upd->yscan >= upd->ints[I_END_Y]) {
6157       ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
6158       pinbot = upd->ints[I_PINS2WRITE];
6159       pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
6160    } else {
6161       ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
6162       pintop = 0;
6163       pinbot = upd->ints[I_PINS2WRITE];
6164    }
6165 
6166    ybegin =  pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
6167    yend   =  pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
6168 
6169 /** Determine Width of this scan */
6170 
6171    xbegin = upd->pwidth;
6172    xend   = -1;
6173 
6174    for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
6175 
6176       if(0 > y) continue; /* Inserted Scanlines */
6177 
6178       scan = upd->scnbuf[y & upd->scnmsk];
6179 
6180       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
6181          if(xbegin > scan[icomp].xbegin[ixpass])
6182             xbegin = scan[icomp].xbegin[ixpass];
6183          if(xend   < scan[icomp].xend[  ixpass])
6184             xend   = scan[icomp].xend[  ixpass];
6185       }                                             /* Compwise test */
6186 
6187    }                                                     /* Pin-testloop */
6188 
6189    if(xbegin <= xend) { /* Some data to write */
6190 
6191       ioutbuf = upd->nbytes;
6192 
6193       if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
6194 
6195 /*
6196  *    Adjust the Printers Y-Position
6197  */
6198       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
6199          if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
6200          else                    y = upd->yscan - upd->yprinter;
6201 
6202          if(      1 < upd->ints[I_YSTEP]) {
6203             n      =  y / upd->ints[I_YSTEP];  /* Major-Steps */
6204             y     -=  n * upd->ints[I_YSTEP];  /* Minor-Steps */
6205          } else if(-1 > upd->ints[I_YSTEP]) {
6206             n      = y * -upd->ints[I_YSTEP];  /* May this work? */
6207             y      = 0;
6208          } else {
6209             n      = y;
6210             y      = 0;
6211          }
6212 
6213          if(n) { /* Coarse Positioning */
6214             memcpy(upd->outbuf+ioutbuf,
6215                        upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
6216             ioutbuf += upd->strings[S_YMOVE].size;
6217 
6218             upd->outbuf[ioutbuf++] =  n     & 0xff;
6219             upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
6220 
6221          }       /* Coarse Positioning */
6222 
6223          if(0 < upd->strings[S_YSTEP].size) {
6224             while(y--) {
6225                memcpy(upd->outbuf+ioutbuf,
6226                           upd->strings[S_YSTEP].data,
6227                           upd->strings[S_YSTEP].size);
6228                ioutbuf += upd->strings[S_YSTEP].size;
6229             }
6230          }
6231 
6232          upd->yprinter = upd->yscan;
6233       }                                 /* Adjust Y-Position */
6234 
6235 /*
6236  * Now write the required components
6237  */
6238       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
6239 /*
6240  *       First check, wether this Component needs printing
6241  */
6242          for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
6243             if(0 > y) continue;
6244             scan = upd->scnbuf[y & upd->scnmsk]+icomp;
6245             if(0 <= scan->xend[ixpass]) break;
6246          }                                                     /* Comp-Test */
6247          if(y >= yend) continue; /* Component not required */
6248 /*
6249  *       Select the Component
6250  */
6251          if((0 < upd->string_a[SA_SETCOMP].size) &&
6252             (upd->icomp != icomp               )   ) { /* Selection enabled */
6253             upd->icomp = icomp;
6254             if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
6255                memcpy(upd->outbuf+ioutbuf,
6256                           upd->string_a[SA_SETCOMP].data[icomp].data,
6257                           upd->string_a[SA_SETCOMP].data[icomp].size);
6258                ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
6259             }
6260          }                                      /* Selection enabled */
6261 /*
6262  *       Establish the X-Position
6263  */
6264          if(xbegin != upd->xprinter) {
6265 
6266             if(0 == upd->strings[S_XMOVE].size) {
6267 
6268                upd->outbuf[ioutbuf++] = '\r';
6269                upd->xprinter          =  0;
6270                n = 0;
6271                x = ixpass;
6272 
6273             } else {
6274 
6275                if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
6276                else                    n = x = xbegin - upd->xprinter;
6277 
6278                if(        1 < upd->ints[I_XSTEP]) {
6279                   if(0 > n) {
6280                      n  -= upd->ints[I_XSTEP];
6281                      x  -= n;
6282                   }
6283                   if(n) n  /= upd->ints[I_XSTEP]; /* Major-Steps */
6284                   if(x) x  %= upd->ints[I_XSTEP]; /* Minor-Steps */
6285 
6286                } else if(-1 > upd->ints[I_XSTEP]) {
6287                   n *= -upd->ints[I_XSTEP]; /* May this work? */
6288                   x  = 0;
6289                }
6290 
6291                if(n) { /* Adjust X-Position */
6292 
6293                  memcpy(upd->outbuf+ioutbuf,
6294                              upd->strings[S_XMOVE].data,
6295                              upd->strings[S_XMOVE].size);
6296                   ioutbuf += upd->strings[S_XMOVE].size;
6297 
6298                   upd->outbuf[ioutbuf++] =  n     & 0xff;
6299                   upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
6300 
6301                }       /* Adjust X-Position */
6302 
6303             }
6304 
6305             if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
6306                while(x--) {
6307                   memcpy(upd->outbuf+ioutbuf,
6308                              upd->strings[S_XSTEP].data,
6309                              upd->strings[S_XSTEP].size);
6310                   ioutbuf += upd->strings[S_XSTEP].size;
6311                }
6312             }                                         /* Fine-Adjust X */
6313          }
6314          upd->xprinter = xend+1;
6315 
6316 /*
6317  *       Send the Write-Command
6318  */
6319          if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
6320             memcpy(upd->outbuf+ioutbuf,
6321                        upd->string_a[SA_WRITECOMP].data[icomp].data,
6322                        upd->string_a[SA_WRITECOMP].data[icomp].size);
6323             ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
6324          }
6325          n = ((xend - xbegin) / upd->ints[I_NXPASS] + 8) & ~7;
6326          upd->outbuf[ioutbuf++] =  n     & 255;
6327          upd->outbuf[ioutbuf++] = (n>>8) & 255;
6328          n >>= 3;
6329 /*
6330  *       Set the Pixels
6331  */
6332          for(pin = 0; pin < pintop; ++pin) {
6333             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6334             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
6335             ioutbuf = upd->nbytes;
6336          }
6337 
6338          for(y = ybegin; 0 > y;    y += upd->ints[I_NYPASS]) {
6339             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6340             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
6341             ioutbuf = upd->nbytes;
6342          }
6343 
6344          for(;           y < yend; y += upd->ints[I_NYPASS]) {
6345             byte * ibytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
6346             obytes = upd->outbuf;
6347             memset(obytes,0,upd->nbytes);
6348             bit = 0x80;
6349             for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
6350                if(ibytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
6351                if(!(bit >>= 1)) { obytes++; bit = 0x80; }
6352             }
6353             ioutbuf += upd_rle(upd->outbuf+ioutbuf,upd->outbuf,n);
6354             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
6355             ioutbuf = upd->nbytes;
6356          }
6357 
6358          for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
6359             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
6360             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
6361             ioutbuf = upd->nbytes;
6362          }
6363       }                                             /* Component-Print */
6364    }                    /* Some data to write */
6365 
6366 /** Advance counters in upd, change modi */
6367 
6368    if(upd->yscan < upd->ints[I_BEG_Y]) {
6369       upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
6370       if(     upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
6371       else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
6372    } else if(upd->yscan >= upd->ints[I_END_Y]) {
6373       upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
6374       if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
6375    } else {
6376       upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
6377       if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
6378       if(upd->yscan >= upd->ints[I_END_Y])         upd->ipass = 0;
6379    }
6380 
6381    return 0;
6382 }
6383 
6384 /* ------------------------------------------------------------------- */
6385 /* upd_rle: The Runlength-Compressor                                   */
6386 /* ------------------------------------------------------------------- */
6387 
6388 private int
upd_rle(byte * out,const byte * in,int nbytes)6389 upd_rle(byte *out,const byte *in,int nbytes)
6390 {
6391 
6392    int used = 0;
6393    int crun,cdata;
6394    byte run;
6395 
6396    if(in != NULL) { /* Data present */
6397 
6398       crun = 1;
6399 
6400       while(nbytes > 0) { /* something to compress */
6401 
6402          run = in[0];
6403 
6404          while((nbytes > crun) && (run == in[crun])) if(++crun == 128) break;
6405 
6406          if((crun > 2) || (crun == nbytes)) { /* use this run */
6407 
6408             *out++  = (257 - crun) & 0xff; *out++ = run; used += 2;
6409 
6410             nbytes -= crun; in    += crun;
6411             crun = 1;
6412 
6413          } else {                            /* ignore this run */
6414 
6415             for(cdata = crun; (nbytes > cdata) && (crun < 4);) {
6416                if(run  == in[cdata]) crun += 1;
6417                else run = in[cdata], crun  = 1;
6418                if(++cdata == 128) break;
6419             }
6420 
6421             if(crun < 3) crun   = 0;    /* ignore trailing run */
6422             else         cdata -= crun;
6423 
6424             *out++ = cdata-1;     used++;
6425             memcpy(out,in,cdata); used += cdata; out   += cdata;
6426 
6427             nbytes -= cdata; in    += cdata;
6428 
6429          }              /* use/ignore run */
6430 
6431       }                  /* something to compress */
6432 
6433    } else {         /* Empty scans to fill bands */
6434 
6435       while(nbytes > 0) {
6436          crun    = nbytes > 128 ? 128 : nbytes;
6437          nbytes -= crun;
6438          *out++  = (257 - crun) & 0xff;
6439          *out++  = 0;
6440          used   += 2;
6441       }
6442    }                /* Data present or empty */
6443    return used;
6444 }
6445 
6446 /* ------------------------------------------------------------------- */
6447 /* upd_open_wrtrtl: Basic HP-RTL Writer                                */
6448 /* ------------------------------------------------------------------- */
6449 
6450 private int
upd_open_wrtrtl(upd_device * udev)6451 upd_open_wrtrtl(upd_device *udev)
6452 {
6453    const upd_p      upd  = udev->upd;
6454    int              error = 0;
6455 
6456 /** Adjust the Raster-Width */
6457 
6458    if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
6459 
6460      int   i,j,state;
6461      char  cv[24];
6462      byte  *bp;
6463      uint  ncv,nbp;
6464 
6465      j     = -1;
6466      state = 0;
6467      for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
6468        const int c = upd->strings[S_BEGIN].data[i];
6469 
6470        switch(state) {
6471 /* ----- any character */
6472          case  0:
6473            if(        c == 0x1b) state =  1; /* ESC */
6474          break;
6475 
6476 /* ----- last was ESC */
6477          case  1:
6478            if(        c == 0x2a) state =  2; /* ESC * */
6479            else if(   c == 0x25) state =  5; /* ESC % */
6480            else                  state =  0;
6481          break;
6482 
6483 /* ----- got ESC * */
6484          case  2:
6485            j = i; /* This character is not part of the replaced text */
6486            if(        c == 0x72) state =  3; /* ESC * r */
6487            else if(   c == 0x74) state =  4; /* ESC * t */
6488            else                  state =  0;
6489          break;
6490 
6491 /* ----- got ESC * r */
6492 /*         Pagewidth and Pagelength might be replaced */
6493          case  3:
6494 
6495            if(       (B_PAGEWIDTH  & upd->flags) &&
6496                      ((c == 0x73) || (c == 0x53))  ) { /* esc * r # S */
6497 
6498              sprintf(cv,"%d",upd->pwidth);
6499              ncv = strlen(cv);
6500 
6501              nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
6502              UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
6503 
6504              if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
6505              memcpy(bp+j+1,    cv,ncv);
6506              memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
6507                                upd->strings[S_BEGIN].size-i);
6508              i = j+1+ncv;
6509              UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
6510              upd->strings[S_BEGIN].data = bp;
6511              upd->strings[S_BEGIN].size = nbp;
6512 
6513            } else if((B_PAGELENGTH & upd->flags) &&
6514                      ((c == 0x74) || (c == 0x54))  ) { /* esc * r # T */
6515 
6516              sprintf(cv,"%d",upd->pheight);
6517              ncv = strlen(cv);
6518 
6519              nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
6520              UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
6521 
6522              if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
6523              memcpy(bp+j+1,    cv,ncv);
6524              memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
6525                                upd->strings[S_BEGIN].size-i);
6526              i = j+1+ncv;
6527              UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
6528              upd->strings[S_BEGIN].data = bp;
6529              upd->strings[S_BEGIN].size = nbp;
6530 
6531            }
6532 
6533            if(       (0x40 < c) && (c < 0x5b))  state = 0; /* Term. cmd. */
6534            else if(!((0x2f < c) && (c < 0x3a))) j     = i; /* Non-Number */
6535 
6536          break;
6537 
6538 /* ----- got ESC * t */
6539 /*         Resolution might be replaced */
6540          case  4: /* esc * t */
6541 
6542            if(        (B_RESOLUTION  & upd->flags) &&
6543                      ((c == 0x72) || (c == 0x52))  ) { /* esc * t # R */
6544 
6545              sprintf(cv,"%d",(int)
6546                ((udev->y_pixels_per_inch < udev->x_pixels_per_inch ?
6547                  udev->x_pixels_per_inch : udev->y_pixels_per_inch)
6548                +0.5));
6549              ncv = strlen(cv);
6550 
6551              nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
6552              UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
6553 
6554              if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
6555              memcpy(bp+j+1,    cv,ncv);
6556              memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
6557                                upd->strings[S_BEGIN].size-i);
6558              i = j+1+ncv;
6559              UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
6560              upd->strings[S_BEGIN].data = bp;
6561              upd->strings[S_BEGIN].size = nbp;
6562 
6563            }
6564 
6565            if(       (0x40 < c) && (c < 0x5b))  state = 0; /* Term. cmd. */
6566            else if(!((0x2f < c) && (c < 0x3a))) j     = i; /* Non-Number */
6567 
6568          break;
6569 
6570          case  5: /* ESC % - 1 2 3 4 5 X */
6571            if( c == 0x2d) state =  6; /* ESC % - */
6572            else           state =  0;
6573          break;
6574 
6575          case  6: /* ESC %  - 1 2 3 4 5 X */
6576            if( c == 0x31) state =  7; /* ESC % - 1 */
6577            else           state =  0;
6578          break;
6579 
6580          case  7: /* ESC %  - 1 2 3 4 5 X */
6581            if( c == 0x32) state =  8; /* ESC % - 1 2 */
6582            else           state =  0;
6583          break;
6584 
6585          case  8: /* ESC %  - 1 2 3 4 5 X */
6586            if( c == 0x33) state =  9; /* ESC % - 1 2 3 */
6587            else           state =  0;
6588          break;
6589 
6590          case  9: /* ESC %  - 1 2 3 4 5 X */
6591            if( c == 0x34) state = 10; /* ESC % - 1 2 3 4 */
6592            else           state =  0;
6593          break;
6594 
6595          case 10: /* ESC %  - 1 2 3 4 5 X */
6596            if( c == 0x35) state = 11; /* ESC % - 1 2 3 4 5 */
6597            else           state =  0;
6598          break;
6599 
6600          case 11: /* ESC %  - 1 2 3 4 5 X */
6601            if( c == 0x58) state = 12; /* ESC % - 1 2 3 4 5 X */
6602            else           state =  0;
6603          break;
6604 
6605          case 12: /* PJL-BOL:  @ P J L ws */
6606            if( c == 0x40) state = 13; /* @ */
6607            else           state =  0;
6608          break;
6609 
6610          case 13: /* PJL-BOL  @ P J L ws */
6611            if( c == 0x50) state = 14; /* @ P */
6612            else           state =  0;
6613          break;
6614 
6615          case 14: /* PJL-BOL  @ P J L ws */
6616            if( c == 0x4a) state = 15; /* @ P J */
6617            else           state =  0;
6618          break;
6619 
6620          case 15: /* PJL-BOL  @ P J L ws */
6621            if( c == 0x4c) state = 16; /* @ P J L */
6622            else           state =  0;
6623          break;
6624 
6625          case 16: /* PJL-BOL  @ P J L ws */
6626            if((c == 0x20) || (c == 0x09)) state = 19; /* @ P J L ws */
6627            else if(           c == 0x0d ) state = 17;
6628            else if(           c == 0x0a ) state = 12;
6629            else                           state =  0; /* PJL-Error */
6630          break;
6631 
6632          case 17: /* PJL-EOL  */
6633            if( c == 0x0a) state = 12; /* Next PJL-Command */
6634            else           state =  0; /* PJL-Error */
6635          break;
6636 
6637          case 18: /* PJL-Eatup: Expect Newline */
6638            if( c == 0x0a) state = 12;
6639          break;
6640 
6641          case 19: /* Begin of PJL-Command */
6642            if(     (c == 0x53) || (c == 0x73)) state = 20; /* S E T*/
6643            else if( c == 0x0a                ) state = 12; /* BOL */
6644            else if( c == 0x0d                ) state = 17;
6645          break;
6646 
6647          case 20: /* PJL-Set: S E T  */
6648            if(     (c == 0x45) || (c == 0x65)) state = 21; /* S E */
6649            else if( c == 0x0a                ) state = 12; /* BOL */
6650            else                                state = 18;
6651          break;
6652 
6653          case 21: /* PJL-Set: S E T  */
6654            if(     (c == 0x54) || (c == 0x74)) state = 22; /* S E T */
6655            else if( c == 0x0a                ) state = 12; /* BOL */
6656            else                                state = 18;
6657          break;
6658 
6659          case 22: /* PJL-Set: S E T ws  */
6660            if(     (c == 0x20) || (c == 0x09)) state = 23; /* S E T ws */
6661            else if( c == 0x0a                ) state = 12; /* BOL */
6662            else                                state = 18;
6663          break;
6664 
6665          case 23: /* PJL-Set: S E T ws  */
6666            if(     (c == 0x50) || (c == 0x70)) state = 24; /* set paper... */
6667            else if((c == 0x52) || (c == 0x72)) state = 41; /* set resolution */
6668            else if( c == 0x0a                ) state = 12; /* BOL */
6669            else                                state = 18;
6670          break;
6671 
6672          case 24: /* PJL-Set: set paper...  */
6673            if(     (c == 0x41) || (c == 0x61)) state = 25; /* set pa */
6674            else if( c == 0x0a                ) state = 12; /* BOL */
6675            else                                state = 18;
6676          break;
6677 
6678          case 25: /* PJL-Set: set paper...  */
6679            if(     (c == 0x50) || (c == 0x70)) state = 26; /* set pap */
6680            else if( c == 0x0a                ) state = 12; /* BOL */
6681            else                                state = 18;
6682          break;
6683 
6684          case 26: /* PJL-Set: set paper...  */
6685            if(     (c == 0x45) || (c == 0x65)) state = 27; /* set pape */
6686            else if( c == 0x0a                ) state = 12; /* BOL */
6687            else                                state = 18;
6688          break;
6689 
6690          case 27: /* PJL-Set: set paper...  */
6691            if(     (c == 0x52) || (c == 0x72)) state = 28; /* set paper */
6692            else if( c == 0x0a                ) state = 12; /* BOL */
6693            else                                state = 18;
6694          break;
6695 
6696          case 28: /* PJL-Set: set paper?  */
6697            if(     (c == 0x4c) || (c == 0x6c)) state = 29; /* set paperlength */
6698            else if((c == 0x57) || (c == 0x77)) state = 36; /* set paperwidth */
6699            else if( c == 0x0a                ) state = 12; /* BOL */
6700            else                                state = 18;
6701          break;
6702 
6703          case 29: /* PJL: set paperlength  */
6704            if(     (c == 0x45) || (c == 0x65)) state = 30; /* set paperle */
6705            else if( c == 0x0a                ) state = 12; /* BOL */
6706            else                                state = 18;
6707          break;
6708 
6709          case 30: /* PJL: set paperlength  */
6710            if(     (c == 0x4e) || (c == 0x6e)) state = 31; /* set paperlen */
6711            else if( c == 0x0a                ) state = 12; /* BOL */
6712            else                                state = 18;
6713          break;
6714 
6715          case 31: /* PJL: set paperlength  */
6716            if(     (c == 0x47) || (c == 0x67)) state = 32; /* set paperleng */
6717            else if( c == 0x0a                ) state = 12; /* BOL */
6718            else                                state = 18;
6719          break;
6720 
6721          case 32: /* PJL: set paperlength  */
6722            if(     (c == 0x54) || (c == 0x74)) state = 33; /* set paperlengt */
6723            else if( c == 0x0a                ) state = 12; /* BOL */
6724            else                                state = 18;
6725          break;
6726 
6727          case 33: /* PJL: set paperlength  */
6728            if(     (c == 0x48) || (c == 0x68)) state = 34; /* set paperlength */
6729            else if( c == 0x0a                ) state = 12; /* BOL */
6730            else                                state = 18;
6731          break;
6732 
6733          case 34: /* PJL: set paperlength  */
6734            j = i; /* This character is not part of the replaced text */
6735            if(      c == 0x3d                ) state = 51; /* set paperlength */
6736            else if( c == 0x0a                ) state = 12; /* BOL */
6737            else if((c != 0x20) && (c != 0x09)) state = 18;
6738          break;
6739 
6740          case 51: /* PJL: set paperlength = ws */
6741            if(     c == 0x0a)                  state = 12;
6742            else if((c == 0x20) || (c == 0x09)) j     = i;
6743            else if(( 0x30 > c) || ( c > 0x39)) state = 18;
6744            else                                state = 35;
6745          break;
6746 
6747          case 35: /* PJL: set paperlength */
6748            if((0x30 > c) || (c > 0x39)) { /* End of number */
6749 
6750              if(B_PAGELENGTH  & upd->flags) { /* insert new number */
6751 
6752                sprintf(cv,"%d",(int)
6753                  (720.0 * udev->height / udev->y_pixels_per_inch + 0.5));
6754                ncv = strlen(cv);
6755 
6756                nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
6757                UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
6758 
6759                if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
6760                memcpy(bp+j+1,    cv,ncv);
6761                memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
6762                                upd->strings[S_BEGIN].size-i);
6763                i = j+1+ncv;
6764                UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
6765                upd->strings[S_BEGIN].data = bp;
6766                upd->strings[S_BEGIN].size = nbp;
6767              }                                /* insert new number */
6768 
6769              if( c == 0x0a ) state = 12;
6770              else            state = 18;
6771            }
6772          break;
6773 
6774          case 36: /* PJL: set paperwidth  */
6775            if(     (c == 0x49) || (c == 0x69)) state = 37; /* set paperwi */
6776            else if( c == 0x0a                ) state = 12; /* BOL */
6777            else                                state = 18;
6778          break;
6779 
6780          case 37: /* PJL: set paperwidth */
6781            if(     (c == 0x44) || (c == 0x64)) state = 38; /* set paperwid */
6782            else if( c == 0x0a                ) state = 12; /* BOL */
6783            else                                state = 18;
6784          break;
6785 
6786          case 38: /* PJL: set paperwidth  */
6787            if(     (c == 0x54) || (c == 0x74)) state = 39; /* set paperwidt */
6788            else if( c == 0x0a                ) state = 12; /* BOL */
6789            else                                state = 18;
6790          break;
6791 
6792          case 39: /* PJL: set paperwidth  */
6793            if(     (c == 0x48) || (c == 0x68)) state = 52; /* set paperwidth */
6794            else if( c == 0x0a                ) state = 12; /* BOL */
6795            else                                state = 18;
6796          break;
6797 
6798          case 52: /* PJL: set paperwidth  */
6799            j = i; /* This character is not part of the replaced text */
6800            if(      c == 0x3d                ) state = 53; /* set paperwidth */
6801            else if( c == 0x0a                ) state = 12; /* BOL */
6802            else if((c != 0x20) && (c != 0x09)) state = 18;
6803          break;
6804 
6805          case 53: /* PJL: set paperwidth = ws */
6806            if(     c == 0x0a)                  state = 12;
6807            else if((c == 0x20) || (c == 0x09)) j     = i;
6808            else if(( 0x30 > c) || ( c > 0x39)) state = 18;
6809            else                                state = 40;
6810          break;
6811 
6812          case 40: /* PJL: set paperlength */
6813            if((0x30 > c) || (c > 0x39)) { /* End of number */
6814 
6815              if(B_PAGEWIDTH  & upd->flags) { /* insert new number */
6816 
6817                sprintf(cv,"%d",(int)
6818                  (720.0 * udev->width / udev->x_pixels_per_inch + 0.5));
6819                ncv = strlen(cv);
6820 
6821                nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
6822                UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
6823 
6824                if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
6825                memcpy(bp+j+1,    cv,ncv);
6826                memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
6827                                upd->strings[S_BEGIN].size-i);
6828                i = j+1+ncv;
6829                UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
6830                upd->strings[S_BEGIN].data = bp;
6831                upd->strings[S_BEGIN].size = nbp;
6832              }                                /* insert new number */
6833 
6834              if( c == 0x0a ) state = 12;
6835              else            state = 18;
6836            }
6837          break;
6838 
6839          case 41: /* PJL: set resolution */
6840            if(     (c == 0x45) || (c == 0x65)) state = 42; /* set re */
6841            else if( c == 0x0a                ) state = 12; /* BOL */
6842            else                                state = 18;
6843          break;
6844 
6845          case 42: /* PJL: set resolution */
6846            if(     (c == 0x53) || (c == 0x73)) state = 43; /* set res */
6847            else if( c == 0x0a                ) state = 12; /* BOL */
6848            else                                state = 18;
6849          break;
6850 
6851          case 43: /* PJL: set resolution */
6852            if(     (c == 0x4f) || (c == 0x6f)) state = 44; /* set reso */
6853            else if( c == 0x0a                ) state = 12; /* BOL */
6854            else                                state = 18;
6855          break;
6856 
6857          case 44: /* PJL: set resolution */
6858            if(     (c == 0x4c) || (c == 0x6c)) state = 45; /* set resol */
6859            else if( c == 0x0a                ) state = 12; /* BOL */
6860            else                                state = 18;
6861          break;
6862 
6863          case 45: /* PJL: set resolution */
6864            if(     (c == 0x55) || (c == 0x75)) state = 46; /* set resolu */
6865            else if( c == 0x0a                ) state = 12; /* BOL */
6866            else                                state = 18;
6867          break;
6868 
6869          case 46: /* PJL: set resolution */
6870            if(     (c == 0x54) || (c == 0x74)) state = 47; /* set resolut */
6871            else if( c == 0x0a                ) state = 12; /* BOL */
6872            else                                state = 18;
6873          break;
6874 
6875          case 47: /* PJL: set resolution */
6876            if(     (c == 0x49) || (c == 0x69)) state = 48; /* set resoluti */
6877            else if( c == 0x0a                ) state = 12; /* BOL */
6878            else                                state = 18;
6879          break;
6880 
6881          case 48: /* PJL: set resolution */
6882            if(     (c == 0x4f) || (c == 0x6f)) state = 49; /* set resolutio */
6883            else if( c == 0x0a                ) state = 12; /* BOL */
6884            else                                state = 18;
6885          break;
6886 
6887          case 49: /* PJL: set resolution */
6888            if(     (c == 0x4e) || (c == 0x6e)) state = 54; /* set resolution */
6889            else if( c == 0x0a                ) state = 12; /* BOL */
6890            else                                state = 18;
6891          break;
6892 
6893          case 54: /* PJL: set resolution  */
6894            j = i; /* This character is not part of the replaced text */
6895            if(      c == 0x3d                ) state = 55; /* set resolution */
6896            else if( c == 0x0a                ) state = 12; /* BOL */
6897            else if((c != 0x20) && (c != 0x09)) state = 18;
6898          break;
6899 
6900          case 55: /* PJL: set resolution = ws */
6901            if(     c == 0x0a)                  state = 12;
6902            else if((c == 0x20) || (c == 0x09)) j     = i;
6903            else if(( 0x30 > c) || ( c > 0x39)) state = 18;
6904            else                                state = 50;
6905          break;
6906 
6907          case 50: /* PJL: set resolution */
6908            if((0x30 > c) || (c > 0x39)) { /* End of number */
6909 
6910              if(B_RESOLUTION  & upd->flags) { /* insert new number */
6911 
6912                sprintf(cv,"%d",(int)
6913                  ((udev->y_pixels_per_inch < udev->x_pixels_per_inch ?
6914                    udev->x_pixels_per_inch : udev->y_pixels_per_inch)
6915                  +0.5));
6916                ncv = strlen(cv);
6917 
6918                nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
6919                UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
6920 
6921                if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
6922                memcpy(bp+j+1,    cv,ncv);
6923                memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
6924                                upd->strings[S_BEGIN].size-i);
6925                i = j+1+ncv;
6926                UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
6927                upd->strings[S_BEGIN].data = bp;
6928                upd->strings[S_BEGIN].size = nbp;
6929              }                                /* insert new number */
6930 
6931              if( c == 0x0a ) state = 12;
6932              else            state = 18;
6933            }
6934          break;
6935 
6936          default:
6937 #if UPD_MESSAGES & UPD_M_ERROR
6938            errprintf("UNIPRINT-Coding error, wrrtl, state = %d\n",state);
6939 #endif
6940            state = 0;
6941          break;
6942        }
6943      }
6944    }                                    /* BOP-Checker */
6945 
6946 /** SA_WRITECOMP must be valid */
6947    if(upd->ocomp > upd->string_a[SA_WRITECOMP].size) {
6948 #if UPD_MESSAGES & UPD_M_WARNING
6949       errprintf(
6950          "PCL-Open: WRITECOMP-Commands must be given\n");
6951 #endif
6952       error = -1;
6953    }
6954 
6955 /**
6956 If all this is correct, it's time to compute the size of the output-buffer.
6957 It must hold:
6958   1. Y-Positioning
6959   2. Component-Data
6960 */
6961    if(0 <= error) {
6962       int32_t ny,noutbuf;
6963       char  tmp[16];
6964 
6965       if(0 < upd->strings[S_YMOVE].size) {
6966          sprintf(tmp,"%d",upd->pheight);
6967          ny = upd->strings[S_YMOVE].size + strlen(tmp);
6968       } else {
6969          ny = 1 + upd->string_a[SA_WRITECOMP].data[upd->ocomp-1].size;
6970          ny *= upd->pheight;
6971       }
6972 
6973       noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
6974 
6975       if(ny > noutbuf) noutbuf = ny;
6976       noutbuf += 16;
6977 
6978       if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
6979          upd->noutbuf      = noutbuf;
6980          upd->writer       = upd_wrtrtl;
6981          error             = 1;
6982       } else {
6983          error = -1;
6984 #if      UPD_MESSAGES & UPD_M_WARNING
6985             errprintf(
6986               "PCL-Open: %ld is unreasonable size of Outputbuffer\n",
6987               (long) noutbuf);
6988 #endif
6989       }
6990    }
6991 
6992    return error;
6993 }
6994 
6995 /* ------------------------------------------------------------------- */
6996 /* upd_wrtrtl: Write a pass                                            */
6997 /* ------------------------------------------------------------------- */
6998 
6999 private int
upd_wrtrtl(upd_p upd,FILE * out)7000 upd_wrtrtl(upd_p upd, FILE *out)
7001 {
7002    const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
7003 
7004    int  x,xend,icomp,ioutbuf;
7005    byte *data;
7006 
7007 /** Determine Width of this scan */
7008 
7009    xend   = -1;
7010    for(icomp = 0; icomp < upd->ocomp; ++icomp) {
7011 
7012       data = scan[icomp].bytes;
7013 
7014       for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
7015       if(x > xend) xend  = x;
7016    }
7017 
7018    if(0 <= xend) { /* Some data to write */
7019 
7020       ioutbuf = 0;
7021       xend   += 1;
7022 /*
7023  *    Adjust the Printers Y-Position
7024  */
7025       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
7026          if(1 < upd->strings[S_YMOVE].size) {
7027            sprintf((char *)upd->outbuf+ioutbuf,
7028              (const char *) upd->strings[S_YMOVE].data,
7029              upd->yscan - upd->yprinter);
7030            ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
7031          } else {
7032            while(upd->yscan > upd->yprinter) {
7033              for(icomp = 0; icomp < upd->ocomp; ++icomp) {
7034                sprintf((char *)upd->outbuf+ioutbuf,
7035                  (const char *) upd->string_a[SA_WRITECOMP].data[icomp].data,0);
7036                ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
7037              }
7038              fwrite(upd->outbuf,1,ioutbuf,out);
7039              ioutbuf = 0;
7040              upd->yprinter += 1;
7041            }
7042          }
7043          upd->yprinter = upd->yscan;
7044          fwrite(upd->outbuf,1,ioutbuf,out);
7045          ioutbuf = 0;
7046       }                                 /* Adjust Y-Position */
7047 /*
7048  * Now write the all! components
7049  */
7050       for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
7051          data = scan[icomp].bytes;
7052          for(x = 0; x <= xend; ++x) if(data[x]) break;
7053          if(x <= xend) {
7054            ioutbuf = upd_rle(upd->outbuf,scan[icomp].bytes,xend);
7055            fprintf(out,
7056             (const char *)upd->string_a[SA_WRITECOMP].data[icomp].data,ioutbuf);
7057             fwrite(upd->outbuf,1,ioutbuf,out);
7058          } else {
7059            fprintf(out,
7060              (const char *)upd->string_a[SA_WRITECOMP].data[icomp].data,0);
7061          }
7062       }
7063 
7064       upd->yprinter += 1;
7065 
7066    }                    /* Some data to write */
7067 
7068 /** Advance scan by one */
7069 
7070    upd->yscan += 1;
7071 
7072    return 0;
7073 }
7074 
7075 /* ------------------------------------------------------------------- */
7076 /* upd_open_wrtcanon: Basic Canon Extended Mode Writer (hr)            */
7077 /* ------------------------------------------------------------------- */
7078 
7079 private int
upd_open_wrtcanon(upd_device * udev)7080 upd_open_wrtcanon(upd_device *udev)
7081 {
7082   const upd_p upd = udev->upd;
7083   int error = 0;
7084 
7085   /* max length of one printer line */
7086   upd->noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
7087   upd->writer  = upd_wrtcanon;
7088   error        = 1;
7089 
7090   return error;
7091 }
7092 
7093 /* ------------------------------------------------------------------- */
7094 /* upd_wrtcanon: Write a pass (hr)                                     */
7095 /* ------------------------------------------------------------------- */
7096 
7097 #define LOW(b)     ((b)&0xFF)
7098 #define HIGH(b)    ((b)>>8)
7099 #define ESC 0x1B
7100 #define CR  0x0D
7101 
7102 private int
upd_wrtcanon(upd_p upd,FILE * out)7103 upd_wrtcanon(upd_p upd, FILE *out)
7104 {
7105   const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
7106 
7107   int x, xend, icomp, ioutbuf, step, ioutbuf1;
7108   byte *data;
7109 
7110 
7111   /* Check length of the printable date */
7112   xend = -1;
7113   for(icomp = 0; icomp < upd->ocomp; ++icomp) {
7114     data = scan[icomp].bytes;
7115 
7116     for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
7117 
7118     if(x > xend) xend  = x;
7119   }
7120 
7121   /* If some date to print */
7122   if(0 <= xend) { /* Some data to write */
7123     ioutbuf = 0;
7124     xend   += 1;
7125 
7126     /* Perform vertical tab */
7127     if(upd->yscan != upd->yprinter) {
7128       step = upd->yscan - upd->yprinter;
7129 
7130       fputc(ESC,        out);
7131       fputc('(',        out);
7132       fputc('e',        out);
7133       fputc(2,          out);
7134       fputc(0,          out);
7135       fputc(HIGH(step), out);
7136       fputc(LOW(step),  out);
7137 
7138       upd->yprinter = upd->yscan;
7139     }
7140 
7141     for(icomp = 0; icomp < upd->ocomp; ++icomp) {
7142 
7143       /* Are there date to print for the selected color component */
7144       data = scan[icomp].bytes;
7145       for(x = 0; x <= xend; ++x) if(data[x]) break;
7146 
7147       /* Compressing of the scan line */
7148       if(x <= xend) {
7149 	ioutbuf = upd_rle(upd->outbuf, scan[icomp].bytes, xend);
7150       } else {
7151 	ioutbuf = 0;
7152       }
7153 
7154       ioutbuf1 = ioutbuf + 1;
7155 
7156       /* prints the scan line */
7157       fputc(ESC,            out);
7158       fputc('(',            out);
7159       fputc('A',            out);
7160       fputc(LOW(ioutbuf1),  out);
7161       fputc(HIGH(ioutbuf1), out);
7162       switch(upd->ocomp) {
7163         case 1:  fputc('K',out); break;
7164         case 3:
7165         case 4:  fputc("YMCK"[icomp],out); break;
7166 /*
7167  *      Please Note:
7168  *         the validity of the NCOMP-setting should be checked
7169  *         in the put_params-routine, thus the default-case is
7170  *         just a matter of coding-style.
7171  */
7172         default: fputc('K',out); break;
7173       }
7174 
7175       fwrite(upd->outbuf, 1, ioutbuf, out);
7176 
7177       fputc(CR,             out);
7178     }
7179 
7180     /* Printer advances one raster line */
7181     fputc(ESC,        out);
7182     fputc('(',        out);
7183     fputc('e',        out);
7184     fputc(2,          out);
7185     fputc(0,          out);
7186     fputc(HIGH(1),    out);
7187     fputc(LOW(1),     out);
7188 
7189     upd->yprinter += 1;
7190 
7191   }
7192 
7193   /* Advance scan by one */
7194   upd->yscan += 1;
7195 
7196   return 0;
7197 }
7198 
7199 
7200 
7201 /* ------------------------------------------------------------------- */
7202 /* All the Pixel-Get Routines                                          */
7203 /* ------------------------------------------------------------------- */
7204 
7205 /* That bunch of Pixel-Get Routines */
7206 
7207 private upd_proc_pxlget(upd_pxlgetnix); /* A Dummy */
7208 
7209 private upd_proc_pxlget(upd_pxlget1f1); /* 1 Bit Forward */
7210 private upd_proc_pxlget(upd_pxlget1f2);
7211 private upd_proc_pxlget(upd_pxlget1f3);
7212 private upd_proc_pxlget(upd_pxlget1f4);
7213 private upd_proc_pxlget(upd_pxlget1f5);
7214 private upd_proc_pxlget(upd_pxlget1f6);
7215 private upd_proc_pxlget(upd_pxlget1f7);
7216 private upd_proc_pxlget(upd_pxlget1f8);
7217 
7218 private upd_proc_pxlget(upd_pxlget1r1); /* 1 Bit Reverse */
7219 private upd_proc_pxlget(upd_pxlget1r2);
7220 private upd_proc_pxlget(upd_pxlget1r3);
7221 private upd_proc_pxlget(upd_pxlget1r4);
7222 private upd_proc_pxlget(upd_pxlget1r5);
7223 private upd_proc_pxlget(upd_pxlget1r6);
7224 private upd_proc_pxlget(upd_pxlget1r7);
7225 private upd_proc_pxlget(upd_pxlget1r8);
7226 
7227 private upd_proc_pxlget(upd_pxlget2f1); /* 2 Bit Forward */
7228 private upd_proc_pxlget(upd_pxlget2f2);
7229 private upd_proc_pxlget(upd_pxlget2f3);
7230 private upd_proc_pxlget(upd_pxlget2f4);
7231 
7232 private upd_proc_pxlget(upd_pxlget2r1); /* 2 Bit Reverse */
7233 private upd_proc_pxlget(upd_pxlget2r2);
7234 private upd_proc_pxlget(upd_pxlget2r3);
7235 private upd_proc_pxlget(upd_pxlget2r4);
7236 
7237 private upd_proc_pxlget(upd_pxlget4f1); /* 4 Bit Forward */
7238 private upd_proc_pxlget(upd_pxlget4f2);
7239 
7240 private upd_proc_pxlget(upd_pxlget4r1); /* 4 Bit Reverse */
7241 private upd_proc_pxlget(upd_pxlget4r2);
7242 
7243 private upd_proc_pxlget(upd_pxlget8f);  /* 8 Bit Forward */
7244 private upd_proc_pxlget(upd_pxlget8r);  /* 8 Bit Reverse */
7245 
7246 private upd_proc_pxlget(upd_pxlget16f); /* 16 Bit Forward */
7247 private upd_proc_pxlget(upd_pxlget16r); /* 16Bit Reverse */
7248 
7249 private upd_proc_pxlget(upd_pxlget24f); /* 24 Bit Forward */
7250 private upd_proc_pxlget(upd_pxlget24r); /* 24 Bit Reverse */
7251 
7252 private upd_proc_pxlget(upd_pxlget32f); /* 32 Bit Forward */
7253 private upd_proc_pxlget(upd_pxlget32r); /* 32 Bit Reverse */
7254 
7255 /* Initialize Forward-Run */
7256 
7257 private uint32_t
upd_pxlfwd(upd_p upd)7258 upd_pxlfwd(upd_p upd)
7259 {
7260    if(!(upd->pxlptr = upd->gsscan)) {
7261 
7262       upd->pxlget = upd_pxlgetnix;
7263 
7264    } else {
7265       switch(upd->int_a[IA_COLOR_INFO].data[1]) {
7266          case  1: upd->pxlget = upd_pxlget1f1; break;
7267          case  2: upd->pxlget = upd_pxlget2f1; break;
7268          case  4: upd->pxlget = upd_pxlget4f1; break;
7269          case  8: upd->pxlget = upd_pxlget8f;  break;
7270          case 16: upd->pxlget = upd_pxlget16f; break;
7271          case 24: upd->pxlget = upd_pxlget24f; break;
7272          case 32: upd->pxlget = upd_pxlget32f; break;
7273          default:
7274 #if UPD_MESSAGES & UPD_M_ERROR
7275            errprintf("upd_pxlfwd: unsupported depth (%d)\n",
7276               upd->int_a[IA_COLOR_INFO].data[1]);
7277 #endif
7278            upd->pxlget = upd_pxlgetnix;
7279            break;
7280       }
7281    }
7282    return (uint32_t) 0;
7283 }
7284 
7285 /* 1 Bit Forward */
7286 
7287 private uint32_t
upd_pxlget1f1(upd_p upd)7288 upd_pxlget1f1(upd_p upd)
7289 {
7290    upd->pxlget = upd_pxlget1f2;
7291    return *upd->pxlptr   & 0x80 ? (uint32_t) 1 : (uint32_t) 0;
7292 }
7293 
7294 private uint32_t
upd_pxlget1f2(upd_p upd)7295 upd_pxlget1f2(upd_p upd)
7296 {
7297    upd->pxlget = upd_pxlget1f3;
7298    return *upd->pxlptr   & 0x40 ? (uint32_t) 1 : (uint32_t) 0;
7299 }
7300 
7301 private uint32_t
upd_pxlget1f3(upd_p upd)7302 upd_pxlget1f3(upd_p upd)
7303 {
7304    upd->pxlget = upd_pxlget1f4;
7305    return *upd->pxlptr   & 0x20 ? (uint32_t) 1 : (uint32_t) 0;
7306 }
7307 
7308 private uint32_t
upd_pxlget1f4(upd_p upd)7309 upd_pxlget1f4(upd_p upd)
7310 {
7311    upd->pxlget = upd_pxlget1f5;
7312    return *upd->pxlptr   & 0x10 ? (uint32_t) 1 : (uint32_t) 0;
7313 }
7314 
7315 private uint32_t
upd_pxlget1f5(upd_p upd)7316 upd_pxlget1f5(upd_p upd)
7317 {
7318    upd->pxlget = upd_pxlget1f6;
7319    return *upd->pxlptr   & 0x08 ? (uint32_t) 1 : (uint32_t) 0;
7320 }
7321 
7322 private uint32_t
upd_pxlget1f6(upd_p upd)7323 upd_pxlget1f6(upd_p upd)
7324 {
7325    upd->pxlget = upd_pxlget1f7;
7326    return *upd->pxlptr   & 0x04 ? (uint32_t) 1 : (uint32_t) 0;
7327 }
7328 
7329 private uint32_t
upd_pxlget1f7(upd_p upd)7330 upd_pxlget1f7(upd_p upd)
7331 {
7332    upd->pxlget = upd_pxlget1f8;
7333    return *upd->pxlptr   & 0x02 ? (uint32_t) 1 : (uint32_t) 0;
7334 }
7335 
7336 private uint32_t
upd_pxlget1f8(upd_p upd)7337 upd_pxlget1f8(upd_p upd)
7338 {
7339    upd->pxlget = upd_pxlget1f1;
7340    return *upd->pxlptr++ & 0x01 ? (uint32_t) 1 : (uint32_t) 0;
7341 }
7342 
7343 /* 2 Bit Forward */
7344 
7345 private uint32_t
upd_pxlget2f1(upd_p upd)7346 upd_pxlget2f1(upd_p upd)
7347 {
7348    upd->pxlget = upd_pxlget2f2;
7349    return ((uint32_t) (*upd->pxlptr  ) & (uint32_t) 0xC0) >> 6;
7350 }
7351 
7352 private uint32_t
upd_pxlget2f2(upd_p upd)7353 upd_pxlget2f2(upd_p upd)
7354 {
7355    upd->pxlget = upd_pxlget2f3;
7356    return ((uint32_t) (*upd->pxlptr  ) & (uint32_t) 0x30) >> 4;
7357 }
7358 
7359 private uint32_t
upd_pxlget2f3(upd_p upd)7360 upd_pxlget2f3(upd_p upd)
7361 {
7362    upd->pxlget = upd_pxlget2f4;
7363    return ((uint32_t) (*upd->pxlptr  ) & (uint32_t) 0x0C) >> 2;
7364 }
7365 
7366 private uint32_t
upd_pxlget2f4(upd_p upd)7367 upd_pxlget2f4(upd_p upd)
7368 {
7369    upd->pxlget = upd_pxlget2f1;
7370    return  (uint32_t) (*upd->pxlptr++) & (uint32_t) 0x03;
7371 }
7372 
7373 
7374 /* 4 Bit Forward */
7375 private uint32_t
upd_pxlget4f1(upd_p upd)7376 upd_pxlget4f1(upd_p upd)
7377 {
7378    upd->pxlget = upd_pxlget4f2;
7379    return ((uint32_t) (*upd->pxlptr  ) & (uint32_t) 0xF0) >> 4;
7380 }
7381 
7382 private uint32_t
upd_pxlget4f2(upd_p upd)7383 upd_pxlget4f2(upd_p upd)
7384 {
7385    upd->pxlget = upd_pxlget4f1;
7386    return  (uint32_t) (*upd->pxlptr++) & (uint32_t) 0x0F;
7387 }
7388 
7389 
7390 /* 8 Bit Forward */
7391 private uint32_t
upd_pxlget8f(upd_p upd)7392 upd_pxlget8f(upd_p upd)
7393 {
7394    return (uint32_t) (*upd->pxlptr++);
7395 }
7396 
7397 
7398 /* 16 Bit Forward */
7399 private uint32_t
upd_pxlget16f(upd_p upd)7400 upd_pxlget16f(upd_p upd)
7401 {
7402    uint32_t ci  = (uint32_t) (*upd->pxlptr++) << 8;
7403                   ci |=                   *upd->pxlptr++;
7404    return         ci;
7405 }
7406 
7407 /* 24 Bit Forward */
7408 private uint32_t
upd_pxlget24f(upd_p upd)7409 upd_pxlget24f(upd_p upd)
7410 {
7411    uint32_t ci  = (uint32_t) (*upd->pxlptr++) << 16;
7412           ci |= (uint32_t) (*upd->pxlptr++) <<  8;
7413           ci |=           *upd->pxlptr++;
7414    return ci;
7415 }
7416 
7417 /* 32 Bit Forward */
7418 private uint32_t
upd_pxlget32f(upd_p upd)7419 upd_pxlget32f(upd_p upd)
7420 {
7421    uint32_t ci  = (uint32_t) (*upd->pxlptr++) << 24;
7422                   ci |= (uint32_t) (*upd->pxlptr++) << 16;
7423                   ci |= (uint32_t) (*upd->pxlptr++) <<  8;
7424                   ci |=                   *upd->pxlptr++;
7425    return         ci;
7426 }
7427 
7428 
7429 /* Dummy-Routine */
7430 
7431 private uint32_t
upd_pxlgetnix(upd_p upd)7432 upd_pxlgetnix(upd_p upd)
7433 {
7434    return (uint32_t) 0;
7435 }
7436 
7437 /* Initialize Reverse-Run */
7438 
7439 private uint32_t
upd_pxlrev(upd_p upd)7440 upd_pxlrev(upd_p upd)
7441 {
7442    const uint width = upd->pwidth < upd->gswidth ? upd->pwidth : upd->gswidth;
7443 
7444    if(!(upd->pxlptr = upd->gsscan)) {
7445 
7446       upd->pxlget = upd_pxlgetnix;
7447 
7448    } else {
7449       uint32_t ofs = (uint32_t) upd->int_a[IA_COLOR_INFO].data[1] * (width-1);
7450 
7451       upd->pxlptr += ofs>>3;
7452 
7453       ofs &= 7;
7454 
7455       switch(upd->int_a[IA_COLOR_INFO].data[1]) {
7456          case  1: switch(ofs) {
7457                case 0:  upd->pxlget = upd_pxlget1r1; break;
7458                case 1:  upd->pxlget = upd_pxlget1r2; break;
7459                case 2:  upd->pxlget = upd_pxlget1r3; break;
7460                case 3:  upd->pxlget = upd_pxlget1r4; break;
7461                case 4:  upd->pxlget = upd_pxlget1r5; break;
7462                case 5:  upd->pxlget = upd_pxlget1r6; break;
7463                case 6:  upd->pxlget = upd_pxlget1r7; break;
7464                case 7:  upd->pxlget = upd_pxlget1r8; break;
7465             } break;
7466          case  2: switch(ofs) {
7467                case 0:  upd->pxlget = upd_pxlget2r1; break;
7468                case 2:  upd->pxlget = upd_pxlget2r2; break;
7469                case 4:  upd->pxlget = upd_pxlget2r3; break;
7470                case 6:  upd->pxlget = upd_pxlget2r4; break;
7471             } break;
7472          case  4: switch(ofs) {
7473                case 0:  upd->pxlget = upd_pxlget4r1; break;
7474                case 4:  upd->pxlget = upd_pxlget4r2; break;
7475             } break;
7476          case  8: upd->pxlget = upd_pxlget8r;  break;
7477          case 16:
7478             upd->pxlget  = upd_pxlget16r;
7479             upd->pxlptr += 1;
7480             break;
7481          case 24:
7482             upd->pxlget = upd_pxlget24r;
7483             upd->pxlptr += 2;
7484             break;
7485          case 32:
7486             upd->pxlget = upd_pxlget32r;
7487             upd->pxlptr += 3;
7488             break;
7489          default:
7490 #if UPD_MESSAGES & UPD_M_ERROR
7491            errprintf("upd_pxlrev: unsupported depth (%d)\n",
7492               upd->int_a[IA_COLOR_INFO].data[1]);
7493 #endif
7494            upd->pxlget = upd_pxlgetnix;
7495            break;
7496       }
7497    }
7498    return (uint32_t) 0;
7499 }
7500 
7501 /* 1 Bit Reverse */
7502 
7503 private uint32_t
upd_pxlget1r1(upd_p upd)7504 upd_pxlget1r1(upd_p upd)
7505 {
7506    upd->pxlget = upd_pxlget1r8;
7507    return *upd->pxlptr-- & 0x80 ? (uint32_t) 1 : (uint32_t) 0;
7508 }
7509 
7510 private uint32_t
upd_pxlget1r2(upd_p upd)7511 upd_pxlget1r2(upd_p upd)
7512 {
7513    upd->pxlget = upd_pxlget1r1;
7514    return *upd->pxlptr   & 0x40 ? (uint32_t) 1 : (uint32_t) 0;
7515 }
7516 
7517 private uint32_t
upd_pxlget1r3(upd_p upd)7518 upd_pxlget1r3(upd_p upd)
7519 {
7520    upd->pxlget = upd_pxlget1r2;
7521    return *upd->pxlptr   & 0x20 ? (uint32_t) 1 : (uint32_t) 0;
7522 }
7523 
7524 private uint32_t
upd_pxlget1r4(upd_p upd)7525 upd_pxlget1r4(upd_p upd)
7526 {
7527    upd->pxlget = upd_pxlget1r3;
7528    return *upd->pxlptr   & 0x10 ? (uint32_t) 1 : (uint32_t) 0;
7529 }
7530 
7531 private uint32_t
upd_pxlget1r5(upd_p upd)7532 upd_pxlget1r5(upd_p upd)
7533 {
7534    upd->pxlget = upd_pxlget1r4;
7535    return *upd->pxlptr   & 0x08 ? (uint32_t) 1 : (uint32_t) 0;
7536 }
7537 
7538 private uint32_t
upd_pxlget1r6(upd_p upd)7539 upd_pxlget1r6(upd_p upd)
7540 {
7541    upd->pxlget = upd_pxlget1r5;
7542    return *upd->pxlptr   & 0x04 ? (uint32_t) 1 : (uint32_t) 0;
7543 }
7544 
7545 private uint32_t
upd_pxlget1r7(upd_p upd)7546 upd_pxlget1r7(upd_p upd)
7547 {
7548    upd->pxlget = upd_pxlget1r6;
7549    return *upd->pxlptr   & 0x02 ? (uint32_t) 1 : (uint32_t) 0;
7550 }
7551 
7552 private uint32_t
upd_pxlget1r8(upd_p upd)7553 upd_pxlget1r8(upd_p upd)
7554 {
7555    upd->pxlget = upd_pxlget1r7;
7556    return *upd->pxlptr   & 0x01 ? (uint32_t) 1 : (uint32_t) 0;
7557 }
7558 
7559 /* 2 Bit Reverse */
7560 
7561 private uint32_t
upd_pxlget2r1(upd_p upd)7562 upd_pxlget2r1(upd_p upd)
7563 {
7564    upd->pxlget = upd_pxlget2r4;
7565    return ((uint32_t) (*upd->pxlptr--) & (uint32_t) 0xC0) >> 6;
7566 }
7567 
7568 private uint32_t
upd_pxlget2r2(upd_p upd)7569 upd_pxlget2r2(upd_p upd)
7570 {
7571    upd->pxlget = upd_pxlget2r1;
7572    return ((uint32_t) (*upd->pxlptr  ) & (uint32_t) 0x30) >> 4;
7573 }
7574 
7575 private uint32_t
upd_pxlget2r3(upd_p upd)7576 upd_pxlget2r3(upd_p upd)
7577 {
7578    upd->pxlget = upd_pxlget2r2;
7579    return ((uint32_t) (*upd->pxlptr  ) & (uint32_t) 0x0C) >> 2;
7580 }
7581 
7582 private uint32_t
upd_pxlget2r4(upd_p upd)7583 upd_pxlget2r4(upd_p upd)
7584 {
7585    upd->pxlget = upd_pxlget2r3;
7586    return  (uint32_t) (*upd->pxlptr  ) & (uint32_t) 0x03;
7587 }
7588 
7589 /* 4 Bit Reverse */
7590 
7591 private uint32_t
upd_pxlget4r1(upd_p upd)7592 upd_pxlget4r1(upd_p upd)
7593 {
7594    upd->pxlget = upd_pxlget4r2;
7595    return ((uint32_t) (*upd->pxlptr--) & (uint32_t) 0xF0) >> 4;
7596 }
7597 
7598 private uint32_t
upd_pxlget4r2(upd_p upd)7599 upd_pxlget4r2(upd_p upd)
7600 {
7601    upd->pxlget = upd_pxlget4r1;
7602    return  (uint32_t) (*upd->pxlptr  ) & (uint32_t) 0x0F;
7603 }
7604 
7605 
7606 /* 8 Bit Reverse */
7607 private uint32_t
upd_pxlget8r(upd_p upd)7608 upd_pxlget8r(upd_p upd)
7609 {
7610    return (uint32_t) (*upd->pxlptr--);
7611 }
7612 
7613 
7614 /* 16 Bit Reverse */
7615 private uint32_t
upd_pxlget16r(upd_p upd)7616 upd_pxlget16r(upd_p upd)
7617 {
7618    uint32_t ci  =                   *upd->pxlptr--;
7619                   ci |= (uint32_t) (*upd->pxlptr--) << 8;
7620    return         ci;
7621 }
7622 
7623 /* 24 Bit Reverse */
7624 private uint32_t
upd_pxlget24r(upd_p upd)7625 upd_pxlget24r(upd_p upd)
7626 {
7627    uint32_t ci  =           *upd->pxlptr--;
7628           ci |= (uint32_t) (*upd->pxlptr--) <<  8;
7629           ci |= (uint32_t) (*upd->pxlptr--) << 16;
7630    return ci;
7631 }
7632 
7633 /* 32 Bit Reverse */
7634 private uint32_t
upd_pxlget32r(upd_p upd)7635 upd_pxlget32r(upd_p upd)
7636 {
7637    uint32_t ci  =                   *upd->pxlptr--;
7638                   ci |= (uint32_t) (*upd->pxlptr--) <<  8;
7639                   ci |= (uint32_t) (*upd->pxlptr--) << 16;
7640                   ci |= (uint32_t) (*upd->pxlptr--) << 24;
7641    return         ci;
7642 }
7643