Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/vector/gdevpdfe.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
17
/* Metadata writer. */
18
#include "gx.h"
19
#include "gserrors.h"
20
#include "string_.h"
21
#include "time_.h"
22
#include "stream.h"
23
#include "gp.h"
24
#include "smd5.h"
25
#include "gscdefs.h"
26
#include "gdevpdfx.h"
27
#include "gdevpdfg.h"
28
#include "gdevpdfo.h"
29
30
static char PDFDocEncodingLookup [92] = {
31
    0x20, 0x22, 0x20, 0x20, 0x20, 0x21, 0x20, 0x26,
32
    0x20, 0x14, 0x20, 0x13, 0x01, 0x92, 0x20, 0x44,
33
    0x20, 0x39, 0x20, 0x3A, 0x22, 0x12, 0x20, 0x30,
34
    0x20, 0x1E, 0x20, 0x1C, 0x20, 0x1D, 0x20, 0x18,
35
    0x20, 0x19, 0x20, 0x1A, 0x21, 0x22, 0xFB, 0x01,
36
    0xFB, 0x02, 0x01, 0x41, 0x01, 0x52, 0x01, 0x60,
37
    0x01, 0x78, 0x01, 0x7D, 0x01, 0x31, 0x01, 0x42,
38
    0x01, 0x53, 0x01, 0x61, 0x01, 0x7E, 0x00, 0x00,
39
    0x20, 0xAC, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3,
40
    0x00, 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7,
41
    0x00, 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB,
42
    0x00, 0xAC, 0x00, 0x00
43
};
44
45
static void
46
copy_bytes(stream *s, const byte **data, int *data_length, int n)
47
11.4k
{
48
36.2k
    while (n-- && (*data_length)--) {
49
24.7k
        stream_putc(s, *((*data)++));
50
24.7k
    }
51
11.4k
}
52
53
/* Write XML data */
54
static void
55
pdf_xml_data_write(stream *s, const byte *data, int data_length)
56
107k
{
57
107k
    int l = data_length;
58
107k
    const byte *p = data;
59
60
3.03M
    while (l > 0) {
61
2.92M
        switch (*p) {
62
92
            case '<' : stream_puts(s, "&lt;"); l--; p++; break;
63
315
            case '>' : stream_puts(s, "&gt;"); l--; p++; break;
64
30
            case '&' : stream_puts(s, "&amp;"); l--; p++; break;
65
551
            case '\'': stream_puts(s, "&apos;"); l--; p++; break;
66
65
            case '"' : stream_puts(s, "&quot;"); l--; p++; break;
67
2.92M
            default:
68
2.92M
                if (*p < 32) {
69
                    /* Not allowed in XML. */
70
13.8k
                    pprintd1(s, "&#%d;", *p);
71
13.8k
                    l--; p++;
72
2.91M
                } else if (*p >= 0x7F && *p <= 0x9f) {
73
                    /* Control characters are discouraged in XML. */
74
0
                    pprintd1(s, "&#%d;", *p);
75
0
                    l--; p++;
76
2.91M
                } else if ((*p & 0xE0) == 0xC0) {
77
                    /* A 2-byte UTF-8 sequence */
78
9.63k
                    copy_bytes(s, &p, &l, 2);
79
2.90M
                } else if ((*p & 0xF0) == 0xE0) {
80
                    /* A 3-byte UTF-8 sequence */
81
1.82k
                    copy_bytes(s, &p, &l, 3);
82
2.90M
                } else if ((*p & 0xF0) == 0xF0) {
83
                    /* A 4-byte UTF-8 sequence */
84
0
                    copy_bytes(s, &p, &l, 4);
85
2.90M
                } else {
86
2.90M
                    stream_putc(s, *p);
87
2.90M
                    l--; p++;
88
2.90M
                }
89
2.92M
        }
90
2.92M
    }
91
107k
}
92
93
/* Write XML string */
94
static inline void
95
pdf_xml_string_write(stream *s, const char *data)
96
89.8k
{
97
89.8k
    pdf_xml_data_write(s, (const byte *)data, strlen(data));
98
89.8k
}
99
100
/* Begin an opening XML tag */
101
static inline void
102
pdf_xml_tag_open_beg(stream *s, const char *data)
103
90.6k
{
104
90.6k
    stream_putc(s, '<');
105
90.6k
    stream_puts(s, data);
106
90.6k
}
107
108
/* End an XML tag */
109
static inline void
110
pdf_xml_tag_end(stream *s)
111
68.6k
{
112
68.6k
    stream_putc(s, '>');
113
68.6k
}
114
115
/* End an empty XML tag */
116
static inline void
117
pdf_xml_tag_end_empty(stream *s)
118
22.0k
{
119
22.0k
    stream_puts(s, "/>");
120
22.0k
}
121
122
/* Write an opening XML tag */
123
static inline void
124
pdf_xml_tag_open(stream *s, const char *data)
125
26.3k
{
126
26.3k
    stream_putc(s, '<');
127
26.3k
    stream_puts(s, data);
128
26.3k
    stream_putc(s, '>');
129
26.3k
}
130
131
/* Write a closing XML tag */
132
static inline void
133
pdf_xml_tag_close(stream *s, const char *data)
134
95.0k
{
135
95.0k
    stream_puts(s, "</");
136
95.0k
    stream_puts(s, data);
137
95.0k
    stream_putc(s, '>');
138
95.0k
}
139
140
/* Write an attribute name */
141
static inline void
142
pdf_xml_attribute_name(stream *s, const char *data)
143
111k
{
144
111k
    stream_putc(s, ' ');
145
111k
    stream_puts(s, data);
146
111k
    stream_putc(s, '=');
147
111k
}
148
149
/* Write a attribute value */
150
static inline void
151
pdf_xml_attribute_value(stream *s, const char *data)
152
89.8k
{
153
89.8k
    stream_putc(s, '\'');
154
89.8k
    pdf_xml_string_write(s, data);
155
89.8k
    stream_putc(s, '\'');
156
89.8k
}
157
/* Write a attribute value */
158
static inline void
159
pdf_xml_attribute_value_data(stream *s, const byte *data, int data_length)
160
10.8k
{
161
10.8k
    stream_putc(s, '\'');
162
10.8k
    pdf_xml_data_write(s, data, data_length);
163
10.8k
    stream_putc(s, '\'');
164
10.8k
}
165
166
/* Begin an  XML instruction */
167
static inline void
168
pdf_xml_ins_beg(stream *s, const char *data)
169
11.2k
{
170
11.2k
    stream_puts(s, "<?");
171
11.2k
    stream_puts(s, data);
172
11.2k
}
173
174
/* End an XML instruction */
175
static inline void
176
pdf_xml_ins_end(stream *s)
177
11.2k
{
178
11.2k
    stream_puts(s, "?>");
179
11.2k
}
180
181
/* Write a newline character */
182
static inline void
183
pdf_xml_newline(stream *s)
184
79.4k
{
185
79.4k
    stream_puts(s, "\n");
186
79.4k
}
187
188
/* Copy to XML output */
189
static inline void
190
pdf_xml_copy(stream *s, const char *data)
191
168k
{
192
168k
    stream_puts(s, data);
193
168k
}
194
195
/* --------------------------------------------  */
196
197
static int
198
pdf_xmp_time(char *buf, int buf_length)
199
0
{
200
    /* We don't write a day time because we don't have a time zone. */
201
0
    struct tm tms;
202
0
    time_t t;
203
0
    char buf1[4+1+2+1+2+1]; /* yyyy-mm-dd\0 */
204
205
#ifdef CLUSTER
206
    memset(&t, 0, sizeof(t));
207
    memset(&tms, 0, sizeof(tms));
208
#else
209
0
    time(&t);
210
0
    tms = *localtime(&t);
211
0
#endif
212
0
    gs_snprintf(buf1, sizeof(buf1),
213
0
            "%04d-%02d-%02d",
214
0
            tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday);
215
0
    strncpy(buf, buf1, buf_length);
216
0
    return strlen(buf);
217
0
}
218
219
static int
220
pdf_xmp_convert_time(char *dt, int dtl, char *buf, int bufl)
221
22.4k
{   /* The 'dt' buffer is of same size as 'buf'. */
222
    /* Input  sample : D:199812231952?08'00' */
223
    /* Output sample : 1997-07-16T19:20:30+01:00 */
224
22.4k
    int l = dtl;
225
226
22.4k
    if (l > bufl)
227
0
        l = bufl;
228
22.4k
    if (dt[0] == 'D' && dt[1] == ':') {
229
22.4k
        l -= 2;
230
22.4k
        memcpy(buf, dt + 2, l);
231
22.4k
    } else
232
0
        memcpy(buf, dt, l);
233
22.4k
    memcpy(dt, buf, 4); /* year */
234
22.4k
    if (l <= 4)
235
0
        return 4;
236
237
22.4k
    dt[4] = '-';
238
22.4k
    memcpy(dt + 5, buf + 4, 2); /* month */
239
22.4k
    if (l <= 6)
240
0
        return 7;
241
242
22.4k
    dt[7] = '-';
243
22.4k
    memcpy(dt + 8, buf + 6, 2); /* day */
244
22.4k
    if (l <= 8)
245
0
        return 10;
246
247
22.4k
    dt[10] = 'T';
248
22.4k
    memcpy(dt + 11, buf + 8, 2); /* hour */
249
22.4k
    dt[13] = ':';
250
22.4k
    memcpy(dt + 14, buf + 10, 2); /* minute */
251
22.4k
    if (l <= 12) {
252
0
        dt[16] = 'Z'; /* Default time zone 0. */
253
0
        return 17;
254
0
    }
255
256
22.4k
    dt[16] = ':';
257
22.4k
    memcpy(dt + 17, buf + 12, 2); /* second */
258
22.4k
    if (l <= 14) {
259
0
        dt[19] = 'Z'; /* Default time zone 0. */
260
0
        return 20;
261
0
    }
262
263
22.4k
    dt[19] = buf[14]; /* designator */
264
22.4k
    if (dt[19] == 'Z')
265
22.4k
        return 20;
266
0
    if (l <= 15)
267
0
        return 20;
268
0
    memcpy(dt + 20, buf + 15, 2); /* Time zone hour difference. */
269
0
    if (l <= 17)
270
0
        return 22;
271
272
0
    dt[22] = ':';
273
    /* Skipping '\'' in 'buf'. */
274
0
    memcpy(dt + 23, buf + 18, 2); /* Time zone minutes difference. */
275
0
    return 25;
276
0
}
277
278
int
279
pdf_get_docinfo_item(gx_device_pdf *pdev, const char *key, char *buf, int buf_length)
280
27.2k
{
281
27.2k
    const cos_value_t *v = cos_dict_find(pdev->Info, (const byte *)key, strlen(key));
282
27.2k
    int l;
283
27.2k
    const byte *s;
284
285
27.2k
    if (v != NULL && (v->value_type == COS_VALUE_SCALAR ||
286
27.2k
                        v->value_type == COS_VALUE_CONST)) {
287
27.2k
        if (v->contents.chars.size >= 2 && v->contents.chars.data[0] == '(') {
288
27.2k
            s = v->contents.chars.data + 1;
289
27.2k
            l = v->contents.chars.size - 2;
290
27.2k
        } else {
291
0
            s = v->contents.chars.data;
292
0
            l = v->contents.chars.size;
293
0
        }
294
27.2k
    } else
295
0
        return 0;
296
27.2k
    if (l < 0)
297
0
        l = 0;
298
27.2k
    if (l > buf_length)
299
0
        l = buf_length;
300
27.2k
    memcpy(buf, s, l);
301
27.2k
    return l;
302
27.2k
}
303
304
static inline byte
305
decode_escape(const byte *data, int data_length, size_t *index)
306
27.9k
{
307
27.9k
    byte c;
308
309
27.9k
    (*index)++; /* skip '\' */
310
27.9k
    if (*index >= data_length)
311
0
        return 0; /* Must_not_happen, because the string is PS encoded. */
312
27.9k
    c = data[*index];
313
27.9k
    switch (c) {
314
1.14k
        case '(': return '(';
315
681
        case ')': return ')';
316
1.18k
        case '\\': return '\\';
317
8
        case 'n': return '\n';
318
4
        case 'r': return '\r';
319
164
        case 't': return '\t';
320
5
        case 'b': return '\b';
321
0
        case 'f': return '\f';
322
24.7k
        default:
323
24.7k
            break;
324
27.9k
    }
325
24.7k
    if (c >= '0' && c <= '7') {
326
24.7k
        int oct_loop;
327
        /* octal */
328
24.7k
        byte v = c - '0';
329
330
        /* Octal values should always be three digits, one is consumed above! */
331
74.3k
        for (oct_loop = 0;oct_loop < 2; oct_loop++) {
332
49.5k
            (*index)++;
333
49.5k
            if (*index >= data_length)
334
                /* Ran out of data, return what we found */
335
0
                return v;
336
49.5k
            c = data[*index];
337
49.5k
            if (c < '0' || c > '7') {
338
                /* Ran out of numeric data, return what we found */
339
                /* Need to 'unget' the non-numeric character */
340
0
                (*index)--;
341
0
                break;
342
0
            }
343
49.5k
            v = v * 8 + (c - '0');
344
49.5k
        }
345
24.7k
        return v;
346
24.7k
    }
347
0
    return c; /* A wrong escapement sequence. */
348
24.7k
}
349
350
/*
351
 * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
352
 * into the first byte, depending on how many bytes follow.  There are
353
 * as many entries in this table as there are UTF-8 sequence types.
354
 * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
355
 * for *legal* UTF-8 will be 4 or fewer bytes total.
356
 */
