Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/vector/gdevxps.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
/* XPS output device */
17
#include "string_.h"
18
#include "stdio_.h"
19
#include "zlib.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gdevvec.h"
23
#include "gxpath.h"
24
#include "gzcpath.h"
25
#include "stream.h"
26
#include "stdint_.h"
27
#include "gdevtifs.h"
28
#include "gsicc_create.h"
29
#include "gsicc_cache.h"
30
#include "gximdecode.h" /* Need so that we can unpack and decode */
31
32
7.67k
#define MAXPRINTERNAME 64
33
34
2.56k
#define MAXNAME 64
35
1.28k
#define PROFILEPATH "Documents/1/Resources/Profiles/"
36
1.28k
#define IMAGEPATH "Documents/1/Resources/Images/"
37
38
/* default resolution. */
39
#ifndef X_DPI
40
#  define X_DPI 96
41
#endif
42
#ifndef Y_DPI
43
#  define Y_DPI 96
44
#endif
45
46
/* default constants */
47
7.67k
#define XPS_DEFAULT_LINEWIDTH   1.0
48
7.67k
#define XPS_DEFAULT_LINECAP     gs_cap_butt
49
7.67k
#define XPS_DEFAULT_LINEJOIN    gs_join_miter
50
7.67k
#define XPS_DEFAULT_MITERLIMIT  4.0
51
52
/* ---------------- Device definition ---------------- */
53
54
/* TODO graphics state definitions are not yet used */
55
56
/* xps join and cap values. */
57
static const char *join_str[] = {"Miter", "Bevel", "Round"};
58
static const char *cap_str[]  = {"Flat",  "Round", "Square", "Triangle"};
59
60
typedef enum {XPS_JOIN, XPS_START_CAP, XPS_END_CAP, XPS_THICK, XPS_MITER_LIMIT,
61
              XPS_STROKE_COLOR, XPS_FILL_COLOR} xps_attr_t;
62
63
typedef struct gx_device_xps_vals {
64
    double f;
65
    uint64_t i;
66
} val_t;
67
68
/* current and default values of state atrributes */
69
typedef struct gx_device_xps_attr_state {
70
    val_t cur;
71
    val_t def;
72
    const char *fmt;
73
    const char **vals;
74
} attr_t;
75
76
/* xps proto state - a copy of this table is made on the heap when the
77
   device is opened and the current state values are filled in at run
78
   time. NB not currently used. */
79
attr_t xps_fixed_state[] = {
80
     /* attribute           current  default         Format String            values */
81
    {/* XPS_JOIN */         {0.0, 0}, {0.0, 0},  "StrokeLineJoin=\"%s\"",     join_str},
82
    {/* XPS_START_CAP */    {0.0, 0}, {0.0, 0},  "StrokeStartLineCap=\"%s\"",  cap_str},
83
    {/* XPS_END_CAP */      {0.0, 0}, {0.0, 0},  "StrokeEndLineCap=\"%s\"",    cap_str},
84
    {/* XPS_THICK */        {0.0, 0}, {1.0, 0},  "StrokeThickness=\"%f\"",     NULL},
85
    {/* XPS_MITER_LIMIT */  {0.0, 0}, {10.0, 0}, "StrokeMiterLimit=\"%f\"",    NULL},
86
    {/* XPS_STROKE_COLOR */ {0.0, 0}, {0.0, 0},  "Stroke=\"%X\"",              NULL},
87
    {/* XPS_FILL_COLOR */   {0.0, 0}, {0.0, 0},  "Fill=\"%X\"",                NULL}
88
};
89
90
/* zip file management - a list of temporary files is maintained along
91
   with the final filename to be used in the archive.  filenames with
92
   associated contents in temporary files are maintained until the end
93
   of the job, at which time we enumerate the list and write the zip
94
   archive.  The exception to this is the image data and icc profiles.  Image
95
   data are stored in temp files and upon end image transferred to the zip
96
   archive and the temp file closed (and removed).  ICC profiles are written
97
   directly to the archive without a temp file. */
98
99
typedef struct gx_device_xps_zdata_s {
100
    gp_file *fp;
101
    ulong count;
102
} gx_device_xps_zdata_t;
103
104
/* Zip info for each file in the zip archive */
105
typedef struct gx_device_xps_zinfo_s {
106
    ulong CRC;
107
    ulong file_size;
108
    gx_device_xps_zdata_t data;
109
    long current_pos;
110
    ushort date;
111
    ushort time;
112
    bool saved;  /* flag to indicate file was already saved (e.g. image or profile) */
113
} gx_device_xps_zinfo_t;
114
115
/* a list of archive file names and their corresponding info
116
   (gx_device_xps_zinfo_t) */
117
typedef struct gx_device_xps_f2i_s {
118
    char *filename;
119
    gx_device_xps_zinfo_t *info;
120
    struct gx_device_xps_f2i_s *next;
121
    gs_memory_t *memory;
122
} gx_device_xps_f2i_t;
123
124
/* Used for keeping track of icc profiles that we have written.   This way we
125
   avoid writing the same one multiple times.  It would be nice to do this
126
   based upon the gs_id for images, but that id is really created after we
127
   have already drawn the path.  Not clear to me how to get a source ID. */
128
typedef struct xps_icc_data_s {
129
    int64_t hash;
130
    int index;
131
    struct xps_icc_data_s *next;
132
} xps_icc_data_t;
133
134
/* Add new page relationships to this linked list, avoiding duplicates.
135
   When page is closed write out all the relationships */
136
typedef struct xps_relations_s xps_relations_t;
137
138
struct xps_relations_s {
139
    char* relation;
140
    xps_relations_t *next;
141
    gs_memory_t *memory;
142
};
143
144
typedef enum {
145
    xps_solidbrush,
146
    xps_imagebrush,
147
    xps_visualbrush
148
} xps_brush_t;
149
150
typedef struct xps_image_enum_s {
151
    gdev_vector_image_enum_common;
152
    gs_matrix mat;
153
    TIFF *tif; /* in non-GC memory */
154
    char file_name[MAXNAME];
155
    char icc_name[MAXNAME];
156
    image_decode_t decode_st;
157
    int bytes_comp;
158
    byte *buffer; /* Needed for unpacking/decoding of image data */
159
    byte *devc_buffer; /* Needed for case where we are mapping to device colors */
160
    gs_color_space *pcs;     /* Needed for Sep, DeviceN, Indexed */
161
    gsicc_link_t *icc_link;  /* Needed for CIELAB */
162
    const gs_gstate *pgs;    /* Needed for color conversions of DeviceN etc */
163
    gp_file *fid;
164
} xps_image_enum_t;
165
166
static void
167
xps_image_enum_finalize(const gs_memory_t *cmem, void *vptr);
168
169
gs_private_st_suffix_add4_final(st_xps_image_enum, xps_image_enum_t,
170
    "xps_image_enum_t", xps_image_enum_enum_ptrs,
171
    xps_image_enum_reloc_ptrs, xps_image_enum_finalize, st_vector_image_enum,
172
    buffer, devc_buffer, pcs, pgs);
173
174
typedef struct gx_device_xps_s {
175
    /* superclass state */
176
    gx_device_vector_common;
177
    /* zip container bookkeeping */
178
    gx_device_xps_f2i_t *f2i;
179
    gx_device_xps_f2i_t *f2i_tail;
180
    /* local state */
181
    int page_count;     /* how many output_page calls we've seen */
182
    int image_count;    /* number of images so far */
183
    xps_relations_t *relations_head;
184
    xps_relations_t *relations_tail;
185
    xps_icc_data_t *icc_data;
186
    gx_color_index strokecolor, fillcolor;
187
    xps_brush_t stroketype, filltype;
188
    xps_image_enum_t *xps_pie;
189
    double linewidth;
190
    gs_line_cap linecap;
191
    gs_line_join linejoin;
192
    double miterlimit;
193
    bool can_stroke;
194
    unsigned char PrinterName[MAXPRINTERNAME];
195
} gx_device_xps;
196
197
gs_public_st_suffix_add1_final(st_device_xps, gx_device_xps,
198
    "gx_device_xps", device_xps_enum_ptrs, device_xps_reloc_ptrs,
199
    gx_device_finalize, st_device_vector, xps_pie);
