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