357
static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
358
359
static int gs_ConvertUTF16(unsigned char *UTF16, size_t UTF16Len, unsigned char **UTF8Start, int UTF8Len)
360
17.6k
{
361
17.6k
    size_t i, bytes = 0;
362
17.6k
    unsigned short U16;
363
17.6k
    unsigned char *UTF8 = *UTF8Start;
364
17.6k
    unsigned char *UTF8End = UTF8 + UTF8Len;
365
366
17.6k
    if (UTF16Len % sizeof(short) != 0)
367
0
        return gs_note_error(gs_error_rangecheck);
368
369
610k
    for (i=0;i<UTF16Len / sizeof(short);i++)
370
592k
    {
371
592k
        U16 = (*UTF16++) << 8;
372
592k
        U16 += *UTF16++;
373
374
592k
        if (U16 >= 0xD800 && U16 <= 0xDBFF) {
375
0
            return gs_note_error(gs_error_rangecheck);
376
0
        }
377
592k
        if (U16 >= 0xDC00 && U16 <= 0xDFFF) {
378
0
            return gs_note_error(gs_error_rangecheck);
379
0
        }
380
381
592k
        if(U16 < 0x80) {
382
581k
            bytes = 1;
383
581k
        } else {
384
11.4k
            if (U16 < 0x800) {
385
9.63k
                    bytes = 2;
386
9.63k
            } else {
387
1.82k
                bytes = 3;
388
1.82k
                U16 = 0xFFFD;
389
1.82k
            }
390
11.4k
        }
391
592k
        if (UTF8 + bytes > UTF8End)
392
0
            return gs_note_error(gs_error_VMerror);
393
394
        /* Write from end to beginning, low bytes first */
395
592k
        UTF8 += bytes;
396
397
592k
        switch(bytes) {
398
1.82k
            case 3:
399
1.82k
                *--UTF8 = (unsigned char)((U16 | 0x80) & 0xBF);
400
1.82k
                U16 >>= 6;
401
11.4k
            case 2:
402
11.4k
                *--UTF8 = (unsigned char)((U16 | 0x80) & 0xBF);
403
11.4k
                U16 >>= 6;
404
592k
            case 1:
405
592k
                *--UTF8 = (unsigned char)(U16 | firstByteMark[bytes]);
406
592k
                break;
407
0
            default:
408
0
                return gs_note_error(gs_error_rangecheck);
409
592k
        }
410
411
        /* Move to start of next set */
412
592k
        UTF8 += bytes;
413
592k
    }
414
17.6k
    *UTF8Start = UTF8;
415
17.6k
    return 0;
416
17.6k
}
417
418
static int
419
pdf_xmp_write_translated(gx_device_pdf *pdev, stream *s, const byte *data, int data_length,
420
                         void(*write)(stream *s, const byte *data, int data_length))