200
201
#define xps_device_body(dname, depth, init)\
202
  std_device_dci_type_body(gx_device_xps, init, dname, &st_device_xps, \
203
                           DEFAULT_WIDTH_10THS * X_DPI / 10, \
204
                           DEFAULT_HEIGHT_10THS * Y_DPI / 10, \
205
                           X_DPI, Y_DPI, \
206
                           (depth > 8 ? 3 : 1), depth, \
207
                           (depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0), \
208
                           (depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
209
210
static dev_proc_open_device(xps_open_device);
211
static dev_proc_output_page(xps_output_page);
212
static dev_proc_close_device(xps_close_device);
213
static dev_proc_get_params(xps_get_params);
214
static dev_proc_put_params(xps_put_params);
215
static dev_proc_fill_path(gdev_xps_fill_path);
216
static dev_proc_stroke_path(gdev_xps_stroke_path);
217
static dev_proc_initialize_device_procs(xps_initialize_device_procs);
218
static dev_proc_begin_typed_image(xps_begin_typed_image);
219
220
const gx_device_xps gs_xpswrite_device = {
221
    xps_device_body("xpswrite", 24, xps_initialize_device_procs),
222
};
223
224
static int
225
xps_initialize_device(gx_device *dev)
226
7.67k
{
227
7.67k
    gx_device_xps *xps = (gx_device_xps*)dev;
228
229
7.67k
    memset(xps->PrinterName, 0x00, MAXPRINTERNAME);
230
231
7.67k
    return 0;
232
7.67k
}
233
234
static void
235
xps_initialize_device_procs(gx_device *dev)
236
7.67k
{
237
7.67k
    set_dev_proc(dev, initialize_device, xps_initialize_device);
238
7.67k
    set_dev_proc(dev, open_device, xps_open_device);
239
7.67k
    set_dev_proc(dev, output_page, xps_output_page);
240
7.67k
    set_dev_proc(dev, close_device, xps_close_device);
241
7.67k
    set_dev_proc(dev, map_rgb_color, gx_default_rgb_map_rgb_color);
242
7.67k
    set_dev_proc(dev, map_color_rgb, gx_default_rgb_map_color_rgb);
243
7.67k
    set_dev_proc(dev, fill_rectangle, gdev_vector_fill_rectangle);
244
7.67k
    set_dev_proc(dev, get_params, xps_get_params);
245
7.67k
    set_dev_proc(dev, put_params, xps_put_params);
246
7.67k
    set_dev_proc(dev, get_page_device, gx_page_device_get_page_device);
247
7.67k
    set_dev_proc(dev, fill_path, gdev_xps_fill_path);
248
7.67k
    set_dev_proc(dev, stroke_path, gdev_xps_stroke_path);
249
7.67k
    set_dev_proc(dev, begin_typed_image, xps_begin_typed_image);
250
7.67k
}
251
252
/* Vector device procedures */
253
static int
254
xps_beginpage(gx_device_vector *vdev);
255
static int
256
xps_setlinewidth(gx_device_vector *vdev, double width);
257
static int
258
xps_setlinecap(gx_device_vector *vdev, gs_line_cap cap);
259
static int
260
xps_setlinejoin(gx_device_vector *vdev, gs_line_join join);
261
static int
262
xps_setmiterlimit(gx_device_vector *vdev, double limit);
263
static int
264
xps_setdash(gx_device_vector *vdev, const float *pattern,
265
            uint count, double offset);
266
static int
267
xps_setlogop(gx_device_vector *vdev, gs_logical_operation_t lop,
268
             gs_logical_operation_t diff);
269
270
static int
271
xps_can_handle_hl_color(gx_device_vector *vdev, const gs_gstate *pgs,
272
                        const gx_drawing_color * pdc);
273
static int
274
xps_setfillcolor(gx_device_vector *vdev, const gs_gstate *pgs,
275
                 const gx_drawing_color *pdc);
276
static int
277
xps_setstrokecolor(gx_device_vector *vdev, const gs_gstate *pgs,
278
                   const gx_drawing_color *pdc);
279
280
static int
281
xps_dorect(gx_device_vector *vdev, fixed x0, fixed y0,
282
           fixed x1, fixed y1, gx_path_type_t type);
283
static int
284
xps_beginpath(gx_device_vector *vdev, gx_path_type_t type);
285
286
static int
287
xps_moveto(gx_device_vector *vdev, double x0, double y0,
288
           double x, double y, gx_path_type_t type);
289
static int
290
xps_lineto(gx_device_vector *vdev, double x0, double y0,
291
           double x, double y, gx_path_type_t type);
292
static int
293
xps_curveto(gx_device_vector *vdev, double x0, double y0,
294
            double x1, double y1, double x2, double y2,
295
            double x3, double y3, gx_path_type_t type);
296
static int
297
xps_closepath(gx_device_vector *vdev, double x, double y,
298
              double x_start, double y_start, gx_path_type_t type);
299
static int
300
xps_endpath(gx_device_vector *vdev, gx_path_type_t type);
301
302
/* Vector device function table */
303
static const gx_device_vector_procs xps_vector_procs = {
304
    xps_beginpage,
305
    xps_setlinewidth,
306
    xps_setlinecap,
307
    xps_setlinejoin,
308
    xps_setmiterlimit,
309
    xps_setdash,
310
    gdev_vector_setflat,
311
    xps_setlogop,
312
    xps_can_handle_hl_color,
313
    xps_setfillcolor,
314
    xps_setstrokecolor,
315
    gdev_vector_dopath,
316
    xps_dorect,
317
    xps_beginpath,
318
    xps_moveto,
319
    xps_lineto,
320
    xps_curveto,
321
    xps_closepath,
322
    xps_endpath
323
};
324
325
/* Various static content we use in all xps jobs.  We don't use all of
326
   these resource types */
327
static char *xps_content_types = (char *)"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
328
    "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">"
329
    "<Default Extension=\"fdseq\" ContentType=\"application/vnd.ms-package.xps-fixeddocumentsequence+xml\" />"
330
    "<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />"
331
    "<Default Extension=\"fdoc\" ContentType=\"application/vnd.ms-package.xps-fixeddocument+xml\" />"
332
    "<Default Extension=\"fpage\" ContentType=\"application/vnd.ms-package.xps-fixedpage+xml\" />"
333
    "<Default Extension=\"ttf\" ContentType=\"application/vnd.ms-opentype\" />"
334
    "<Default Extension = \"icc\" ContentType = \"application/vnd.ms-color.iccprofile\" />"
335
    "<Default Extension=\"tif\" ContentType=\"image/tiff\" />"
336
    "<Default Extension=\"png\" ContentType=\"image/png\" /></Types>";
337
338
static char *fixed_document_sequence = (char *)"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
339
    "<FixedDocumentSequence xmlns=\"http://schemas.microsoft.com/xps/2005/06\">"
340
    "<DocumentReference Source=\"Documents/1/FixedDocument.fdoc\" />"
341
    "</FixedDocumentSequence>";
342
343
static char *fixed_document_fdoc_header = (char *)"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
344
    "<FixedDocument xmlns=\"http://schemas.microsoft.com/xps/2005/06\">";
345
346
static char *rels_header = (char *)"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
347
    "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n";
348
349
static char *rels_fdseq = (char *)"<Relationship Type=\"http://schemas.microsoft.com/xps/2005/06/fixedrepresentation\" "
350
    "Target=\"/FixedDocumentSequence.fdseq\" Id=\"Rdd12fb46c1de43ab\" />\n"
351
    "</Relationships>\n";
352
353
static char *rels_req_type = (char *) "\"http://schemas.microsoft.com/xps/2005/06/required-resource\"";
354
355
    /* Procedures to manage the containing zip archive */
356
357
/* Append a node of info for this archive file */
358
static int
359
zip_new_info_node(gx_device_xps *xps_dev, const char *filename)
360
37.9k
{
361
37.9k
    gx_device *dev = (gx_device *)xps_dev;
362
37.9k
    gs_memory_t *mem = dev->memory;
363
37.9k
    int lenstr;
364
365
    /* NB should use GC */
366
37.9k
    gx_device_xps_zinfo_t *info =
367
37.9k
        (gx_device_xps_zinfo_t *)gs_alloc_bytes(mem->non_gc_memory, sizeof(gx_device_xps_zinfo_t), "zinfo");
368
37.9k
    gx_device_xps_f2i_t *f2i =
369
37.9k
        (gx_device_xps_f2i_t *)gs_alloc_bytes(mem->non_gc_memory, sizeof(gx_device_xps_f2i_t), "zinfo node");
370
371
37.9k
    if_debug1m('_', dev->memory, "new node %s\n", filename);
372
373
37.9k
    if (info == NULL || f2i == NULL)
374
0
        return gs_throw_code(gs_error_VMerror);
375
376
37.9k
    f2i->info = info;
377
37.9k
    f2i->next = NULL;
378
37.9k
    f2i->memory = mem->non_gc_memory;
379
380
37.9k
    if (xps_dev->f2i == 0) { /* no head */
381
7.67k
        xps_dev->f2i = f2i;
382
7.67k
        xps_dev->f2i_tail = f2i;
383
30.3k
    } else { /* append the node */
384
30.3k
        xps_dev->f2i_tail->next = f2i;
385
30.3k
        xps_dev->f2i_tail = f2i;
386
30.3k
    }
387
388
37.9k
    lenstr = strlen(filename);
389
37.9k
    f2i->filename = (char*)gs_alloc_bytes(mem->non_gc_memory, lenstr + 1, "zinfo_filename");
390
37.9k
    if (f2i->filename == NULL)
391
0
        return gs_throw_code(gs_error_VMerror);
392
37.9k
    strcpy(f2i->filename, filename);
393
394
37.9k
    info->data.fp = 0;
395
37.9k
    info->data.count = 0;
396
37.9k
    info->saved = false;
397
398
37.9k
    if (gs_debug_c('_')) {
399
0
        gx_device_xps_f2i_t *f2i = xps_dev->f2i;
400
#ifdef DEBUG
401
        int node = 1;
402
        gx_device_xps_f2i_t *prev_f2i;
403
#endif
404
405
0
        while (f2i != NULL) {
406
0
            if_debug2m('_', dev->memory, "node:%d %s\n", node++, f2i->filename);
407
#ifdef DEBUG
408
            prev_f2i = f2i;
409
#endif
410
0
            f2i=f2i->next;
411
0
        }
412
0
        if_debug1m('_', dev->memory, "tail okay=%s\n", prev_f2i == xps_dev->f2i_tail ? "yes" : "no");
413
0
    }
414
37.9k
    return 0;
415
37.9k
}
416
417
/* add a new file to the zip archive */
418
static int
419
zip_add_file(gx_device_xps *xps_dev, const char *filename)
420
37.9k
{
421
37.9k
    int code = zip_new_info_node(xps_dev, filename);
422
37.9k
    if (code < 0)
423
0
        return gs_throw_code(gs_error_Fatal);
424
37.9k
    return 0;
425
37.9k
}
426
427
/* look up the information associated with the zip archive [filename] */
428
static gx_device_xps_zinfo_t *
429
zip_look_up_file_info(gx_device_xps *xps_dev, const char *filename)
430
73.7M
{
431
73.7M
    gx_device_xps_f2i_t *cur = xps_dev->f2i;
432
485M
    while (cur) {
433
485M
        if (!strcmp(cur->filename, filename))
434
73.6M
            break;
435
411M
        cur = cur->next;
436
411M
    }
437
73.7M
    return (cur ? cur->info : NULL);
438
73.7M
}
439
440
/* Add data to an archived zip file, create the file if it doesn't exist */
441
static int
442
zip_append_data(gs_memory_t *mem, gx_device_xps_zinfo_t *info, byte *data, uint len)
443
73.6M
{
444
73.6M
    uint count;
445
446
    /* if there is no data then this is the first call for this
447
       archive file, open a temporary file to store the data. */
448
73.6M
    if (info->data.count == 0) {
449
35.7k
        char *filename =
450
35.7k
          (char *)gs_alloc_bytes(mem->non_gc_memory, gp_file_name_sizeof,
451
35.7k
                "zip_append_data(filename)");
452
35.7k
        gp_file *fp;
453
454
35.7k
        if (!filename) {
455
0
            return(gs_throw_code(gs_error_VMerror));
456
0
        }
457
458
35.7k
        fp = gp_open_scratch_file_rm(mem, "xpsdata-",
459
35.7k
                                        filename, "wb+");
460
35.7k
        gs_free_object(mem->non_gc_memory, filename, "zip_append_data(filename)");
461
35.7k
        info->data.fp = fp;
462
35.7k
    }
463
464
    /* shouldn't happen unless the first call opens the temporary file
465
       but writes no data. */
466
73.6M
    if (info->data.fp == NULL)
467
0
        return gs_throw_code(gs_error_Fatal);
468
469
73.6M
    count = gp_fwrite(data, 1, len, info->data.fp);
470
73.6M
    if (count != len) {
471
0
        gp_fclose(info->data.fp);
472
0
        return -1;
473
0
    }
474
    /* probably unnecessary but makes debugging easier */
475
73.6M
    gp_fflush(info->data.fp);
476
73.6M
    info->data.count += len;
477
478
73.6M
    return 0;
479
73.6M
}
480
481
/* write to one of the archives (filename) in the zip archive */
482
static int
483
write_to_zip_file(gx_device_xps *xps_dev, const char *filename,
484
                  byte *data, uint len)
485
73.6M
{
486
73.6M
    gx_device *dev = (gx_device *)xps_dev;
487
73.6M
    gs_memory_t *mem = dev->memory;
488
489
73.6M
    gx_device_xps_zinfo_t *info = zip_look_up_file_info(xps_dev, filename);
490
73.6M
    int code = 0;
491
492
    /* No information on this archive file, create a new zip entry
493
       info node */
494
73.6M
    if (info == NULL) {
495
35.7k
        code = zip_add_file(xps_dev, filename);
496
35.7k
        if (code < 0)
497
0
            return gs_rethrow_code(code);
498
35.7k
        info = zip_look_up_file_info(xps_dev, filename);
499
35.7k
    }
500
501
73.6M
    if (info == NULL)
502
0
        return gs_throw_code(gs_error_Fatal);
503
504
73.6M
    code = zip_append_data(mem, info, data, len);
505
73.6M
    if (code < 0)
506
0
        return gs_rethrow_code(code);
507
508
73.6M
    return code;
509
73.6M
}
510
511
static void
512
put_bytes(stream *zs, byte *buf, uint len)
513
436M
{
514
436M
    uint used;
515
436M
    sputs(zs, buf, len, &used);
516
    /* NB return value */
517
436M
}
518
519
static void
520
put_u32(stream *zs, unsigned long l)
521
402k
{
522
402k
    sputc(zs, (byte)(l));
523
402k
    sputc(zs, (byte)(l >> 8));
524
402k
    sputc(zs, (byte)(l >> 16));
525
402k
    sputc(zs, (byte)(l >> 24));
526
402k
}
527
528
static void
529
put_u16(stream *zs, ushort s)
530
722k
{
531
722k
    sputc(zs, (byte)(s));
532
722k
    sputc(zs, (byte)(s >> 8));
533
722k
}
534
535
/* TODO - the following 2 definitions need to done correctly */
536
static ushort
537
make_dos_date(uint year, uint month, uint day)
538
37.9k
{
539
37.9k
    uint delta_1980 = year - 1980;
540
37.9k
    return (delta_1980 << 9 | month << 5 | day);
541
37.9k
}
542
543
static ushort
544
make_dos_time(uint hour, uint min, uint sec)
545
37.9k
{
546
    /* note the seconds are multiplied by 2 */
547
37.9k
    return (hour << 11 | min << 5 | sec >> 1);
548
37.9k
}
549
550
/* convenience routine. */
551
static int
552
write_str_to_zip_file(gx_device_xps *xps_dev, const char *filename,
553
                      const char *str)
554
73.6M
{
555
73.6M
    return write_to_zip_file(xps_dev, filename, (byte *)str, strlen(str));
556
73.6M
}
557
558
/* Used to add ICC profiles to the zip file. */
559
static int
560
add_data_to_zip_file(gx_device_xps *xps_dev, const char *filename, byte *buf, long size)
561
918
{
562
918
    gx_device_xps_zinfo_t *info = zip_look_up_file_info(xps_dev, filename);
563
918
    int code;
564
918
    long curr_pos;
565
918
    unsigned long crc = 0;
566
918
    stream *f;
567
918
    ushort date, time;
568
569
    /* This file should not yet exist */
570
918
    if (info == NULL) {
571
918
        code = zip_add_file(xps_dev, filename);
572
918
        if (code < 0)
573
0
            return gs_rethrow_code(code);
574
918
        info = zip_look_up_file_info(xps_dev, filename);
575
918
    }
576
0
    else {
577
0
        return gs_throw_code(gs_error_Fatal);
578
0
    }
579
918
    f = ((gx_device_vector*)xps_dev)->strm;
580
918
    curr_pos = stell(f);
581
582
    /* Figure out the crc */
583
918
    crc = crc32(0L, Z_NULL, 0);
584
918
    crc = crc32(crc, buf, size);
585
586
918
    date = make_dos_date(2012, 2, 16);
587
918
    time = make_dos_time(9, 15, 0);
588
589
918
    put_u32(f, 0x04034b50); /* magic */
590
918
    put_u16(f, 20);         /* version */
591
918
    put_u16(f, 0);          /* flags */
592
918
    put_u16(f, 0);          /* method */
593
918
    put_u16(f, time);
594
918
    put_u16(f, date);
595
918
    put_u32(f, crc);
596
918
    put_u32(f, size); /* compressed */
597
918
    put_u32(f, size); /* uncompressed */
598
918
    put_u16(f, strlen(filename));
599
918
    put_u16(f, 0);         /* extra field length */
600
918
    put_bytes(f, (byte *)filename, strlen(filename));
601
918
    put_bytes(f, buf, size);
602
918
    put_bytes(f, 0, 0); /* extra field */
603
604
    /* Now we need to add the info about this file */
605
918
    xps_dev->f2i_tail->info->CRC = crc;
606
918
    xps_dev->f2i_tail->info->time = time;
607
918
    xps_dev->f2i_tail->info->date = date;
608
918
    xps_dev->f2i_tail->info->data.count = size;
609
918
    xps_dev->f2i_tail->info->current_pos = curr_pos;
610
918
    xps_dev->f2i_tail->info->file_size = size;
611
    /* Mark the file as already stored */
612
918
    xps_dev->f2i_tail->info->saved = true;
613
918
    return 0;
614
918
}
615
616
/* Used to add images to the zip file. This file is added now
617
and not later like the other files */
618
static int
619
add_file_to_zip_file(gx_device_xps *xps_dev, const char *filename, gp_file *src)
620
1.27k
{
621
1.27k
    gx_device_xps_zinfo_t *info = zip_look_up_file_info(xps_dev, filename);
622
1.27k
    int code = 0;
623
1.27k
    long curr_pos;
624
1.27k
    unsigned long crc = 0;
625
1.27k
    byte buf[4];
626
1.27k
    uint nread;
627
1.27k
    unsigned long count = 0;
628
1.27k
    stream *f;
629
1.27k
    ushort date, time;
630
631
    /* This file should not yet exist */
632
1.27k
    if (info == NULL) {
633
1.27k
        code = zip_add_file(xps_dev, filename);
634
1.27k
        if (code < 0)
635
0
            return gs_rethrow_code(code);
636
1.27k
        info = zip_look_up_file_info(xps_dev, filename);
637
1.27k
    }
638
0
    else {
639
0
        return gs_throw_code(gs_error_Fatal);
640
0
    }
641
642
1.27k
    f = ((gx_device_vector*)xps_dev)->strm;
643
1.27k
    curr_pos = stell(f);
644
645
    /* Get to the start */
646
1.27k
    if (gp_fseek(src, 0, 0) < 0)
647
0
        return gs_throw_code(gs_error_Fatal);
648
649
    /* Figure out the crc */
650
1.27k
    crc = crc32(0L, Z_NULL, 0);
651
    /* Chunks of 4 until we get to remainder */
652
45.7M
    while (!gp_feof(src)) {
653
45.7M
        nread = gp_fread(buf, 1, sizeof(buf), src);
654
45.7M
        count = count + nread;
655
45.7M
        crc = crc32(crc, buf, nread);
656
45.7M
    }
657
658
1.27k
    date = make_dos_date(2012, 2, 16);
659
1.27k
    time = make_dos_time(9, 15, 0);
660
661
1.27k
    put_u32(f, 0x04034b50); /* magic */
662
1.27k
    put_u16(f, 20);         /* version */
663
1.27k
    put_u16(f, 0);          /* flags */
664
1.27k
    put_u16(f, 0);          /* method */
665
1.27k
    put_u16(f, time);
666
1.27k
    put_u16(f, date);
667
1.27k
    put_u32(f, crc);
668
1.27k
    put_u32(f, count); /* compressed */
669
1.27k
    put_u32(f, count); /* uncompressed */
670
1.27k
    put_u16(f, strlen(filename));
671
1.27k
    put_u16(f, 0);         /* extra field length */
672
1.27k
    put_bytes(f, (byte *)filename, strlen(filename));
673
1.27k
    {
674
1.27k
        if (gp_fseek(src, (gs_offset_t)0, 0) < 0)
675
0
            return gs_throw_code(gs_error_Fatal);
676
45.7M
        while (!gp_feof(src)) {
677
45.7M
            ulong nread = gp_fread(buf, 1, sizeof(buf), src);
678
45.7M
            put_bytes(f, buf, nread);
679
45.7M
        }
680
1.27k
    }
681
0
    put_bytes(f, 0, 0); /* extra field */
682
683
    /* Now we need to add the info about this file */
684
1.27k
    xps_dev->f2i_tail->info->CRC = crc;
685
1.27k
    xps_dev->f2i_tail->info->time = time;
686
1.27k
    xps_dev->f2i_tail->info->date = date;
687
1.27k
    xps_dev->f2i_tail->info->data.count = count;
688
1.27k
    xps_dev->f2i_tail->info->current_pos = curr_pos;
689
1.27k
    xps_dev->f2i_tail->info->file_size = count;
690
    /* Mark the file as already stored */
691
1.27k
    xps_dev->f2i_tail->info->saved = true;
692
1.27k
    return 0;
693
1.27k
}
694
695
/* zip up a single file moving its data from the temporary file to the
696
   zip container. */
697
static int
698
zip_close_archive_file(gx_device_xps *xps_dev, const char *filename)
699
37.9k
{
700
37.9k
    gx_device_xps_zinfo_t *info = zip_look_up_file_info(xps_dev, filename);
701
37.9k
    gx_device_xps_zdata_t data;
702
37.9k
    byte buf[4];
703
37.9k
    unsigned long crc = 0;
704
37.9k
    int count = 0;
705
37.9k
    int len;
706
    /* we can't use the vector stream accessor because it calls beginpage */
707
37.9k
    stream *f = ((gx_device_vector*)xps_dev)->strm;
708
709
37.9k
    if (info == NULL)
710
0
        return -1;
711
712
    /* Already stored */
713
37.9k
    if (info->saved)
714
2.19k
        return 0;
715
716
35.7k
    data = info->data;
717
35.7k
    if ((int)data.count >= 0) {
718
35.7k
        gp_file *fp = data.fp;
719
35.7k
        uint nread;
720
721
35.7k
        if (fp == NULL)
722
0
            return gs_throw_code(gs_error_Fatal);
723
724
35.7k
        crc = crc32(0L, Z_NULL, 0);
725
35.7k
        gp_rewind(fp);
726
390M
        while (!gp_feof(fp)) {
727
390M
            nread = gp_fread(buf, 1, sizeof(buf), fp);
728
390M
            crc = crc32(crc, buf, nread);
729
390M
            count = count + nread;
730
390M
        }
731
        /* If this is a TIFF file, then update the data count information.
732
           During the writing of the TIFF directory there is seeking and
733
           relocations that occur, which make data.count incorrect.
734
           We could just do this for all the files and avoid the test. */
735
35.7k
        len = strlen(filename);
736
35.7k
        if (len > 3 && (strncmp("tif", &(filename[len - 3]), 3) == 0)) {
737
0
            info->data.count = count;
738
0
            data = info->data;
739
0
            data.fp = fp;
740
0
        }
741
35.7k
    }
742
743
35.7k
    info->current_pos = stell(f);
744
35.7k
    info->CRC = crc;
745
746
    /* NB should use ghostscript "gp" time and date functions for
747
       this, for now we hardwire the dates. */
748
35.7k
    info->date = make_dos_date(2012, 2, 16);
749
35.7k
    info->time = make_dos_time(9, 15, 0);
750
751
35.7k
    put_u32(f, 0x04034b50); /* magic */
752
35.7k
    put_u16(f, 20);         /* version */
753
35.7k
    put_u16(f, 0);          /* flags */
754
35.7k
    put_u16(f, 0);          /* method */
755
35.7k
    put_u16(f, info->time);
756
35.7k
    put_u16(f, info->date);
757
35.7k
    put_u32(f, crc);
758
35.7k
    put_u32(f, data.count); /* compressed */
759
35.7k
    put_u32(f, data.count); /* uncompressed */
760
35.7k
    put_u16(f, strlen(filename));
761
35.7k
    put_u16(f, 0);         /* extra field length */
762
35.7k
    put_bytes(f, (byte *)filename, strlen(filename));
763
35.7k
    {
764
35.7k
        gp_file *fp = data.fp;
765
35.7k
        gp_rewind(fp);
766
390M
        while (!gp_feof(fp)) {
767
390M
                ulong nread = gp_fread(buf, 1, sizeof(buf), fp);
768
390M
                put_bytes(f, buf, nread);
769
390M
        }
770
35.7k
        gp_fclose(fp);
771
35.7k
    }
772
35.7k
    put_bytes(f, 0, 0); /* extra field */
773
774
    /* Mark as saved */
775
35.7k
    info->saved = true;
776
35.7k
    return 0;
777
35.7k
}
778
779
/* walk the file info node list writing all the files to the
780
   archive */
781
static int
782
zip_close_all_archive_files(gx_device_xps *xps_dev)
783
7.67k
{
784
7.67k
    gx_device_xps_f2i_t *f2i = xps_dev->f2i;
785
45.6k
    while (f2i) {
786
37.9k
        int code = zip_close_archive_file(xps_dev, f2i->filename);
787
37.9k
        if (code < 0) {
788
0
            return code;
789
0
        }
790
37.9k
        f2i = f2i->next;
791
37.9k
    }
792
7.67k
    return 0;
793
7.67k
}
794
795
/* write all files to the zip container and write the zip central
796
   directory */
797
static int
798
zip_close_archive(gx_device_xps *xps_dev)
799
7.67k
{
800
7.67k
    gx_device_xps_f2i_t *f2i = xps_dev->f2i;
801
802
7.67k
    int entry_count = 0;
803
7.67k
    long pos_before_cd;
804
7.67k
    long pos_after_cd;
805
    /* we can't use the vector stream accessor because it calls beginpage */
806
7.67k
    stream *f = ((gx_device_vector*)xps_dev)->strm;
807
7.67k
    int code = zip_close_all_archive_files(xps_dev);
808
809
7.67k
    pos_before_cd = stell(f);
810
811
7.67k
    if (code < 0)
812
0
        return code;
813
814
45.6k
    while (f2i) {
815
37.9k
        gx_device_xps_zinfo_t *info = f2i->info;
816
37.9k
        put_u32(f, 0x02014b50); /* magic */
817
37.9k
        put_u16(f, 20); /* version made by */
818
37.9k
        put_u16(f, 20); /* version required */
819
37.9k
        put_u16(f, 0); /* bit flag */
820
37.9k
        put_u16(f, 0); /* compression method */
821
37.9k
        put_u16(f, info->time);
822
37.9k
        put_u16(f, info->date);
823
37.9k
        put_u32(f, info->CRC);
824
37.9k
        put_u32(f, info->data.count);  /* compressed */
825
37.9k
        put_u32(f, info->data.count); /* uncompressed */
826
37.9k
        put_u16(f, strlen(f2i->filename));
827
828
        /* probably will never use the next 6 so we just set them to
829
           zero here */
830
37.9k
        put_u16(f, 0); /* extra field length */
831
37.9k
        put_u16(f, 0); /* file comment length */
832
37.9k
        put_u16(f, 0); /* disk number */
833
37.9k
        put_u16(f, 0); /* internal file attributes */
834
37.9k
        put_u32(f, 0); /* external file attributes */
835
836
37.9k
        put_u32(f, info->current_pos);
837
37.9k
        put_bytes(f, (byte *)f2i->filename, strlen(f2i->filename));
838
839
37.9k
        put_bytes(f, 0, 0); /* extra field */
840
37.9k
        put_bytes(f, 0, 0); /* extra comment */
841
842
37.9k
        entry_count++;
843
37.9k
        f2i = f2i->next;
844
37.9k
    }
845
846
7.67k
    pos_after_cd = stell(f);
847
848
7.67k
    put_u32(f, 0x06054b50);
849
7.67k
    put_u16(f, 0); /* number of disks */
850
7.67k
    put_u16(f, 0); /* disk where central directory starts */
851
7.67k
    put_u16(f, entry_count); /* # of records in cd */
852
7.67k
    put_u16(f, entry_count); /* total # of records in cd */
853
7.67k
    put_u32(f, pos_after_cd - pos_before_cd); /* size of central cd */
854
7.67k
    put_u32(f, pos_before_cd); /* offset of central directory */
855
7.67k
    put_u16(f, 0); /* comment length */
856
7.67k
    put_bytes(f, 0, 0); /* comment */
857
858
7.67k
    return 0;
859
7.67k
}
860
861
/* Brush management */
862
static void
863
xps_setstrokebrush(gx_device_xps *xps, xps_brush_t type)
864
10.2k
{
865
10.2k
    if_debug1m('_', xps->memory, "xps_setstrokebrush:%d\n", (int)type);
866
867
10.2k
    xps->stroketype = type;
868
10.2k
}
869
870
static void
871
xps_setfillbrush(gx_device_xps *xps, xps_brush_t type)
872
10.2k
{
873
10.2k
    if_debug1m('_', xps->memory, "xps_setfillbrush:%d\n", (int)type);
874
875
10.2k
    xps->filltype = type;
876
10.2k
}
877
878
/* Device procedures */
879
static int
880
xps_open_device(gx_device *dev)
881
7.67k
{
882
7.67k
    gx_device_vector * vdev = (gx_device_vector*)dev;
883
7.67k
    gx_device_xps * xps = (gx_device_xps*)dev;
884
7.67k
    int code = 0;
885
886
7.67k
    vdev->v_memory = dev->memory;
887
7.67k
    vdev->vec_procs = &xps_vector_procs;
888
7.67k
    gdev_vector_init(vdev);
889
7.67k
    code = gdev_vector_open_file_options(vdev, 512,
890
7.67k
        VECTOR_OPEN_FILE_SEQUENTIAL);
891
7.67k
    if (code < 0)
892
0
      return gs_rethrow_code(code);
893
894
    /* In case ths device has been subclassed, descend to the terminal
895
     * of the chain. (Setting the variables in a subclassing device
896
     * doesn't do anythign useful.....)
897
     */
898
7.67k
    while(vdev->child)
899
0
        vdev = (gx_device_vector *)vdev->child;
900
7.67k
    xps = (gx_device_xps*)vdev;
901
902
    /* xps-specific initialization goes here */
903
7.67k
    xps->page_count = 0;
904
7.67k
    xps->relations_head = NULL;
905
7.67k
    xps->relations_tail = NULL;
906
7.67k
    xps->strokecolor = gx_no_color_index;
907
7.67k
    xps->fillcolor = gx_no_color_index;
908
7.67k
    xps_setstrokebrush(xps, xps_solidbrush);
909
7.67k
    xps_setfillbrush(xps, xps_solidbrush);
910
    /* these should be the graphics library defaults instead? */
911
7.67k
    xps->linewidth = XPS_DEFAULT_LINEWIDTH;
912
7.67k
    xps->linecap = XPS_DEFAULT_LINECAP;
913
7.67k
    xps->linejoin = XPS_DEFAULT_LINEJOIN;
914
7.67k
    xps->miterlimit = XPS_DEFAULT_MITERLIMIT;
915
7.67k
    xps->can_stroke = true;
916
    /* zip info */
917
7.67k
    xps->f2i = NULL;
918
7.67k
    xps->f2i_tail = NULL;
919
920
    /* Image related stuff */
921
7.67k
    xps->image_count = 0;
922
7.67k
    xps->xps_pie = NULL;
923
924
    /* ICC related stuff */
925
7.67k
    xps->icc_data = NULL;
926
927
7.67k
    code = write_str_to_zip_file(xps, (char *)"FixedDocumentSequence.fdseq",
928
7.67k
                                 fixed_document_sequence);
929
7.67k
    if (code < 0)
930
0
        return gs_rethrow_code(code);
931
932
7.67k
    code = write_str_to_zip_file(xps, (char *)"[Content_Types].xml",
933
7.67k
                                 xps_content_types);
934
7.67k
    if (code < 0)
935
0
        return gs_rethrow_code(code);
936
937
7.67k
    code = write_str_to_zip_file(xps,
938
7.67k
                                 (char *)"Documents/1/FixedDocument.fdoc",
939
7.67k
                                 fixed_document_fdoc_header);
940
7.67k
    if (code < 0)
941
0
        return gs_rethrow_code(code);
942
943
    /* Right out the magical stuff related to the fix document sequence relationship */
944
7.67k
    code = write_str_to_zip_file(xps, (char *)"_rels/.rels", rels_header);
945
7.67k
    if (code < 0)
946
0
        return gs_rethrow_code(code);
947
948
7.67k
    code = write_str_to_zip_file(xps, (char *)"_rels/.rels", rels_fdseq);
949
7.67k
    if (code < 0)
950
0
        return gs_rethrow_code(code);
951
952
7.67k
    return code;
953
7.67k
}
954
955
/* write xps commands to Pages/%d.fpage */
956
static int
957
write_str_to_current_page(gx_device_xps *xps, const char *str)
958
73.5M
{
959
73.5M
    const char *page_template = "Documents/1/Pages/%d.fpage";
960
73.5M
    char buf[128]; /* easily enough to accommodate the string and a page number */
961
962
    /* we're one ahead of the page count */
963
73.5M
    int code = gs_snprintf(buf, sizeof(buf), page_template, xps->page_count+1);
964
73.5M
    if (code < 0)
965
0
        return gs_rethrow_code(code);
966
967
73.5M
    return write_str_to_zip_file(xps, buf, str);
968
73.5M
}
969
970
/* add relationship to Pages/_rels/%d.fpage.rels */
971
static int
972
add_new_relationship(gx_device_xps *xps, const char *str)
973
2.55k
{
974
2.55k
    xps_relations_t *rel;
975
976
    /* See if we already have this one */
977
4.96k
    for (rel = xps->relations_head; rel; rel = rel->next)
978
2.65k
        if (!strcmp(rel->relation, str))
979
242
            return 0;
980
981
2.31k
    rel = (xps_relations_t*)gs_alloc_bytes(xps->memory->non_gc_memory,
982
2.31k
        sizeof(xps_relations_t), "add_new_relationship");
983
2.31k
    if (!rel) {
984
0
        return gs_throw_code(gs_error_VMerror);
985
0
    }
986
2.31k
    rel->memory = xps->memory->non_gc_memory;
987
2.31k
    rel->next = NULL;
988
989
2.31k
    rel->relation = (char*)gs_alloc_bytes(xps->memory->non_gc_memory,
990
2.31k
        strlen(str) + 1, "add_new_relationship");
991
2.31k
    if (!rel->relation) {
992
0
        gs_free_object(rel->memory, rel, "add_new_relationship");
993
0
        return gs_throw_code(gs_error_VMerror);
994
0
    }
995
2.31k
    memcpy(rel->relation, str, strlen(str) + 1);
996
997
2.31k
    if (!xps->relations_head) {
998
969
        xps->relations_head = rel;
999
969
        xps->relations_tail = rel;
1000
1.34k
    } else {
1001
1.34k
        xps->relations_tail->next = rel;
1002
1.34k
        xps->relations_tail = rel;
1003
1.34k
    }
1004
1005
2.31k
    return 0;
1006
2.31k
}
1007
1008
static int
1009
close_page_relationship(gx_device_xps *xps)
1010
969
{
1011
969
    const char *rels_template = "Documents/1/Pages/_rels/%d.fpage.rels";
1012
969
    char buf[128]; /* easily enough to accommodate the string and a page number */
1013
1014
969
    int code = gs_snprintf(buf, sizeof(buf), rels_template, xps->page_count + 1);
1015
969
    if (code < 0)
1016
0
        return gs_rethrow_code(code);
1017
1018
969
    write_str_to_zip_file(xps, buf, "</Relationships>");
1019
969
    return 0;
1020
969
}
1021
1022
static int
1023
write_page_relationship(gx_device_xps* xps)
1024
969
{
1025
969
    const char* rels_template = "Documents/1/Pages/_rels/%d.fpage.rels";
1026
969
    char buf[128]; /* easily enough to accommodate the string and a page number */
1027
969
    char line[300];
1028
969
    const char* fmt;
1029
969
    int count = 0;
1030
969
    xps_relations_t *rel = xps->relations_head;
1031
1032
969
    int code = gs_snprintf(buf, sizeof(buf), rels_template, xps->page_count + 1);
1033
969
    if (code < 0)
1034
0
        return gs_rethrow_code(code);
1035
1036
969
    write_str_to_zip_file(xps, buf, rels_header);
1037
969
    fmt = "<Relationship Target = \"/%s\" Id = \"R%d\" Type = %s/>\n";
1038
1039
3.28k
    while (rel) {
1040
2.31k
        gs_snprintf(line, sizeof(line), fmt, rel->relation, count, rels_req_type);
1041
2.31k
        write_str_to_zip_file(xps, buf, line);
1042
2.31k
        rel = rel->next;
1043
2.31k
        count++;
1044
2.31k
    }
1045
1046
969
    return 0;
1047
969
}
1048
1049
static void
1050
release_relationship(gx_device_xps* xps)
1051
969
{
1052
969
    xps_relations_t *rel = xps->relations_head;
1053
969
    xps_relations_t *old;
1054
1055
3.28k
    while (rel) {
1056
2.31k
        old = rel;
1057
2.31k
        rel = rel->next;
1058
2.31k
        gs_free_object(old->memory, old->relation, "release_relationship");
1059
2.31k
        gs_free_object(old->memory, old, "release_relationship");
1060
2.31k
    }
1061
1062
969
    xps->relations_head = NULL;
1063
969
    xps->relations_tail = NULL;
1064
969
    return;
1065
969
}
1066
1067
        /* Page management */
1068
1069
/* Complete a page */
1070
static int
1071
xps_output_page(gx_device *dev, int num_copies, int flush)
1072
3.64k
{
1073
3.64k
    gx_device_xps *const xps = (gx_device_xps*)dev;
1074
3.64k
    gx_device_vector *vdev = (gx_device_vector *)dev;
1075
3.64k
    int code;
1076
1077
3.64k
    write_str_to_current_page(xps, "</Canvas></FixedPage>");
1078
1079
3.64k
    if (xps->relations_head)
1080
969
    {
1081
        /* Write all the relations for the page */
1082
969
        code = write_page_relationship(xps);
1083
969
        if (code < 0)
1084
0
            return gs_rethrow_code(code);
1085
1086
        /* Close the relationship xml */
1087
969
        code = close_page_relationship(xps);
1088
969
        if (code < 0)
1089
0
            return gs_rethrow_code(code);
1090
1091
969
        release_relationship(xps);
1092
969
    }
1093
1094
3.64k
    xps->page_count++;
1095
1096
3.64k
    if (gp_ferror(xps->file))
1097
0
      return gs_throw_code(gs_error_ioerror);
1098
1099
3.64k
    if ((code=gx_finish_output_page(dev, num_copies, flush)) < 0)
1100
0
        return code;
1101
1102
    /* Check if we need to change the output file for separate
1103
       pages. NB not sure if this will work correctly. */
1104
3.64k
    if (gx_outputfile_is_separate_pages(((gx_device_vector *)dev)->fname, dev->memory)) {
1105
0
        if ((code = xps_close_device(dev)) < 0)
1106
0
            return code;
1107
0
        code = xps_open_device(dev);
1108
0
    }
1109
1110
3.64k
    if_debug1m('_', dev->memory, "xps_output_page - page=%d\n", xps->page_count);
1111
3.64k
    vdev->in_page = false;
1112
1113
3.64k
    return code;
1114
3.64k
}
1115
1116
static void
1117
xps_release_icc_info(gx_device *dev)
1118
7.67k
{
1119
7.67k
    gx_device_xps *xps = (gx_device_xps*)dev;
1120
7.67k
    xps_icc_data_t *curr;
1121
7.67k
    xps_icc_data_t *icc_data = xps->icc_data;
1122
1123
8.59k
    while (icc_data != NULL) {
1124
918
        curr = icc_data;
1125
918
        icc_data = icc_data->next;
1126
918
        gs_free(dev->memory->non_gc_memory, curr, sizeof(xps_icc_data_t), 1,
1127
918
            "xps_release_icc_info");
1128
918
    }
1129
7.67k
    return;
1130
7.67k
}
1131
1132
static void
1133
xps_release_achive_file_names(gx_device* dev)
1134
7.67k
{
1135
7.67k
    gx_device_xps* xps = (gx_device_xps*)dev;
1136
7.67k
    gx_device_xps_f2i_t *curr;
1137
7.67k
    gx_device_xps_f2i_t *f2i = xps->f2i;
1138
1139
45.6k
    while (f2i) {
1140
37.9k
        curr = f2i;
1141
37.9k
        f2i = f2i->next;
1142
37.9k
        gs_free_object(curr->memory, curr->info, "xps_release_achive_file_names(info)");
1143
37.9k
        gs_free_object(curr->memory, curr->filename, "xps_release_achive_file_names(filename)");
1144
37.9k
        gs_free_object(curr->memory, curr, "xps_release_achive_file_names(f2i)");
1145
37.9k
    }
1146
7.67k
    return;
1147
7.67k
}
1148
1149
/* Close the device */
1150
static int
1151
xps_close_device(gx_device *dev)
1152
7.67k
{
1153
7.67k
    gx_device_xps *xps = (gx_device_xps*)dev;
1154
7.67k
    int code;
1155
1156
    /* closing for the FixedDocument */
1157
7.67k
    code = write_str_to_zip_file(xps, "Documents/1/FixedDocument.fdoc", "</FixedDocument>");
1158
7.67k
    if (code < 0)
1159
0
        return gs_rethrow_code(code);
1160
1161
7.67k
    if (gp_ferror(xps->file))
1162
0
      return gs_throw_code(gs_error_ioerror);
1163
1164
7.67k
    code = zip_close_archive(xps);
1165
7.67k
    if (code < 0)
1166
0
        return gs_rethrow_code(code);
1167
1168
    /* Release the icc info */
1169
7.67k
    xps_release_icc_info(dev);
1170
1171
    /* Release the archive file names */
1172
7.67k
    xps_release_achive_file_names(dev);
1173
1174
7.67k
    code = gdev_vector_close_file((gx_device_vector*)dev);
1175
7.67k
    if (code < 0)
1176
0
        return gs_rethrow_code(code);
1177
1178
7.67k
    if (strlen((const char *)xps->PrinterName)) {
1179
0
        int reason;
1180
0
        code = gp_xpsprint(xps->fname, (char *)xps->PrinterName, &reason);
1181
0
        if (code < 0) {
1182
0
            switch(code) {
1183
0
                case -1:
1184
0
                    break;
1185
0
                case -2:
1186
0
                    eprintf1("ERROR: Could not create competion event: %08X\n", reason);
1187
0
                    break;
1188
0
                case -3:
1189
0
                    eprintf1("ERROR: Could not create MultiByteString from PrinerName: %s\n", xps->PrinterName);
1190
0
                    break;
1191
0
                case -4:
1192
0
                    eprintf1("ERROR: Could not start XPS print job: %08X\n", reason);
1193
0
                    break;
1194
0
                case -5:
1195
0
                    eprintf1("ERROR: Could not create XPS OM Object Factory: %08X\n", reason);
1196
0
                    break;
1197
0
                case -6:
1198
0
                    eprintf1("ERROR: Could not create MultiByteString from OutputFile: %s\n", xps->fname);
1199
0
                    break;
1200
0
                case -7:
1201
0
                    eprintf1("ERROR: Could not create Package from File %08X\n", reason);
1202
0
                    break;
1203
0
                case -8:
1204
0
                    eprintf1("ERROR: Could not write Package to stream %08X\n", reason);
1205
0
                    break;
1206
0
                case -9:
1207
0
                    eprintf1("ERROR: Could not close job stream: %08X\n", reason);
1208
0
                    break;
1209
0
                case -10:
1210
0
                    eprintf1("ERROR: Wait for completion event failed: %08X\n", reason);
1211
0
                    break;
1212
0
                case -11:
1213
0
                    eprintf1("ERROR: Could not get job status: %08X\n", reason);
1214
0
                    break;
1215
0
                case -12:
1216
0
                    eprintf("ERROR: job was cancelled\n");
1217
0
                    break;
1218
0
                case -13:
1219
0
                    eprintf1("ERROR: Print job failed: %08X\n", reason);
1220
0
                    break;
1221
0
                case -14:
1222
0
                    eprintf("ERROR: unexpected failure\n");
1223
0
                    break;
1224
0
                case -15:
1225
0
                case -16:
1226
0
                    eprintf("ERROR: XpsPrint.dll does not exist or is missing a required method\n");
1227
0
                    break;
1228
0
            }
1229
0
            return(gs_throw_code(gs_error_invalidaccess));
1230
0
        }
1231
0
    }
1232
7.67k
    return(0);
1233
7.67k
}
1234
1235
/* Respond to a device parameter query from the client */
1236
static int
1237
xps_get_params(gx_device *dev, gs_param_list *plist)
1238
134k
{
1239
134k
    int code = 0;
1240
1241
134k
    if_debug0m('_', dev->memory, "xps_get_params\n");
1242
1243
    /* call our superclass to add its standard set */
1244
134k
    code = gdev_vector_get_params(dev, plist);
1245
134k
    if (code < 0)
1246
0
      return gs_rethrow_code(code);
1247
1248
#if defined(__WIN32__) && XPSPRINT==1
1249
    {
1250
        gs_param_string ofns;
1251
        gx_device_xps *const xps = (gx_device_xps*)dev;
1252
1253
        /* xps specific parameters are added to plist here */
1254
        ofns.data = (const byte *)&xps->PrinterName;
1255
        ofns.size = strlen(xps->fname);
1256
        ofns.persistent = false;
1257
        if ((code = param_write_string(plist, "PrinterName", &ofns)) < 0)
1258
            return code;
1259
    }
1260
#endif
1261
134k
    return code;
1262
134k
}
1263
1264
/* Read the device parameters passed to us by the client */
1265
static int
1266
xps_put_params(gx_device *dev, gs_param_list *plist)
1267
63.0k
{
1268
63.0k
    int code = 0;
1269
1270
63.0k
    if_debug0m('_', dev->memory, "xps_put_params\n");
1271
1272
    /* xps specific parameters are parsed here */
1273
#if defined(__WIN32__) && XPSPRINT==1
1274
    { /* NB: The following is not strictly correct since changes are */
1275
        /*     made even if 'gdev_vector_put_params' returns an error. */
1276
        gs_param_name param_name;
1277
        gs_param_string pps;
1278
        gx_device_xps *const xps = (gx_device_xps*)dev;
1279
        switch (code = param_read_string(plist, (param_name = "PrinterName"), &pps)) {
1280
        case 0:
1281
            if (pps.size > 64) {
1282
                eprintf1("\nERROR: PrinterName too long (max %d)\n", MAXPRINTERNAME);
1283
            } else {
1284
                memcpy(xps->PrinterName, pps.data, pps.size);
1285
                xps->PrinterName[pps.size] = 0;
1286
            }
1287
            break;
1288
        default:
1289
            param_signal_error(plist, param_name, code);
1290
        case 1:
1291
            /*            memset(&xps->PrinterName, 0x00, MAXPRINTERNAME);*/
1292
            break;
1293
        }
1294
    }
1295
#endif
1296
    /* call our superclass to get its parameters, like OutputFile */
1297
63.0k
    code = gdev_vector_put_params(dev, plist);  /* errors are handled by caller  or setpagedevice */
1298
1299
63.0k
    return code;
1300
63.0k
}
1301
1302
static int
1303
set_state_color(gx_device_vector *vdev, const gx_drawing_color *pdc, gx_color_index *color)
1304
1.33M
{
1305
1.33M
    gx_device_xps *xps = (gx_device_xps *)vdev;
1306
1307
    /* hack so beginpage is called */
1308
1.33M
    (void)gdev_vector_stream((gx_device_vector*)xps);
1309
1310
    /* Usually this is not an actual error but a signal to the
1311
       graphics library to simplify the color */
1312
1.33M
    if (!gx_dc_is_pure(pdc)) {
1313
1.23k
        return_error(gs_error_rangecheck);
1314
1.23k
    }
1315
1316
1.33M
    *color = gx_dc_pure_color(pdc);
1317
1.33M
    return 0;
1318
1.33M
}
1319
1320
static int
1321
xps_setfillcolor(gx_device_vector *vdev, const gs_gstate *pgs, const gx_drawing_color *pdc)
1322
1.33M
{
1323
1.33M
    gx_device_xps *xps = (gx_device_xps *)vdev;
1324
1325
1.33M
    if_debug1m('_', xps->memory, "xps_setfillcolor:%06X\n", (uint32_t)gx_dc_pure_color(pdc));
1326
1327
1.33M
    return set_state_color(vdev, pdc, &xps->fillcolor);
1328
1.33M
}
1329
1330
static int
1331
xps_setstrokecolor(gx_device_vector *vdev, const gs_gstate *pgs, const gx_drawing_color *pdc)
1332
1.78k
{
1333
1.78k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1334
1335
1.78k
    if_debug1m('_', xps->memory, "xps_setstrokecolor:%06X\n", (uint32_t)gx_dc_pure_color(pdc));
1336
1337
1.78k
    return set_state_color(vdev, pdc, &xps->strokecolor);
1338
1.78k
}
1339
1340
static int
1341
xps_beginpage(gx_device_vector *vdev)
1342
3.62k
{
1343
1344
3.62k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1345
3.62k
    char buf[128];
1346
3.62k
    int code = 0;
1347
1348
3.62k
    if_debug0m('_', xps->memory, "xps_beginpage\n");
1349
1350
3.62k
    {
1351
3.62k
        const char *template = "<PageContent Source=\"Pages/%d.fpage\" />";
1352
        /* Note page count is 1 less than the current page */
1353
3.62k
        code = gs_snprintf(buf, sizeof(buf), template, xps->page_count + 1);
1354
3.62k
        if (code < 0)
1355
0
            return gs_rethrow_code(code);
1356
1357
        /* Put a reference to this new page in the FixedDocument */
1358
3.62k
        code = write_str_to_zip_file(xps, "Documents/1/FixedDocument.fdoc", buf);
1359
3.62k
        if (code < 0)
1360
0
            return gs_rethrow_code(code);
1361
1362
3.62k
    }
1363
1364
3.62k
    {
1365
3.62k
        const char *page_size_template = "<FixedPage Width=\"%d\" Height=\"%d\" "
1366
3.62k
            "xmlns=\"http://schemas.microsoft.com/xps/2005/06\" xml:lang=\"en-US\">\n";
1367
3.62k
        code = gs_snprintf(buf, sizeof(buf), page_size_template,
1368
3.62k
                       (int)(xps->MediaSize[0] * 4.0/3.0),  /* pts -> 1/96 inch */
1369
3.62k
                       (int)(xps->MediaSize[1] * 4.0/3.0));
1370
3.62k
        if (code < 0)
1371
0
            return gs_rethrow_code(code);
1372
3.62k
        code = write_str_to_current_page(xps, buf);
1373
3.62k
        if (code < 0)
1374
0
            return gs_rethrow_code(code);
1375
3.62k
    }
1376
3.62k
    {
1377
3.62k
        const char *canvas_template = "<Canvas RenderTransform=\"%g,%g,%g,%g,%g,%g\">\n";
1378
3.62k
        code = gs_snprintf(buf, sizeof(buf), canvas_template,
1379
3.62k
                       96.0/xps->HWResolution[0], 0.0, 0.0,
1380
3.62k
                       96.0/xps->HWResolution[1], 0.0, 0.0);
1381
3.62k
        if (code < 0)
1382
0
            return gs_rethrow_code(code);
1383
1384
3.62k
        code = write_str_to_current_page(xps, buf);
1385
3.62k
        if (code < 0)
1386
0
            return gs_rethrow_code(code);
1387
3.62k
    }
1388
1389
3.62k
    if_debug4m('_', xps->memory,
1390
3.62k
               "page info: resx=%g resy=%g width=%d height=%d\n",
1391
3.62k
               xps->HWResolution[0], xps->HWResolution[1],
1392
3.62k
               (int)xps->MediaSize[0], (int)xps->MediaSize[1]);
1393
1394
3.62k
    return code;
1395
3.62k
}
1396
1397
static int
1398
xps_setlinewidth(gx_device_vector *vdev, double width)
1399
1.67k
{
1400
1.67k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1401
1402
1.67k
    if_debug1m('_', xps->memory, "xps_setlinewidth(%lf)\n", width);
1403
1404
1.67k
    xps->linewidth = width;
1405
1406
1.67k
    return 0;
1407
1.67k
}
1408
static int
1409
xps_setlinecap(gx_device_vector *vdev, gs_line_cap cap)
1410
255
{
1411
255
    gx_device_xps *xps = (gx_device_xps *)vdev;
1412
#ifdef DEBUG
1413
    /* Only used for debug print, so guiard to prevent warnings on non-debug builds */
1414
    const char *linecap_names[] = {"butt", "round", "square",
1415
        "triangle", "unknown"};
1416
#endif
1417
1418
255
    if ((int)cap < 0 || (int)cap > gs_cap_unknown)
1419
0
        return gs_throw_code(gs_error_rangecheck);
1420
255
    if_debug1m('_', xps->memory, "xps_setlinecap(%s)\n", linecap_names[cap]);
1421
1422
255
    xps->linecap = cap;
1423
1424
255
    return 0;
1425
255
}
1426
static int
1427
xps_setlinejoin(gx_device_vector *vdev, gs_line_join join)
1428
152
{
1429
152
    gx_device_xps *xps = (gx_device_xps *)vdev;
1430
#ifdef DEBUG
1431
    /* Only used for debug print, so guiard to prevent warnings on non-debug builds */
1432
    const char *linejoin_names[] = {"miter", "round", "bevel",
1433
        "none", "triangle", "unknown"};
1434
#endif
1435
1436
152
    if ((int)join < 0 || (int)join > gs_join_unknown)
1437
0
        return gs_throw_code(gs_error_rangecheck);
1438
152
    if_debug1m('_', xps->memory, "xps_setlinejoin(%s)\n", linejoin_names[join]);
1439
1440
152
    xps->linejoin = join;
1441
1442
152
    return 0;
1443
152
}
1444
static int
1445
xps_setmiterlimit(gx_device_vector *vdev, double limit)
1446
330
{
1447
330
    if_debug1m('_', vdev->memory, "xps_setmiterlimit(%lf)\n", limit);
1448
330
    return 0;
1449
330
}
1450
static int
1451
xps_setdash(gx_device_vector *vdev, const float *pattern,
1452
            uint count, double offset)
1453
142
{
1454
142
    gx_device_xps *xps = (gx_device_xps *)vdev;
1455
142
    if_debug2m('_', vdev->memory, "xps_setdash count:%d offset:%g\n", count, offset);
1456
142
    xps->can_stroke = (count == 0);
1457
142
    return 0;
1458
142
}
1459
static int
1460
xps_setlogop(gx_device_vector *vdev, gs_logical_operation_t lop,
1461
             gs_logical_operation_t diff)
1462
27.8k
{
1463
27.8k
    if_debug2m('_', vdev->memory, "xps_setlogop(%u,%u) set logical operation\n",
1464
27.8k
        lop, diff);
1465
    /* XPS can fake some simpler modes, but we ignore this for now. */
1466
27.8k
    return 0;
1467
27.8k
}
1468
1469
        /* Other state */
1470
1471
static int
1472
xps_can_handle_hl_color(gx_device_vector *vdev, const gs_gstate *pgs,
1473
                          const gx_drawing_color *pdc)
1474
23.3M
{
1475
23.3M
    if_debug0m('_', vdev->memory, "xps_can_handle_hl_color\n");
1476
23.3M
    return 0;
1477
23.3M
}
1478
1479
/* Paths */
1480
static bool
1481
image_brush_fill(gx_path_type_t path_type, xps_brush_t brush_type)
1482
23.9M
{
1483
23.9M
    return brush_type == xps_imagebrush;
1484
23.9M
}
1485
1486
static bool
1487
drawing_path(gx_path_type_t path_type, xps_brush_t brush_type)
1488
27.5M
{
1489
27.5M
    return ((path_type & gx_path_type_stroke) || (path_type & gx_path_type_fill) ||
1490
27.5M
        image_brush_fill(path_type, brush_type));
1491
27.5M
}
1492
1493
static void
1494
xps_finish_image_path(gx_device_vector *vdev)
1495
2.96k
{
1496
2.96k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1497
2.96k
    char line[300];
1498
2.96k
    const char *fmt;
1499
2.96k
    gs_matrix matrix;
1500
1501
    /* If an error occurs during an image, we can get here after the enumerator
1502
     * has been freed - if that's the case, just bail out immediately
1503
     */
1504
2.96k
    if (xps->xps_pie == NULL)
1505
1.68k
        return;
1506
    /* Path is started.  Do the image brush image brush and close the path */
1507
1.27k
    write_str_to_current_page(xps, "\t<Path.Fill>\n");
1508
1.27k
    write_str_to_current_page(xps, "\t\t<ImageBrush ");
1509
1.27k
    fmt = "ImageSource = \"{ColorConvertedBitmap /%s /%s}\" Viewbox=\"%d, %d, %d, %d\" ViewboxUnits = \"Absolute\" Viewport = \"%d, %d, %d, %d\" ViewportUnits = \"Absolute\" TileMode = \"None\" >\n";
1510
1.27k
    gs_snprintf(line, sizeof(line), fmt, xps->xps_pie->file_name, xps->xps_pie->icc_name,
1511
1.27k
        0, 0, xps->xps_pie->width, xps->xps_pie->height, 0, 0,
1512
1.27k
        xps->xps_pie->width, xps->xps_pie->height);
1513
1.27k
    write_str_to_current_page(xps, line);
1514
1515
    /* Now the render transform.  This is applied to the image brush. Path
1516
    is already transformed */
1517
1.27k
    write_str_to_current_page(xps, "\t\t\t<ImageBrush.Transform>\n");
1518
1.27k
    fmt = "\t\t\t\t<MatrixTransform Matrix = \"%g,%g,%g,%g,%g,%g\" />\n";
1519
1.27k
    matrix = xps->xps_pie->mat;
1520
1.27k
    gs_snprintf(line, sizeof(line), fmt,
1521
1.27k
        matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.tx, matrix.ty);
1522
1.27k
    write_str_to_current_page(xps, line);
1523
1.27k
    write_str_to_current_page(xps, "\t\t\t</ImageBrush.Transform>\n");
1524
1.27k
    write_str_to_current_page(xps, "\t\t</ImageBrush>\n");
1525
1.27k
    write_str_to_current_page(xps, "\t</Path.Fill>\n");
1526
    /* End this path */
1527
1.27k
    write_str_to_current_page(xps, "</Path>\n");
1528
1.27k
}
1529
1530
static int
1531
xps_dorect(gx_device_vector *vdev, fixed x0, fixed y0,
1532
           fixed x1, fixed y1, gx_path_type_t type)
1533
22.8M
{
1534
22.8M
    gx_device_xps *xps = (gx_device_xps *)vdev;
1535
22.8M
    char line[300];
1536
22.8M
    const char *fmt;
1537
22.8M
    uint32_t c;
1538
1539
22.8M
    (void)gdev_vector_stream((gx_device_vector*)xps);
1540
1541
22.8M
    if_debug9m('_', xps->memory,
1542
22.8M
               "rect type=%d coords=%g,%g %g,%g %g,%g %g,%g\n", type,
1543
22.8M
                fixed2float(x0), fixed2float(y0),
1544
22.8M
                fixed2float(x0), fixed2float(y1),
1545
22.8M
                fixed2float(x1), fixed2float(y1),
1546
22.8M
                fixed2float(x1), fixed2float(y0));
1547
1548
1549
    /* skip non-drawing paths for now */
1550
22.8M
    if (!drawing_path(type, xps->filltype)) {
1551
20.8k
        if_debug1m('_', xps->memory, "xps_dorect: type not supported %x\n", type);
1552
20.8k
        return 0;
1553
20.8k
    }
1554
1555
22.8M
    if ((type & gx_path_type_stroke) && !xps->can_stroke) {
1556
10
        return_error(gs_error_rangecheck);
1557
10
    }
1558
1559
22.8M
    if (image_brush_fill(type, xps->filltype)) {
1560
        /* Do the path data  */
1561
2.03k
        fmt = "<Path Data=\"M %g, %g L %g, %g %g, %g %g, %g Z\" >\n";
1562
2.03k
        gs_snprintf(line, sizeof(line), fmt,
1563
2.03k
            fixed2float(x0), fixed2float(y0),
1564
2.03k
            fixed2float(x0), fixed2float(y1),
1565
2.03k
            fixed2float(x1), fixed2float(y1),
1566
2.03k
            fixed2float(x1), fixed2float(y0));
1567
2.03k
        write_str_to_current_page(xps, line);
1568
        /* And now the rest of the details */
1569
2.03k
        xps_finish_image_path(vdev);
1570
22.8M
    } else if (type & gx_path_type_fill) {
1571
        /* Solid fill */
1572
22.8M
        write_str_to_current_page(xps, "<Path ");
1573
        /* NB - F0 should be changed for a different winding type */
1574
22.8M
        fmt = "Fill=\"#%06X\" Data=\"M %g,%g V %g H %g V %g Z\" ";
1575
22.8M
        c = xps->fillcolor & 0xffffffL;
1576
22.8M
        gs_snprintf(line, sizeof(line), fmt, c,
1577
22.8M
                   fixed2float(x0), fixed2float(y0),
1578
22.8M
                   fixed2float(y1), fixed2float(x1),
1579
22.8M
                   fixed2float(y0));
1580
22.8M
        write_str_to_current_page(xps, line);
1581
22.8M
        write_str_to_current_page(xps, "/>\n");
1582
22.8M
    } else {
1583
        /* Solid stroke */
1584
11.1k
        write_str_to_current_page(xps, "<Path ");
1585
11.1k
        fmt = "Stroke=\"#%06X\" Data=\"M %g,%g V %g H %g V %g Z\" ";
1586
11.1k
        c = xps->strokecolor & 0xffffffL;
1587
11.1k
        gs_snprintf(line, sizeof(line), fmt, c,
1588
11.1k
                   fixed2float(x0), fixed2float(y0),
1589
11.1k
                   fixed2float(y1), fixed2float(x1),
1590
11.1k
                   fixed2float(y0));
1591
11.1k
        write_str_to_current_page(xps, line);
1592
1593
11.1k
        if (type & gx_path_type_stroke) {
1594
            /* NB format width. */
1595
11.1k
            fmt = "StrokeThickness=\"%g\" ";
1596
11.1k
            gs_snprintf(line, sizeof(line), fmt, xps->linewidth);
1597
11.1k
            write_str_to_current_page(xps, line);
1598
11.1k
        }
1599
11.1k
        write_str_to_current_page(xps, "/>\n");
1600
11.1k
    }
1601
    /* end and close NB \n not necessary. */
1602
22.8M
    return 0;
1603
22.8M
}
1604
1605
static int
1606
gdev_xps_fill_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath,
1607
                   const gx_fill_params * params,
1608
                   const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1609
520k
{
1610
520k
    if (gx_path_is_void(ppath)) {
1611
5.39k
        return 0;
1612
5.39k
    }
1613
515k
    return gdev_vector_fill_path(dev, pgs, ppath, params, pdcolor, pcpath);
1614
520k
}
1615
1616
static int
1617
gdev_xps_stroke_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath,
1618
                     const gx_stroke_params * params,
1619
                     const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
1620
27.1k
{
1621
27.1k
    if (gx_path_is_void(ppath)) {
1622
660
        return 0;
1623
660
    }
1624
26.5k
    return gdev_vector_stroke_path(dev, pgs, ppath, params, pdcolor, pcpath);
1625
27.1k
}
1626
1627
static int
1628
xps_beginpath(gx_device_vector *vdev, gx_path_type_t type)
1629
484k
{
1630
484k
    char line[300];
1631
484k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1632
484k
    uint32_t c;
1633
484k
    const char *fmt;
1634
1635
484k
    (void)gdev_vector_stream((gx_device_vector*)xps);
1636
1637
    /* skip non-drawing paths for now */
1638
484k
    if (!drawing_path(type, xps->filltype)) {
1639
15.6k
        if_debug1m('_', xps->memory, "xps_beginpath: type not supported %x\n", type);
1640
15.6k
        return 0;
1641
15.6k
    }
1642
1643
469k
    if (!xps->can_stroke) {
1644
489
        return_error(gs_error_rangecheck);
1645
489
    }
1646
1647
468k
    c = type & gx_path_type_fill ? xps->fillcolor : xps->strokecolor;
1648
468k
    c &= 0xffffffL;
1649
1650
468k
    if (!image_brush_fill(type, xps->filltype)) {
1651
467k
        write_str_to_current_page(xps, "<Path ");
1652
467k
        if (type & gx_path_type_fill)
1653
459k
            fmt = "Fill=\"#%06X\" Data=\"";
1654
8.34k
        else
1655
8.34k
            fmt = "Stroke=\"#%06X\" Data=\"";
1656
467k
        gs_snprintf(line, sizeof(line), fmt, c);
1657
467k
        write_str_to_current_page(xps, line);
1658
467k
    }
1659
930
    else {
1660
930
        write_str_to_current_page(xps, "<Path Data=\"");
1661
930
    }
1662
1663
468k
    if_debug1m('_', xps->memory, "xps_beginpath %s\n", line);
1664
1665
468k
    return 0;
1666
469k
}
1667
1668
static int
1669
xps_moveto(gx_device_vector *vdev, double x0, double y0,
1670
           double x, double y, gx_path_type_t type)
1671
559k
{
1672
559k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1673
559k
    char line[300];
1674
1675
559k
    if_debug2m('_', xps->memory, "xps_moveto %g %g\n", x, y);
1676
1677
    /* skip non-drawing paths for now */
1678
559k
    if (!drawing_path(type, xps->filltype)) {
1679
33.5k
        if_debug1m('_', xps->memory, "xps_moveto: type not supported %x\n", type);
1680
33.5k
        return 0;
1681
33.5k
    }
1682
1683
526k
    gs_snprintf(line, sizeof(line), " M %g,%g", x, y);
1684
526k
    write_str_to_current_page(xps, line);
1685
526k
    if_debug1m('_', xps->memory, "xps_moveto %s", line);
1686
526k
    return 0;
1687
559k
}
1688
1689
static int
1690
xps_lineto(gx_device_vector *vdev, double x0, double y0,
1691
           double x, double y, gx_path_type_t type)
1692
2.25M
{
1693
2.25M
    gx_device_xps *xps = (gx_device_xps *)vdev;
1694
2.25M
    char line[200];
1695
1696
2.25M
    if_debug2m('_', xps->memory, "xps_lineto %g %g\n", x, y);
1697
1698
    /* skip non-drawing paths for now */
1699
2.25M
    if (!drawing_path(type, xps->filltype)) {
1700
100k
        if_debug1m('_', xps->memory, "xps_lineto: type not supported %x\n", type);
1701
100k
        return 0;
1702
100k
    }
1703
2.15M
    gs_snprintf(line, sizeof(line), " L %g,%g", x, y);
1704
2.15M
    write_str_to_current_page(xps, line);
1705
2.15M
    if_debug1m('_', xps->memory, "xps_lineto %s\n", line);
1706
2.15M
    return 0;
1707
2.25M
}
1708
1709
static int
1710
xps_curveto(gx_device_vector *vdev, double x0, double y0,
1711
            double x1, double y1, double x2, double y2,
1712
            double x3, double y3, gx_path_type_t type)
1713
933k
{
1714
933k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1715
933k
    char line[200];
1716
1717
    /* skip non-drawing paths for now */
1718
933k
    if (!drawing_path(type, xps->filltype)) {
1719
162
        if_debug1m('_', xps->memory, "xps_curveto: type not supported %x\n", type);
1720
162
        return 0;
1721
162
    }
1722
1723
933k
    gs_snprintf(line, sizeof(line), " C %g,%g %g,%g %g,%g", x1, y1,
1724
933k
            x2,y2,x3,y3);
1725
933k
    write_str_to_current_page(xps,line);
1726
933k
    if_debug1m('_', xps->memory, "xps_curveto %s\n", line);
1727
1728
933k
    return 0;
1729
933k
}
1730
1731
static int
1732
xps_closepath(gx_device_vector *vdev, double x, double y,
1733
              double x_start, double y_start, gx_path_type_t type)
1734
16.8k
{
1735
16.8k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1736
1737
    /* skip non-drawing paths for now */
1738
16.8k
    if (!drawing_path(type, xps->filltype)) {
1739
67
        if_debug1m('_', xps->memory, "xps_closepath: type not supported %x\n", type);
1740
67
        return 0;
1741
67
    }
1742
1743
16.8k
    write_str_to_current_page(xps, " Z");
1744
16.8k
    if_debug0m('_', xps->memory, "xps_closepath");
1745
1746
16.8k
    return 0;
1747
16.8k
}
1748
1749
static int
1750
xps_endpath(gx_device_vector *vdev, gx_path_type_t type)
1751
484k
{
1752
484k
    gx_device_xps *xps = (gx_device_xps *)vdev;
1753
484k
    char line[200];
1754
484k
    const char *fmt;
1755
1756
    /* skip non-drawing paths for now */
1757
484k
    if (!drawing_path(type, xps->filltype)) {
1758
15.6k
        if_debug1m('_', xps->memory, "xps_endpath: type not supported %x\n", type);
1759
15.6k
        return 0;
1760
15.6k
    }
1761
1762
468k
    if (image_brush_fill(type, xps->filltype)) {
1763
930
        write_str_to_current_page(xps, "\" >\n");
1764
        /* And now the rest of the details */
1765
930
        xps_finish_image_path(vdev);
1766
467k
    } else if (type & gx_path_type_stroke) {
1767
        /* NB format width. */
1768
8.34k
        fmt = "\" StrokeThickness=\"%g\" />\n";
1769
8.34k
        gs_snprintf(line, sizeof(line), fmt, xps->linewidth);
1770
8.34k
        write_str_to_current_page(xps, line);
1771
459k
    } else { /* fill */
1772
        /* close the path data attribute */
1773
459k
        write_str_to_current_page(xps, "\" />\n");
1774
459k
    }
1775
1776
468k
    return 0;
1777
484k
}
1778
1779
/* Image handling */
1780
static image_enum_proc_plane_data(xps_image_data);
1781
static image_enum_proc_end_image(xps_image_end_image);
1782
static const gx_image_enum_procs_t xps_image_enum_procs = {
1783
    xps_image_data, xps_image_end_image
1784
};
1785
1786
/* High level image support */
1787
/* Prototypes */
1788
static TIFF* tiff_from_name(gx_device_xps *dev, const char *name, int big_endian,
1789
    bool usebigtiff);
1790
static int tiff_set_values(xps_image_enum_t *pie, TIFF *tif,
1791
                            cmm_profile_t *profile, bool force8bit);
1792
static void xps_tiff_set_handlers(void);
1793
static void xps_tiff_cleanup(xps_image_enum_t *xpie);
1794
1795
/* Check if we have the ICC profile in the package */
1796
static xps_icc_data_t*
1797
xps_find_icc(const gx_device_xps *xdev, cmm_profile_t *icc_profile)
1798
2.56k
{
1799
2.56k
    xps_icc_data_t *icc_data = xdev->icc_data;
1800
1801
2.64k
    while (icc_data != NULL) {
1802
1.72k
        if (icc_data->hash == gsicc_get_hash(icc_profile)) {
1803
1.64k
            return icc_data;
1804
1.64k
        }
1805
78
        icc_data = icc_data->next;
1806
78
    }
1807
918
    return NULL;
1808
2.56k
}
1809
1810
static int
1811
xps_create_icc_name(const gx_device_xps *xps_dev, cmm_profile_t *profile, char *name)
1812
1.28k
{
1813
1.28k
    xps_icc_data_t *icc_data;
1814
1815
1.28k
    icc_data = xps_find_icc(xps_dev, profile);
1816
1.28k
    if (icc_data == NULL)
1817
0
        return gs_throw_code(gs_error_rangecheck);  /* Should be there */
1818
1819
1.28k
    snprintf(name, MAXNAME, "%sProfile_%d.icc", PROFILEPATH, icc_data->index);
1820
1.28k
    return 0;
1821
1.28k
}
1822
1823
static void
1824
xps_create_image_name(gx_device *dev, char *name)
1825
1.28k
{
1826
1.28k
    gx_device_xps *const xdev = (gx_device_xps *)dev;
1827
1828
1.28k
    snprintf(name, MAXNAME, "%s%d.tif", IMAGEPATH, xdev->image_count);
1829
1.28k
    xdev->image_count++;
1830
1.28k
}
1831
1832
static int
1833
xps_add_icc_relationship(xps_image_enum_t *pie)
1834
1.28k
{
1835
1.28k
    gx_device_xps *xps = (gx_device_xps*) (pie->dev);
1836
1.28k
    int code;
1837
1838
1.28k
    code = add_new_relationship(xps, pie->icc_name);
1839
1.28k
    if (code < 0)
1840
0
        return gs_rethrow_code(code);
1841
1842
1.28k
    return 0;
1843
1.28k
}
1844
1845
static int
1846
xps_add_image_relationship(xps_image_enum_t *pie)
1847
1.27k
{
1848
1.27k
    gx_device_xps *xps = (gx_device_xps*) (pie->dev);
1849
1.27k
    int code;
1850
1851
1.27k
    code = add_new_relationship(xps, pie->file_name);
1852
1.27k
    if (code < 0)
1853
0
        return gs_rethrow_code(code);
1854
1.27k
    return 0;
1855
1.27k
}
1856
1857
static int
1858
xps_write_profile(const gs_gstate *pgs, char *name, cmm_profile_t *profile, gx_device_xps *xps_dev)
1859
918
{
1860
918
    byte *profile_buffer;
1861
918
    int size;
1862
1863
    /* Need V2 ICC Profile */
1864
918
    profile_buffer = gsicc_create_getv2buffer(pgs, profile, &size);
1865
1866
    /* Now go ahead and add to the zip archive */
1867
918
    return add_data_to_zip_file(xps_dev, name, profile_buffer, size);
1868
918
}
1869
1870
static int
1871
xps_begin_typed_image(gx_device               *dev,
1872
                const gs_gstate               *pgs,
1873
                const gs_matrix               *pmat,
1874
                const gs_image_common_t       *pic,
1875
                const gs_int_rect             *prect,
1876
                const gx_drawing_color        *pdcolor,
1877
                const gx_clip_path            *pcpath,
1878
                      gs_memory_t             *mem,
1879
                      gx_image_enum_common_t **pinfo)
1880
1.55k
{
1881
1.55k
    gx_device_vector *vdev = (gx_device_vector *)dev;
1882
1.55k
    gx_device_xps *xdev = (gx_device_xps *)dev;
1883
1.55k
    const gs_image_t *pim = (const gs_image_t *)pic;
1884
1.55k
    gs_color_space *pcs;
1885
1.55k
    xps_image_enum_t *pie = NULL;
1886
1.55k
    xps_icc_data_t *icc_data;
1887
1.55k
    gs_matrix mat;
1888
1.55k
    int code;
1889
1.55k
    gx_clip_path cpath;
1890
1.55k
    gs_fixed_rect bbox;
1891
1.55k
    int bits_per_pixel;
1892
1.55k
    int num_components;
1893
1.55k
    int bsize;
1894
1.55k
    cmm_profile_t *icc_profile = NULL;
1895
1.55k
    gs_color_space_index csindex;
1896
1.55k
    float index_decode[2];
1897
1.55k
    gsicc_rendering_param_t rendering_params;
1898
1.55k
    bool force8bit = false;
1899
1900
1.55k
    if (pic->type->index != 1)
1901
14
        goto use_default;
1902
1903
1.53k
    pcs = pim->ColorSpace;
1904
    /* No image mask yet.  Also, need a color space */
1905
1.53k
    if (pcs == NULL || ((const gs_image1_t *)pim)->ImageMask)
1906
221
        goto use_default;
1907
1908
    /* No indexed images that are not 8 bit. */
1909
1.31k
    csindex = gs_color_space_get_index(pcs);
1910
1.31k
    if (csindex == gs_color_space_index_Indexed && pim->BitsPerComponent != 8)
1911
32
        goto use_default;
1912
1913
    /* Also need  gs_gstate for these color spaces */
1914
1.28k
    if (pgs == NULL && (csindex == gs_color_space_index_Indexed ||
1915
0
        csindex == gs_color_space_index_Separation ||
1916
0
        csindex == gs_color_space_index_DeviceN))
1917
0
        goto use_default;
1918
1919
1.28k
    if (gs_matrix_invert(&pim->ImageMatrix, &mat) < 0)
1920
2
        goto use_default;
1921
1.28k
    if (pmat == NULL)
1922
1.28k
        pmat = &ctm_only(pgs);
1923
1.28k
    if (pgs)
1924
1.28k
        gs_matrix_multiply(&mat, pmat, &mat);
1925
1926
1.28k
    pie = gs_alloc_struct(mem, xps_image_enum_t, &st_xps_image_enum,
1927
1.28k
                          "xps_begin_image");
1928
1.28k
    if (pie == 0)
1929
0
        return_error(gs_error_VMerror);
1930
1.28k
    pie->buffer = NULL;
1931
1.28k
    pie->devc_buffer = NULL;
1932
1.28k
    pie->pgs = NULL;
1933
1.28k
    pie->tif = NULL;
1934
1935
    /* Set the brush types to image */
1936
1.28k
    xps_setstrokebrush(xdev, xps_imagebrush);
1937
1.28k
    xps_setfillbrush(xdev, xps_imagebrush);
1938
1.28k
    pie->mat = mat;
1939
1.28k
    xdev->xps_pie = pie;
1940
    /* We need this set a bit early for the ICC relationship writing */
1941
1.28k
    pie->dev = (gx_device*) xdev;
1942
1943
    /* If the color space is DeviceN, Sep or indexed these end up getting
1944
       mapped to the color space defined by the device profile.  XPS only
1945
       support RGB indexed images so we just expand if for now. ICC link
1946
       creation etc is handled during the remap/concretization of the colors */
1947
1.28k
    if (csindex == gs_color_space_index_Indexed ||
1948
1.28k
        csindex == gs_color_space_index_Separation ||
1949
1.28k
        csindex == gs_color_space_index_DeviceN) {
1950
133
        cmm_dev_profile_t *dev_profile;
1951
133
        pie->pcs = pcs;
1952
133
        rc_increment(pcs);
1953
133
        code = dev_proc(dev, get_profile)(dev, &(dev_profile));
1954
        /* Just use the "default" profile for now */
1955
133
        icc_profile = dev_profile->device_profile[GS_DEFAULT_DEVICE_PROFILE];
1956
133
        force8bit = true; /* Output image is 8 bit regardless of source */
1957
1.14k
    } else {
1958
        /* An ICC, RGB, CMYK, Gray color space */
1959
1.14k
        pie->pcs = NULL;
1960
        /* Get the ICC profile */
1961
1.14k
        if (gs_color_space_is_PSCIE(pcs)) {
1962
0
            if (pcs->icc_equivalent == NULL) {
1963
0
                bool is_lab;
1964
0
                if (pgs == NULL) {
1965
0
                    gs_free_object(mem, *pinfo, "xps_begin_image");
1966
0
                    return_error(gs_error_invalidaccess);
1967
0
                }
1968
0
                gs_colorspace_set_icc_equivalent(pcs, &is_lab, pgs->memory);
1969
0
            }
1970
0
            icc_profile = pcs->icc_equivalent->cmm_icc_profile_data;
1971
1.14k
        } else {
1972
1.14k
            icc_profile = pcs->cmm_icc_profile_data;
1973
1.14k
        }
1974
1.14k
    }
1975
1976
    /* Set up for handling case where we are in CIELAB. In this case, we are
1977
       going out to the default RGB color space */
1978
1.28k
    if (icc_profile->islab) {
1979
        /* Create the link */
1980
0
        rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
1981
0
        rendering_params.graphics_type_tag = GS_IMAGE_TAG;
1982
0
        rendering_params.override_icc = false;
1983
0
        rendering_params.preserve_black = gsBKPRESNOTSPECIFIED;
1984
0
        rendering_params.rendering_intent = gsPERCEPTUAL;
1985
0
        rendering_params.cmm = gsCMM_DEFAULT;
1986
0
        if (pgs == NULL) {
1987
0
            gs_free_object(mem, *pinfo, "xps_begin_image");
1988
0
            return_error(gs_error_invalidaccess);
1989
0
        }
1990
0
        pie->icc_link = gsicc_get_link_profile(pgs, dev, icc_profile,
1991
0
            pgs->icc_manager->default_rgb, &rendering_params, pgs->memory, false);
1992
0
        icc_profile = pgs->icc_manager->default_rgb;
1993
1.28k
    } else {
1994
1.28k
        pie->icc_link = NULL;
1995
1.28k
    }
1996
1997
    /* Now we actually write out the image and icc profile data to the zip
1998
      package. Test if profile is already here. If not, add it. */
1999
1.28k
    if (xps_find_icc(xdev, icc_profile) == NULL) {
2000
918
        icc_data = (xps_icc_data_t*)gs_alloc_bytes(dev->memory->non_gc_memory,
2001
918
            sizeof(xps_icc_data_t), "xps_begin_image");
2002
918
        if (icc_data == NULL) {
2003
0
            gs_free_object(mem, *pinfo, "xps_begin_image");
2004
0
            gs_throw(gs_error_VMerror, "Allocation of icc_data failed");
2005
0
            return_error(gs_error_VMerror);
2006
0
        }
2007
2008
918
        icc_data->hash = gsicc_get_hash(icc_profile);
2009
918
        if (xdev->icc_data == NULL) {
2010
846
            icc_data->index = 0;
2011
846
            xdev->icc_data = icc_data;
2012
846
            xdev->icc_data->next = NULL;
2013
846
        } else {
2014
72
            icc_data->next = xdev->icc_data;
2015
72
            icc_data->index = icc_data->next->index + 1;
2016
72
            xdev->icc_data = icc_data;
2017
72
        }
2018
2019
        /* Get name for mark up and for relationship. Have to wait and do
2020
           this after it is added to the package */
2021
918
        code = xps_create_icc_name(xdev, icc_profile, &(pie->icc_name[0]));
2022
918
        if (code < 0) {
2023
0
            gs_free_object(mem, *pinfo, "xps_begin_image");
2024
0
            return_error(gs_rethrow_code(code));
2025
0
        }
2026
2027
        /* Add profile to the package. Here like images we are going to write
2028
           the data now.  Rather than later. */
2029
918
        if (pgs == NULL) {
2030
0
            gs_free_object(mem, *pinfo, "xps_begin_image");
2031
0
            return_error(gs_error_invalidaccess);
2032
0
        }
2033
918
        code = xps_write_profile(pgs, &(pie->icc_name[0]), icc_profile, xdev);
2034
918
        if (code < 0) {
2035
0
            gs_free_object(mem, *pinfo, "xps_begin_image");
2036
0
            return_error(gs_rethrow_code(code));
2037
0
        }
2038
2039
        /* Add ICC relationship */
2040
918
        xps_add_icc_relationship(pie);
2041
918
    } else {
2042
        /* Get name for mark up.  We already have it in the resource list */
2043
364
        code = xps_create_icc_name(xdev, icc_profile, &(pie->icc_name[0]));
2044
364
        if (code < 0) {
2045
0
            gs_free_object(mem, *pinfo, "xps_begin_image");
2046
0
            return_error(gs_rethrow_code(code));
2047
0
        }
2048
2049
        /* Add ICC relationship.  It may not yet be present for this page. */
2050
364
        xps_add_icc_relationship(pie);
2051
364
    }
2052
2053
    /* Get image name for mark up */
2054
1.28k
    xps_create_image_name(dev, &(pie->file_name[0]));
2055
    /* Set width and height here */
2056
1.28k
    pie->width = pim->Width;
2057
1.28k
    pie->height = pim->Height;
2058
2059
1.28k
    if (pcpath == NULL) {
2060
338
        (*dev_proc(dev, get_clipping_box)) (dev, &bbox);
2061
338
        gx_cpath_init_local(&cpath, dev->memory);
2062
338
        code = gx_cpath_from_rectangle(&cpath, &bbox);
2063
338
        if (code < 0) {
2064
0
            gs_free_object(mem, *pinfo, "xps_begin_image");
2065
0
            return_error(gs_rethrow_code(code));
2066
0
        }
2067
338
        pcpath = &cpath;
2068
944
    } else {
2069
        /* Force vector device to do new path as the clip path is the image
2070
           path.  I had a case where the clip path ids were the same but the
2071
           CTM was changing which resulted in subsequent images coming up
2072
           missing on the page. i.e. only the first one was shown. */
2073
944
        ((gx_device_vector*) vdev)->clip_path_id = vdev->no_clip_path_id;
2074
944
    }
2075
2076
1.28k
    if (pgs == NULL) {
2077
0
        gs_free_object(mem, *pinfo, "xps_begin_image");
2078
0
        return_error(gs_error_invalidaccess);
2079
0
    }
2080
1.28k
    code = gdev_vector_begin_image(vdev, pgs, pim, pim->format, prect,
2081
1.28k
        pdcolor, pcpath, mem, &xps_image_enum_procs,
2082
1.28k
        (gdev_vector_image_enum_t *)pie);
2083
1.28k
    if (code < 0) {
2084
5
        gs_free_object(mem, pie, "xps_begin_image");
2085
5
        return_error(gs_rethrow_code(code));
2086
5
    }
2087
2088
1.27k
    if ((pie->tif = tiff_from_name(xdev, pie->file_name, false, false)) == NULL) {
2089
0
        gs_free_object(mem, pie, "xps_begin_image");
2090
0
        return_error(gs_error_VMerror);
2091
0
    }
2092
2093
    /* Null out pie.  Only needed for the above vector command and tiff set up */
2094
1.27k
    xdev->xps_pie = NULL;
2095
1.27k
    xps_tiff_set_handlers();
2096
1.27k
    code = tiff_set_values(pie, pie->tif, icc_profile, force8bit);
2097
1.27k
    if (code < 0) {
2098
0
        gs_free_object(mem, pie, "xps_begin_image");
2099
0
        return_error(gs_rethrow_code(code));
2100
0
    }
2101
1.27k
    code = TIFFCheckpointDirectory(pie->tif);
2102
2103
1.27k
    num_components = gs_color_space_num_components(pcs);
2104
1.27k
    bits_per_pixel = pim->BitsPerComponent * num_components;
2105
1.27k
    pie->decode_st.bps = bits_per_pixel / num_components;
2106
1.27k
    pie->bytes_comp = (pie->decode_st.bps > 8 ? 2 : 1);
2107
1.27k
    pie->decode_st.spp = num_components;
2108
1.27k
    pie->decode_st.unpack = NULL;
2109
1.27k
    get_unpack_proc((gx_image_enum_common_t*)pie, &(pie->decode_st), pim->format,
2110
1.27k
        pim->Decode);
2111
2112
    /* The decode mapping for index colors needs an adjustment */
2113
1.27k
    if (csindex == gs_color_space_index_Indexed) {
2114
127
        if (pim->Decode[0] == 0 &&
2115
127
            pim->Decode[1] == 255) {
2116
125
            index_decode[0] = 0;
2117
125
            index_decode[1] = 1.0;
2118
125
        } else {
2119
2
            index_decode[0] = pim->Decode[0];
2120
2
            index_decode[1] = pim->Decode[1];
2121
2
        }
2122
127
        get_map(&(pie->decode_st), pim->format, index_decode);
2123
1.15k
    } else {
2124
1.15k
        get_map(&(pie->decode_st), pim->format, pim->Decode);
2125
1.15k
    }
2126
2127
    /* Allocate our decode buffer. */
2128
1.27k
    bsize = ((pie->decode_st.bps > 8 ? (pim->Width) * 2 : pim->Width) + 15) * num_components;
2129
1.27k
    pie->buffer = gs_alloc_bytes(mem, bsize, "xps_begin_typed_image(buffer)");
2130
1.27k
    if (pie->buffer == 0) {
2131
2
        gs_free_object(mem, pie, "xps_begin_typed_image");
2132
2
        *pinfo = NULL;
2133
2
        return_error(gs_error_VMerror);
2134
2
    }
2135
2136
    /* If needed, allocate our device color buffer.  We will always do 8 bit here */
2137
1.27k
    if (csindex == gs_color_space_index_Indexed ||
2138
1.27k
        csindex == gs_color_space_index_Separation ||
2139
1.27k
        csindex == gs_color_space_index_DeviceN) {
2140
131
        bsize = (pim->Width + 15) * icc_profile->num_comps;
2141
131
        pie->devc_buffer = gs_alloc_bytes(mem, bsize, "xps_begin_typed_image(devc_buffer)");
2142
131
        if (pie->devc_buffer == 0) {
2143
0
            gs_free_object(mem, pie, "xps_begin_typed_image");
2144
0
            *pinfo = NULL;
2145
0
            return_error(gs_error_VMerror);
2146
0
        }
2147
        /* Also, the color remaps need the gs_gstate */
2148
131
        pie->pgs = pgs;
2149
131
    }
2150
2151
1.27k
    *pinfo = (gx_image_enum_common_t *)pie;
2152
1.27k
    return 0;
2153
2154
269
use_default:
2155
269
    return gx_default_begin_typed_image(dev, pgs, pmat, pic, prect,
2156
269
                                        pdcolor, pcpath, mem, pinfo);
2157
1.27k
}
2158
2159
/* Handles conversion from decoded DeviceN, Sep or Indexed space to Device color
2160
   space. The encoding specified by the image object is already handled at this
2161
   point. Slow due to the multitude of conversions that take place.  I.e. conv to
2162
   float, frac and back to byte, but it will get the job done. Since we can have
2163
   indexed spaces that reference DeviceN spaces etc, we really have to do it
2164
   this way or code up a bunch of optimized special cases.  Note here we always
2165
   output 8 bit regardless of input */
2166
static int
2167
set_device_colors(xps_image_enum_t *pie)
2168
19.7k
{
2169
19.7k
    gx_device *pdev = pie->dev;
2170
19.7k
    const gs_gstate *pgs = pie->pgs;
2171
19.7k
    gs_color_space *pcs = pie->pcs;
2172
19.7k
    byte *src = pie->buffer;
2173
19.7k
    byte *des = pie->devc_buffer;
2174
19.7k
    int num_src = gs_color_space_num_components(pcs);
2175
19.7k
    int num_des = pdev->color_info.num_components;
2176
19.7k
    int width = pie->width;
2177
19.7k
    cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
2178
19.7k
    int i, j, code = 0;
2179
19.7k
    gs_client_color cc;
2180
19.7k
    gx_device_color devc;
2181
19.7k
    gx_color_value cm_values[GX_DEVICE_COLOR_MAX_COMPONENTS];
2182
19.7k
    float scale = 1.0;
2183
2184
19.7k
    if (pie->decode_st.bps > 8) {
2185
0
        unsigned short *src_ptr = (unsigned short*)src;
2186
0
        int pos_src = 0;
2187
0
        int pos_des = 0;
2188
0
        for (i = 0; i < width; i++) {
2189
0
            for (j = 0; j < num_src; j++, pos_src++) {
2190
0
                cc.paint.values[j] = (float)(src_ptr[pos_src]) / 65535.0;
2191
0
            }
2192
0
            code = remap_color(&cc, pcs, &devc, pgs, pdev, gs_color_select_source);
2193
0
            dev_proc(pdev, decode_color)(pdev, devc.colors.pure, cm_values);
2194
0
            for (j = 0; j < num_des; j++, pos_des++) {
2195
0
                des[pos_des] = (cm_values[j] >> 8);
2196
0
            }
2197
0
        }
2198
19.7k
    } else {
2199
19.7k
        int pos_src = 0;
2200
19.7k
        int pos_des = 0;
2201
19.7k
        if (gs_color_space_get_index(pcs) != gs_color_space_index_Indexed)
2202
196
            scale = 255.0;
2203
3.08M
        for (i = 0; i < width; i++) {
2204
6.12M
            for (j = 0; j < num_src; j++, pos_src++) {
2205
3.06M
                cc.paint.values[j] = (float)(src[pos_src]) / scale;
2206
3.06M
            }
2207
3.06M
            code = remap_color(&cc, pcs, &devc, pgs, pdev, gs_color_select_source);
2208
3.06M
            dev_proc(pdev, decode_color)(pdev, devc.colors.pure, cm_values);
2209
12.2M
            for (j = 0; j < num_des; j++, pos_des++) {
2210
9.19M
                des[pos_des] = (cm_values[j] >> 8);
2211
9.19M
            }
2212
3.06M
        }
2213
19.7k
    }
2214
19.7k
    return code;
2215
19.7k
}
2216
2217
/* Chunky or planar in and chunky out */
2218
static int
2219
xps_image_data(gx_image_enum_common_t *info,
2220
const gx_image_plane_t *planes, int height, int *rows_used)
2221
803k
{
2222
803k
    xps_image_enum_t *pie = (xps_image_enum_t *)info;
2223
803k
    int data_bit = planes[0].data_x * info->plane_depths[0];
2224
803k
    int width_bits = pie->width * info->plane_depths[0];
2225
803k
    int bytes_comp = pie->bytes_comp;
2226
803k
    int i, plane;
2227
803k
    int code = 0;
2228
803k
    int width = pie->width;
2229
803k
    int num_planes = pie->num_planes;
2230
803k
    int dsize = (((width + (planes[0]).data_x) * pie->decode_st.spp *
2231
803k
        pie->decode_st.bps / num_planes + 7) >> 3);
2232
803k
    void *bufend = (void*)(pie->buffer + width * bytes_comp * pie->decode_st.spp);
2233
803k
    byte *outbuffer;
2234
2235
803k
    if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
2236
0
        return_error(gs_error_rangecheck);
2237
803k
    if (height > pie->height - pie->y)
2238
39
        height = pie->height - pie->y;
2239
2240
1.68M
    for (i = 0; i < height; pie->y++, i++) {
2241
877k
        int pdata_x;
2242
        /* Plane zero done here to get the pointer to the data */
2243
877k
        const byte *data_ptr = planes[0].data + planes[0].raster * i + (data_bit >> 3);
2244
877k
        byte *des_ptr = pie->buffer;
2245
877k
        byte *buffer = (byte *)(*pie->decode_st.unpack)(des_ptr, &pdata_x,
2246
877k
            data_ptr, 0, dsize, &(pie->decode_st.map[0]),
2247
877k
            pie->decode_st.spread, pie->decode_st.spp);
2248
2249
        /* Step through the planes having decode do the repack to chunky as
2250
           well as any decoding needed */
2251
877k
        for (plane = 1; plane < num_planes; plane++) {
2252
0
            data_ptr = planes[plane].data + planes[plane].raster * i + (data_bit >> 3);
2253
0
            des_ptr = pie->buffer + plane * pie->bytes_comp;
2254
            /* This does the planar to chunky conversion */
2255
0
            (*pie->decode_st.unpack)(des_ptr, &pdata_x,
2256
0
                data_ptr, 0, dsize, &(pie->decode_st.map[plane]),
2257
0
                pie->decode_st.spread, pie->decode_st.spp);
2258
0
        }
2259
2260
        /* CIELAB does not get mapped.  Handled in color management */
2261
877k
        if (pie->icc_link == NULL) {
2262
877k
            pie->decode_st.applymap(pie->decode_st.map, (void*)buffer,
2263
877k
                pie->decode_st.spp, (void*)pie->buffer, bufend);
2264
            /* Index, Sep and DeviceN are mapped to color space defined by
2265
            device profile */
2266
877k
            if (pie->pcs != NULL) {
2267
                /* In device color space */
2268
19.7k
                code = set_device_colors(pie);
2269
19.7k
                if (code < 0)
2270
0
                    return gs_rethrow_code(code);
2271
19.7k
                outbuffer = pie->devc_buffer;
2272
857k
            } else {
2273
                /* In source color space */
2274
857k
                outbuffer = pie->buffer;
2275
857k
            }
2276
877k
        } else {
2277
            /* CIELAB to default RGB */
2278
0
            gsicc_bufferdesc_t input_buff_desc;
2279
0
            gsicc_bufferdesc_t output_buff_desc;
2280
0
            gsicc_init_buffer(&input_buff_desc, 3, bytes_comp,
2281
0
                false, false, false, 0, width * bytes_comp * 3,
2282
0
                1, width);
2283
0
            gsicc_init_buffer(&output_buff_desc, 3, bytes_comp,
2284
0
                false, false, false, 0, width * bytes_comp * 3,
2285
0
                1, width);
2286
0
            code = (pie->icc_link->procs.map_buffer)(pie->dev, pie->icc_link,
2287
0
                &input_buff_desc, &output_buff_desc, (void*)buffer,
2288
0
                (void*)pie->buffer);
2289
0
            if (code < 0)
2290
0
                return code;
2291
0
            outbuffer = pie->buffer;
2292
0
        }
2293
877k
        code = TIFFWriteScanline(pie->tif, outbuffer, pie->y, 0);
2294
877k
        if (code < 0)
2295
0
            return code;
2296
877k
    }
2297
803k
    *rows_used = height;
2298
803k
    return pie->y >= pie->height;
2299
803k
}
2300
2301
static int
2302
xps_add_tiff_image(xps_image_enum_t *pie)
2303
1.27k
{
2304
1.27k
    gx_device_xps *xdev = (gx_device_xps *)(pie->dev);
2305
1.27k
    int code;
2306
2307
1.27k
    code = add_file_to_zip_file(xdev, pie->file_name, pie->fid);
2308
1.27k
    gp_fclose(pie->fid);
2309
1.27k
    return code;
2310
1.27k
}
2311
2312
/* Clean up by releasing the buffers. */
2313
static int
2314
xps_image_end_image(gx_image_enum_common_t * info, bool draw_last)
2315
1.27k
{
2316
1.27k
    xps_image_enum_t *pie = (xps_image_enum_t *)info;
2317
1.27k
    int code = 0;
2318
2319
    /* N.B. Write the final strip, if any. */
2320
2321
1.27k
    code = TIFFWriteDirectory(pie->tif);
2322
1.27k
    xps_tiff_cleanup(pie);
2323
2324
    /* Stuff the image into the zip archive and close the file */
2325
1.27k
    code = xps_add_tiff_image(pie);
2326
1.27k
    if (code < 0)
2327
0
        goto exit;
2328
2329
    /* Reset the brush type to solid */
2330
1.27k
    xps_setstrokebrush((gx_device_xps *) (pie->dev), xps_solidbrush);
2331
1.27k
    xps_setfillbrush((gx_device_xps *) (pie->dev), xps_solidbrush);
2332
2333
    /* Add the image relationship */
2334
1.27k
    code = xps_add_image_relationship(pie);
2335
2336
1.27k
    gs_free_object(pie->memory, pie, "xps_image_end_image");
2337
1.27k
exit:
2338
1.27k
    return code;
2339
1.27k
}
2340
2341
/* Tiff related code so that we can output all the image data in Tiff format.
2342
   Tiff has the advantage of supporting Gray, RGB, CMYK as well as multiple
2343
   bit depts and having lossless compression.  Much of this was borrowed from
2344
   gstiffio.c */
2345
#define TIFF_PRINT_BUF_LENGTH 1024
2346
static const char tifs_msg_truncated[] = "\n*** Previous line has been truncated.\n";
2347
2348
static int
2349
tiff_set_values(xps_image_enum_t *pie, TIFF *tif, cmm_profile_t *profile,
2350
                bool force8bit)
2351
1.27k
{
2352
1.27k
    int bits = 8;
2353
2354
1.27k
    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, pie->height);
2355
1.27k
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, pie->width);
2356
1.27k
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, pie->height);
2357
1.27k
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
2358
1.27k
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
2359
1.27k
    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
