]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/raster.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / filter / raster.c
1 /*
2 * Raster file routines for CUPS.
3 *
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
6 *
7 * This file is part of the CUPS Imaging library.
8 *
9 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
10 */
11
12 /*
13 * Include necessary headers...
14 */
15
16 #include <cups/raster-private.h>
17 #ifdef HAVE_STDINT_H
18 # include <stdint.h>
19 #endif /* HAVE_STDINT_H */
20
21
22 /*
23 * Private structures...
24 */
25
26 struct _cups_raster_s /**** Raster stream data ****/
27 {
28 unsigned sync; /* Sync word from start of stream */
29 void *ctx; /* File descriptor */
30 cups_raster_iocb_t iocb; /* IO callback */
31 cups_mode_t mode; /* Read/write mode */
32 cups_page_header2_t header; /* Raster header for current page */
33 unsigned rowheight, /* Row height in lines */
34 count, /* Current row run-length count */
35 remaining, /* Remaining rows in page image */
36 bpp; /* Bytes per pixel/color */
37 unsigned char *pixels, /* Pixels for current row */
38 *pend, /* End of pixel buffer */
39 *pcurrent; /* Current byte in pixel buffer */
40 int compressed, /* Non-zero if data is compressed */
41 swapped; /* Non-zero if data is byte-swapped */
42 unsigned char *buffer, /* Read/write buffer */
43 *bufptr, /* Current (read) position in buffer */
44 *bufend; /* End of current (read) buffer */
45 size_t bufsize; /* Buffer size */
46 #ifdef DEBUG
47 size_t iocount; /* Number of bytes read/written */
48 #endif /* DEBUG */
49 unsigned apple_page_count;/* Apple raster page count */
50 };
51
52
53 /*
54 * Local functions...
55 */
56
57 static ssize_t cups_raster_io(cups_raster_t *r, unsigned char *buf, size_t bytes);
58 static unsigned cups_raster_read_header(cups_raster_t *r);
59 static ssize_t cups_raster_read(cups_raster_t *r, unsigned char *buf,
60 size_t bytes);
61 static int cups_raster_update(cups_raster_t *r);
62 static ssize_t cups_raster_write(cups_raster_t *r,
63 const unsigned char *pixels);
64 static ssize_t cups_read_fd(void *ctx, unsigned char *buf, size_t bytes);
65 static void cups_swap(unsigned char *buf, size_t bytes);
66 static ssize_t cups_write_fd(void *ctx, unsigned char *buf, size_t bytes);
67
68
69 /*
70 * 'cupsRasterClose()' - Close a raster stream.
71 *
72 * The file descriptor associated with the raster stream must be closed
73 * separately as needed.
74 */
75
76 void
77 cupsRasterClose(cups_raster_t *r) /* I - Stream to close */
78 {
79 if (r != NULL)
80 {
81 if (r->buffer)
82 free(r->buffer);
83
84 if (r->pixels)
85 free(r->pixels);
86
87 free(r);
88 }
89 }
90
91
92 /*
93 * 'cupsRasterInitPWGHeader()' - Initialize a page header for PWG Raster output.
94 *
95 * The "media" argument specifies the media to use.
96 *
97 * The "type" argument specifies a "pwg-raster-document-type-supported" value
98 * that controls the color space and bit depth of the raster data.
99 *
100 * The "xres" and "yres" arguments specify the raster resolution in dots per
101 * inch.
102 *
103 * The "sheet_back" argument specifies a "pwg-raster-document-sheet-back" value
104 * to apply for the back side of a page. Pass @code NULL@ for the front side.
105 *
106 * @since CUPS 2.2/macOS 10.12@
107 */
108
109 int /* O - 1 on success, 0 on failure */
110 cupsRasterInitPWGHeader(
111 cups_page_header2_t *h, /* I - Page header */
112 pwg_media_t *media, /* I - PWG media information */
113 const char *type, /* I - PWG raster type string */
114 int xdpi, /* I - Cross-feed direction (horizontal) resolution */
115 int ydpi, /* I - Feed direction (vertical) resolution */
116 const char *sides, /* I - IPP "sides" option value */
117 const char *sheet_back) /* I - Transform for back side or @code NULL@ for none */
118 {
119 if (!h || !media || !type || xdpi <= 0 || ydpi <= 0)
120 {
121 _cupsRasterAddError("%s", strerror(EINVAL));
122 return (0);
123 }
124
125 /*
126 * Initialize the page header...
127 */
128
129 memset(h, 0, sizeof(cups_page_header2_t));
130
131 strlcpy(h->cupsPageSizeName, media->pwg, sizeof(h->cupsPageSizeName));
132
133 h->PageSize[0] = (unsigned)(72 * media->width / 2540);
134 h->PageSize[1] = (unsigned)(72 * media->length / 2540);
135
136 /* This never gets written but is needed for some applications */
137 h->cupsPageSize[0] = 72.0f * media->width / 2540.0f;
138 h->cupsPageSize[1] = 72.0f * media->length / 2540.0f;
139
140 h->ImagingBoundingBox[2] = h->PageSize[0];
141 h->ImagingBoundingBox[3] = h->PageSize[1];
142
143 h->HWResolution[0] = (unsigned)xdpi;
144 h->HWResolution[1] = (unsigned)ydpi;
145
146 h->cupsWidth = (unsigned)(media->width * xdpi / 2540);
147 h->cupsHeight = (unsigned)(media->length * ydpi / 2540);
148
149 if (h->cupsWidth > 0x00ffffff || h->cupsHeight > 0x00ffffff)
150 {
151 _cupsRasterAddError("Raster dimensions too large.");
152 return (0);
153 }
154
155 h->cupsInteger[CUPS_RASTER_PWG_ImageBoxRight] = h->cupsWidth;
156 h->cupsInteger[CUPS_RASTER_PWG_ImageBoxBottom] = h->cupsHeight;
157
158 /*
159 * Colorspace and bytes per line...
160 */
161
162 if (!strcmp(type, "adobe-rgb_8"))
163 {
164 h->cupsBitsPerColor = 8;
165 h->cupsBitsPerPixel = 24;
166 h->cupsColorSpace = CUPS_CSPACE_ADOBERGB;
167 }
168 else if (!strcmp(type, "adobe-rgb_16"))
169 {
170 h->cupsBitsPerColor = 16;
171 h->cupsBitsPerPixel = 48;
172 h->cupsColorSpace = CUPS_CSPACE_ADOBERGB;
173 }
174 else if (!strcmp(type, "black_1"))
175 {
176 h->cupsBitsPerColor = 1;
177 h->cupsBitsPerPixel = 1;
178 h->cupsColorSpace = CUPS_CSPACE_K;
179 }
180 else if (!strcmp(type, "black_8"))
181 {
182 h->cupsBitsPerColor = 8;
183 h->cupsBitsPerPixel = 8;
184 h->cupsColorSpace = CUPS_CSPACE_K;
185 }
186 else if (!strcmp(type, "black_16"))
187 {
188 h->cupsBitsPerColor = 16;
189 h->cupsBitsPerPixel = 16;
190 h->cupsColorSpace = CUPS_CSPACE_K;
191 }
192 else if (!strcmp(type, "cmyk_8"))
193 {
194 h->cupsBitsPerColor = 8;
195 h->cupsBitsPerPixel = 32;
196 h->cupsColorSpace = CUPS_CSPACE_CMYK;
197 }
198 else if (!strcmp(type, "cmyk_16"))
199 {
200 h->cupsBitsPerColor = 16;
201 h->cupsBitsPerPixel = 64;
202 h->cupsColorSpace = CUPS_CSPACE_CMYK;
203 }
204 else if (!strncmp(type, "device", 6) && type[6] >= '1' && type[6] <= '9')
205 {
206 int ncolors, bits; /* Number of colors and bits */
207
208
209 if (sscanf(type, "device%d_%d", &ncolors, &bits) != 2 || ncolors > 15 || (bits != 8 && bits != 16))
210 {
211 _cupsRasterAddError("Unsupported raster type \'%s\'.", type);
212 return (0);
213 }
214
215 h->cupsBitsPerColor = (unsigned)bits;
216 h->cupsBitsPerPixel = (unsigned)(ncolors * bits);
217 h->cupsColorSpace = (cups_cspace_t)(CUPS_CSPACE_DEVICE1 + ncolors - 1);
218 }
219 else if (!strcmp(type, "rgb_8"))
220 {
221 h->cupsBitsPerColor = 8;
222 h->cupsBitsPerPixel = 24;
223 h->cupsColorSpace = CUPS_CSPACE_RGB;
224 }
225 else if (!strcmp(type, "rgb_16"))
226 {
227 h->cupsBitsPerColor = 16;
228 h->cupsBitsPerPixel = 48;
229 h->cupsColorSpace = CUPS_CSPACE_RGB;
230 }
231 else if (!strcmp(type, "sgray_1"))
232 {
233 h->cupsBitsPerColor = 1;
234 h->cupsBitsPerPixel = 1;
235 h->cupsColorSpace = CUPS_CSPACE_SW;
236 }
237 else if (!strcmp(type, "sgray_8"))
238 {
239 h->cupsBitsPerColor = 8;
240 h->cupsBitsPerPixel = 8;
241 h->cupsColorSpace = CUPS_CSPACE_SW;
242 }
243 else if (!strcmp(type, "sgray_16"))
244 {
245 h->cupsBitsPerColor = 16;
246 h->cupsBitsPerPixel = 16;
247 h->cupsColorSpace = CUPS_CSPACE_SW;
248 }
249 else if (!strcmp(type, "srgb_8"))
250 {
251 h->cupsBitsPerColor = 8;
252 h->cupsBitsPerPixel = 24;
253 h->cupsColorSpace = CUPS_CSPACE_SRGB;
254 }
255 else if (!strcmp(type, "srgb_16"))
256 {
257 h->cupsBitsPerColor = 16;
258 h->cupsBitsPerPixel = 48;
259 h->cupsColorSpace = CUPS_CSPACE_SRGB;
260 }
261 else
262 {
263 _cupsRasterAddError("Unsupported raster type \'%s\'.", type);
264 return (0);
265 }
266
267 h->cupsColorOrder = CUPS_ORDER_CHUNKED;
268 h->cupsNumColors = h->cupsBitsPerPixel / h->cupsBitsPerColor;
269 h->cupsBytesPerLine = (h->cupsWidth * h->cupsBitsPerPixel + 7) / 8;
270
271 /*
272 * Duplex support...
273 */
274
275 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 1;
276 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 1;
277
278 if (sides)
279 {
280 if (!strcmp(sides, "two-sided-long-edge"))
281 {
282 h->Duplex = 1;
283 }
284 else if (!strcmp(sides, "two-sided-short-edge"))
285 {
286 h->Duplex = 1;
287 h->Tumble = 1;
288 }
289 else if (strcmp(sides, "one-sided"))
290 {
291 _cupsRasterAddError("Unsupported sides value \'%s\'.", sides);
292 return (0);
293 }
294
295 if (sheet_back)
296 {
297 if (!strcmp(sheet_back, "flipped"))
298 {
299 if (h->Tumble)
300 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU;
301 else
302 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU;
303 }
304 else if (!strcmp(sheet_back, "manual-tumble"))
305 {
306 if (h->Tumble)
307 {
308 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU;
309 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU;
310 }
311 }
312 else if (!strcmp(sheet_back, "rotated"))
313 {
314 if (!h->Tumble)
315 {
316 h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU;
317 h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU;
318 }
319 }
320 else if (strcmp(sheet_back, "normal"))
321 {
322 _cupsRasterAddError("Unsupported sheet_back value \'%s\'.", sheet_back);
323 return (0);
324 }
325 }
326 }
327
328 return (1);
329 }
330
331
332 /*
333 * 'cupsRasterOpen()' - Open a raster stream using a file descriptor.
334 *
335 * This function associates a raster stream with the given file descriptor.
336 * For most printer driver filters, "fd" will be 0 (stdin). For most raster
337 * image processor (RIP) filters that generate raster data, "fd" will be 1
338 * (stdout).
339 *
340 * When writing raster data, the @code CUPS_RASTER_WRITE@,
341 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
342 * be used - compressed and PWG output is generally 25-50% smaller but adds a
343 * 100-300% execution time overhead.
344 */
345
346 cups_raster_t * /* O - New stream */
347 cupsRasterOpen(int fd, /* I - File descriptor */
348 cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
349 @code CUPS_RASTER_WRITE@,
350 @code CUPS_RASTER_WRITE_COMPRESSED@,
351 or @code CUPS_RASTER_WRITE_PWG@ */
352 {
353 if (mode == CUPS_RASTER_READ)
354 return (cupsRasterOpenIO(cups_read_fd, (void *)((intptr_t)fd), mode));
355 else
356 return (cupsRasterOpenIO(cups_write_fd, (void *)((intptr_t)fd), mode));
357 }
358
359
360 /*
361 * 'cupsRasterOpenIO()' - Open a raster stream using a callback function.
362 *
363 * This function associates a raster stream with the given callback function and
364 * context pointer.
365 *
366 * When writing raster data, the @code CUPS_RASTER_WRITE@,
367 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
368 * be used - compressed and PWG output is generally 25-50% smaller but adds a
369 * 100-300% execution time overhead.
370 */
371
372 cups_raster_t * /* O - New stream */
373 cupsRasterOpenIO(
374 cups_raster_iocb_t iocb, /* I - Read/write callback */
375 void *ctx, /* I - Context pointer for callback */
376 cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
377 @code CUPS_RASTER_WRITE@,
378 @code CUPS_RASTER_WRITE_COMPRESSED@,
379 or @code CUPS_RASTER_WRITE_PWG@ */
380 {
381 cups_raster_t *r; /* New stream */
382
383
384 _cupsRasterClearError();
385
386 if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL)
387 {
388 _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n",
389 strerror(errno));
390 return (NULL);
391 }
392
393 r->ctx = ctx;
394 r->iocb = iocb;
395 r->mode = mode;
396
397 if (mode == CUPS_RASTER_READ)
398 {
399 /*
400 * Open for read - get sync word...
401 */
402
403 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) !=
404 sizeof(r->sync))
405 {
406 _cupsRasterAddError("Unable to read header from raster stream: %s\n",
407 strerror(errno));
408 free(r);
409 return (NULL);
410 }
411
412 if (r->sync != CUPS_RASTER_SYNC &&
413 r->sync != CUPS_RASTER_REVSYNC &&
414 r->sync != CUPS_RASTER_SYNCv1 &&
415 r->sync != CUPS_RASTER_REVSYNCv1 &&
416 r->sync != CUPS_RASTER_SYNCv2 &&
417 r->sync != CUPS_RASTER_REVSYNCv2 &&
418 r->sync != CUPS_RASTER_SYNCapple &&
419 r->sync != CUPS_RASTER_REVSYNCapple)
420 {
421 _cupsRasterAddError("Unknown raster format %08x!\n", r->sync);
422 free(r);
423 return (NULL);
424 }
425
426 if (r->sync == CUPS_RASTER_SYNCv2 ||
427 r->sync == CUPS_RASTER_REVSYNCv2 ||
428 r->sync == CUPS_RASTER_SYNCapple ||
429 r->sync == CUPS_RASTER_REVSYNCapple)
430 r->compressed = 1;
431
432 if (r->sync == CUPS_RASTER_REVSYNC ||
433 r->sync == CUPS_RASTER_REVSYNCv1 ||
434 r->sync == CUPS_RASTER_REVSYNCv2 ||
435 r->sync == CUPS_RASTER_REVSYNCapple)
436 r->swapped = 1;
437
438 if (r->sync == CUPS_RASTER_SYNCapple ||
439 r->sync == CUPS_RASTER_REVSYNCapple)
440 {
441 unsigned char header[8]; /* File header */
442
443 if (cups_raster_io(r, (unsigned char *)header, sizeof(header)) !=
444 sizeof(header))
445 {
446 _cupsRasterAddError("Unable to read header from raster stream: %s\n",
447 strerror(errno));
448 free(r);
449 return (NULL);
450 }
451
452 }
453
454 DEBUG_printf(("1cupsRasterOpenIO: r->swapped=%d, r->sync=%08x\n", r->swapped, r->sync));
455 }
456 else
457 {
458 /*
459 * Open for write - put sync word...
460 */
461
462 switch (mode)
463 {
464 default :
465 case CUPS_RASTER_WRITE :
466 r->sync = CUPS_RASTER_SYNC;
467 break;
468
469 case CUPS_RASTER_WRITE_COMPRESSED :
470 r->compressed = 1;
471 r->sync = CUPS_RASTER_SYNCv2;
472 break;
473
474 case CUPS_RASTER_WRITE_PWG :
475 r->compressed = 1;
476 r->sync = htonl(CUPS_RASTER_SYNC_PWG);
477 r->swapped = r->sync != CUPS_RASTER_SYNC_PWG;
478 break;
479
480 case CUPS_RASTER_WRITE_APPLE :
481 r->compressed = 1;
482 r->sync = htonl(CUPS_RASTER_SYNCapple);
483 r->swapped = r->sync != CUPS_RASTER_SYNCapple;
484 r->apple_page_count = 0xffffffffU;
485 break;
486 }
487
488 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) < (ssize_t)sizeof(r->sync))
489 {
490 _cupsRasterAddError("Unable to write raster stream header: %s\n",
491 strerror(errno));
492 free(r);
493 return (NULL);
494 }
495 }
496
497 return (r);
498 }
499
500
501 /*
502 * 'cupsRasterReadHeader()' - Read a raster page header and store it in a
503 * version 1 page header structure.
504 *
505 * This function is deprecated. Use @link cupsRasterReadHeader2@ instead.
506 *
507 * Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset
508 * of the version 2 page header data. This function handles reading version 2
509 * page headers and copying only the version 1 data into the provided buffer.
510 *
511 * @deprecated@
512 */
513
514 unsigned /* O - 1 on success, 0 on failure/end-of-file */
515 cupsRasterReadHeader(
516 cups_raster_t *r, /* I - Raster stream */
517 cups_page_header_t *h) /* I - Pointer to header data */
518 {
519 /*
520 * Get the raster header...
521 */
522
523 if (!cups_raster_read_header(r))
524 {
525 memset(h, 0, sizeof(cups_page_header_t));
526 return (0);
527 }
528
529 /*
530 * Copy the header to the user-supplied buffer...
531 */
532
533 memcpy(h, &(r->header), sizeof(cups_page_header_t));
534
535 return (1);
536 }
537
538
539 /*
540 * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a
541 * version 2 page header structure.
542 *
543 * @since CUPS 1.2/macOS 10.5@
544 */
545
546 unsigned /* O - 1 on success, 0 on failure/end-of-file */
547 cupsRasterReadHeader2(
548 cups_raster_t *r, /* I - Raster stream */
549 cups_page_header2_t *h) /* I - Pointer to header data */
550 {
551 /*
552 * Get the raster header...
553 */
554
555 DEBUG_printf(("cupsRasterReadHeader2(r=%p, h=%p)", (void *)r, (void *)h));
556
557 if (!cups_raster_read_header(r))
558 {
559 memset(h, 0, sizeof(cups_page_header2_t));
560 return (0);
561 }
562
563 /*
564 * Copy the header to the user-supplied buffer...
565 */
566
567 memcpy(h, &(r->header), sizeof(cups_page_header2_t));
568
569 return (1);
570 }
571
572
573 /*
574 * 'cupsRasterReadPixels()' - Read raster pixels.
575 *
576 * For best performance, filters should read one or more whole lines.
577 * The "cupsBytesPerLine" value from the page header can be used to allocate
578 * the line buffer and as the number of bytes to read.
579 */
580
581 unsigned /* O - Number of bytes read */
582 cupsRasterReadPixels(cups_raster_t *r, /* I - Raster stream */
583 unsigned char *p, /* I - Pointer to pixel buffer */
584 unsigned len) /* I - Number of bytes to read */
585 {
586 ssize_t bytes; /* Bytes read */
587 unsigned cupsBytesPerLine; /* cupsBytesPerLine value */
588 unsigned remaining; /* Bytes remaining */
589 unsigned char *ptr, /* Pointer to read buffer */
590 byte, /* Byte from file */
591 *temp; /* Pointer into buffer */
592 unsigned count; /* Repetition count */
593
594
595 DEBUG_printf(("cupsRasterReadPixels(r=%p, p=%p, len=%u)", (void *)r, (void *)p, len));
596
597 if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0 ||
598 r->header.cupsBytesPerLine == 0)
599 {
600 DEBUG_puts("1cupsRasterReadPixels: Returning 0.");
601 return (0);
602 }
603
604 DEBUG_printf(("1cupsRasterReadPixels: compressed=%d, remaining=%u", r->compressed, r->remaining));
605
606 if (!r->compressed)
607 {
608 /*
609 * Read without compression...
610 */
611
612 r->remaining -= len / r->header.cupsBytesPerLine;
613
614 if (cups_raster_io(r, p, len) < (ssize_t)len)
615 {
616 DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0.");
617 return (0);
618 }
619
620 /*
621 * Swap bytes as needed...
622 */
623
624 if (r->swapped &&
625 (r->header.cupsBitsPerColor == 16 ||
626 r->header.cupsBitsPerPixel == 12 ||
627 r->header.cupsBitsPerPixel == 16))
628 cups_swap(p, len);
629
630 /*
631 * Return...
632 */
633
634 DEBUG_printf(("1cupsRasterReadPixels: Returning %u", len));
635
636 return (len);
637 }
638
639 /*
640 * Read compressed data...
641 */
642
643 remaining = len;
644 cupsBytesPerLine = r->header.cupsBytesPerLine;
645
646 while (remaining > 0 && r->remaining > 0)
647 {
648 if (r->count == 0)
649 {
650 /*
651 * Need to read a new row...
652 */
653
654 if (remaining == cupsBytesPerLine)
655 ptr = p;
656 else
657 ptr = r->pixels;
658
659 /*
660 * Read using a modified PackBits compression...
661 */
662
663 if (!cups_raster_read(r, &byte, 1))
664 {
665 DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0.");
666 return (0);
667 }
668
669 r->count = (unsigned)byte + 1;
670
671 if (r->count > 1)
672 ptr = r->pixels;
673
674 temp = ptr;
675 bytes = (ssize_t)cupsBytesPerLine;
676
677 while (bytes > 0)
678 {
679 /*
680 * Get a new repeat count...
681 */
682
683 if (!cups_raster_read(r, &byte, 1))
684 {
685 DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0.");
686 return (0);
687 }
688
689 if (byte == 128)
690 {
691 /*
692 * Clear to end of line...
693 */
694
695 switch (r->header.cupsColorSpace)
696 {
697 case CUPS_CSPACE_W :
698 case CUPS_CSPACE_RGB :
699 case CUPS_CSPACE_SW :
700 case CUPS_CSPACE_SRGB :
701 case CUPS_CSPACE_RGBW :
702 case CUPS_CSPACE_ADOBERGB :
703 memset(temp, 0xff, (size_t)bytes);
704 break;
705 default :
706 memset(temp, 0x00, (size_t)bytes);
707 break;
708 }
709
710 temp += bytes;
711 bytes = 0;
712 }
713 else if (byte & 128)
714 {
715 /*
716 * Copy N literal pixels...
717 */
718
719 count = (unsigned)(257 - byte) * r->bpp;
720
721 if (count > (unsigned)bytes)
722 count = (unsigned)bytes;
723
724 if (!cups_raster_read(r, temp, count))
725 {
726 DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0.");
727 return (0);
728 }
729
730 temp += count;
731 bytes -= (ssize_t)count;
732 }
733 else
734 {
735 /*
736 * Repeat the next N bytes...
737 */
738
739 count = ((unsigned)byte + 1) * r->bpp;
740 if (count > (unsigned)bytes)
741 count = (unsigned)bytes;
742
743 if (count < r->bpp)
744 break;
745
746 bytes -= (ssize_t)count;
747
748 if (!cups_raster_read(r, temp, r->bpp))
749 {
750 DEBUG_puts("1cupsRasterReadPixels: Read error, returning 0.");
751 return (0);
752 }
753
754 temp += r->bpp;
755 count -= r->bpp;
756
757 while (count > 0)
758 {
759 memcpy(temp, temp - r->bpp, r->bpp);
760 temp += r->bpp;
761 count -= r->bpp;
762 }
763 }
764 }
765
766 /*
767 * Swap bytes as needed...
768 */
769
770 if ((r->header.cupsBitsPerColor == 16 ||
771 r->header.cupsBitsPerPixel == 12 ||
772 r->header.cupsBitsPerPixel == 16) &&
773 r->swapped)
774 cups_swap(ptr, (size_t)bytes);
775
776 /*
777 * Update pointers...
778 */
779
780 if (remaining >= cupsBytesPerLine)
781 {
782 bytes = (ssize_t)cupsBytesPerLine;
783 r->pcurrent = r->pixels;
784 r->count --;
785 r->remaining --;
786 }
787 else
788 {
789 bytes = (ssize_t)remaining;
790 r->pcurrent = r->pixels + bytes;
791 }
792
793 /*
794 * Copy data as needed...
795 */
796
797 if (ptr != p)
798 memcpy(p, ptr, (size_t)bytes);
799 }
800 else
801 {
802 /*
803 * Copy fragment from buffer...
804 */
805
806 if ((unsigned)(bytes = (int)(r->pend - r->pcurrent)) > remaining)
807 bytes = (ssize_t)remaining;
808
809 memcpy(p, r->pcurrent, (size_t)bytes);
810 r->pcurrent += bytes;
811
812 if (r->pcurrent >= r->pend)
813 {
814 r->pcurrent = r->pixels;
815 r->count --;
816 r->remaining --;
817 }
818 }
819
820 remaining -= (unsigned)bytes;
821 p += bytes;
822 }
823
824 DEBUG_printf(("1cupsRasterReadPixels: Returning %u", len));
825
826 return (len);
827 }
828
829
830 /*
831 * 'cupsRasterWriteHeader()' - Write a raster page header from a version 1 page
832 * header structure.
833 *
834 * This function is deprecated. Use @link cupsRasterWriteHeader2@ instead.
835 *
836 * @deprecated@
837 */
838
839 unsigned /* O - 1 on success, 0 on failure */
840 cupsRasterWriteHeader(
841 cups_raster_t *r, /* I - Raster stream */
842 cups_page_header_t *h) /* I - Raster page header */
843 {
844 if (r == NULL || r->mode == CUPS_RASTER_READ)
845 return (0);
846
847 /*
848 * Make a copy of the header, and compute the number of raster
849 * lines in the page image...
850 */
851
852 memset(&(r->header), 0, sizeof(r->header));
853 memcpy(&(r->header), h, sizeof(cups_page_header_t));
854
855 if (!cups_raster_update(r))
856 return (0);
857
858 /*
859 * Write the raster header...
860 */
861
862 if (r->mode == CUPS_RASTER_WRITE_PWG)
863 {
864 /*
865 * PWG raster data is always network byte order with much of the page header
866 * zeroed.
867 */
868
869 cups_page_header2_t fh; /* File page header */
870
871 memset(&fh, 0, sizeof(fh));
872
873 strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass));
874 /* PwgRaster */
875 strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor));
876 strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType));
877 strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType));
878 /* PrintContentType */
879
880 fh.CutMedia = htonl(r->header.CutMedia);
881 fh.Duplex = htonl(r->header.Duplex);
882 fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
883 fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
884 fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]);
885 fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]);
886 fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]);
887 fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]);
888 fh.InsertSheet = htonl(r->header.InsertSheet);
889 fh.Jog = htonl(r->header.Jog);
890 fh.LeadingEdge = htonl(r->header.LeadingEdge);
891 fh.ManualFeed = htonl(r->header.ManualFeed);
892 fh.MediaPosition = htonl(r->header.MediaPosition);
893 fh.MediaWeight = htonl(r->header.MediaWeight);
894 fh.NumCopies = htonl(r->header.NumCopies);
895 fh.Orientation = htonl(r->header.Orientation);
896 fh.PageSize[0] = htonl(r->header.PageSize[0]);
897 fh.PageSize[1] = htonl(r->header.PageSize[1]);
898 fh.Tumble = htonl(r->header.Tumble);
899 fh.cupsWidth = htonl(r->header.cupsWidth);
900 fh.cupsHeight = htonl(r->header.cupsHeight);
901 fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
902 fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
903 fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
904 fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
905 fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
906 fh.cupsNumColors = htonl(r->header.cupsNumColors);
907 fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]);
908 /* TotalPageCount */
909 fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]);
910 /* CrossFeedTransform */
911 fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]);
912 /* FeedTransform */
913 fh.cupsInteger[3] = htonl(r->header.cupsInteger[3]);
914 /* ImageBoxLeft */
915 fh.cupsInteger[4] = htonl(r->header.cupsInteger[4]);
916 /* ImageBoxTop */
917 fh.cupsInteger[5] = htonl(r->header.cupsInteger[5]);
918 /* ImageBoxRight */
919 fh.cupsInteger[6] = htonl(r->header.cupsInteger[6]);
920 /* ImageBoxBottom */
921 fh.cupsInteger[7] = htonl(r->header.cupsInteger[7]);
922 /* BlackPrimary */
923 fh.cupsInteger[8] = htonl(r->header.cupsInteger[8]);
924 /* PrintQuality */
925 fh.cupsInteger[14] = htonl(r->header.cupsInteger[14]);
926 /* VendorIdentifier */
927 fh.cupsInteger[15] = htonl(r->header.cupsInteger[15]);
928 /* VendorLength */
929
930 void *dst = fh.cupsReal; /* Bypass bogus compiler warning */
931 void *src = r->header.cupsReal;
932 memcpy(dst, src, sizeof(fh.cupsReal) + sizeof(fh.cupsString));
933 /* VendorData */
934
935 strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent,
936 sizeof(fh.cupsRenderingIntent));
937 strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName,
938 sizeof(fh.cupsPageSizeName));
939
940 return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
941 }
942 else if (r->mode == CUPS_RASTER_WRITE_APPLE)
943 {
944 /*
945 * Raw raster data is always network byte order with most of the page header
946 * zeroed.
947 */
948
949 unsigned char appleheader[32]; /* Raw page header */
950
951 if (r->apple_page_count == 0xffffffffU)
952 {
953 /*
954 * Write raw page count from raster page header...
955 */
956
957 r->apple_page_count = r->header.cupsInteger[0];
958
959 appleheader[0] = 'A';
960 appleheader[1] = 'S';
961 appleheader[2] = 'T';
962 appleheader[3] = 0;
963 appleheader[4] = (unsigned char)(r->apple_page_count >> 24);
964 appleheader[5] = (unsigned char)(r->apple_page_count >> 16);
965 appleheader[6] = (unsigned char)(r->apple_page_count >> 8);
966 appleheader[7] = (unsigned char)(r->apple_page_count);
967
968 if (cups_raster_io(r, appleheader, 8) != 8)
969 return (0);
970 }
971
972 memset(appleheader, 0, sizeof(appleheader));
973
974 appleheader[0] = (unsigned char)r->header.cupsBitsPerPixel;
975 appleheader[1] = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 :
976 r->header.cupsColorSpace == CUPS_CSPACE_RGBW ? 2 :
977 r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 :
978 r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 :
979 r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 :
980 r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0;
981 appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24);
982 appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16);
983 appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8);
984 appleheader[15] = (unsigned char)(r->header.cupsWidth);
985 appleheader[16] = (unsigned char)(r->header.cupsHeight >> 24);
986 appleheader[17] = (unsigned char)(r->header.cupsHeight >> 16);
987 appleheader[18] = (unsigned char)(r->header.cupsHeight >> 8);
988 appleheader[19] = (unsigned char)(r->header.cupsHeight);
989 appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24);
990 appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16);
991 appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8);
992 appleheader[23] = (unsigned char)(r->header.HWResolution[0]);
993
994 return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader));
995 }
996 else
997 return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
998 == sizeof(r->header));
999 }
1000
1001
1002 /*
1003 * 'cupsRasterWriteHeader2()' - Write a raster page header from a version 2
1004 * page header structure.
1005 *
1006 * The page header can be initialized using @link cupsRasterInitPWGHeader@.
1007 *
1008 * @since CUPS 1.2/macOS 10.5@
1009 */
1010
1011 unsigned /* O - 1 on success, 0 on failure */
1012 cupsRasterWriteHeader2(
1013 cups_raster_t *r, /* I - Raster stream */
1014 cups_page_header2_t *h) /* I - Raster page header */
1015 {
1016 if (r == NULL || r->mode == CUPS_RASTER_READ)
1017 return (0);
1018
1019 /*
1020 * Make a copy of the header, and compute the number of raster
1021 * lines in the page image...
1022 */
1023
1024 memcpy(&(r->header), h, sizeof(cups_page_header2_t));
1025
1026 if (!cups_raster_update(r))
1027 return (0);
1028
1029 if (r->mode == CUPS_RASTER_WRITE_APPLE)
1030 {
1031 r->rowheight = h->HWResolution[0] / h->HWResolution[1];
1032
1033 if (h->HWResolution[0] != (r->rowheight * h->HWResolution[1]))
1034 return (0);
1035 }
1036 else
1037 r->rowheight = 1;
1038
1039 /*
1040 * Write the raster header...
1041 */
1042
1043 if (r->mode == CUPS_RASTER_WRITE_PWG)
1044 {
1045 /*
1046 * PWG raster data is always network byte order with most of the page header
1047 * zeroed.
1048 */
1049
1050 cups_page_header2_t fh; /* File page header */
1051
1052 memset(&fh, 0, sizeof(fh));
1053 strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass));
1054 strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor));
1055 strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType));
1056 strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType));
1057 strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent,
1058 sizeof(fh.cupsRenderingIntent));
1059 strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName,
1060 sizeof(fh.cupsPageSizeName));
1061
1062 fh.CutMedia = htonl(r->header.CutMedia);
1063 fh.Duplex = htonl(r->header.Duplex);
1064 fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
1065 fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
1066 fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]);
1067 fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]);
1068 fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]);
1069 fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]);
1070 fh.InsertSheet = htonl(r->header.InsertSheet);
1071 fh.Jog = htonl(r->header.Jog);
1072 fh.LeadingEdge = htonl(r->header.LeadingEdge);
1073 fh.ManualFeed = htonl(r->header.ManualFeed);
1074 fh.MediaPosition = htonl(r->header.MediaPosition);
1075 fh.MediaWeight = htonl(r->header.MediaWeight);
1076 fh.NumCopies = htonl(r->header.NumCopies);
1077 fh.Orientation = htonl(r->header.Orientation);
1078 fh.PageSize[0] = htonl(r->header.PageSize[0]);
1079 fh.PageSize[1] = htonl(r->header.PageSize[1]);
1080 fh.Tumble = htonl(r->header.Tumble);
1081 fh.cupsWidth = htonl(r->header.cupsWidth);
1082 fh.cupsHeight = htonl(r->header.cupsHeight);
1083 fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
1084 fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
1085 fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
1086 fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
1087 fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
1088 fh.cupsNumColors = htonl(r->header.cupsNumColors);
1089 fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]);
1090 fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]);
1091 fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]);
1092 fh.cupsInteger[3] = htonl((unsigned)(r->header.cupsImagingBBox[0] * r->header.HWResolution[0] / 72.0));
1093 fh.cupsInteger[4] = htonl((unsigned)(r->header.cupsImagingBBox[1] * r->header.HWResolution[1] / 72.0));
1094 fh.cupsInteger[5] = htonl((unsigned)(r->header.cupsImagingBBox[2] * r->header.HWResolution[0] / 72.0));
1095 fh.cupsInteger[6] = htonl((unsigned)(r->header.cupsImagingBBox[3] * r->header.HWResolution[1] / 72.0));
1096 fh.cupsInteger[7] = htonl(0xffffff);
1097
1098 return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
1099 }
1100 else if (r->mode == CUPS_RASTER_WRITE_APPLE)
1101 {
1102 /*
1103 * Raw raster data is always network byte order with most of the page header
1104 * zeroed.
1105 */
1106
1107 unsigned char appleheader[32]; /* Raw page header */
1108 unsigned height = r->header.cupsHeight * r->rowheight;
1109 /* Computed page height */
1110
1111 if (r->apple_page_count == 0xffffffffU)
1112 {
1113 /*
1114 * Write raw page count from raster page header...
1115 */
1116
1117 r->apple_page_count = r->header.cupsInteger[0];
1118
1119 appleheader[0] = 'A';
1120 appleheader[1] = 'S';
1121 appleheader[2] = 'T';
1122 appleheader[3] = 0;
1123 appleheader[4] = (unsigned char)(r->apple_page_count >> 24);
1124 appleheader[5] = (unsigned char)(r->apple_page_count >> 16);
1125 appleheader[6] = (unsigned char)(r->apple_page_count >> 8);
1126 appleheader[7] = (unsigned char)(r->apple_page_count);
1127
1128 if (cups_raster_io(r, appleheader, 8) != 8)
1129 return (0);
1130 }
1131
1132 memset(appleheader, 0, sizeof(appleheader));
1133
1134 appleheader[0] = (unsigned char)r->header.cupsBitsPerPixel;
1135 appleheader[1] = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 :
1136 r->header.cupsColorSpace == CUPS_CSPACE_RGBW ? 2 :
1137 r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 :
1138 r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 :
1139 r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 :
1140 r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0;
1141 appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24);
1142 appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16);
1143 appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8);
1144 appleheader[15] = (unsigned char)(r->header.cupsWidth);
1145 appleheader[16] = (unsigned char)(height >> 24);
1146 appleheader[17] = (unsigned char)(height >> 16);
1147 appleheader[18] = (unsigned char)(height >> 8);
1148 appleheader[19] = (unsigned char)(height);
1149 appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24);
1150 appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16);
1151 appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8);
1152 appleheader[23] = (unsigned char)(r->header.HWResolution[0]);
1153
1154 return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader));
1155 }
1156 else
1157 return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
1158 == sizeof(r->header));
1159 }
1160
1161
1162 /*
1163 * 'cupsRasterWritePixels()' - Write raster pixels.
1164 *
1165 * For best performance, filters should write one or more whole lines.
1166 * The "cupsBytesPerLine" value from the page header can be used to allocate
1167 * the line buffer and as the number of bytes to write.
1168 */
1169
1170 unsigned /* O - Number of bytes written */
1171 cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */
1172 unsigned char *p, /* I - Bytes to write */
1173 unsigned len)/* I - Number of bytes to write */
1174 {
1175 ssize_t bytes; /* Bytes read */
1176 unsigned remaining; /* Bytes remaining */
1177
1178
1179 DEBUG_printf(("cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u", (void *)r, (void *)p, len, r->remaining));
1180
1181 if (r == NULL || r->mode == CUPS_RASTER_READ || r->remaining == 0)
1182 return (0);
1183
1184 if (!r->compressed)
1185 {
1186 /*
1187 * Without compression, just write the raster data raw unless the data needs
1188 * to be swapped...
1189 */
1190
1191 r->remaining -= len / r->header.cupsBytesPerLine;
1192
1193 if (r->swapped &&
1194 (r->header.cupsBitsPerColor == 16 ||
1195 r->header.cupsBitsPerPixel == 12 ||
1196 r->header.cupsBitsPerPixel == 16))
1197 {
1198 unsigned char *bufptr; /* Pointer into write buffer */
1199 unsigned count; /* Remaining count */
1200
1201 /*
1202 * Allocate a write buffer as needed...
1203 */
1204
1205 if ((size_t)len > r->bufsize)
1206 {
1207 if (r->buffer)
1208 bufptr = realloc(r->buffer, len);
1209 else
1210 bufptr = malloc(len);
1211
1212 if (!bufptr)
1213 return (0);
1214
1215 r->buffer = bufptr;
1216 r->bufsize = len;
1217 }
1218
1219 /*
1220 * Byte swap the pixels...
1221 */
1222
1223 for (bufptr = r->buffer, count = len; count > 1; count -= 2, bufptr += 2)
1224 {
1225 bufptr[1] = *p++;
1226 bufptr[0] = *p++;
1227 }
1228
1229 if (count) /* This should never happen... */
1230 *bufptr = *p;
1231
1232 /*
1233 * Write the byte-swapped buffer...
1234 */
1235
1236 bytes = cups_raster_io(r, r->buffer, len);
1237 }
1238 else
1239 bytes = cups_raster_io(r, p, len);
1240
1241 if (bytes < len)
1242 return (0);
1243 else
1244 return (len);
1245 }
1246
1247 /*
1248 * Otherwise, compress each line...
1249 */
1250
1251 for (remaining = len; remaining > 0; remaining -= (unsigned)bytes, p += bytes)
1252 {
1253 /*
1254 * Figure out the number of remaining bytes on the current line...
1255 */
1256
1257 if ((bytes = (ssize_t)remaining) > (ssize_t)(r->pend - r->pcurrent))
1258 bytes = (ssize_t)(r->pend - r->pcurrent);
1259
1260 if (r->count > 0)
1261 {
1262 /*
1263 * Check to see if this line is the same as the previous line...
1264 */
1265
1266 if (memcmp(p, r->pcurrent, (size_t)bytes))
1267 {
1268 if (cups_raster_write(r, r->pixels) <= 0)
1269 return (0);
1270
1271 r->count = 0;
1272 }
1273 else
1274 {
1275 /*
1276 * Mark more bytes as the same...
1277 */
1278
1279 r->pcurrent += bytes;
1280
1281 if (r->pcurrent >= r->pend)
1282 {
1283 /*
1284 * Increase the repeat count...
1285 */
1286
1287 r->count += r->rowheight;
1288 r->pcurrent = r->pixels;
1289
1290 /*
1291 * Flush out this line if it is the last one...
1292 */
1293
1294 r->remaining --;
1295
1296 if (r->remaining == 0)
1297 {
1298 if (cups_raster_write(r, r->pixels) <= 0)
1299 return (0);
1300 else
1301 return (len);
1302 }
1303 else if (r->count > (256 - r->rowheight))
1304 {
1305 if (cups_raster_write(r, r->pixels) <= 0)
1306 return (0);
1307
1308 r->count = 0;
1309 }
1310 }
1311
1312 continue;
1313 }
1314 }
1315
1316 if (r->count == 0)
1317 {
1318 /*
1319 * Copy the raster data to the buffer...
1320 */
1321
1322 memcpy(r->pcurrent, p, (size_t)bytes);
1323
1324 r->pcurrent += bytes;
1325
1326 if (r->pcurrent >= r->pend)
1327 {
1328 /*
1329 * Increase the repeat count...
1330 */
1331
1332 r->count += r->rowheight;
1333 r->pcurrent = r->pixels;
1334
1335 /*
1336 * Flush out this line if it is the last one...
1337 */
1338
1339 r->remaining --;
1340
1341 if (r->remaining == 0)
1342 {
1343 if (cups_raster_write(r, r->pixels) <= 0)
1344 return (0);
1345 }
1346 }
1347 }
1348 }
1349
1350 return (len);
1351 }
1352
1353
1354 /*
1355 * 'cups_raster_read_header()' - Read a raster page header.
1356 */
1357
1358 static unsigned /* O - 1 on success, 0 on fail */
1359 cups_raster_read_header(
1360 cups_raster_t *r) /* I - Raster stream */
1361 {
1362 size_t len; /* Length for read/swap */
1363
1364
1365 DEBUG_printf(("3cups_raster_read_header(r=%p), r->mode=%d", (void *)r, r ? r->mode : 0));
1366
1367 if (r == NULL || r->mode != CUPS_RASTER_READ)
1368 return (0);
1369
1370 DEBUG_printf(("4cups_raster_read_header: r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
1371
1372 memset(&(r->header), 0, sizeof(r->header));
1373
1374 /*
1375 * Read the header...
1376 */
1377
1378 switch (r->sync)
1379 {
1380 default :
1381 /*
1382 * Get the length of the raster header...
1383 */
1384
1385 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
1386 len = sizeof(cups_page_header_t);
1387 else
1388 len = sizeof(cups_page_header2_t);
1389
1390 DEBUG_printf(("4cups_raster_read_header: len=%d", (int)len));
1391
1392 /*
1393 * Read it...
1394 */
1395
1396 if (cups_raster_read(r, (unsigned char *)&(r->header), len) < (ssize_t)len)
1397 {
1398 DEBUG_printf(("4cups_raster_read_header: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
1399 return (0);
1400 }
1401
1402 /*
1403 * Swap bytes as needed...
1404 */
1405
1406 if (r->swapped)
1407 {
1408 unsigned *s, /* Current word */
1409 temp; /* Temporary copy */
1410
1411
1412 DEBUG_puts("4cups_raster_read_header: Swapping header bytes.");
1413
1414 for (len = 81, s = &(r->header.AdvanceDistance);
1415 len > 0;
1416 len --, s ++)
1417 {
1418 temp = *s;
1419 *s = ((temp & 0xff) << 24) |
1420 ((temp & 0xff00) << 8) |
1421 ((temp & 0xff0000) >> 8) |
1422 ((temp & 0xff000000) >> 24);
1423
1424 DEBUG_printf(("4cups_raster_read_header: %08x => %08x", temp, *s));
1425 }
1426 }
1427 break;
1428
1429 case CUPS_RASTER_SYNCapple :
1430 case CUPS_RASTER_REVSYNCapple :
1431 {
1432 unsigned char appleheader[32]; /* Raw header */
1433 static const unsigned rawcspace[] =
1434 {
1435 CUPS_CSPACE_SW,
1436 CUPS_CSPACE_SRGB,
1437 CUPS_CSPACE_RGBW,
1438 CUPS_CSPACE_ADOBERGB,
1439 CUPS_CSPACE_W,
1440 CUPS_CSPACE_RGB,
1441 CUPS_CSPACE_CMYK
1442 };
1443 static const unsigned rawnumcolors[] =
1444 {
1445 1,
1446 3,
1447 4,
1448 3,
1449 1,
1450 3,
1451 4
1452 };
1453
1454 if (cups_raster_read(r, appleheader, sizeof(appleheader)) < (ssize_t)sizeof(appleheader))
1455 {
1456 DEBUG_printf(("4cups_raster_read_header: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
1457 return (0);
1458 }
1459
1460 strlcpy(r->header.MediaClass, "PwgRaster", sizeof(r->header.MediaClass));
1461 /* PwgRaster */
1462 r->header.cupsBitsPerPixel = appleheader[0];
1463 r->header.cupsColorSpace = appleheader[1] >= (sizeof(rawcspace) / sizeof(rawcspace[0])) ? CUPS_CSPACE_DEVICE1 : rawcspace[appleheader[1]];
1464 r->header.cupsNumColors = appleheader[1] >= (sizeof(rawnumcolors) / sizeof(rawnumcolors[0])) ? 1 : rawnumcolors[appleheader[1]];
1465 r->header.cupsBitsPerColor = r->header.cupsBitsPerPixel / r->header.cupsNumColors;
1466 r->header.cupsWidth = ((((((unsigned)appleheader[12] << 8) | (unsigned)appleheader[13]) << 8) | (unsigned)appleheader[14]) << 8) | (unsigned)appleheader[15];
1467 r->header.cupsHeight = ((((((unsigned)appleheader[16] << 8) | (unsigned)appleheader[17]) << 8) | (unsigned)appleheader[18]) << 8) | (unsigned)appleheader[19];
1468 r->header.cupsBytesPerLine = r->header.cupsWidth * r->header.cupsBitsPerPixel / 8;
1469 r->header.cupsColorOrder = CUPS_ORDER_CHUNKED;
1470 r->header.HWResolution[0] = r->header.HWResolution[1] = ((((((unsigned)appleheader[20] << 8) | (unsigned)appleheader[21]) << 8) | (unsigned)appleheader[22]) << 8) | (unsigned)appleheader[23];
1471
1472 if (r->header.HWResolution[0] > 0)
1473 {
1474 r->header.PageSize[0] = (unsigned)(r->header.cupsWidth * 72 / r->header.HWResolution[0]);
1475 r->header.PageSize[1] = (unsigned)(r->header.cupsHeight * 72 / r->header.HWResolution[1]);
1476 r->header.cupsPageSize[0] = (float)(r->header.cupsWidth * 72.0 / r->header.HWResolution[0]);
1477 r->header.cupsPageSize[1] = (float)(r->header.cupsHeight * 72.0 / r->header.HWResolution[1]);
1478 }
1479
1480 r->header.cupsInteger[0] = r->apple_page_count;
1481 r->header.cupsInteger[7] = 0xffffff;
1482 }
1483 break;
1484 }
1485
1486 /*
1487 * Update the header and row count...
1488 */
1489
1490 if (!cups_raster_update(r))
1491 return (0);
1492
1493 DEBUG_printf(("4cups_raster_read_header: cupsBitsPerPixel=%u, cupsBitsPerColor=%u, cupsBytesPerLine=%u, cupsWidth=%u, cupsHeight=%u, r->bpp=%d", r->header.cupsBitsPerPixel, r->header.cupsBitsPerColor, r->header.cupsBytesPerLine, r->header.cupsWidth, r->header.cupsHeight, r->bpp));
1494
1495 return (r->header.cupsBitsPerPixel > 0 && r->header.cupsBitsPerPixel <= 240 && r->header.cupsBitsPerColor > 0 && r->header.cupsBitsPerColor <= 16 && r->header.cupsBytesPerLine > 0 && r->header.cupsBytesPerLine <= 0x7fffffff && r->header.cupsHeight != 0 && (r->header.cupsBytesPerLine % r->bpp) == 0);
1496 }
1497
1498
1499 /*
1500 * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions.
1501 */
1502
1503 static ssize_t /* O - Bytes read/write or -1 */
1504 cups_raster_io(cups_raster_t *r, /* I - Raster stream */
1505 unsigned char *buf, /* I - Buffer for read/write */
1506 size_t bytes) /* I - Number of bytes to read/write */
1507 {
1508 ssize_t count, /* Number of bytes read/written */
1509 total; /* Total bytes read/written */
1510
1511
1512 DEBUG_printf(("5cups_raster_io(r=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)r, (void *)buf, CUPS_LLCAST bytes));
1513
1514 for (total = 0; total < (ssize_t)bytes; total += count, buf += count)
1515 {
1516 count = (*r->iocb)(r->ctx, buf, bytes - (size_t)total);
1517
1518 DEBUG_printf(("6cups_raster_io: count=%d, total=%d", (int)count, (int)total));
1519 if (count == 0)
1520 {
1521 DEBUG_puts("6cups_raster_io: Returning 0.");
1522 return (0);
1523 }
1524 else if (count < 0)
1525 {
1526 DEBUG_puts("6cups_raster_io: Returning -1 on error.");
1527 return (-1);
1528 }
1529
1530 #ifdef DEBUG
1531 r->iocount += (size_t)count;
1532 #endif /* DEBUG */
1533 }
1534
1535 DEBUG_printf(("6cups_raster_io: Returning " CUPS_LLFMT ".", CUPS_LLCAST total));
1536
1537 return (total);
1538 }
1539
1540
1541 /*
1542 * 'cups_raster_read()' - Read through the raster buffer.
1543 */
1544
1545 static ssize_t /* O - Number of bytes read */
1546 cups_raster_read(cups_raster_t *r, /* I - Raster stream */
1547 unsigned char *buf, /* I - Buffer */
1548 size_t bytes) /* I - Number of bytes to read */
1549 {
1550 ssize_t count, /* Number of bytes read */
1551 remaining, /* Remaining bytes in buffer */
1552 total; /* Total bytes read */
1553
1554
1555 DEBUG_printf(("5cups_raster_read(r=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)r, (void *)buf, CUPS_LLCAST bytes));
1556
1557 if (!r->compressed)
1558 return (cups_raster_io(r, buf, bytes));
1559
1560 /*
1561 * Allocate a read buffer as needed...
1562 */
1563
1564 count = (ssize_t)(2 * r->header.cupsBytesPerLine);
1565 if (count < 65536)
1566 count = 65536;
1567
1568 if ((size_t)count > r->bufsize)
1569 {
1570 ssize_t offset = r->bufptr - r->buffer;
1571 /* Offset to current start of buffer */
1572 ssize_t end = r->bufend - r->buffer;/* Offset to current end of buffer */
1573 unsigned char *rptr; /* Pointer in read buffer */
1574
1575 if (r->buffer)
1576 rptr = realloc(r->buffer, (size_t)count);
1577 else
1578 rptr = malloc((size_t)count);
1579
1580 if (!rptr)
1581 return (0);
1582
1583 r->buffer = rptr;
1584 r->bufptr = rptr + offset;
1585 r->bufend = rptr + end;
1586 r->bufsize = (size_t)count;
1587 }
1588
1589 /*
1590 * Loop until we have read everything...
1591 */
1592
1593 for (total = 0, remaining = (int)(r->bufend - r->bufptr);
1594 total < (ssize_t)bytes;
1595 total += count, buf += count)
1596 {
1597 count = (ssize_t)bytes - total;
1598
1599 DEBUG_printf(("6cups_raster_read: count=" CUPS_LLFMT ", remaining=" CUPS_LLFMT ", buf=%p, bufptr=%p, bufend=%p", CUPS_LLCAST count, CUPS_LLCAST remaining, (void *)buf, (void *)r->bufptr, (void *)r->bufend));
1600
1601 if (remaining == 0)
1602 {
1603 if (count < 16)
1604 {
1605 /*
1606 * Read into the raster buffer and then copy...
1607 */
1608
1609 remaining = (*r->iocb)(r->ctx, r->buffer, r->bufsize);
1610 if (remaining <= 0)
1611 return (0);
1612
1613 r->bufptr = r->buffer;
1614 r->bufend = r->buffer + remaining;
1615
1616 #ifdef DEBUG
1617 r->iocount += (size_t)remaining;
1618 #endif /* DEBUG */
1619 }
1620 else
1621 {
1622 /*
1623 * Read directly into "buf"...
1624 */
1625
1626 count = (*r->iocb)(r->ctx, buf, (size_t)count);
1627
1628 if (count <= 0)
1629 return (0);
1630
1631 #ifdef DEBUG
1632 r->iocount += (size_t)count;
1633 #endif /* DEBUG */
1634
1635 continue;
1636 }
1637 }
1638
1639 /*
1640 * Copy bytes from raster buffer to "buf"...
1641 */
1642
1643 if (count > remaining)
1644 count = remaining;
1645
1646 if (count == 1)
1647 {
1648 /*
1649 * Copy 1 byte...
1650 */
1651
1652 *buf = *(r->bufptr)++;
1653 remaining --;
1654 }
1655 else if (count < 128)
1656 {
1657 /*
1658 * Copy up to 127 bytes without using memcpy(); this is
1659 * faster because it avoids an extra function call and is
1660 * often further optimized by the compiler...
1661 */
1662
1663 unsigned char *bufptr; /* Temporary buffer pointer */
1664
1665 remaining -= count;
1666
1667 for (bufptr = r->bufptr; count > 0; count --, total ++)
1668 *buf++ = *bufptr++;
1669
1670 r->bufptr = bufptr;
1671 }
1672 else
1673 {
1674 /*
1675 * Use memcpy() for a large read...
1676 */
1677
1678 memcpy(buf, r->bufptr, (size_t)count);
1679 r->bufptr += count;
1680 remaining -= count;
1681 }
1682 }
1683
1684 DEBUG_printf(("6cups_raster_read: Returning %ld", (long)total));
1685
1686 return (total);
1687 }
1688
1689
1690 /*
1691 * 'cups_raster_update()' - Update the raster header and row count for the
1692 * current page.
1693 */
1694
1695 static int /* O - 1 on success, 0 on failure */
1696 cups_raster_update(cups_raster_t *r) /* I - Raster stream */
1697 {
1698 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 ||
1699 r->header.cupsNumColors == 0)
1700 {
1701 /*
1702 * Set the "cupsNumColors" field according to the colorspace...
1703 */
1704
1705 switch (r->header.cupsColorSpace)
1706 {
1707 case CUPS_CSPACE_W :
1708 case CUPS_CSPACE_K :
1709 case CUPS_CSPACE_WHITE :
1710 case CUPS_CSPACE_GOLD :
1711 case CUPS_CSPACE_SILVER :
1712 case CUPS_CSPACE_SW :
1713 r->header.cupsNumColors = 1;
1714 break;
1715
1716 case CUPS_CSPACE_RGB :
1717 case CUPS_CSPACE_CMY :
1718 case CUPS_CSPACE_YMC :
1719 case CUPS_CSPACE_CIEXYZ :
1720 case CUPS_CSPACE_CIELab :
1721 case CUPS_CSPACE_SRGB :
1722 case CUPS_CSPACE_ADOBERGB :
1723 case CUPS_CSPACE_ICC1 :
1724 case CUPS_CSPACE_ICC2 :
1725 case CUPS_CSPACE_ICC3 :
1726 case CUPS_CSPACE_ICC4 :
1727 case CUPS_CSPACE_ICC5 :
1728 case CUPS_CSPACE_ICC6 :
1729 case CUPS_CSPACE_ICC7 :
1730 case CUPS_CSPACE_ICC8 :
1731 case CUPS_CSPACE_ICC9 :
1732 case CUPS_CSPACE_ICCA :
1733 case CUPS_CSPACE_ICCB :
1734 case CUPS_CSPACE_ICCC :
1735 case CUPS_CSPACE_ICCD :
1736 case CUPS_CSPACE_ICCE :
1737 case CUPS_CSPACE_ICCF :
1738 r->header.cupsNumColors = 3;
1739 break;
1740
1741 case CUPS_CSPACE_RGBA :
1742 case CUPS_CSPACE_RGBW :
1743 case CUPS_CSPACE_CMYK :
1744 case CUPS_CSPACE_YMCK :
1745 case CUPS_CSPACE_KCMY :
1746 case CUPS_CSPACE_GMCK :
1747 case CUPS_CSPACE_GMCS :
1748 r->header.cupsNumColors = 4;
1749 break;
1750
1751 case CUPS_CSPACE_KCMYcm :
1752 if (r->header.cupsBitsPerPixel < 8)
1753 r->header.cupsNumColors = 6;
1754 else
1755 r->header.cupsNumColors = 4;
1756 break;
1757
1758 case CUPS_CSPACE_DEVICE1 :
1759 case CUPS_CSPACE_DEVICE2 :
1760 case CUPS_CSPACE_DEVICE3 :
1761 case CUPS_CSPACE_DEVICE4 :
1762 case CUPS_CSPACE_DEVICE5 :
1763 case CUPS_CSPACE_DEVICE6 :
1764 case CUPS_CSPACE_DEVICE7 :
1765 case CUPS_CSPACE_DEVICE8 :
1766 case CUPS_CSPACE_DEVICE9 :
1767 case CUPS_CSPACE_DEVICEA :
1768 case CUPS_CSPACE_DEVICEB :
1769 case CUPS_CSPACE_DEVICEC :
1770 case CUPS_CSPACE_DEVICED :
1771 case CUPS_CSPACE_DEVICEE :
1772 case CUPS_CSPACE_DEVICEF :
1773 r->header.cupsNumColors = r->header.cupsColorSpace -
1774 CUPS_CSPACE_DEVICE1 + 1;
1775 break;
1776
1777 default :
1778 /* Unknown color space */
1779 return (0);
1780 }
1781 }
1782
1783 /*
1784 * Set the number of bytes per pixel/color...
1785 */
1786
1787 if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED)
1788 r->bpp = (r->header.cupsBitsPerPixel + 7) / 8;
1789 else
1790 r->bpp = (r->header.cupsBitsPerColor + 7) / 8;
1791
1792 if (r->bpp == 0)
1793 r->bpp = 1;
1794
1795 /*
1796 * Set the number of remaining rows...
1797 */
1798
1799 if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR)
1800 r->remaining = r->header.cupsHeight * r->header.cupsNumColors;
1801 else
1802 r->remaining = r->header.cupsHeight;
1803
1804 /*
1805 * Allocate the compression buffer...
1806 */
1807
1808 if (r->compressed)
1809 {
1810 if (r->pixels != NULL)
1811 free(r->pixels);
1812
1813 if ((r->pixels = calloc(r->header.cupsBytesPerLine, 1)) == NULL)
1814 {
1815 r->pcurrent = NULL;
1816 r->pend = NULL;
1817 r->count = 0;
1818
1819 return (0);
1820 }
1821
1822 r->pcurrent = r->pixels;
1823 r->pend = r->pixels + r->header.cupsBytesPerLine;
1824 r->count = 0;
1825 }
1826
1827 return (1);
1828 }
1829
1830
1831 /*
1832 * 'cups_raster_write()' - Write a row of compressed raster data...
1833 */
1834
1835 static ssize_t /* O - Number of bytes written */
1836 cups_raster_write(
1837 cups_raster_t *r, /* I - Raster stream */
1838 const unsigned char *pixels) /* I - Pixel data to write */
1839 {
1840 const unsigned char *start, /* Start of sequence */
1841 *ptr, /* Current pointer in sequence */
1842 *pend, /* End of raster buffer */
1843 *plast; /* Pointer to last pixel */
1844 unsigned char *wptr; /* Pointer into write buffer */
1845 unsigned bpp, /* Bytes per pixel */
1846 count; /* Count */
1847
1848
1849 DEBUG_printf(("3cups_raster_write(r=%p, pixels=%p)", (void *)r, (void *)pixels));
1850
1851 /*
1852 * Allocate a write buffer as needed...
1853 */
1854
1855 count = r->header.cupsBytesPerLine * 2;
1856 if (count < 65536)
1857 count = 65536;
1858
1859 if ((size_t)count > r->bufsize)
1860 {
1861 if (r->buffer)
1862 wptr = realloc(r->buffer, count);
1863 else
1864 wptr = malloc(count);
1865
1866 if (!wptr)
1867 {
1868 DEBUG_printf(("4cups_raster_write: Unable to allocate " CUPS_LLFMT " bytes for raster buffer: %s", CUPS_LLCAST count, strerror(errno)));
1869 return (-1);
1870 }
1871
1872 r->buffer = wptr;
1873 r->bufsize = count;
1874 }
1875
1876 /*
1877 * Write the row repeat count...
1878 */
1879
1880 bpp = r->bpp;
1881 pend = pixels + r->header.cupsBytesPerLine;
1882 plast = pend - bpp;
1883 wptr = r->buffer;
1884 *wptr++ = (unsigned char)(r->count - 1);
1885
1886 /*
1887 * Write using a modified PackBits compression...
1888 */
1889
1890 for (ptr = pixels; ptr < pend;)
1891 {
1892 start = ptr;
1893 ptr += bpp;
1894
1895 if (ptr == pend)
1896 {
1897 /*
1898 * Encode a single pixel at the end...
1899 */
1900
1901 *wptr++ = 0;
1902 for (count = bpp; count > 0; count --)
1903 *wptr++ = *start++;
1904 }
1905 else if (!memcmp(start, ptr, bpp))
1906 {
1907 /*
1908 * Encode a sequence of repeating pixels...
1909 */
1910
1911 for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp)
1912 if (memcmp(ptr, ptr + bpp, bpp))
1913 break;
1914
1915 *wptr++ = (unsigned char)(count - 1);
1916 for (count = bpp; count > 0; count --)
1917 *wptr++ = *ptr++;
1918 }
1919 else
1920 {
1921 /*
1922 * Encode a sequence of non-repeating pixels...
1923 */
1924
1925 for (count = 1; count < 128 && ptr < plast; count ++, ptr += bpp)
1926 if (!memcmp(ptr, ptr + bpp, bpp))
1927 break;
1928
1929 if (ptr >= plast && count < 128)
1930 {
1931 count ++;
1932 ptr += bpp;
1933 }
1934
1935 *wptr++ = (unsigned char)(257 - count);
1936
1937 count *= bpp;
1938 memcpy(wptr, start, count);
1939 wptr += count;
1940 }
1941 }
1942
1943 DEBUG_printf(("4cups_raster_write: Writing " CUPS_LLFMT " bytes.", CUPS_LLCAST (wptr - r->buffer)));
1944
1945 return (cups_raster_io(r, r->buffer, (size_t)(wptr - r->buffer)));
1946 }
1947
1948
1949 /*
1950 * 'cups_read_fd()' - Read bytes from a file.
1951 */
1952
1953 static ssize_t /* O - Bytes read or -1 */
1954 cups_read_fd(void *ctx, /* I - File descriptor as pointer */
1955 unsigned char *buf, /* I - Buffer for read */
1956 size_t bytes) /* I - Maximum number of bytes to read */
1957 {
1958 int fd = (int)((intptr_t)ctx);
1959 /* File descriptor */
1960 ssize_t count; /* Number of bytes read */
1961
1962
1963 #ifdef WIN32 /* Sigh */
1964 while ((count = read(fd, buf, (unsigned)bytes)) < 0)
1965 #else
1966 while ((count = read(fd, buf, bytes)) < 0)
1967 #endif /* WIN32 */
1968 if (errno != EINTR && errno != EAGAIN)
1969 {
1970 DEBUG_printf(("4cups_read_fd: %s", strerror(errno)));
1971 return (-1);
1972 }
1973
1974 DEBUG_printf(("4cups_read_fd: Returning %d bytes.", (int)count));
1975
1976 return (count);
1977 }
1978
1979
1980 /*
1981 * 'cups_swap()' - Swap bytes in raster data...
1982 */
1983
1984 static void
1985 cups_swap(unsigned char *buf, /* I - Buffer to swap */
1986 size_t bytes) /* I - Number of bytes to swap */
1987 {
1988 unsigned char even, odd; /* Temporary variables */
1989
1990
1991 bytes /= 2;
1992
1993 while (bytes > 0)
1994 {
1995 even = buf[0];
1996 odd = buf[1];
1997 buf[0] = odd;
1998 buf[1] = even;
1999
2000 buf += 2;
2001 bytes --;
2002 }
2003 }
2004
2005
2006 /*
2007 * 'cups_write_fd()' - Write bytes to a file.
2008 */
2009
2010 static ssize_t /* O - Bytes written or -1 */
2011 cups_write_fd(void *ctx, /* I - File descriptor pointer */
2012 unsigned char *buf, /* I - Bytes to write */
2013 size_t bytes) /* I - Number of bytes to write */
2014 {
2015 int fd = (int)((intptr_t)ctx);
2016 /* File descriptor */
2017 ssize_t count; /* Number of bytes written */
2018
2019
2020 #ifdef WIN32 /* Sigh */
2021 while ((count = write(fd, buf, (unsigned)bytes)) < 0)
2022 #else
2023 while ((count = write(fd, buf, bytes)) < 0)
2024 #endif /* WIN32 */
2025 if (errno != EINTR && errno != EAGAIN)
2026 {
2027 DEBUG_printf(("4cups_write_fd: %s", strerror(errno)));
2028 return (-1);
2029 }
2030
2031 return (count);
2032 }