Coverage Report

Created: 2026-03-19 07:49

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