2360
1.27k
    TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
2361
1.27k
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, 96.0);
2362
1.27k
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, 96.0);
2363
2364
1.27k
    switch (profile->data_cs) {
2365
264
        case  gsGRAY:
2366
264
            if (pie->bits_per_pixel > 8 && !force8bit)
2367
0
                bits = 16;
2368
264
            TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits);
2369
264
            TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
2370
264
            TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
2371
264
            break;
2372
894
        case  gsRGB:
2373
894
        case gsCIELAB:
2374
894
            if ((pie->num_planes > 1 && pie->bits_per_pixel > 8 && !force8bit) ||
2375
894
                (pie->num_planes == 1 && pie->bits_per_pixel / 3 > 8 && !force8bit))
2376
0
                bits = 16;
2377
894
            TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits);
2378
894
            TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
2379
894
            TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
2380
894
            break;
2381
119
        case gsCMYK:
2382
119
            if ((pie->num_planes > 1 && pie->bits_per_pixel > 8 && !force8bit) ||
2383
119
                (pie->num_planes == 1 && pie->bits_per_pixel / 4 > 8 && !force8bit))
2384
0
                bits = 16;
2385
119
            TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits);
2386
119
            TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED);
2387
119
            TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
2388
119
            break;
2389
0
        default:
2390
0
            return gs_throw_code(gs_error_rangecheck);
