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