]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/raster.c
Full sweep of all Clang warnings, plus some bug fixes for incorrect memcpy usage.
[thirdparty/cups.git] / filter / raster.c
1 /*
2 * "$Id$"
3 *
4 * Raster file routines for CUPS.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * This file is part of the CUPS Imaging library.
10 *
11 * These coded instructions, statements, and computer programs are the
12 * property of Apple Inc. and are protected by Federal copyright
13 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
14 * which should have been included with this file. If this file is
15 * file is missing or damaged, see the license at "http://www.cups.org/".
16 *
17 * This file is subject to the Apple OS-Developed Software exception.
18 */
19
20 /*
21 * Include necessary headers...
22 */
23
24 #include <cups/raster-private.h>
25 #ifdef HAVE_STDINT_H
26 # include <stdint.h>
27 #endif /* HAVE_STDINT_H */
28
29
30 /*
31 * Private structures...
32 */
33
34 struct _cups_raster_s /**** Raster stream data ****/
35 {
36 unsigned sync; /* Sync word from start of stream */
37 void *ctx; /* File descriptor */
38 cups_raster_iocb_t iocb; /* IO callback */
39 cups_mode_t mode; /* Read/write mode */
40 cups_page_header2_t header; /* Raster header for current page */
41 unsigned count, /* Current row run-length count */
42 remaining, /* Remaining rows in page image */
43 bpp; /* Bytes per pixel/color */
44 unsigned char *pixels, /* Pixels for current row */
45 *pend, /* End of pixel buffer */
46 *pcurrent; /* Current byte in pixel buffer */
47 int compressed, /* Non-zero if data is compressed */
48 swapped; /* Non-zero if data is byte-swapped */
49 unsigned char *buffer, /* Read/write buffer */
50 *bufptr, /* Current (read) position in buffer */
51 *bufend; /* End of current (read) buffer */
52 size_t bufsize; /* Buffer size */
53 };
54
55
56 /*
57 * Local functions...
58 */
59
60 static ssize_t cups_raster_io(cups_raster_t *r, unsigned char *buf, size_t bytes);
61 static unsigned cups_raster_read_header(cups_raster_t *r);
62 static ssize_t cups_raster_read(cups_raster_t *r, unsigned char *buf,
63 size_t bytes);
64 static void cups_raster_update(cups_raster_t *r);
65 static ssize_t cups_raster_write(cups_raster_t *r,
66 const unsigned char *pixels);
67 static ssize_t cups_read_fd(void *ctx, unsigned char *buf, size_t bytes);
68 static void cups_swap(unsigned char *buf, size_t bytes);
69 static ssize_t cups_write_fd(void *ctx, unsigned char *buf, size_t bytes);
70
71
72 /*
73 * 'cupsRasterClose()' - Close a raster stream.
74 *
75 * The file descriptor associated with the raster stream must be closed
76 * separately as needed.
77 */
78
79 void
80 cupsRasterClose(cups_raster_t *r) /* I - Stream to close */
81 {
82 if (r != NULL)
83 {
84 if (r->buffer)
85 free(r->buffer);
86
87 if (r->pixels)
88 free(r->pixels);
89
90 free(r);
91 }
92 }
93
94
95 /*
96 * 'cupsRasterOpen()' - Open a raster stream using a file descriptor.
97 *
98 * This function associates a raster stream with the given file descriptor.
99 * For most printer driver filters, "fd" will be 0 (stdin). For most raster
100 * image processor (RIP) filters that generate raster data, "fd" will be 1
101 * (stdout).
102 *
103 * When writing raster data, the @code CUPS_RASTER_WRITE@,
104 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
105 * be used - compressed and PWG output is generally 25-50% smaller but adds a
106 * 100-300% execution time overhead.
107 */
108
109 cups_raster_t * /* O - New stream */
110 cupsRasterOpen(int fd, /* I - File descriptor */
111 cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
112 @code CUPS_RASTER_WRITE@,
113 @code CUPS_RASTER_WRITE_COMPRESSED@,
114 or @code CUPS_RASTER_WRITE_PWG@ */
115 {
116 if (mode == CUPS_RASTER_READ)
117 return (cupsRasterOpenIO(cups_read_fd, (void *)((intptr_t)fd), mode));
118 else
119 return (cupsRasterOpenIO(cups_write_fd, (void *)((intptr_t)fd), mode));
120 }
121
122
123 /*
124 * 'cupsRasterOpenIO()' - Open a raster stream using a callback function.
125 *
126 * This function associates a raster stream with the given callback function and
127 * context pointer.
128 *
129 * When writing raster data, the @code CUPS_RASTER_WRITE@,
130 * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can
131 * be used - compressed and PWG output is generally 25-50% smaller but adds a
132 * 100-300% execution time overhead.
133 */
134
135 cups_raster_t * /* O - New stream */
136 cupsRasterOpenIO(
137 cups_raster_iocb_t iocb, /* I - Read/write callback */
138 void *ctx, /* I - Context pointer for callback */
139 cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@,
140 @code CUPS_RASTER_WRITE@,
141 @code CUPS_RASTER_WRITE_COMPRESSED@,
142 or @code CUPS_RASTER_WRITE_PWG@ */
143 {
144 cups_raster_t *r; /* New stream */
145
146
147 _cupsRasterClearError();
148
149 if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL)
150 {
151 _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n",
152 strerror(errno));
153 return (NULL);
154 }
155
156 r->ctx = ctx;
157 r->iocb = iocb;
158 r->mode = mode;
159
160 if (mode == CUPS_RASTER_READ)
161 {
162 /*
163 * Open for read - get sync word...
164 */
165
166 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) !=
167 sizeof(r->sync))
168 {
169 _cupsRasterAddError("Unable to read header from raster stream: %s\n",
170 strerror(errno));
171 free(r);
172 return (NULL);
173 }
174
175 if (r->sync != CUPS_RASTER_SYNC &&
176 r->sync != CUPS_RASTER_REVSYNC &&
177 r->sync != CUPS_RASTER_SYNCv1 &&
178 r->sync != CUPS_RASTER_REVSYNCv1 &&
179 r->sync != CUPS_RASTER_SYNCv2 &&
180 r->sync != CUPS_RASTER_REVSYNCv2)
181 {
182 _cupsRasterAddError("Unknown raster format %08x!\n", r->sync);
183 free(r);
184 return (NULL);
185 }
186
187 if (r->sync == CUPS_RASTER_SYNCv2 ||
188 r->sync == CUPS_RASTER_REVSYNCv2)
189 r->compressed = 1;
190
191 if (r->sync == CUPS_RASTER_REVSYNC ||
192 r->sync == CUPS_RASTER_REVSYNCv1 ||
193 r->sync == CUPS_RASTER_REVSYNCv2)
194 r->swapped = 1;
195
196 DEBUG_printf(("r->swapped=%d, r->sync=%08x\n", r->swapped, r->sync));
197 }
198 else
199 {
200 /*
201 * Open for write - put sync word...
202 */
203
204 switch (mode)
205 {
206 default :
207 case CUPS_RASTER_WRITE :
208 r->sync = CUPS_RASTER_SYNC;
209 break;
210
211 case CUPS_RASTER_WRITE_COMPRESSED :
212 r->compressed = 1;
213 r->sync = CUPS_RASTER_SYNCv2;
214 break;
215
216 case CUPS_RASTER_WRITE_PWG :
217 r->compressed = 1;
218 r->sync = htonl(CUPS_RASTER_SYNC_PWG);
219 r->swapped = r->sync != CUPS_RASTER_SYNC_PWG;
220 break;
221 }
222
223 if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) < (ssize_t)sizeof(r->sync))
224 {
225 _cupsRasterAddError("Unable to write raster stream header: %s\n",
226 strerror(errno));
227 free(r);
228 return (NULL);
229 }
230 }
231
232 return (r);
233 }
234
235
236 /*
237 * 'cupsRasterReadHeader()' - Read a raster page header and store it in a
238 * version 1 page header structure.
239 *
240 * This function is deprecated. Use @link cupsRasterReadHeader2@ instead.
241 *
242 * Version 1 page headers were used in CUPS 1.0 and 1.1 and contain a subset
243 * of the version 2 page header data. This function handles reading version 2
244 * page headers and copying only the version 1 data into the provided buffer.
245 *
246 * @deprecated@
247 */
248
249 unsigned /* O - 1 on success, 0 on failure/end-of-file */
250 cupsRasterReadHeader(
251 cups_raster_t *r, /* I - Raster stream */
252 cups_page_header_t *h) /* I - Pointer to header data */
253 {
254 /*
255 * Get the raster header...
256 */
257
258 if (!cups_raster_read_header(r))
259 return (0);
260
261 /*
262 * Copy the header to the user-supplied buffer...
263 */
264
265 memcpy(h, &(r->header), sizeof(cups_page_header_t));
266
267 return (1);
268 }
269
270
271 /*
272 * 'cupsRasterReadHeader2()' - Read a raster page header and store it in a
273 * version 2 page header structure.
274 *
275 * @since CUPS 1.2/OS X 10.5@
276 */
277
278 unsigned /* O - 1 on success, 0 on failure/end-of-file */
279 cupsRasterReadHeader2(
280 cups_raster_t *r, /* I - Raster stream */
281 cups_page_header2_t *h) /* I - Pointer to header data */
282 {
283 /*
284 * Get the raster header...
285 */
286
287 if (!cups_raster_read_header(r))
288 return (0);
289
290 /*
291 * Copy the header to the user-supplied buffer...
292 */
293
294 memcpy(h, &(r->header), sizeof(cups_page_header2_t));
295
296 return (1);
297 }
298
299
300 /*
301 * 'cupsRasterReadPixels()' - Read raster pixels.
302 *
303 * For best performance, filters should read one or more whole lines.
304 * The "cupsBytesPerLine" value from the page header can be used to allocate
305 * the line buffer and as the number of bytes to read.
306 */
307
308 unsigned /* O - Number of bytes read */
309 cupsRasterReadPixels(cups_raster_t *r, /* I - Raster stream */
310 unsigned char *p, /* I - Pointer to pixel buffer */
311 unsigned len) /* I - Number of bytes to read */
312 {
313 ssize_t bytes; /* Bytes read */
314 unsigned cupsBytesPerLine; /* cupsBytesPerLine value */
315 unsigned remaining; /* Bytes remaining */
316 unsigned char *ptr, /* Pointer to read buffer */
317 byte, /* Byte from file */
318 *temp; /* Pointer into buffer */
319 unsigned count; /* Repetition count */
320
321
322 if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0 ||
323 r->header.cupsBytesPerLine == 0)
324 return (0);
325
326 if (!r->compressed)
327 {
328 /*
329 * Read without compression...
330 */
331
332 r->remaining -= len / r->header.cupsBytesPerLine;
333
334 if (cups_raster_io(r, p, len) < (ssize_t)len)
335 return (0);
336
337 /*
338 * Swap bytes as needed...
339 */
340
341 if (r->swapped &&
342 (r->header.cupsBitsPerColor == 16 ||
343 r->header.cupsBitsPerPixel == 12 ||
344 r->header.cupsBitsPerPixel == 16))
345 cups_swap(p, len);
346
347 /*
348 * Return...
349 */
350
351 return (len);
352 }
353
354 /*
355 * Read compressed data...
356 */
357
358 remaining = len;
359 cupsBytesPerLine = r->header.cupsBytesPerLine;
360
361 while (remaining > 0 && r->remaining > 0)
362 {
363 if (r->count == 0)
364 {
365 /*
366 * Need to read a new row...
367 */
368
369 if (remaining == cupsBytesPerLine)
370 ptr = p;
371 else
372 ptr = r->pixels;
373
374 /*
375 * Read using a modified PackBits compression...
376 */
377
378 if (!cups_raster_read(r, &byte, 1))
379 return (0);
380
381 r->count = byte + 1;
382
383 if (r->count > 1)
384 ptr = r->pixels;
385
386 temp = ptr;
387 bytes = (ssize_t)cupsBytesPerLine;
388
389 while (bytes > 0)
390 {
391 /*
392 * Get a new repeat count...
393 */
394
395 if (!cups_raster_read(r, &byte, 1))
396 return (0);
397
398 if (byte & 128)
399 {
400 /*
401 * Copy N literal pixels...
402 */
403
404 count = (unsigned)(257 - byte) * r->bpp;
405
406 if (count > (unsigned)bytes)
407 count = (unsigned)bytes;
408
409 if (!cups_raster_read(r, temp, count))
410 return (0);
411
412 temp += count;
413 bytes -= count;
414 }
415 else
416 {
417 /*
418 * Repeat the next N bytes...
419 */
420
421 count = (byte + 1) * r->bpp;
422 if (count > (unsigned)bytes)
423 count = (unsigned)bytes;
424
425 if (count < r->bpp)
426 break;
427
428 bytes -= count;
429
430 if (!cups_raster_read(r, temp, r->bpp))
431 return (0);
432
433 temp += r->bpp;
434 count -= r->bpp;
435
436 while (count > 0)
437 {
438 memcpy(temp, temp - r->bpp, r->bpp);
439 temp += r->bpp;
440 count -= r->bpp;
441 }
442 }
443 }
444
445 /*
446 * Swap bytes as needed...
447 */
448
449 if ((r->header.cupsBitsPerColor == 16 ||
450 r->header.cupsBitsPerPixel == 12 ||
451 r->header.cupsBitsPerPixel == 16) &&
452 r->swapped)
453 cups_swap(ptr, (size_t)bytes);
454
455 /*
456 * Update pointers...
457 */
458
459 if (remaining >= cupsBytesPerLine)
460 {
461 bytes = (ssize_t)cupsBytesPerLine;
462 r->pcurrent = r->pixels;
463 r->count --;
464 r->remaining --;
465 }
466 else
467 {
468 bytes = (ssize_t)remaining;
469 r->pcurrent = r->pixels + bytes;
470 }
471
472 /*
473 * Copy data as needed...
474 */
475
476 if (ptr != p)
477 memcpy(p, ptr, bytes);
478 }
479 else
480 {
481 /*
482 * Copy fragment from buffer...
483 */
484
485 if ((unsigned)(bytes = (int)(r->pend - r->pcurrent)) > remaining)
486 bytes = (ssize_t)remaining;
487
488 memcpy(p, r->pcurrent, bytes);
489 r->pcurrent += bytes;
490
491 if (r->pcurrent >= r->pend)
492 {
493 r->pcurrent = r->pixels;
494 r->count --;
495 r->remaining --;
496 }
497 }
498
499 remaining -= (unsigned)bytes;
500 p += bytes;
501 }
502
503 return (len);
504 }
505
506
507 /*
508 * 'cupsRasterWriteHeader()' - Write a raster page header from a version 1 page
509 * header structure.
510 *
511 * This function is deprecated. Use @link cupsRasterWriteHeader2@ instead.
512 *
513 * @deprecated@
514 */
515
516 unsigned /* O - 1 on success, 0 on failure */
517 cupsRasterWriteHeader(
518 cups_raster_t *r, /* I - Raster stream */
519 cups_page_header_t *h) /* I - Raster page header */
520 {
521 if (r == NULL || r->mode == CUPS_RASTER_READ)
522 return (0);
523
524 /*
525 * Make a copy of the header, and compute the number of raster
526 * lines in the page image...
527 */
528
529 memset(&(r->header), 0, sizeof(r->header));
530 memcpy(&(r->header), h, sizeof(cups_page_header_t));
531
532 cups_raster_update(r);
533
534 /*
535 * Write the raster header...
536 */
537
538 if (r->mode == CUPS_RASTER_WRITE_PWG)
539 {
540 /*
541 * PWG raster data is always network byte order with much of the page header
542 * zeroed.
543 */
544
545 cups_page_header2_t fh; /* File page header */
546
547 memset(&fh, 0, sizeof(fh));
548
549 strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass));
550 /* PwgRaster */
551 strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor));
552 strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType));
553 strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType));
554 /* PrintContentType */
555
556 fh.CutMedia = htonl(r->header.CutMedia);
557 fh.Duplex = htonl(r->header.Duplex);
558 fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
559 fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
560 fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]);
561 fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]);
562 fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]);
563 fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]);
564 fh.InsertSheet = htonl(r->header.InsertSheet);
565 fh.Jog = htonl(r->header.Jog);
566 fh.LeadingEdge = htonl(r->header.LeadingEdge);
567 fh.ManualFeed = htonl(r->header.ManualFeed);
568 fh.MediaPosition = htonl(r->header.MediaPosition);
569 fh.MediaWeight = htonl(r->header.MediaWeight);
570 fh.NumCopies = htonl(r->header.NumCopies);
571 fh.Orientation = htonl(r->header.Orientation);
572 fh.PageSize[0] = htonl(r->header.PageSize[0]);
573 fh.PageSize[1] = htonl(r->header.PageSize[1]);
574 fh.Tumble = htonl(r->header.Tumble);
575 fh.cupsWidth = htonl(r->header.cupsWidth);
576 fh.cupsHeight = htonl(r->header.cupsHeight);
577 fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
578 fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
579 fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
580 fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
581 fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
582 fh.cupsNumColors = htonl(r->header.cupsNumColors);
583 fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]);
584 /* TotalPageCount */
585 fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]);
586 /* CrossFeedTransform */
587 fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]);
588 /* FeedTransform */
589 fh.cupsInteger[3] = htonl(r->header.cupsInteger[3]);
590 /* ImageBoxLeft */
591 fh.cupsInteger[4] = htonl(r->header.cupsInteger[4]);
592 /* ImageBoxTop */
593 fh.cupsInteger[5] = htonl(r->header.cupsInteger[5]);
594 /* ImageBoxRight */
595 fh.cupsInteger[6] = htonl(r->header.cupsInteger[6]);
596 /* ImageBoxBottom */
597 fh.cupsInteger[7] = htonl(r->header.cupsInteger[7]);
598 /* BlackPrimary */
599 fh.cupsInteger[8] = htonl(r->header.cupsInteger[8]);
600 /* PrintQuality */
601 fh.cupsInteger[14] = htonl(r->header.cupsInteger[14]);
602 /* VendorIdentifier */
603 fh.cupsInteger[15] = htonl(r->header.cupsInteger[15]);
604 /* VendorLength */
605
606 memcpy(fh.cupsReal, r->header.cupsReal,
607 sizeof(fh.cupsReal) + sizeof(fh.cupsString));
608 /* VendorData */
609
610 strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent,
611 sizeof(fh.cupsRenderingIntent));
612 strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName,
613 sizeof(fh.cupsPageSizeName));
614
615 return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
616 }
617 else
618 return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
619 == sizeof(r->header));
620 }
621
622
623 /*
624 * 'cupsRasterWriteHeader2()' - Write a raster page header from a version 2
625 * page header structure.
626 *
627 * The page header can be initialized using @link cupsRasterInterpretPPD@.
628 *
629 * @since CUPS 1.2/OS X 10.5@
630 */
631
632 unsigned /* O - 1 on success, 0 on failure */
633 cupsRasterWriteHeader2(
634 cups_raster_t *r, /* I - Raster stream */
635 cups_page_header2_t *h) /* I - Raster page header */
636 {
637 if (r == NULL || r->mode == CUPS_RASTER_READ)
638 return (0);
639
640 /*
641 * Make a copy of the header, and compute the number of raster
642 * lines in the page image...
643 */
644
645 memcpy(&(r->header), h, sizeof(cups_page_header2_t));
646
647 cups_raster_update(r);
648
649 /*
650 * Write the raster header...
651 */
652
653 if (r->mode == CUPS_RASTER_WRITE_PWG)
654 {
655 /*
656 * PWG raster data is always network byte order with most of the page header
657 * zeroed.
658 */
659
660 cups_page_header2_t fh; /* File page header */
661
662 memset(&fh, 0, sizeof(fh));
663 strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass));
664 strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor));
665 strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType));
666 strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType));
667 strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent,
668 sizeof(fh.cupsRenderingIntent));
669 strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName,
670 sizeof(fh.cupsPageSizeName));
671
672 fh.CutMedia = htonl(r->header.CutMedia);
673 fh.Duplex = htonl(r->header.Duplex);
674 fh.HWResolution[0] = htonl(r->header.HWResolution[0]);
675 fh.HWResolution[1] = htonl(r->header.HWResolution[1]);
676 fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]);
677 fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]);
678 fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]);
679 fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]);
680 fh.InsertSheet = htonl(r->header.InsertSheet);
681 fh.Jog = htonl(r->header.Jog);
682 fh.LeadingEdge = htonl(r->header.LeadingEdge);
683 fh.ManualFeed = htonl(r->header.ManualFeed);
684 fh.MediaPosition = htonl(r->header.MediaPosition);
685 fh.MediaWeight = htonl(r->header.MediaWeight);
686 fh.NumCopies = htonl(r->header.NumCopies);
687 fh.Orientation = htonl(r->header.Orientation);
688 fh.PageSize[0] = htonl(r->header.PageSize[0]);
689 fh.PageSize[1] = htonl(r->header.PageSize[1]);
690 fh.Tumble = htonl(r->header.Tumble);
691 fh.cupsWidth = htonl(r->header.cupsWidth);
692 fh.cupsHeight = htonl(r->header.cupsHeight);
693 fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor);
694 fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel);
695 fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine);
696 fh.cupsColorOrder = htonl(r->header.cupsColorOrder);
697 fh.cupsColorSpace = htonl(r->header.cupsColorSpace);
698 fh.cupsNumColors = htonl(r->header.cupsNumColors);
699 fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]);
700 fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]);
701 fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]);
702 fh.cupsInteger[3] = htonl((unsigned)(r->header.cupsImagingBBox[0] *
703 r->header.HWResolution[0]));
704 fh.cupsInteger[4] = htonl((unsigned)(r->header.cupsImagingBBox[1] *
705 r->header.HWResolution[1]));
706 fh.cupsInteger[5] = htonl((unsigned)(r->header.cupsImagingBBox[2] *
707 r->header.HWResolution[0]));
708 fh.cupsInteger[6] = htonl((unsigned)(r->header.cupsImagingBBox[3] *
709 r->header.HWResolution[1]));
710 fh.cupsInteger[7] = htonl(0xffffff);
711
712 return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
713 }
714 else
715 return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
716 == sizeof(r->header));
717 }
718
719
720 /*
721 * 'cupsRasterWritePixels()' - Write raster pixels.
722 *
723 * For best performance, filters should write one or more whole lines.
724 * The "cupsBytesPerLine" value from the page header can be used to allocate
725 * the line buffer and as the number of bytes to write.
726 */
727
728 unsigned /* O - Number of bytes written */
729 cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */
730 unsigned char *p, /* I - Bytes to write */
731 unsigned len)/* I - Number of bytes to write */
732 {
733 ssize_t bytes; /* Bytes read */
734 unsigned remaining; /* Bytes remaining */
735
736
737 DEBUG_printf(("cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u\n",
738 r, p, len, r->remaining));
739
740 if (r == NULL || r->mode == CUPS_RASTER_READ || r->remaining == 0)
741 return (0);
742
743 if (!r->compressed)
744 {
745 /*
746 * Without compression, just write the raster data raw unless the data needs
747 * to be swapped...
748 */
749
750 r->remaining -= len / r->header.cupsBytesPerLine;
751
752 if (r->swapped &&
753 (r->header.cupsBitsPerColor == 16 ||
754 r->header.cupsBitsPerPixel == 12 ||
755 r->header.cupsBitsPerPixel == 16))
756 {
757 unsigned char *bufptr; /* Pointer into write buffer */
758 unsigned count; /* Remaining count */
759
760 /*
761 * Allocate a write buffer as needed...
762 */
763
764 if ((size_t)len > r->bufsize)
765 {
766 if (r->buffer)
767 bufptr = realloc(r->buffer, len);
768 else
769 bufptr = malloc(len);
770
771 if (!bufptr)
772 return (0);
773
774 r->buffer = bufptr;
775 r->bufsize = len;
776 }
777
778 /*
779 * Byte swap the pixels...
780 */
781
782 for (bufptr = r->buffer, count = len; count > 1; count -= 2, bufptr += 2)
783 {
784 bufptr[1] = *p++;
785 bufptr[0] = *p++;
786 }
787
788 if (count) /* This should never happen... */
789 *bufptr = *p;
790
791 /*
792 * Write the byte-swapped buffer...
793 */
794
795 return ((unsigned)cups_raster_io(r, r->buffer, len));
796 }
797 else
798 return ((unsigned)cups_raster_io(r, p, len));
799 }
800
801 /*
802 * Otherwise, compress each line...
803 */
804
805 for (remaining = len; remaining > 0; remaining -= (unsigned)bytes, p += bytes)
806 {
807 /*
808 * Figure out the number of remaining bytes on the current line...
809 */
810
811 if ((bytes = (ssize_t)remaining) > (ssize_t)(r->pend - r->pcurrent))
812 bytes = (ssize_t)(r->pend - r->pcurrent);
813
814 if (r->count > 0)
815 {
816 /*
817 * Check to see if this line is the same as the previous line...
818 */
819
820 if (memcmp(p, r->pcurrent, (size_t)bytes))
821 {
822 if (!cups_raster_write(r, r->pixels))
823 return (0);
824
825 r->count = 0;
826 }
827 else
828 {
829 /*
830 * Mark more bytes as the same...
831 */
832
833 r->pcurrent += bytes;
834
835 if (r->pcurrent >= r->pend)
836 {
837 /*
838 * Increase the repeat count...
839 */
840
841 r->count ++;
842 r->pcurrent = r->pixels;
843
844 /*
845 * Flush out this line if it is the last one...
846 */
847
848 r->remaining --;
849
850 if (r->remaining == 0)
851 return ((unsigned)cups_raster_write(r, r->pixels));
852 else if (r->count == 256)
853 {
854 if (cups_raster_write(r, r->pixels) == 0)
855 return (0);
856
857 r->count = 0;
858 }
859 }
860
861 continue;
862 }
863 }
864
865 if (r->count == 0)
866 {
867 /*
868 * Copy the raster data to the buffer...
869 */
870
871 memcpy(r->pcurrent, p, bytes);
872
873 r->pcurrent += bytes;
874
875 if (r->pcurrent >= r->pend)
876 {
877 /*
878 * Increase the repeat count...
879 */
880
881 r->count ++;
882 r->pcurrent = r->pixels;
883
884 /*
885 * Flush out this line if it is the last one...
886 */
887
888 r->remaining --;
889
890 if (r->remaining == 0)
891 return ((unsigned)cups_raster_write(r, r->pixels));
892 }
893 }
894 }
895
896 return (len);
897 }
898
899
900 /*
901 * 'cups_raster_read_header()' - Read a raster page header.
902 */
903
904 static unsigned /* O - 1 on success, 0 on fail */
905 cups_raster_read_header(
906 cups_raster_t *r) /* I - Raster stream */
907 {
908 size_t len; /* Length for read/swap */
909
910
911 if (r == NULL || r->mode != CUPS_RASTER_READ)
912 return (0);
913
914 /*
915 * Get the length of the raster header...
916 */
917
918 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
919 len = sizeof(cups_page_header_t);
920 else
921 len = sizeof(cups_page_header2_t);
922
923 /*
924 * Read the header...
925 */
926
927 memset(&(r->header), 0, sizeof(r->header));
928
929 if (cups_raster_read(r, (unsigned char *)&(r->header), len) < (ssize_t)len)
930 return (0);
931
932 /*
933 * Swap bytes as needed...
934 */
935
936 if (r->swapped)
937 {
938 unsigned *s, /* Current word */
939 temp; /* Temporary copy */
940
941
942 DEBUG_puts("Swapping header bytes...");
943
944 for (len = 81, s = &(r->header.AdvanceDistance);
945 len > 0;
946 len --, s ++)
947 {
948 DEBUG_printf(("%08x =>", *s));
949
950 temp = *s;
951 *s = ((temp & 0xff) << 24) |
952 ((temp & 0xff00) << 8) |
953 ((temp & 0xff0000) >> 8) |
954 ((temp & 0xff000000) >> 24);
955
956 DEBUG_printf((" %08x\n", *s));
957 }
958 }
959
960 /*
961 * Update the header and row count...
962 */
963
964 cups_raster_update(r);
965
966 return (r->header.cupsBytesPerLine != 0 && r->header.cupsHeight != 0);
967 }
968
969
970 /*
971 * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions.
972 */
973
974 static ssize_t /* O - Bytes read/write or -1 */
975 cups_raster_io(cups_raster_t *r, /* I - Raster stream */
976 unsigned char *buf, /* I - Buffer for read/write */
977 size_t bytes) /* I - Number of bytes to read/write */
978 {
979 ssize_t count, /* Number of bytes read/written */
980 total; /* Total bytes read/written */
981
982
983 DEBUG_printf(("4cups_raster_io(r=%p, buf=%p, bytes=" CUPS_LLFMT ")", r, buf, CUPS_LLCAST bytes));
984
985 for (total = 0; total < (ssize_t)bytes; total += count, buf += count)
986 {
987 count = (*r->iocb)(r->ctx, buf, bytes - (size_t)total);
988
989 DEBUG_printf(("5cups_raster_io: count=%d, total=%d", (int)count,
990 (int)total));
991 if (count == 0)
992 return (0);
993 else if (count < 0)
994 return (-1);
995 }
996
997 return (total);
998 }
999
1000
1001 /*
1002 * 'cups_raster_read()' - Read through the raster buffer.
1003 */
1004
1005 static ssize_t /* O - Number of bytes read */
1006 cups_raster_read(cups_raster_t *r, /* I - Raster stream */
1007 unsigned char *buf, /* I - Buffer */
1008 size_t bytes) /* I - Number of bytes to read */
1009 {
1010 ssize_t count, /* Number of bytes read */
1011 remaining, /* Remaining bytes in buffer */
1012 total; /* Total bytes read */
1013
1014
1015 DEBUG_printf(("cups_raster_read(r=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", r, buf, CUPS_LLCAST bytes));
1016
1017 if (!r->compressed)
1018 return (cups_raster_io(r, buf, bytes));
1019
1020 /*
1021 * Allocate a read buffer as needed...
1022 */
1023
1024 count = (ssize_t)(2 * r->header.cupsBytesPerLine);
1025
1026 if ((size_t)count > r->bufsize)
1027 {
1028 ssize_t offset = r->bufptr - r->buffer;
1029 /* Offset to current start of buffer */
1030 ssize_t end = r->bufend - r->buffer;/* Offset to current end of buffer */
1031 unsigned char *rptr; /* Pointer in read buffer */
1032
1033 if (r->buffer)
1034 rptr = realloc(r->buffer, (size_t)count);
1035 else
1036 rptr = malloc((size_t)count);
1037
1038 if (!rptr)
1039 return (0);
1040
1041 r->buffer = rptr;
1042 r->bufptr = rptr + offset;
1043 r->bufend = rptr + end;
1044 r->bufsize = (size_t)count;
1045 }
1046
1047 /*
1048 * Loop until we have read everything...
1049 */
1050
1051 for (total = 0, remaining = (int)(r->bufend - r->bufptr);
1052 total < (ssize_t)bytes;
1053 total += count, buf += count)
1054 {
1055 count = (ssize_t)bytes - total;
1056
1057 DEBUG_printf(("count=" CUPS_LLFMT ", remaining=" CUPS_LLFMT ", buf=%p, bufptr=%p, bufend=%p...\n", CUPS_LLCAST count, CUPS_LLCAST remaining, buf, r->bufptr, r->bufend));
1058
1059 if (remaining == 0)
1060 {
1061 if (count < 16)
1062 {
1063 /*
1064 * Read into the raster buffer and then copy...
1065 */
1066
1067 remaining = (*r->iocb)(r->ctx, r->buffer, r->bufsize);
1068 if (remaining <= 0)
1069 return (0);
1070
1071 r->bufptr = r->buffer;
1072 r->bufend = r->buffer + remaining;
1073 }
1074 else
1075 {
1076 /*
1077 * Read directly into "buf"...
1078 */
1079
1080 count = (*r->iocb)(r->ctx, buf, (size_t)count);
1081
1082 if (count <= 0)
1083 return (0);
1084
1085 continue;
1086 }
1087 }
1088
1089 /*
1090 * Copy bytes from raster buffer to "buf"...
1091 */
1092
1093 if (count > remaining)
1094 count = remaining;
1095
1096 if (count == 1)
1097 {
1098 /*
1099 * Copy 1 byte...
1100 */
1101
1102 *buf = *(r->bufptr)++;
1103 remaining --;
1104 }
1105 else if (count < 128)
1106 {
1107 /*
1108 * Copy up to 127 bytes without using memcpy(); this is
1109 * faster because it avoids an extra function call and is
1110 * often further optimized by the compiler...
1111 */
1112
1113 unsigned char *bufptr; /* Temporary buffer pointer */
1114
1115 remaining -= count;
1116
1117 for (bufptr = r->bufptr; count > 0; count --, total ++)
1118 *buf++ = *bufptr++;
1119
1120 r->bufptr = bufptr;
1121 }
1122 else
1123 {
1124 /*
1125 * Use memcpy() for a large read...
1126 */
1127
1128 memcpy(buf, r->bufptr, count);
1129 r->bufptr += count;
1130 remaining -= count;
1131 }
1132 }
1133
1134 return (total);
1135 }
1136
1137
1138 /*
1139 * 'cups_raster_update()' - Update the raster header and row count for the
1140 * current page.
1141 */
1142
1143 static void
1144 cups_raster_update(cups_raster_t *r) /* I - Raster stream */
1145 {
1146 if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 ||
1147 r->header.cupsNumColors == 0)
1148 {
1149 /*
1150 * Set the "cupsNumColors" field according to the colorspace...
1151 */
1152
1153 switch (r->header.cupsColorSpace)
1154 {
1155 case CUPS_CSPACE_W :
1156 case CUPS_CSPACE_K :
1157 case CUPS_CSPACE_WHITE :
1158 case CUPS_CSPACE_GOLD :
1159 case CUPS_CSPACE_SILVER :
1160 case CUPS_CSPACE_SW :
1161 r->header.cupsNumColors = 1;
1162 break;
1163
1164 case CUPS_CSPACE_RGB :
1165 case CUPS_CSPACE_CMY :
1166 case CUPS_CSPACE_YMC :
1167 case CUPS_CSPACE_CIEXYZ :
1168 case CUPS_CSPACE_CIELab :
1169 case CUPS_CSPACE_SRGB :
1170 case CUPS_CSPACE_ADOBERGB :
1171 case CUPS_CSPACE_ICC1 :
1172 case CUPS_CSPACE_ICC2 :
1173 case CUPS_CSPACE_ICC3 :
1174 case CUPS_CSPACE_ICC4 :
1175 case CUPS_CSPACE_ICC5 :
1176 case CUPS_CSPACE_ICC6 :
1177 case CUPS_CSPACE_ICC7 :
1178 case CUPS_CSPACE_ICC8 :
1179 case CUPS_CSPACE_ICC9 :
1180 case CUPS_CSPACE_ICCA :
1181 case CUPS_CSPACE_ICCB :
1182 case CUPS_CSPACE_ICCC :
1183 case CUPS_CSPACE_ICCD :
1184 case CUPS_CSPACE_ICCE :
1185 case CUPS_CSPACE_ICCF :
1186 r->header.cupsNumColors = 3;
1187 break;
1188
1189 case CUPS_CSPACE_RGBA :
1190 case CUPS_CSPACE_RGBW :
1191 case CUPS_CSPACE_CMYK :
1192 case CUPS_CSPACE_YMCK :
1193 case CUPS_CSPACE_KCMY :
1194 case CUPS_CSPACE_GMCK :
1195 case CUPS_CSPACE_GMCS :
1196 r->header.cupsNumColors = 4;
1197 break;
1198
1199 case CUPS_CSPACE_KCMYcm :
1200 if (r->header.cupsBitsPerPixel < 8)
1201 r->header.cupsNumColors = 6;
1202 else
1203 r->header.cupsNumColors = 4;
1204 break;
1205
1206 case CUPS_CSPACE_DEVICE1 :
1207 case CUPS_CSPACE_DEVICE2 :
1208 case CUPS_CSPACE_DEVICE3 :
1209 case CUPS_CSPACE_DEVICE4 :
1210 case CUPS_CSPACE_DEVICE5 :
1211 case CUPS_CSPACE_DEVICE6 :
1212 case CUPS_CSPACE_DEVICE7 :
1213 case CUPS_CSPACE_DEVICE8 :
1214 case CUPS_CSPACE_DEVICE9 :
1215 case CUPS_CSPACE_DEVICEA :
1216 case CUPS_CSPACE_DEVICEB :
1217 case CUPS_CSPACE_DEVICEC :
1218 case CUPS_CSPACE_DEVICED :
1219 case CUPS_CSPACE_DEVICEE :
1220 case CUPS_CSPACE_DEVICEF :
1221 r->header.cupsNumColors = r->header.cupsColorSpace -
1222 CUPS_CSPACE_DEVICE1 + 1;
1223 break;
1224 }
1225 }
1226
1227 /*
1228 * Set the number of bytes per pixel/color...
1229 */
1230
1231 if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED)
1232 r->bpp = (r->header.cupsBitsPerPixel + 7) / 8;
1233 else
1234 r->bpp = (r->header.cupsBitsPerColor + 7) / 8;
1235
1236 /*
1237 * Set the number of remaining rows...
1238 */
1239
1240 if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR)
1241 r->remaining = r->header.cupsHeight * r->header.cupsNumColors;
1242 else
1243 r->remaining = r->header.cupsHeight;
1244
1245 /*
1246 * Allocate the compression buffer...
1247 */
1248
1249 if (r->compressed)
1250 {
1251 if (r->pixels != NULL)
1252 free(r->pixels);
1253
1254 r->pixels = calloc(r->header.cupsBytesPerLine, 1);
1255 r->pcurrent = r->pixels;
1256 r->pend = r->pixels + r->header.cupsBytesPerLine;
1257 r->count = 0;
1258 }
1259 }
1260
1261
1262 /*
1263 * 'cups_raster_write()' - Write a row of compressed raster data...
1264 */
1265
1266 static ssize_t /* O - Number of bytes written */
1267 cups_raster_write(
1268 cups_raster_t *r, /* I - Raster stream */
1269 const unsigned char *pixels) /* I - Pixel data to write */
1270 {
1271 const unsigned char *start, /* Start of sequence */
1272 *ptr, /* Current pointer in sequence */
1273 *pend, /* End of raster buffer */
1274 *plast; /* Pointer to last pixel */
1275 unsigned char *wptr; /* Pointer into write buffer */
1276 unsigned bpp, /* Bytes per pixel */
1277 count; /* Count */
1278
1279
1280 DEBUG_printf(("cups_raster_write(r=%p, pixels=%p)\n", r, pixels));
1281
1282 /*
1283 * Allocate a write buffer as needed...
1284 */
1285
1286 count = r->header.cupsBytesPerLine * 2;
1287 if ((size_t)count > r->bufsize)
1288 {
1289 if (r->buffer)
1290 wptr = realloc(r->buffer, count);
1291 else
1292 wptr = malloc(count);
1293
1294 if (!wptr)
1295 return (-1);
1296
1297 r->buffer = wptr;
1298 r->bufsize = count;
1299 }
1300
1301 /*
1302 * Write the row repeat count...
1303 */
1304
1305 bpp = r->bpp;
1306 pend = pixels + r->header.cupsBytesPerLine;
1307 plast = pend - bpp;
1308 wptr = r->buffer;
1309 *wptr++ = (unsigned char)(r->count - 1);
1310
1311 /*
1312 * Write using a modified PackBits compression...
1313 */
1314
1315 for (ptr = pixels; ptr < pend;)
1316 {
1317 start = ptr;
1318 ptr += bpp;
1319
1320 if (ptr == pend)
1321 {
1322 /*
1323 * Encode a single pixel at the end...
1324 */
1325
1326 *wptr++ = 0;
1327 for (count = bpp; count > 0; count --)
1328 *wptr++ = *start++;
1329 }
1330 else if (!memcmp(start, ptr, bpp))
1331 {
1332 /*
1333 * Encode a sequence of repeating pixels...
1334 */
1335
1336 for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp)
1337 if (memcmp(ptr, ptr + bpp, bpp))
1338 break;
1339
1340 *wptr++ = (unsigned char)(count - 1);
1341 for (count = bpp; count > 0; count --)
1342 *wptr++ = *ptr++;
1343 }
1344 else
1345 {
1346 /*
1347 * Encode a sequence of non-repeating pixels...
1348 */
1349
1350 for (count = 1; count < 128 && ptr < plast; count ++, ptr += bpp)
1351 if (!memcmp(ptr, ptr + bpp, bpp))
1352 break;
1353
1354 if (ptr >= plast && count < 128)
1355 {
1356 count ++;
1357 ptr += bpp;
1358 }
1359
1360 *wptr++ = (unsigned char)(257 - count);
1361
1362 count *= bpp;
1363 memcpy(wptr, start, count);
1364 wptr += count;
1365 }
1366 }
1367
1368 return (cups_raster_io(r, r->buffer, (size_t)(wptr - r->buffer)));
1369 }
1370
1371
1372 /*
1373 * 'cups_read_fd()' - Read bytes from a file.
1374 */
1375
1376 static ssize_t /* O - Bytes read or -1 */
1377 cups_read_fd(void *ctx, /* I - File descriptor as pointer */
1378 unsigned char *buf, /* I - Buffer for read */
1379 size_t bytes) /* I - Maximum number of bytes to read */
1380 {
1381 int fd = (int)((intptr_t)ctx);
1382 /* File descriptor */
1383 ssize_t count; /* Number of bytes read */
1384
1385
1386 #ifdef WIN32 /* Sigh */
1387 while ((count = read(fd, buf, (unsigned)bytes)) < 0)
1388 #else
1389 while ((count = read(fd, buf, bytes)) < 0)
1390 #endif /* WIN32 */
1391 if (errno != EINTR && errno != EAGAIN)
1392 return (-1);
1393
1394 return (count);
1395 }
1396
1397
1398 /*
1399 * 'cups_swap()' - Swap bytes in raster data...
1400 */
1401
1402 static void
1403 cups_swap(unsigned char *buf, /* I - Buffer to swap */
1404 size_t bytes) /* I - Number of bytes to swap */
1405 {
1406 unsigned char even, odd; /* Temporary variables */
1407
1408
1409 bytes /= 2;
1410
1411 while (bytes > 0)
1412 {
1413 even = buf[0];
1414 odd = buf[1];
1415 buf[0] = odd;
1416 buf[1] = even;
1417
1418 buf += 2;
1419 bytes --;
1420 }
1421 }
1422
1423
1424 /*
1425 * 'cups_write_fd()' - Write bytes to a file.
1426 */
1427
1428 static ssize_t /* O - Bytes written or -1 */
1429 cups_write_fd(void *ctx, /* I - File descriptor pointer */
1430 unsigned char *buf, /* I - Bytes to write */
1431 size_t bytes) /* I - Number of bytes to write */
1432 {
1433 int fd = (int)((intptr_t)ctx);
1434 /* File descriptor */
1435 ssize_t count; /* Number of bytes written */
1436
1437
1438 #ifdef WIN32 /* Sigh */
1439 while ((count = write(fd, buf, (unsigned)bytes)) < 0)
1440 #else
1441 while ((count = write(fd, buf, bytes)) < 0)
1442 #endif /* WIN32 */
1443 if (errno != EINTR && errno != EAGAIN)
1444 return (-1);
1445
1446 return (count);
1447 }
1448
1449
1450 /*
1451 * End of "$Id$".
1452 */