2391
1.27k
    }
2392
1.27k
    return 0;
2393
1.27k
}
2394
2395
/* place to hold the data for our libtiff i/o hooks */
2396
typedef struct tifs_io_xps_t
2397
{
2398
    gx_device_xps *pdev;
2399
    gp_file *fid;
2400
} tifs_io_xps;
2401
2402
/* libtiff i/o hooks */
2403
static size_t
2404
xps_tifsWriteProc(thandle_t fd, void* buf, size_t size)
2405
13.3k
{
2406
13.3k
    tifs_io_xps *tiffio = (tifs_io_xps *)fd;
2407
13.3k
    size_t size_io = (size_t)size;
2408
13.3k
    gp_file *fid = tiffio->fid;
2409
13.3k
    size_t count;
2410
2411
13.3k
    if ((size_t)size_io != size) {
2412
0
        return (size_t)-1;
2413
0
    }
2414
2415
13.3k
    if (fid == NULL)
2416
0
        return gs_throw_code(gs_error_Fatal);
2417
2418
13.3k
    count = gp_fwrite(buf, 1, size, fid);
2419
13.3k
    if (count != size) {
2420
0
        gp_fclose(fid);
2421
0
        return gs_rethrow_code(-1);
2422
0
    }
2423
13.3k
    gp_fflush(fid);
2424
13.3k
    return size;
2425
13.3k
}
2426
2427
static uint64_t
2428
xps_tifsSeekProc(thandle_t fd, uint64_t off, int origin)
2429
15.8k
{
2430
15.8k
    tifs_io_xps *tiffio = (tifs_io_xps *)fd;
2431
15.8k
    gs_offset_t off_io = (gs_offset_t)off;
2432
15.8k
    gp_file *fid = tiffio->fid;
2433
2434
15.8k
    if ((uint64_t)off_io != off) {
2435
0
        return (uint64_t)-1;
2436
0
    }
2437
2438
15.8k
    if (fid == NULL && off == 0)
2439
0
        return 0;
2440
2441
15.8k
    if (fid == NULL)
2442
0
        return (uint64_t)-1;
2443
2444
15.8k
    if (gp_fseek(fid, (gs_offset_t)off, origin) < 0) {
2445
0
        return (uint64_t)-1;
2446
0
    }
2447
15.8k
    return (gp_ftell(fid));
2448
15.8k
}
2449
2450
static int
2451
xps_tifsCloseProc(thandle_t fd)
2452
0
{
2453
0
    tifs_io_xps *tiffio = (tifs_io_xps *)fd;
2454
0
    gx_device_xps *pdev = tiffio->pdev;
2455
2456
0
    gs_free(pdev->memory->non_gc_memory, tiffio, sizeof(tifs_io_xps), 1,
2457
0
        "xps_tifsCloseProc");
2458
0
    return 0;
2459
0
}
2460
2461
static int
2462
xps_tifsDummyMapProc(thandle_t fd, void** pbase, toff_t* psize)
2463
0
{
2464
0
    (void)fd;
2465
0
    (void)pbase;
2466
0
    (void)psize;
2467
0
    return (0);
2468
0
}
2469
2470
static void
2471
xps_tifsDummyUnmapProc(thandle_t fd, void* base, toff_t size)
2472
0
{
2473
0
    (void)fd;
2474
0
    (void)base;
2475
0
    (void)size;
2476
0
}
2477
2478
static size_t
2479
xps_tifsReadProc(thandle_t fd, void* buf, size_t size)
2480
0
{
2481
0
    size_t size_io = (size_t)size;
2482
2483
0
    if ((size_t)size_io != size) {
2484
0
        return (size_t)-1;
2485
0
    }
2486
0
    return 0;
2487
0
}
2488
2489
/* Could not see where this was getting used so basically a dummy proc
2490
   for now. */