421
18.0k
{
422
18.0k
    size_t i, j=0;
423
18.0k
    unsigned char *buf0;
424
425
18.0k
    if (data_length == 0)
426
429
        return 0;
427
428
17.6k
    buf0 = (unsigned char *)gs_alloc_bytes(pdev->memory, data_length * sizeof(unsigned char),
429
17.6k
                    "pdf_xmp_write_translated");
430
17.6k
    if (buf0 == NULL)
431
0
        return_error(gs_error_VMerror);
432
612k
    for (i = 0; i < (size_t)data_length; i++) {
433
594k
        byte c = data[i];
434
435
594k
        if (c == '\\')
436
27.9k
            c = decode_escape(data, data_length, &i);
437
594k
        buf0[j] = c;
438
594k
        j++;
439
594k
    }
440
17.6k
    if (buf0[0] != 0xfe || buf0[1] != 0xff) {
441
17.5k
        unsigned char *buf1;
442
        /* We must assume that the information is PDFDocEncoding. In this case
443
         * we need to convert it into UTF-8. If we just convert it to UTF-16
444
         * then we can safely fall through to the code below.
445
         */
446
        /* NB the code below skips the BOM in positions 0 and 1, so we need
447
         * two extra bytes, to be ignored.
448
         */
449
17.5k
        buf1 = (unsigned char *)gs_alloc_bytes(pdev->memory, (j * sizeof(short)) + 2,
450
17.5k
                    "pdf_xmp_write_translated");
451
17.5k
        if (buf1 == NULL) {
452
0
            gs_free_object(pdev->memory, buf0, "pdf_xmp_write_translated");
453
0
            return_error(gs_error_VMerror);
454
0
        }
455
17.5k
        memset(buf1, 0x00, (j * sizeof(short)) + 2);
456
608k
        for (i = 0; i < j; i++) {
457
591k
            if (buf0[i] <= 0x7f || buf0[i] >= 0xAE) {
458
587k
                if (buf0[i] == 0x7f) {
459
2.05k
                    emprintf1(pdev->memory, "PDFDocEncoding %x cannot be represented in Unicode\n",
460
2.05k
                        buf0[i]);
461
2.05k
                } else
462
585k
                    buf1[(i * 2) + 3] = buf0[i];
463
587k
            } else {
464
3.33k
                buf1[(i * 2) + 2] = PDFDocEncodingLookup[(buf0[i] - 0x80) * 2];
465
3.33k
                buf1[(i * 2) + 3] = PDFDocEncodingLookup[((buf0[i] - 0x80) * 2) + 1];
466
3.33k
                if (PDFDocEncodingLookup[((buf0[i] - 0x80) * 2) + 1] == 0x00)
467
42
                    emprintf1(pdev->memory, "PDFDocEncoding %x cannot be represented in Unicode\n",
468
3.33k
                        PDFDocEncodingLookup[((buf0[i] - 0x80) * 2) + 1]);
469
3.33k
            }
470
591k
        }
471
17.5k
        gs_free_object(pdev->memory, buf0, "pdf_xmp_write_translated");
472
17.5k
        buf0 = buf1;
473
17.5k
        data_length = j = (j * 2) + 2;
474
17.5k
    }
475
17.6k
    {
476
        /* Its a Unicode (UTF-16BE) string, convert to UTF-8 */
477
17.6k
        short *buf0b;
478
17.6k
        char *buf1, *buf1b;
479
17.6k
        int code;
480
481
        /* A single UTF-16 (2 bytes) can end up as 4 bytes in UTF-8 */
482
17.6k
        buf1 = (char *)gs_alloc_bytes(pdev->memory, data_length * 2 * sizeof(unsigned char),
483
17.6k
                    "pdf_xmp_write_translated");
484
17.6k
        if (buf1 == NULL) {
485
0
            gs_free_object(pdev->memory, buf0, "pdf_xmp_write_translated");
486
0
            return_error(gs_error_VMerror);
487
0
        }
488
17.6k
        buf1b = buf1;
489
        /* Skip the Byte Order Mark (0xfe 0xff) */
490
17.6k
        buf0b = (short *)(buf0 + 2);
491
17.6k
        code = gs_ConvertUTF16((unsigned char *)buf0b, j - 2, (unsigned char **)&buf1b, data_length * 2 * sizeof(unsigned char));
492
17.6k
        if (code < 0) {
493
0
            gs_free_object(pdev->memory, buf0, "pdf_xmp_write_translated");
494
0
            gs_free_object(pdev->memory, buf1, "pdf_xmp_write_translated");
495
0
            return code;
496
0
        }
497
17.6k
        write(s, (const byte *)buf1, buf1b - buf1);
498
17.6k
        gs_free_object(pdev->memory, buf1, "pdf_xmp_write_translated");
499
17.6k
    }
500
17.6k
    gs_free_object(pdev->memory, buf0, "pdf_xmp_write_translated");
501
17.6k
    return 0;
502
17.6k
}
503
504
static int
505
pdf_xmp_write_docinfo_item(gx_device_pdf *pdev, stream *s, const char *key, const char *default_value,
506
                           void(*write)(stream *s, const byte *data, int data_length))
