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