2491
static uint64_t
2492
xps_tifsSizeProc(thandle_t fd)
2493
0
{
2494
0
    uint64_t length = 0;
2495
2496
0
    return length;
2497
0
}
2498
2499
static void
2500
xps_tifsWarningHandlerEx(thandle_t client_data, const char *module,
2501
                         const char *fmt, va_list ap)
2502
0
{
2503
0
    tifs_io_xps *tiffio = (tifs_io_xps *)client_data;
2504
0
    gx_device_xps *pdev = tiffio->pdev;
2505
0
    int count;
2506
0
    char buf[TIFF_PRINT_BUF_LENGTH];
2507
2508
0
    count = vsnprintf(buf, sizeof(buf), fmt, ap);
2509
0
    if (count >= sizeof(buf) || count < 0)  { /* C99 || MSVC */
2510
0
        dmlprintf1(pdev->memory, "%s", buf);
2511
0
        dmlprintf1(pdev->memory, "%s\n", tifs_msg_truncated);
2512
0
    }
2513
0
    else {
2514
0
        dmlprintf1(pdev->memory, "%s\n", buf);
2515
0
    }
2516
0
}
2517
2518
static void
2519
xps_tifsErrorHandlerEx(thandle_t client_data, const char *module,
2520
                       const char *fmt, va_list ap)