507
35.4k
{
508
35.4k
    const cos_value_t *v = cos_dict_find(pdev->Info, (const byte *)key, strlen(key));
509
510
35.4k
    if (v != NULL && (v->value_type == COS_VALUE_SCALAR ||
511
18.0k
                        v->value_type == COS_VALUE_CONST)) {
512
18.0k
        if (v->contents.chars.size >= 2 && v->contents.chars.data[0] == '(')
513
18.0k
            return pdf_xmp_write_translated(pdev, s, v->contents.chars.data + 1,
514
18.0k
                        v->contents.chars.size - 2, write);
515
14
        else
516
14
            return pdf_xmp_write_translated(pdev, s, v->contents.chars.data,
517
14
                        v->contents.chars.size, write);
518
18.0k
    } else {
519
17.3k
        stream_puts(s, default_value);
520
17.3k
        return 0;
521
17.3k
    }
522
35.4k
}
523
524
static uint64_t
525
pdf_uuid_time(gx_device_pdf *pdev)
526
22.4k
{
527
22.4k
    long *dt = pdev->uuid_time; /* In seconds since Jan. 1, 1980 and fraction in nanoseconds. */
528
22.4k
    uint64_t t;
529
530
    /* UUIDs use time in 100ns ticks since Oct 15, 1582. */
531
22.4k
    t = (uint64_t)10000000 * dt[0] + dt[0] / 100; /* since Jan. 1, 1980 */
532
22.4k
    t += (uint64_t) (1000*1000*10)         /* seconds */
533
22.4k
       * (uint64_t) (60 * 60 * 24)         /* days */
534
22.4k
       * (uint64_t) (17+30+31+365*397+99); /* # of days */
535
22.4k
    return t;
536
22.4k
}
537
538
static void writehex(char **p, ulong v, int l)
539
247k
{
540
247k
    int i = l * 2;
541
247k
    static const char digit[] = "0123456789abcdef";
542
543
965k
    for (; i--;)
544
718k
        *((*p)++) = digit[v >> (i * 4) & 15];
545
247k
}
546
547
static void
548
pdf_make_uuid(const byte node[6], uint64_t uuid_time, ulong time_seq, char *buf, int buf_length)
549
22.4k
{
550
22.4k
    char b[45], *p = b;
551
22.4k
    ulong  uuid_time_lo = (ulong)(uuid_time & 0xFFFFFFFF);       /* MSVC 7.1.3088           */
552
22.4k
    ushort uuid_time_md = (ushort)((uuid_time >> 32) & 0xFFFF);  /* cannot compile this     */
553
22.4k
    ushort uuid_time_hi = (ushort)((uuid_time >> 48) & 0x0FFF);  /* as function arguments.  */
554
555
22.4k
    writehex(&p, uuid_time_lo, 4); /* time_low */
556
22.4k
    *(p++) = '-';
557
22.4k
    writehex(&p, uuid_time_md, 2); /* time_mid */
558
22.4k
    *(p++) = '-';
559
22.4k
    writehex(&p, uuid_time_hi | (ushort)(1 << 12), 2); /* time_hi_and_version */
560
22.4k
    *(p++) = '-';
561
22.4k
    writehex(&p, (time_seq & 0x3F00) >> 8, 1); /* clock_seq_hi_and_reserved */
562
22.4k
    writehex(&p, time_seq & 0xFF, 1); /* clock_seq & 0xFF */
563
22.4k
    *(p++) = '-';
564
22.4k
    writehex(&p, node[0], 1);
565
22.4k
    writehex(&p, node[1], 1);
566
22.4k
    writehex(&p, node[2], 1);
567
22.4k
    writehex(&p, node[3], 1);
568
22.4k
    writehex(&p, node[4], 1);
569
22.4k
    writehex(&p, node[5], 1);
570
22.4k
    *p = 0;
571
22.4k
    strncpy(buf, b, strlen(b) + 1);
572
22.4k
}
573
574
static int
575
pdf_make_instance_uuid(gx_device_pdf *pdev, const byte digest[6], char *buf, int buf_length)
576
11.2k
{
577
11.2k
    char URI_prefix[5] = "uuid:";
578
579
11.2k
    memcpy(buf, URI_prefix, 5);
580
11.2k
    if (pdev->InstanceUUID.size) {
581
0
        int l = min(buf_length - 6, pdev->InstanceUUID.size);
582
583
0
        memcpy(buf+5, pdev->InstanceUUID.data, l);
584
0
        buf[l+5] = 0;
585
0
    } else
586
11.2k
        pdf_make_uuid(digest, pdf_uuid_time(pdev), pdev->DocumentTimeSeq, buf + 5, buf_length - 5);
587
11.2k
    return 0;
588
11.2k
}
589
590
static int
591
pdf_make_document_uuid(gx_device_pdf *pdev, const byte digest[6], char *buf, int buf_length)
592
11.2k
{
593
11.2k
    char URI_prefix[5] = "uuid:";
594
595
11.2k
    memcpy(buf, URI_prefix, 5);
596
11.2k
    if (pdev->DocumentUUID.size) {
597
0
        int l = min(buf_length - 6, pdev->DocumentUUID.size);
598
599
0
        memcpy(buf+5, pdev->DocumentUUID.data, l);
600
0
        buf[l+5] = 0;
601
0
    } else
602
11.2k
        pdf_make_uuid(digest, pdf_uuid_time(pdev), pdev->DocumentTimeSeq, buf+5, buf_length - 5);
603
11.2k
    return 0;
604
11.2k
}
605
606
static const char dd[]={'\'', '\357', '\273', '\277', '\'', 0};
607
608
/* --------------------------------------------  */
609
610
/* Write Document metadata */
611
static int
612
pdf_write_document_metadata(gx_device_pdf *pdev, const byte digest[6])
613
11.2k
{
614
11.2k
    char instance_uuid[45], document_uuid[45], cre_date_time[40], mod_date_time[40], date_time_buf[40];
615
11.2k
    int cre_date_time_len, mod_date_time_len;
616
11.2k
    int code;
617
11.2k
    stream *s = pdev->strm;
618
619
11.2k
    code = pdf_make_instance_uuid(pdev, digest, instance_uuid, sizeof(instance_uuid));
620
11.2k
    if (code < 0)
621
0
        return code;
622
11.2k
    code = pdf_make_document_uuid(pdev, digest, document_uuid, sizeof(document_uuid));
623
11.2k
    if (code < 0)
624
0
        return code;
625
626
    /* PDF/A XMP reference recommends setting UUID to empty. If not empty must be a URI */
627
11.2k
    if (pdev->PDFA != 0)
628
0
        instance_uuid[0] = 0x00;
629
630
11.2k
    cre_date_time_len = pdf_get_docinfo_item(pdev, "/CreationDate", cre_date_time, sizeof(cre_date_time));
631
11.2k
    if (!cre_date_time_len)
632
0
        cre_date_time_len = pdf_xmp_time(cre_date_time, sizeof(cre_date_time));
633
11.2k
    else
634
11.2k
        cre_date_time_len = pdf_xmp_convert_time(cre_date_time, cre_date_time_len, date_time_buf, sizeof(date_time_buf));
635
11.2k
    mod_date_time_len = pdf_get_docinfo_item(pdev, "/ModDate", mod_date_time, sizeof(mod_date_time));
636
11.2k
    if (!mod_date_time_len)
637
0
        mod_date_time_len = pdf_xmp_time(mod_date_time, sizeof(mod_date_time));
638
11.2k
    else
639
11.2k
        mod_date_time_len = pdf_xmp_convert_time(mod_date_time, mod_date_time_len, date_time_buf, sizeof(date_time_buf));
640
641
11.2k
    pdf_xml_ins_beg(s, "xpacket");
642
11.2k
    pdf_xml_attribute_name(s, "begin");
643
11.2k
    pdf_xml_copy(s, dd);
644
11.2k
    pdf_xml_attribute_name(s, "id");
645
11.2k
    pdf_xml_attribute_value(s, "W5M0MpCehiHzreSzNTczkc9d");
646
11.2k
    pdf_xml_ins_end(s);
647
11.2k
    pdf_xml_newline(s);
648
649
11.2k
    pdf_xml_copy(s, "<?adobe-xap-filters esc=\"CRLF\"?>\n");
650
11.2k
    pdf_xml_copy(s, "<x:xmpmeta xmlns:x='adobe:ns:meta/'"
651
11.2k
                              " x:xmptk='XMP toolkit 2.9.1-13, framework 1.6'>\n");
652
11.2k
    {
653
11.2k
        pdf_xml_copy(s, "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' "
654
11.2k
                                 "xmlns:iX='http://ns.adobe.com/iX/1.0/'>\n");
655
11.2k
        {
656
657
11.2k
            pdf_xml_tag_open_beg(s, "rdf:Description");
658
11.2k
            pdf_xml_copy(s, " rdf:about=\"\"");
659
11.2k
            pdf_xml_attribute_name(s, "xmlns:pdf");
660
11.2k
            pdf_xml_attribute_value(s, "http://ns.adobe.com/pdf/1.3/");
661
662
11.2k
            if (cos_dict_find(pdev->Info, (const byte *)"/Keywords", 9)) {
663
396
                pdf_xml_tag_end(s);
664
396
                pdf_xml_tag_open_beg(s, "pdf:Producer");
665
396
                pdf_xml_tag_end(s);
666
396
                code = pdf_xmp_write_docinfo_item(pdev, s,  "/Producer", "UnknownProducer",
667
396
                        pdf_xml_data_write);
668
396
                if (code < 0)
669
0
                    return code;
670
396
                pdf_xml_tag_close(s, "pdf:Producer");
671
396
                pdf_xml_newline(s);
672
673
396
                pdf_xml_tag_open_beg(s, "pdf:Keywords");
674
396
                pdf_xml_tag_end(s);
675
396
                code = pdf_xmp_write_docinfo_item(pdev, s,  "/Keywords", "Unknown",
676
396
                        pdf_xml_data_write);
677
396
                if (code < 0)
678
0
                    return code;
679
396
                pdf_xml_tag_close(s, "pdf:Keywords");
680
396
                pdf_xml_newline(s);
681
682
396
                pdf_xml_tag_close(s, "rdf:Description");
683
396
                pdf_xml_newline(s);
684
10.8k
            } else {
685
10.8k
                pdf_xml_attribute_name(s, "pdf:Producer");
686
10.8k
                code = pdf_xmp_write_docinfo_item(pdev, s,  "/Producer", "UnknownProducer",
687
10.8k
                        pdf_xml_attribute_value_data);
688
10.8k
                if (code < 0)
689
0
                    return code;
690
10.8k
                pdf_xml_tag_end_empty(s);
691
10.8k
                pdf_xml_newline(s);
692
10.8k
            }
693
694
11.2k
            pdf_xml_tag_open_beg(s, "rdf:Description");
695
11.2k
            pdf_xml_copy(s, " rdf:about=\"\"");
696
11.2k
            pdf_xml_attribute_name(s, "xmlns:xmp");
697
11.2k
            pdf_xml_attribute_value(s, "http://ns.adobe.com/xap/1.0/");
698
11.2k
            pdf_xml_tag_end(s);
699
11.2k
            if (!pdev->OmitInfoDate) {
700
11.2k
                {
701
11.2k
                    pdf_xml_tag_open_beg(s, "xmp:ModifyDate");
702
11.2k
                    pdf_xml_tag_end(s);
703
11.2k
                    mod_date_time[mod_date_time_len] = 0x00;
704
11.2k
                    pdf_xml_copy(s, mod_date_time);
705
11.2k
                    pdf_xml_tag_close(s, "xmp:ModifyDate");
706
11.2k
                    pdf_xml_newline(s);
707
11.2k
                }
708
11.2k
                {
709
11.2k
                    pdf_xml_tag_open_beg(s, "xmp:CreateDate");
710
11.2k
                    pdf_xml_tag_end(s);
711
11.2k
                    cre_date_time[cre_date_time_len] = 0x00;
712
11.2k
                    pdf_xml_copy(s, cre_date_time);
713
11.2k
                    pdf_xml_tag_close(s, "xmp:CreateDate");
714
11.2k
                    pdf_xml_newline(s);
715
11.2k
                }
716
11.2k
            }
717
11.2k
            {
718
11.2k
                pdf_xml_tag_open_beg(s, "xmp:CreatorTool");
719
11.2k
                pdf_xml_tag_end(s);
720
11.2k
                code = pdf_xmp_write_docinfo_item(pdev, s,  "/Creator", "UnknownApplication",
721
11.2k
                        pdf_xml_data_write);
722
11.2k
                if (code < 0)
723
0
                    return code;
724
11.2k
                pdf_xml_tag_close(s, "xmp:CreatorTool");
725
11.2k
            }
726
0
            pdf_xml_tag_close(s, "rdf:Description");
727
11.2k
            pdf_xml_newline(s);
728
729
11.2k
            pdf_xml_tag_open_beg(s, "rdf:Description");
730
11.2k
            pdf_xml_copy(s, " rdf:about=\"\"");
731
11.2k
            pdf_xml_attribute_name(s, "xmlns:xapMM");
732
11.2k
            pdf_xml_attribute_value(s, "http://ns.adobe.com/xap/1.0/mm/");
733
11.2k
            pdf_xml_attribute_name(s, "xapMM:DocumentID");
734
11.2k
            pdf_xml_attribute_value(s, document_uuid);
735
11.2k
            pdf_xml_tag_end_empty(s);
736
11.2k
            pdf_xml_newline(s);
737
738
11.2k
            pdf_xml_tag_open_beg(s, "rdf:Description");
739
11.2k
            pdf_xml_copy(s, " rdf:about=\"\"");
740
11.2k
            pdf_xml_attribute_name(s, "xmlns:dc");
741
11.2k
            pdf_xml_attribute_value(s, "http://purl.org/dc/elements/1.1/");
742
11.2k
            pdf_xml_attribute_name(s, "dc:format");
743
11.2k
            pdf_xml_attribute_value(s,"application/pdf");
744
11.2k
            pdf_xml_tag_end(s);
745
11.2k
            {
746
11.2k
                pdf_xml_tag_open(s, "dc:title");
747
11.2k
                {
748
11.2k
                    pdf_xml_tag_open(s, "rdf:Alt");
749
11.2k
                    {
750
11.2k
                        pdf_xml_tag_open_beg(s, "rdf:li");
751
11.2k
                        pdf_xml_attribute_name(s, "xml:lang");
752
11.2k
                        pdf_xml_attribute_value(s, "x-default");
753
11.2k
                        pdf_xml_tag_end(s);
754
11.2k
                        {
755
11.2k
                           code = pdf_xmp_write_docinfo_item(pdev, s,  "/Title", "Untitled",
756
11.2k
                                    pdf_xml_data_write);
757
11.2k
                            if (code < 0)
758
0
                                return code;
759
11.2k
                        }
760
11.2k
                        pdf_xml_tag_close(s, "rdf:li");
761
11.2k
                    }
762
0
                    pdf_xml_tag_close(s, "rdf:Alt");
763
11.2k
                }
764
0
                pdf_xml_tag_close(s, "dc:title");
765
766
11.2k
                if (cos_dict_find(pdev->Info, (const byte *)"/Author", 7)) {
767
1.28k
                    pdf_xml_tag_open(s, "dc:creator");
768
1.28k
                    {   /* According to the PDF/A specification
769
                           "it shall be represented by an ordered Text array of
770
                           length one whose single entry shall consist
771
                           of one or more names". */
772
1.28k
                        pdf_xml_tag_open(s, "rdf:Seq");
773
1.28k
                        {
774
1.28k
                            pdf_xml_tag_open(s, "rdf:li");
775
1.28k
                            {
776
1.28k
                                code = pdf_xmp_write_docinfo_item(pdev, s,  "/Author", "Unknown",
777
1.28k
                                            pdf_xml_data_write);
778
1.28k
                                if (code < 0)
779
0
                                    return code;
780
1.28k
                            }
781
1.28k
                            pdf_xml_tag_close(s, "rdf:li");
782
1.28k
                        }
783
0
                        pdf_xml_tag_close(s, "rdf:Seq");
784
1.28k
                    }
785
0
                    pdf_xml_tag_close(s, "dc:creator");
786
1.28k
                }
787
11.2k
                if (cos_dict_find(pdev->Info, (const byte *)"/Subject", 8)) {
788
44
                    pdf_xml_tag_open(s, "dc:description");
789
44
                    {
790
44
                        pdf_xml_tag_open(s, "rdf:Alt");
791
44
                        {
792
44
                            pdf_xml_tag_open_beg(s, "rdf:li");
793
44
                            pdf_xml_attribute_name(s, "xml:lang");
794
44
                            pdf_xml_attribute_value(s, "x-default");
795
44
                            pdf_xml_tag_end(s);
796
44
                            {
797
44
                                code = pdf_xmp_write_docinfo_item(pdev, s,  "/Subject", "No Subject",
798
44
                                            pdf_xml_data_write);
799
44
                                if (code < 0)
800
0
                                    return code;
801
44
                            }
802
44
                            pdf_xml_tag_close(s, "rdf:li");
803
44
                        }
804
0
                        pdf_xml_tag_close(s, "rdf:Alt");
805
44
                    }
806
0
                    pdf_xml_tag_close(s, "dc:description");
807
44
                }
808
11.2k
            }
809
11.2k
            pdf_xml_tag_close(s, "rdf:Description");
810
11.2k
            pdf_xml_newline(s);
811
11.2k
            if (pdev->PDFA != 0) {
812
0
                pdf_xml_tag_open_beg(s, "rdf:Description");
813
0
                pdf_xml_copy(s, " rdf:about=\"\"");
814
0
                pdf_xml_attribute_name(s, "xmlns:pdfaid");
815
0
                pdf_xml_attribute_value(s, "http://www.aiim.org/pdfa/ns/id/");
816
0
                pdf_xml_attribute_name(s, "pdfaid:part");
817
0
                switch(pdev->PDFA) {
818
0
                    case 1:
819
0
                        pdf_xml_attribute_value(s,"1");
820
0
                        break;
821
0
                    case 2:
822
0
                        pdf_xml_attribute_value(s,"2");
823
0
                        break;
824
0
                    case 3:
825
0
                        pdf_xml_attribute_value(s,"3");
826
0
                        break;
827
0
                }
828
0
                pdf_xml_attribute_name(s, "pdfaid:conformance");
829
0
                pdf_xml_attribute_value(s,"B");
830
0
                pdf_xml_tag_end_empty(s);
831
0
           }
832
11.2k
        }
833
11.2k
        if (pdev->ExtensionMetadata) {
834
0
            pdf_xml_copy(s, pdev->ExtensionMetadata);
835
0
        }
836
11.2k
        pdf_xml_copy(s, "</rdf:RDF>\n");
837
11.2k
    }
838
0
    pdf_xml_copy(s, "</x:xmpmeta>\n");
839
840
11.2k
    pdf_xml_copy(s, "                                                                        \n");
841
11.2k
    pdf_xml_copy(s, "                                                                        \n");
842
11.2k
    pdf_xml_copy(s, "<?xpacket end='w'?>");
843
11.2k
    return 0;
844
11.2k
}
845
846
int
847
pdf_document_metadata(gx_device_pdf *pdev)
848
11.2k
{
849
11.2k
    if (pdev->CompatibilityLevel < 1.4)
850
6
        return 0;
851
11.2k
    if (cos_dict_find_c_key(pdev->Catalog, "/Metadata"))
852
0
        return 0;
853
854
11.2k
    if (pdev->ParseDSCCommentsForDocInfo || pdev->PreserveEPSInfo || pdev->PDFA) {
855
11.2k
        pdf_resource_t *pres;
856
11.2k
        char buf[20];
857
11.2k
        byte digest[6] = {0,0,0,0,0,0};
858
11.2k
        int code;
859
11.2k
        int options = DATA_STREAM_NOT_BINARY;
860
861
11.2k
        sflush(pdev->strm);
862
11.2k
        s_MD5C_get_digest(pdev->strm, digest, sizeof(digest));
863
11.2k
        if (pdev->EncryptMetadata)
864
11.2k
            options |= DATA_STREAM_ENCRYPT;
865
11.2k
        code = pdf_open_aside(pdev, resourceMetadata, gs_no_id, &pres, true, options);
866
11.2k
        if (code < 0)
867
0
            return code;
868
11.2k
        code = cos_dict_put_c_key_string((cos_dict_t *)pres->object, "/Type", (const byte *)"/Metadata", 9);
869
11.2k
        if (code < 0) {
870
0
            pdf_close_aside(pdev);
871
0
            return code;
872
0
        }
873
11.2k
        code = cos_dict_put_c_key_string((cos_dict_t *)pres->object, "/Subtype", (const byte *)"/XML", 4);
874
11.2k
        if (code < 0) {
875
0
            pdf_close_aside(pdev);
876
0
            return code;
877
0
        }
878
11.2k
        code = pdf_write_document_metadata(pdev, digest);
879
11.2k
        if (code < 0) {
880
0
            pdf_close_aside(pdev);
881
0
            return code;
882
0
        }
883
11.2k
        code = pdf_close_aside(pdev);
884
11.2k
        if (code < 0)
885
0
            return code;
886
11.2k
        code = COS_WRITE_OBJECT(pres->object, pdev, resourceNone);
887
11.2k
        if (code < 0)
888
0
            return code;
889
11.2k
        gs_snprintf(buf, sizeof(buf), "%ld 0 R", pres->object->id);
890
11.2k
        pdf_record_usage(pdev, pres->object->id, resource_usage_part9_structure);
891
892
11.2k
        code = cos_dict_put_c_key_object(pdev->Catalog, "/Metadata", pres->object);
893
11.2k
        if (code < 0)
894
0
            return code;
895
896
11.2k
    }
897
11.2k
    return 0;
898
11.2k
}
899
900
/* --------------------------------------------  */