2521
0
{
2522
0
    tifs_io_xps *tiffio = (tifs_io_xps *)client_data;
2523
0
    gx_device_xps *pdev = tiffio->pdev;
2524
0
    const char *max_size_error = "Maximum TIFF file size exceeded";
2525
0
    int count;
2526
0
    char buf[TIFF_PRINT_BUF_LENGTH];
2527
2528
0
    count = vsnprintf(buf, sizeof(buf), fmt, ap);
2529
0
    if (count >= sizeof(buf) || count < 0)  { /* C99 || MSVC */
2530
0
        dmlprintf1(pdev->memory, "%s\n", buf);
2531
0
        dmlprintf1(pdev->memory, "%s", tifs_msg_truncated);
2532
0
    }
2533
0
    else {
2534
0
        dmlprintf1(pdev->memory, "%s\n", buf);
2535
0
    }
2536
2537
0
#if (TIFFLIB_VERSION >= 20111221)
2538
0
    if (!strncmp(fmt, max_size_error, strlen(max_size_error))) {
2539
0
        dmlprintf(pdev->memory, "Use -dUseBigTIFF(=true) for BigTIFF output\n");
2540
0
    }
2541
0
#endif
2542
0
}
2543
2544
static void
2545
xps_tiff_set_handlers(void)
2546
1.27k
{
2547
1.27k
    (void)TIFFSetErrorHandler(NULL);
2548
1.27k
    (void)TIFFSetWarningHandler(NULL);
2549
1.27k
    (void)TIFFSetErrorHandlerExt(xps_tifsErrorHandlerEx);
2550
1.27k
    (void)TIFFSetWarningHandlerExt(xps_tifsWarningHandlerEx);
2551
1.27k
}
2552
2553
static TIFF *
2554
tiff_from_name(gx_device_xps *dev, const char *name, int big_endian, bool usebigtiff)
2555
1.27k
{
2556
1.27k
    char mode[5] = "w";
2557
1.27k
    int modelen = 1;
2558
1.27k
    TIFF *t;
2559
1.27k
    tifs_io_xps *tiffio;
2560
1.27k
    gs_memory_t *mem = dev->memory->non_gc_memory;
2561
1.27k
    char *filename;
2562
2563
1.27k
    if (big_endian)
2564
0
        mode[modelen++] = 'b';
2565
1.27k
    else
2566
1.27k
        mode[modelen++] = 'l';
2567
2568
1.27k
    if (usebigtiff)
2569
        /* this should never happen for libtiff < 4.0 - see tiff_put_some_params() */
2570
0
        mode[modelen++] = '8';
2571
2572
1.27k
    mode[modelen] = (char)0;
2573
2574
1.27k
    tiffio = (tifs_io_xps *)gs_malloc(dev->memory->non_gc_memory,
2575
1.27k
        sizeof(tifs_io_xps), 1, "tiff_from_name");
2576
1.27k
    if (!tiffio) {
2577
0
        return NULL;
2578
0
    }
2579
1.27k
    tiffio->pdev = dev;
2580
2581
1.27k
    filename = (char *)gs_alloc_bytes(mem, gp_file_name_sizeof,
2582
1.27k
        "tiff_from_name(filename)");
2583
1.27k
    if (!filename)
2584
0
        return NULL;
2585
2586
1.27k
    tiffio->fid = gp_open_scratch_file_rm(mem, "tif-", filename, "wb+");
2587
1.27k
    dev->xps_pie->fid = tiffio->fid;  /* We will be closing it from here */
2588
2589
1.27k
    gs_free_object(mem, filename, "tiff_from_name(filename)");
2590
2591
1.27k
    t = TIFFClientOpen(name, mode,
2592
1.27k
        (thandle_t)tiffio, (TIFFReadWriteProc)xps_tifsReadProc,
2593
1.27k
        (TIFFReadWriteProc)xps_tifsWriteProc, (TIFFSeekProc)xps_tifsSeekProc,
2594
1.27k
        xps_tifsCloseProc, (TIFFSizeProc)xps_tifsSizeProc, xps_tifsDummyMapProc,
2595
1.27k
        xps_tifsDummyUnmapProc);
2596
1.27k
    return t;
2597
1.27k
}
2598
2599
static void xps_tiff_cleanup(xps_image_enum_t *xpie)
2600
2.55k
{
2601
2.55k
    if (xpie->tif != NULL) {
2602
1.27k
        void *t = TIFFClientdata(xpie->tif);
2603
1.27k
        TIFFCleanup(xpie->tif);
2604
1.27k
        xpie->tif = NULL;
2605
1.27k
        gs_free_object(xpie->memory->non_gc_memory, t, "xps_image_enum_finalize");
2606
1.27k
    }
2607
2.55k
}
2608
2609
static void
2610
xps_image_enum_finalize(const gs_memory_t *cmem, void *vptr)
2611
1.28k
{
2612
1.28k
    xps_image_enum_t *xpie = (xps_image_enum_t *)vptr;
2613
1.28k
    gx_device_xps *xdev = (gx_device_xps *)xpie->dev;
2614
2615
1.28k
    xps_tiff_cleanup(xpie);
2616
2617
1.28k
    xpie->dev = NULL;
2618
1.28k
    if (xpie->pcs != NULL)
2619
1.28k
        rc_decrement(xpie->pcs, "xps_image_end_image (pcs)");
2620
1.28k
    if (xpie->buffer != NULL)
2621
1.27k
        gs_free_object(xpie->memory, xpie->buffer, "xps_image_end_image");
2622
1.28k
    if (xpie->devc_buffer != NULL)
2623
131
        gs_free_object(xpie->memory, xpie->devc_buffer, "xps_image_end_image");
2624
2625
    /* ICC clean up */
2626
1.28k
    if (xpie->icc_link != NULL)
2627
0
        gsicc_release_link(xpie->icc_link);
2628
1.28k
    xdev->xps_pie = NULL;
2629
1.28k
}