Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpsf1.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Write an embedded Type 1 font */
18
#include "math.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsccode.h"
23
#include "gsmatrix.h"
24
#include "gxfixed.h"
25
#include "gxfont.h"
26
#include "gxfont1.h"
27
#include "gxmatrix.h"   /* for gxtype1.h */
28
#include "gxtype1.h"
29
#include "strimpl.h"    /* required by Watcom compiler (why?) */
30
#include "stream.h"
31
#include "sfilter.h"
32
#include "spsdf.h"
33
#include "sstring.h"
34
#include "spprint.h"
35
#include "gdevpsf.h"
36
37
/* ------ Utilities shared with CFF writer ------ */
38
39
/* Gather glyph information for a Type 1 or Type 2 font. */
40
int
41
psf_type1_glyph_data(gs_font_base *pbfont, gs_glyph glyph,
42
                     gs_glyph_data_t *pgd, gs_font_type1 **ppfont)
43
1.27M
{
44
1.27M
    gs_font_type1 *const pfont = (gs_font_type1 *)pbfont;
45
46
1.27M
    *ppfont = pfont;
47
1.27M
    return pfont->data.procs.glyph_data(pfont, glyph, pgd);
48
1.27M
}
49
int
50
psf_get_type1_glyphs(psf_outline_glyphs_t *pglyphs, gs_font_type1 *pfont,
51
                     gs_glyph *subset_glyphs, uint subset_size)
52
18.4k
{
53
18.4k
    return psf_get_outline_glyphs(pglyphs, (gs_font_base *)pfont,
54
18.4k
                                  subset_glyphs, subset_size,
55
18.4k
                                  psf_type1_glyph_data);
56
18.4k
}
57
58
/* ------ Main program ------ */
59
60
/* Write a (named) array of floats. */
61
static int
62
write_float_array(gs_param_list *plist, const char *key, const float *values,
63
                  int count)
64
105k
{
65
105k
    if (count != 0) {
66
63.8k
        gs_param_float_array fa;
67
68
63.8k
        fa.persistent = false;
69
63.8k
        fa.size = count;
70
63.8k
        fa.data = values;
71
63.8k
        return param_write_float_array(plist, key, &fa);
72
63.8k
    }
73
41.3k
    return 0;
74
105k
}
75
76
/* Write a UniqueID and/or XUID. */
77
static void
78
write_uid(stream *s, const gs_uid *puid, int options)
79
26.3k
{
80
26.3k
    if (uid_is_UniqueID(puid))
81
0
        pprintld1(s, "/UniqueID %ld def\n", puid->id);
82
26.3k
    else if (uid_is_XUID(puid) && (options & WRITE_TYPE1_XUID) != 0) {
83
0
        uint i, n = uid_XUID_size(puid);
84
85
        /* Adobe products (specifically Acrobat but the same limitation is mentioned
86
         * in the PLRM) cannot handle XUIDs > 16 entries.
87
         */
88
0
        if (n > 16)
89
0
            n = 16;
90
91
0
        stream_puts(s, "/XUID [");
92
0
        for (i = 0; i < n; ++i)
93
0
            pprintld1(s, "%ld ", uid_XUID_values(puid)[i]);
94
0
        stream_puts(s, "] readonly def\n");
95
0
    }
96
26.3k
}
97
98
/* Write the font name. */
99
static void
100
write_font_name(stream *s, const gs_font_type1 *pfont,
101
                const gs_const_string *alt_font_name, bool as_name)
102
26.3k
{
103
26.3k
    const byte *c;
104
26.3k
    const byte *name = (alt_font_name ? alt_font_name->data : pfont->font_name.chars);
105
26.3k
    int         n    = (alt_font_name ? alt_font_name->size : pfont->font_name.size);
106
107
26.3k
    if (n == 0)
108
        /* empty name, may need to write it as empty string */
109
0
        stream_puts(s, (as_name ? "/" : "()"));
110
26.3k
    else {
111
499k
        for (c = (byte *)"()<>[]{}/% \n\r\t\b\f\004\033"; *c; c++)
112
472k
            if (memchr(name, *c, n))
113
76
                break;
114
26.3k
        if (*c || memchr(name, 0, n)) {
115
            /* name contains whitespace (NUL included) or a PostScript separator */
116
76
            byte pssebuf[1 + 4 * gs_font_name_max + 1]; /* "(" + "\ooo" * gs_font_name_max + ")" */
117
76
            stream_cursor_read  r;
118
76
            stream_cursor_write w;
119
120
76
            pssebuf[0] = '(';
121
76
            r.limit = (r.ptr = name - 1) + n;
122
76
            w.limit = (w.ptr = pssebuf) + sizeof pssebuf - 1;
123
76
            s_PSSE_template.process(NULL, &r, &w, true);
124
76
            stream_write(s, pssebuf, w.ptr - pssebuf + 1);
125
76
            if (as_name)
126
38
                stream_puts(s, " cvn");
127
26.2k
        } else {
128
            /* name without any special characters */
129
26.2k
            if (as_name)
130
13.1k
                stream_putc(s, '/');
131
26.2k
            stream_write(s, name, n);
132
26.2k
        }
133
26.3k
    }
134
26.3k
}
135
/*
136
 * Write the Encoding array.  This is a separate procedure only for
137
 * readability.
138
 */
139
static int
140
write_Encoding(stream *s, gs_font_type1 *pfont, int options,
141
              gs_glyph *subset_glyphs, uint subset_size, gs_glyph notdef)
142
13.1k
{
143
13.1k
    stream_puts(s, "/Encoding ");
144
13.1k
    switch (pfont->encoding_index) {
145
0
        case ENCODING_INDEX_STANDARD:
146
0
            stream_puts(s, "StandardEncoding");
147
0
            break;
148
0
        case ENCODING_INDEX_ISOLATIN1:
149
            /* ATM only recognizes StandardEncoding. */
150
0
            if (options & WRITE_TYPE1_POSTSCRIPT) {
151
0
                stream_puts(s, "ISOLatin1Encoding");
152
0
                break;
153
0
            }
154
13.1k
        default:{
155
13.1k
                gs_char i;
156
157
13.1k
                stream_puts(s, "256 array\n");
158
13.1k
                stream_puts(s, "0 1 255 {1 index exch /.notdef put} for\n");
159
3.37M
                for (i = 0; i < 256; ++i) {
160
3.36M
                    gs_glyph glyph =
161
3.36M
                        (*pfont->procs.encode_char)
162
3.36M
                        ((gs_font *)pfont, (gs_char)i, GLYPH_SPACE_NAME);
163
3.36M
                    gs_const_string namestr;
164
165
3.36M
                    if (subset_glyphs && subset_size) {
166
                        /*
167
                         * Only write Encoding entries for glyphs in the
168
                         * subset.  Use binary search to check each glyph,
169
                         * since subset_glyphs are sorted.
170
                         */
171
0
                        if (!psf_sorted_glyphs_include(subset_glyphs,
172
0
                                                        subset_size, glyph))
173
0
                            continue;
174
0
                    }
175
3.36M
                    if (glyph != GS_NO_GLYPH && glyph != notdef &&
176
3.36M
                        pfont->procs.glyph_name((gs_font *)pfont, glyph,
177
240k
                                                &namestr) >= 0
178
3.36M
                        ) {
179
240k
                        pprintd1(s, "dup %d /", (int)i);
180
240k
                        stream_write(s, namestr.data, namestr.size);
181
240k
                        stream_puts(s, " put\n");
182
240k
                    }
183
3.36M
                }
184
13.1k
                stream_puts(s, "readonly");
185
13.1k
            }
186
13.1k
    }
187
13.1k
    stream_puts(s, " def\n");
188
13.1k
    return 0;
189
13.1k
}
190
191
static int WriteNumber (byte *dest, int value)
192
0
{
193
0
    if (value >= -107 && value <= 107) {
194
0
        *dest = value + 139;
195
0
        return 1;
196
0
    } else {
197
0
        if (value >= 108 && value <= 1131) {
198
0
            int quotient = (int)floor((value - 108) / (double)256);
199
0
            dest[0] = quotient + 247;
200
0
            dest[1] = value - 108 - quotient * 256;
201
0
            return 2;
202
0
        } else {
203
0
            if (value <= -108 && value >= -1131) {
204
0
                int quotient = (int)floor((value + 108) / -256);
205
0
                int newval = value + 256 * quotient + 108;
206
0
                dest[0] = quotient + 251;
207
0
                dest[1] = newval * -1;
208
0
                return 2;
209
0
            } else {
210
0
                dest[0] = 255;
211
0
                dest[1] = value >> 24;
212
0
                dest[2] = (value & 0xFF0000) >> 16;
213
0
                dest[3] = (value & 0xFF00) >> 8;
214
0
                dest[4] = value & 0xFF;
215
0
                return 5;
216
0
            }
217
0
        }
218
0
    }
219
0
    return 0;
220
0
}
221
222
/* The following 2 routines attempt to parse out Multiple Master 'OtherSubrs'
223
 * calls, and replace the multiple arguments to $Blend with the two 'base'
224
 * parameters. This works reasonably well but can be defeated. FOr example a
225
 * CharString which puts some parameters on the operand stack, then calls a
226
 * Subr which puts the remaining parameters on the stack, and calls a MM
227
 * OtherSubr (constructions like this have been observed). In general we
228
 * work around this by storing the operands on the stack, but it is possible
229
 * that the values are calculated (eg x y div) which is a common way to get
230
 * float values into the interpreter. This will defeat the code below.
231
 *
232
 * The only way to solve this is to actually fully interpret the CharString
233
 * and any /Subrs it calls, and then emit the result as a non-MM CharString
234
 * by blending the values. This would mean writing a new routine like
235
 * 'psf_convert_type1_to_type2' (see gdevpsfx.c) or modifying that routine
236
 * so that it outputs type 1 CharStrings (which is probably simpler to do).
237
 */
238
static int CheckSubrForMM (gs_glyph_data_t *gdata, gs_font_type1 *pfont)
239
0
{
240
0
    crypt_state state = crypt_charstring_seed;
241
0
    int code = 0;
242
0
    gs_bytestring *data = (gs_bytestring *)&gdata->bits;
243
0
    byte *source = data->data, *end = source + data->size;
244
0
    int CurrentNumberIndex = 0, Stack[32];
245
246
0
    memset(Stack, 0x00, sizeof(Stack));
247
0
    gs_type1_decrypt(source, source, data->size, &state);
248
249
0
    if (pfont->data.lenIV >= data->size) {
250
0
        code = gs_note_error(gs_error_invalidfont);
251
0
        goto error;
252
0
    }
253
254
0
    if(pfont->data.lenIV > 0)
255
0
        source += pfont->data.lenIV;
256
257
0
    while (source < end) {
258
0
        if (*source < 32) {
259
            /* Command */
260
0
            switch (*source) {
261
0
                case 12:
262
0
                    if (source + 2 > end) {
263
0
                        code = gs_note_error(gs_error_invalidfont);
264
0
                        goto error;
265
0
                    }
266
0
                    if (*(source + 1) == 16) {
267
0
                        if (CurrentNumberIndex < 1) {
268
0
                      code = gs_note_error(gs_error_rangecheck);
269
0
                            goto error;
270
0
                        }
271
0
                        switch(Stack[CurrentNumberIndex-1]) {
272
0
                            case 18:
273
0
                                code = 6;
274
0
                                break;
275
0
                            case 17:
276
0
                                code = 4;
277
0
                                break;
278
0
                            case 16:
279
0
                                code = 3;
280
0
                                break;
281
0
                            case 15:
282
0
                                code = 2;
283
0
                                break;
284
0
                            case 14:
285
0
                                code = 1;
286
0
                                break;
287
0
                            default:
288
0
                                code = 0;
289
0
                                break;
290
0
                        }
291
0
                        source += 2;
292
0
                    } else {
293
0
                        source +=2;
294
0
                    }
295
0
                    break;
296
0
                default:
297
0
                    source++;
298
0
                    break;
299
0
            }
300
0
            CurrentNumberIndex = 0;
301
0
        } else {
302
            /* Number */
303
0
            if (CurrentNumberIndex >= count_of(Stack)) {
304
0
                code = gs_note_error(gs_error_rangecheck);
305
0
                goto error;
306
0
            }
307
0
            if (*source < 247) {
308
0
                Stack[CurrentNumberIndex++] = *source++ - 139;
309
0
            } else {
310
0
                if (*source < 251) {
311
0
                    if (source + 2 > end) {
312
0
                        code = gs_note_error(gs_error_invalidfont);
313
0
                        goto error;
314
0
                    }
315
0
                    Stack[CurrentNumberIndex] = ((*source++ - 247) * 256) + 108;
316
0
                    Stack[CurrentNumberIndex++] += *source++;
317
0
                } else {
318
0
                    if (*source < 255) {
319
0
                        if (source + 2 > end) {
320
0
                            code = gs_note_error(gs_error_invalidfont);
321
0
                            goto error;
322
0
                        }
323
0
                        Stack[CurrentNumberIndex] = ((*source++ - 251) * -256) - 108;
324
0
                        Stack[CurrentNumberIndex++] -= *source++;
325
0
                    } else {
326
0
                        if (source + 5 > end) {
327
0
                            code = gs_note_error(gs_error_invalidfont);
328
0
                            goto error;
329
0
                        }
330
0
                        source++;
331
0
                        Stack[CurrentNumberIndex] = *source++ << 24;
332
0
                        Stack[CurrentNumberIndex] += *source++ << 16;
333
0
                        Stack[CurrentNumberIndex] += *source++ << 8;
334
0
                        Stack[CurrentNumberIndex++] += *source++;
335
0
                    }
336
0
                }
337
0
            }
338
0
        }
339
0
    }
340
    /* We decrypted the data in place at the start of the routine, we must re-encrypt it
341
     * before we return, even if there's an error.
342
     */
343
0
error:
344
0
    state = crypt_charstring_seed;
345
0
    source = data->data;
346
0
    gs_type1_encrypt(source, source, data->size, &state);
347
0
    return code;
348
0
}
349
#undef MM_STACK_SIZE
350
351
static int strip_othersubrs(gs_glyph_data_t *gdata, gs_font_type1 *pfont, byte *stripped, byte *SubrsWithMM, int SubrsCount)
352
0
{
353
0
    crypt_state state = crypt_charstring_seed;
354
0
    gs_bytestring *data = (gs_bytestring *)&gdata->bits;
355
0
    byte *source = data->data, *dest = stripped, *end = source + data->size;
356
0
    int i, dest_length = 0, CurrentNumberIndex = 0, Stack[64], written;
357
0
    int OnlyCalcLength = 0;
358
0
    char Buffer[16];
359
360
0
    memset(Stack, 0x00, 64 * sizeof(int));
361
0
    if (stripped == NULL) {
362
0
        OnlyCalcLength = 1;
363
0
        dest = (byte *)&Buffer;
364
0
    }
365
366
0
    if (pfont->data.lenIV >= data->size)
367
0
        return gs_note_error(gs_error_invalidfont);
368
369
0
    gs_type1_decrypt(source, source, data->size, &state);
370
371
0
    if(pfont->data.lenIV >= 0) {
372
0
        for (i=0;i<pfont->data.lenIV;i++) {
373
0
            if (!OnlyCalcLength)
374
0
                *dest++ = *source++;
375
0
            else
376
0
                source++;
377
0
        }
378
0
        dest_length += pfont->data.lenIV;
379
0
    }
380
0
    while (source < end) {
381
0
        if (*source < 32) {
382
            /* Command */
383
0
            switch (*source) {
384
0
                case 12:
385
0
                    if (source + 2 > end) {
386
0
                        dest_length = gs_note_error(gs_error_invalidfont);
387
0
                        goto error;
388
0
                    }
389
0
                    if (*(source + 1) == 16) {
390
0
                        if (CurrentNumberIndex < 1) {
391
0
                            dest_length = gs_note_error(gs_error_rangecheck);
392
0
                            goto error;
393
0
                        }
394
                        /* Callothersubsr, the only thing we care about */
395
0
                        switch(Stack[CurrentNumberIndex-1]) {
396
                            /* If we find a Multiple Master call, remove all but the
397
                             * first set of arguments. Mimics the result of a call.
398
                             * Adobe 'encourages' the use of Subrs to do MM, but
399
                             * the spec doens't say you have to, so we need to be
400
                             * prepared, just in case. I doubt we will ever execute
401
                             * this code.
402
                             */
403
0
                            case 14:
404
0
                                CurrentNumberIndex -= pfont->data.WeightVector.count - 1;
405
0
                                for (i = 0;i < CurrentNumberIndex;i++) {
406
0
                                    written = WriteNumber(dest, Stack[i]);
407
0
                                    dest_length += written;
408
0
                                    if (!OnlyCalcLength)
409
0
                                        dest += written;
410
0
                                }
411
0
                                source += 2;
412
0
                                break;
413
0
                            case 15:
414
0
                                CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 2;
415
0
                                for (i = 0;i < CurrentNumberIndex;i++) {
416
0
                                    written = WriteNumber(dest, Stack[i]);
417
0
                                    dest_length += written;
418
0
                                    if (!OnlyCalcLength)
419
0
                                        dest += written;
420
0
                                }
421
0
                                source += 2;
422
0
                                break;
423
0
                            case 16:
424
0
                                CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 3;
425
0
                                for (i = 0;i < CurrentNumberIndex;i++) {
426
0
                                    written = WriteNumber(dest, Stack[i]);
427
0
                                    dest_length += written;
428
0
                                    if (!OnlyCalcLength)
429
0
                                        dest += written;
430
0
                                }
431
0
                                source += 2;
432
0
                                break;
433
0
                            case 17:
434
0
                                CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 4;
435
0
                                for (i = 0;i < CurrentNumberIndex;i++) {
436
0
                                    written = WriteNumber(dest, Stack[i]);
437
0
                                    dest_length += written;
438
0
                                    if (!OnlyCalcLength)
439
0
                                        dest += written;
440
0
                                }
441
0
                                source += 2;
442
0
                                break;
443
0
                            case 18:
444
0
                                CurrentNumberIndex -= (pfont->data.WeightVector.count - 1) * 6;
445
0
                                for (i = 0;i < CurrentNumberIndex;i++) {
446
0
                                    written = WriteNumber(dest, Stack[i]);
447
0
                                    dest_length += written;
448
0
                                    if (!OnlyCalcLength)
449
0
                                        dest += written;
450
0
                                }
451
0
                                source += 2;
452
0
                                break;
453
0
                            default:
454
0
                                for (i = 0;i < CurrentNumberIndex;i++) {
455
0
                                    written = WriteNumber(dest, Stack[i]);
456
0
                                    dest_length += written;
457
0
                                    if (!OnlyCalcLength)
458
0
                                        dest += written;
459
0
                                }
460
0
                                if (!OnlyCalcLength) {
461
0
                                    *dest++ = *source++;
462
0
                                    *dest++ = *source++;
463
0
                                } else {
464
0
                                    source += 2;
465
0
                                }
466
0
                                dest_length += 2;
467
0
                                break;
468
0
                        }
469
0
                    } else {
470
0
                        for (i = 0;i < CurrentNumberIndex;i++) {
471
0
                            written = WriteNumber(dest, Stack[i]);
472
0
                            dest_length += written;
473
0
                            if (!OnlyCalcLength)
474
0
                                dest += written;
475
0
                        }
476
0
                        if (!OnlyCalcLength) {
477
0
                            *dest++ = *source++;
478
0
                            *dest++ = *source++;
479
0
                        } else {
480
0
                            source += 2;
481
0
                        }
482
0
                        dest_length += 2;
483
0
                    }
484
0
                    break;
485
0
                case 10:
486
0
                    if (CurrentNumberIndex != 0 && Stack[CurrentNumberIndex - 1] >= 0 &&
487
0
                        Stack[CurrentNumberIndex - 1] < SubrsCount && SubrsWithMM != NULL && SubrsWithMM[Stack[CurrentNumberIndex - 1]] != 0)
488
0
                    {
489
0
                        int index = Stack[CurrentNumberIndex - 1];
490
0
                        int StackBase = CurrentNumberIndex - 1 - pfont->data.WeightVector.count * SubrsWithMM[index];
491
492
0
                        CurrentNumberIndex--; /* Remove the subr index */
493
494
0
                        if (StackBase > CurrentNumberIndex) {
495
0
                            dest_length = gs_note_error(gs_error_invalidfont);
496
0
                            goto error;
497
0
                        }
498
499
0
                        for (i=0;i < StackBase; i++) {
500
0
                            written = WriteNumber(dest, Stack[i]);
501
0
                            dest_length += written;
502
0
                            if (!OnlyCalcLength)
503
0
                                dest += written;
504
0
                        }
505
0
                        for (i=0;i<SubrsWithMM[index];i++) {
506
                            /* See above, it may be that we don't have enough numbers on the stack
507
                             * (due to constructs such as x y div), if we don't have enough parameters
508
                             * just write a 0 instead. We know this is incorrect.....
509
                             */
510
0
                            if (StackBase + i >= 0 && StackBase + i < CurrentNumberIndex)
511
0
                                written = WriteNumber(dest, Stack[StackBase + i]);
512
0
                            else
513
0
                                written = WriteNumber(dest, 0);
514
0
                            dest_length += written;
515
0
                            if (!OnlyCalcLength)
516
0
                                dest += written;
517
0
                        }
518
0
                        source++;
519
0
                    } else {
520
0
                        for (i = 0;i < CurrentNumberIndex;i++) {
521
0
                            written = WriteNumber(dest, Stack[i]);
522
0
                            dest_length += written;
523
0
                            if (!OnlyCalcLength)
524
0
                                dest += written;
525
0
                        }
526
0
                        if (!OnlyCalcLength)
527
0
                            *dest++ = *source++;
528
0
                        else
529
0
                            source++;
530
0
                        dest_length++;
531
0
                    }
532
0
                    break;
533
0
                default:
534
0
                    for (i = 0;i < CurrentNumberIndex;i++) {
535
0
                        written = WriteNumber(dest, Stack[i]);
536
0
                        dest_length += written;
537
0
                        if (!OnlyCalcLength)
538
0
                            dest += written;
539
0
                    }
540
0
                    if (!OnlyCalcLength)
541
0
                        *dest++ = *source++;
542
0
                    else
543
0
                        source++;
544
0
                    dest_length++;
545
0
            }
546
0
            CurrentNumberIndex = 0;
547
0
        } else {
548
0
            if (CurrentNumberIndex >= count_of(Stack)) {
549
0
                dest_length = gs_note_error(gs_error_rangecheck);
550
0
                goto error;
551
0
            }
552
            /* Number */
553
0
            if (*source < 247) {
554
0
                Stack[CurrentNumberIndex++] = *source++ - 139;
555
0
            } else {
556
0
                if (*source < 251) {
557
0
                    if (source + 2 > end) {
558
0
                        dest_length = gs_note_error(gs_error_invalidfont);
559
0
                        goto error;
560
0
                    }
561
0
                    Stack[CurrentNumberIndex] = ((*source++ - 247) * 256) + 108;
562
0
                    Stack[CurrentNumberIndex++] += *source++;
563
0
                } else {
564
0
                    if (*source < 255) {
565
0
                        if (source + 2 > end) {
566
0
                            dest_length = gs_note_error(gs_error_invalidfont);
567
0
                            goto error;
568
0
                        }
569
0
                        Stack[CurrentNumberIndex] = ((*source++ - 251) * -256) - 108;
570
0
                        Stack[CurrentNumberIndex++] -= *source++;
571
0
                    } else {
572
0
                        if (source + 5 > end) {
573
0
                            dest_length = gs_note_error(gs_error_invalidfont);
574
0
                            goto error;
575
0
                        }
576
0
                        source++;
577
0
                        Stack[CurrentNumberIndex] = *source++ << 24;
578
0
                        Stack[CurrentNumberIndex] += *source++ << 16;
579
0
                        Stack[CurrentNumberIndex] += *source++ << 8;
580
0
                        Stack[CurrentNumberIndex++] += *source++;
581
0
                    }
582
0
                }
583
0
            }
584
0
        }
585
0
    }
586
    /* We decrypted the data in place at the start of the routine, we must re-encrypt it
587
     * before we return, even if there's an error.
588
     */
589
0
error:
590
0
    source = data->data;
591
0
    state = crypt_charstring_seed;
592
0
    gs_type1_encrypt(source, source, data->size, &state);
593
594
0
    if (!OnlyCalcLength && dest_length > 0) {
595
0
        state = crypt_charstring_seed;
596
0
        gs_type1_encrypt(stripped, stripped, dest_length, &state);
597
0
    }
598
0
    return dest_length;
599
0
}
600
601
/*
602
 * Write the Private dictionary.  This is a separate procedure only for
603
 * readability.  write_CharString is a parameter so that we can encrypt
604
 * Subrs and CharStrings when the font's lenIV == -1 but we are writing
605
 * the font with lenIV = 0.
606
 */
607
static int
608
write_Private(stream *s, gs_font_type1 *pfont,
609
              gs_glyph *subset_glyphs, uint subset_size,
610
              gs_glyph notdef, int lenIV,
611
              int (*write_CharString)(stream *, const void *, uint),
612
              const param_printer_params_t *ppp, int options)
613
13.1k
{
614
13.1k
    const gs_type1_data *const pdata = &pfont->data;
615
13.1k
    printer_param_list_t rlist;
616
13.1k
    gs_param_list *const plist = (gs_param_list *)&rlist;
617
13.1k
    int code = s_init_param_printer(&rlist, ppp, s);
618
13.1k
    byte *SubrsWithMM = 0;
619
13.1k
    int SubrsCount = 0;
620
621
13.1k
    if (code < 0)
622
0
        return 0;
623
13.1k
    stream_puts(s, "dup /Private 17 dict dup begin\n");
624
13.1k
    stream_puts(s, "/-|{string currentfile exch readstring pop}executeonly def\n");
625
13.1k
    stream_puts(s, "/|-{noaccess def}executeonly def\n");
626
13.1k
    stream_puts(s, "/|{noaccess put}executeonly def\n");
627
13.1k
    {
628
13.1k
        static const gs_param_item_t private_items[] = {
629
13.1k
            {"BlueFuzz", gs_param_type_int,
630
13.1k
             offset_of(gs_type1_data, BlueFuzz)},
631
13.1k
            {"BlueScale", gs_param_type_float,
632
13.1k
             offset_of(gs_type1_data, BlueScale)},
633
13.1k
            {"BlueShift", gs_param_type_float,
634
13.1k
             offset_of(gs_type1_data, BlueShift)},
635
13.1k
            {"ExpansionFactor", gs_param_type_float,
636
13.1k
             offset_of(gs_type1_data, ExpansionFactor)},
637
13.1k
            {"ForceBold", gs_param_type_bool,
638
13.1k
             offset_of(gs_type1_data, ForceBold)},
639
13.1k
            {"LanguageGroup", gs_param_type_int,
640
13.1k
             offset_of(gs_type1_data, LanguageGroup)},
641
13.1k
            {"RndStemUp", gs_param_type_bool,
642
13.1k
             offset_of(gs_type1_data, RndStemUp)},
643
13.1k
            gs_param_item_end
644
13.1k
        };
645
13.1k
        gs_type1_data defaults;
646
647
13.1k
        defaults.BlueFuzz = 1;
648
13.1k
        defaults.BlueScale = (float)0.039625;
649
13.1k
        defaults.BlueShift = 7.0;
650
13.1k
        defaults.ExpansionFactor = (float)0.06;
651
13.1k
        defaults.ForceBold = false;
652
13.1k
        defaults.LanguageGroup = 0;
653
13.1k
        defaults.RndStemUp = true;
654
13.1k
        code = gs_param_write_items(plist, pdata, &defaults, private_items);
655
13.1k
        if (code < 0)
656
0
            return code;
657
13.1k
        if (lenIV != 4) {
658
24
            code = param_write_int(plist, "lenIV", &lenIV);
659
24
            if (code < 0)
660
0
                return code;
661
24
        }
662
13.1k
        write_float_array(plist, "BlueValues", pdata->BlueValues.values,
663
13.1k
                          pdata->BlueValues.count);
664
13.1k
        write_float_array(plist, "OtherBlues", pdata->OtherBlues.values,
665
13.1k
                          pdata->OtherBlues.count);
666
13.1k
        write_float_array(plist, "FamilyBlues", pdata->FamilyBlues.values,
667
13.1k
                          pdata->FamilyBlues.count);
668
13.1k
        write_float_array(plist, "FamilyOtherBlues", pdata->FamilyOtherBlues.values,
669
13.1k
                          pdata->FamilyOtherBlues.count);
670
13.1k
        write_float_array(plist, "StdHW", pdata->StdHW.values,
671
13.1k
                          pdata->StdHW.count);
672
13.1k
        write_float_array(plist, "StdVW", pdata->StdVW.values,
673
13.1k
                          pdata->StdVW.count);
674
13.1k
        write_float_array(plist, "StemSnapH", pdata->StemSnapH.values,
675
13.1k
                          pdata->StemSnapH.count);
676
13.1k
        write_float_array(plist, "StemSnapV", pdata->StemSnapV.values,
677
13.1k
                          pdata->StemSnapV.count);
678
13.1k
    }
679
0
    write_uid(s, &pfont->UID, options);
680
13.1k
    stream_puts(s, "/MinFeature{16 16} def\n");
681
13.1k
    stream_puts(s, "/password 5839 def\n");
682
683
    /*
684
     * Write the Subrs.  We always write them all, even for subsets.
685
     * (We will fix this someday.)
686
     */
687
688
13.1k
    {
689
13.1k
        int n, i;
690
13.1k
        gs_glyph_data_t gdata;
691
13.1k
        int code;
692
693
13.1k
        gdata.memory = pfont->memory;
694
13.1k
        for (n = 0;
695
206k
             (code = pdata->procs.subr_data(pfont, n, false, &gdata)) !=
696
206k
                 gs_error_rangecheck;
697
193k
             ) {
698
193k
            ++n;
699
193k
            if (code >= 0)
700
193k
                gs_glyph_data_free(&gdata, "write_Private(Subrs)");
701
193k
        }
702
13.1k
        if (pfont->data.WeightVector.count != 0) {
703
0
            SubrsCount = n;
704
0
            SubrsWithMM = gs_alloc_bytes(pfont->memory, n, "Subrs record");
705
0
        }
706
707
13.1k
        pprintd1(s, "/Subrs %d array\n", n);
708
709
        /* prescan the /Subrs array to see if any of the Subrs call out to OtherSubrs */
710
13.1k
        if (pfont->data.WeightVector.count != 0) {
711
0
            for (i = 0; i < n; ++i) {
712
0
                if ((code = pdata->procs.subr_data(pfont, i, false, &gdata)) >= 0) {
713
0
                        code = CheckSubrForMM(&gdata, pfont);
714
0
                        gs_glyph_data_free(&gdata, "write_Private(Subrs)");
715
0
                        if (code < 0) {
716
0
                            if (SubrsWithMM != 0)
717
0
                                gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
718
0
                            return code;
719
0
                        }
720
0
                        if (SubrsWithMM != 0)
721
0
                            SubrsWithMM[i] = code;
722
0
                }
723
0
            }
724
0
        }
725
726
206k
        for (i = 0; i < n; ++i)
727
193k
            if ((code = pdata->procs.subr_data(pfont, i, false, &gdata)) >= 0) {
728
193k
                char buf[50];
729
730
193k
                if (gdata.bits.size) {
731
193k
                    if (pfont->data.WeightVector.count != 0) {
732
0
                        byte *stripped = NULL;
733
0
                        int length = 0;
734
735
0
                        length = strip_othersubrs(&gdata, pfont, NULL, SubrsWithMM, SubrsCount);
736
0
                        if (length < 0) {
737
0
                            gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
738
0
                            if (SubrsWithMM != 0)
739
0
                                 gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
740
0
                            return length;
741
0
                        }
742
0
                        if (length > 0) {
743
0
                            stripped = gs_alloc_bytes(pfont->memory, length, "Subrs copy for OtherSubrs");
744
0
                            if (stripped == NULL) {
745
0
                                if (SubrsWithMM != 0)
746
0
                                    gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
747
0
                                gs_glyph_data_free(&gdata, "write_Private(Subrs)");
748
0
                                return gs_note_error(gs_error_VMerror);
749
0
                            }
750
0
                            length = strip_othersubrs(&gdata, pfont, stripped, SubrsWithMM, SubrsCount);
751
0
                            if (length < 0) {
752
0
                                gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
753
0
                                gs_free_object(pfont->memory, stripped, "free CharStrings copy for OtherSubrs");
754
0
                                if (SubrsWithMM != 0)
755
0
                                     gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
756
0
                                return length;
757
0
                            }
758
0
                            gs_snprintf(buf, sizeof(buf), "dup %d %u -| ", i, length);
759
0
                            stream_puts(s, buf);
760
0
                            write_CharString(s, stripped, length);
761
0
                            gs_free_object(pfont->memory, stripped, "free Subrs copy for OtherSubrs");
762
0
                        } else {
763
0
                            gs_snprintf(buf, sizeof(buf), "dup %d 0 -| ", i);
764
0
                            stream_puts(s, buf);
765
0
                        }
766
193k
                    } else {
767
193k
                        gs_snprintf(buf, sizeof(buf), "dup %d %u -| ", i, gdata.bits.size);
768
193k
                        stream_puts(s, buf);
769
193k
                        write_CharString(s, gdata.bits.data, gdata.bits.size);
770
193k
                    }
771
193k
                    stream_puts(s, " |\n");
772
193k
                }
773
193k
                gs_glyph_data_free(&gdata, "write_Private(Subrs)");
774
193k
            }
775
13.1k
        stream_puts(s, "|-\n");
776
13.1k
    }
777
778
    /* We don't write OtherSubrs -- there had better not be any! */
779
780
    /* Write the CharStrings. */
781
782
0
    {
783
13.1k
        int num_chars = 0;
784
13.1k
        gs_glyph glyph;
785
13.1k
        psf_glyph_enum_t genum;
786
13.1k
        gs_glyph_data_t gdata;
787
13.1k
        int code;
788
789
13.1k
        gdata.memory = pfont->memory;
790
13.1k
        psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, subset_glyphs,
791
13.1k
                                    (subset_glyphs ? subset_size : 0),
792
13.1k
                                    GLYPH_SPACE_NAME);
793
13.1k
        for (glyph = GS_NO_GLYPH;
794
266k
             (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1;
795
13.1k
             )
796
253k
            if (code == 0 &&
797
253k
                (code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0
798
253k
                ) {
799
253k
                ++num_chars;
800
253k
                gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
801
253k
            }
802
13.1k
        pprintd1(s, "2 index /CharStrings %d dict dup begin\n", num_chars);
803
13.1k
        psf_enumerate_glyphs_reset(&genum);
804
13.1k
        for (glyph = GS_NO_GLYPH;
805
266k
             (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1;
806
13.1k
            )
807
253k
            if (code == 0 &&
808
253k
                (code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0
809
253k
                ) {
810
253k
                gs_const_string gstr;
811
253k
                int code;
812
813
253k
                code = pfont->procs.glyph_name((gs_font *)pfont, glyph, &gstr);
814
253k
                if (code < 0) {
815
0
                    if (SubrsWithMM != 0)
816
0
                        gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
817
0
                    gs_glyph_data_free(&gdata, "write_Private(Subrs)");
818
0
                    return code;
819
0
                }
820
821
253k
                stream_puts(s, "/");
822
253k
                stream_write(s, gstr.data, gstr.size);
823
824
253k
                if (pfont->data.WeightVector.count != 0) {
825
0
                    byte *stripped = NULL;
826
0
                    int length = 0;
827
828
0
                    length = strip_othersubrs(&gdata, pfont, NULL, SubrsWithMM, SubrsCount);
829
0
                    if (length < 0) {
830
0
                        gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
831
0
                        if (SubrsWithMM != 0)
832
0
                             gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
833
0
                        return length;
834
0
                    }
835
0
                    if (length > 0) {
836
0
                        stripped = gs_alloc_bytes(pfont->memory, length, "Subrs copy for OtherSubrs");
837
0
                        if (stripped == NULL) {
838
0
                            if (SubrsWithMM != 0)
839
0
                                gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
840
0
                            gs_glyph_data_free(&gdata, "write_Private(Subrs)");
841
0
                            return gs_note_error(gs_error_VMerror);
842
0
                        }
843
0
                        length = strip_othersubrs(&gdata, pfont, stripped, SubrsWithMM, SubrsCount);
844
0
                        if (length < 0) {
845
0
                            gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
846
0
                            gs_free_object(pfont->memory, stripped, "free CharStrings copy for OtherSubrs");
847
0
                            if (SubrsWithMM != 0)
848
0
                                 gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
849
0
                            return length;
850
0
                        }
851
0
                        pprintd1(s, " %d -| ", length);
852
0
                        write_CharString(s, stripped, length);
853
0
                        gs_free_object(pfont->memory, stripped, "free CharStrings copy for OtherSubrs");
854
0
                    } else
855
0
                        pprintd1(s, " %d -| ", 0);
856
253k
                } else {
857
253k
                    pprintd1(s, " %d -| ", gdata.bits.size);
858
253k
                    write_CharString(s, gdata.bits.data, gdata.bits.size);
859
253k
                }
860
861
253k
                stream_puts(s, " |-\n");
862
253k
                gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
863
253k
            }
864
13.1k
    }
865
13.1k
    if (SubrsWithMM != 0)
866
0
        gs_free_object(pfont->memory, SubrsWithMM, "free Subrs record");
867
868
    /* Wrap up. */
869
870
13.1k
    stream_puts(s, "end\nend\nreadonly put\nnoaccess put\n");
871
13.1k
    s_release_param_printer(&rlist);
872
13.1k
    return 0;
873
13.1k
}
874
875
/* Encrypt and write a CharString. */
876
static int
877
stream_write_encrypted(stream *s, const void *ptr, uint count)
878
138
{
879
138
    const byte *const data = ptr;
880
138
    crypt_state state = crypt_charstring_seed;
881
138
    byte buf[50];   /* arbitrary */
882
138
    uint left, n;
883
138
    int code = 0;
884
885
679
    for (left = count; left > 0; left -= n) {
886
541
        n = min(left, sizeof(buf));
887
541
        gs_type1_encrypt(buf, data + count - left, n, &state);
888
541
        code = stream_write(s, buf, n);
889
541
    }
890
138
    return code;
891
138
}
892
893
/* Write one FontInfo entry. */
894
static void
895
write_font_info(stream *s, const char *key, const gs_const_string *pvalue,
896
                int do_write)
897
52.6k
{
898
52.6k
    if (do_write) {
899
51.3k
        pprints1(s, "\n/%s ", key);
900
51.3k
        s_write_ps_string(s, pvalue->data, pvalue->size, PRINT_HEX_NOT_OK);
901
51.3k
        stream_puts(s, " def");
902
51.3k
    }
903
52.6k
}
904
905
/* Write the definition of a Type 1 font. */
906
int
907
psf_write_type1_font(stream *s, gs_font_type1 *pfont, int options,
908
                      gs_glyph *orig_subset_glyphs, uint orig_subset_size,
909
                      const gs_const_string *alt_font_name, int lengths[3])
910
13.1k
{
911
13.1k
    stream *es = s;
912
13.1k
    gs_offset_t start = stell(s);
913
13.1k
    param_printer_params_t ppp;
914
13.1k
    printer_param_list_t rlist;
915
13.1k
    gs_param_list *const plist = (gs_param_list *)&rlist;
916
13.1k
    stream AXE_stream;
917
13.1k
    stream_AXE_state AXE_state;
918
13.1k
    byte AXE_buf[200];    /* arbitrary */
919
13.1k
    stream exE_stream;
920
13.1k
    stream_exE_state exE_state;
921
13.1k
    byte exE_buf[200];    /* arbitrary */
922
13.1k
    psf_outline_glyphs_t glyphs;
923
13.1k
    int lenIV = pfont->data.lenIV;
924
13.1k
    int (*write_CharString)(stream *, const void *, uint) = stream_write;
925
13.1k
    int code = psf_get_type1_glyphs(&glyphs, pfont, orig_subset_glyphs,
926
13.1k
                                     orig_subset_size);
927
928
13.1k
    if (code < 0)
929
0
        return code;
930
931
    /* Initialize the parameter printer. */
932
933
13.1k
    ppp = param_printer_params_default;
934
13.1k
    ppp.item_suffix = " def\n";
935
13.1k
    ppp.print_ok =
936
13.1k
        (options & WRITE_TYPE1_ASCIIHEX ? 0 : PRINT_BINARY_OK) |
937
13.1k
        PRINT_HEX_NOT_OK;
938
13.1k
    code = s_init_param_printer(&rlist, &ppp, s);
939
13.1k
    if (code < 0)
940
0
        return code;
941
942
    /* Write the font header. */
943
944
13.1k
    stream_puts(s, "%!FontType1-1.0: ");
945
13.1k
    write_font_name(s, pfont, alt_font_name, false);
946
13.1k
    stream_puts(s, "\n11 dict begin\n");
947
948
    /* Write FontInfo. */
949
950
13.1k
    stream_puts(s, "/FontInfo 5 dict dup begin");
951
13.1k
    {
952
13.1k
        gs_font_info_t info;
953
13.1k
        int code = pfont->procs.font_info((gs_font *)pfont, NULL,
954
13.1k
                        (FONT_INFO_COPYRIGHT | FONT_INFO_NOTICE |
955
13.1k
                         FONT_INFO_FAMILY_NAME | FONT_INFO_FULL_NAME),
956
13.1k
                                          &info);
957
958
13.1k
        if (code >= 0) {
959
13.1k
            write_font_info(s, "Copyright", &info.Copyright,
960
13.1k
                            info.members & FONT_INFO_COPYRIGHT);
961
13.1k
            write_font_info(s, "Notice", &info.Notice,
962
13.1k
                            info.members & FONT_INFO_NOTICE);
963
13.1k
            write_font_info(s, "FamilyName", &info.FamilyName,
964
13.1k
                            info.members & FONT_INFO_FAMILY_NAME);
965
13.1k
            write_font_info(s, "FullName", &info.FullName,
966
13.1k
                            info.members & FONT_INFO_FULL_NAME);
967
13.1k
        }
968
13.1k
    }
969
13.1k
    stream_puts(s, "\nend readonly def\n");
970
971
    /* Write the main font dictionary. */
972
973
13.1k
    stream_puts(s, "/FontName ");
974
13.1k
    write_font_name(s, pfont, alt_font_name, true);
975
13.1k
    stream_puts(s, " def\n");
976
13.1k
    code = write_Encoding(s, pfont, options, glyphs.subset_glyphs,
977
13.1k
                          glyphs.subset_size, glyphs.notdef);
978
13.1k
    if (code < 0)
979
0
        return code;
980
13.1k
    pprintg6(s, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
981
13.1k
             pfont->FontMatrix.xx, pfont->FontMatrix.xy,
982
13.1k
             pfont->FontMatrix.yx, pfont->FontMatrix.yy,
983
13.1k
             pfont->FontMatrix.tx, pfont->FontMatrix.ty);
984
13.1k
    write_uid(s, &pfont->UID, options);
985
13.1k
    pprintg4(s, "/FontBBox {%g %g %g %g} readonly def\n",
986
13.1k
             pfont->FontBBox.p.x, pfont->FontBBox.p.y,
987
13.1k
             pfont->FontBBox.q.x, pfont->FontBBox.q.y);
988
13.1k
    {
989
13.1k
        static const gs_param_item_t font_items[] = {
990
13.1k
            {"FontType", gs_param_type_int,
991
13.1k
             offset_of(gs_font_type1, FontType)},
992
13.1k
            {"PaintType", gs_param_type_int,
993
13.1k
             offset_of(gs_font_type1, PaintType)},
994
13.1k
            {"StrokeWidth", gs_param_type_float,
995
13.1k
             offset_of(gs_font_type1, StrokeWidth)},
996
13.1k
            gs_param_item_end
997
13.1k
        };
998
999
13.1k
        code = gs_param_write_items(plist, pfont, NULL, font_items);
1000
13.1k
        if (code < 0)
1001
0
            return code;
1002
13.1k
    }
1003
1004
    /*
1005
     * This is nonsense. We cna't write the WeightVector alonr from a Multiple
1006
     * Master and expect any sensible results. Since its useless alone, there's
1007
     * no point in emitting it at all. Leaving the code in place in case we
1008
     * decide to write MM fonts one day.
1009
    {
1010
        const gs_type1_data *const pdata = &pfont->data;
1011
1012
        write_float_array(plist, "WeightVector", pdata->WeightVector.values,
1013
                          pdata->WeightVector.count);
1014
    }
1015
    */
1016
13.1k
    stream_puts(s, "currentdict end\n");
1017
1018
    /* Write the Private dictionary. */
1019
1020
13.1k
    if (lenIV < 0 && (options & WRITE_TYPE1_WITH_LENIV)) {
1021
        /* We'll have to encrypt the CharStrings. */
1022
16
        lenIV = 0;
1023
16
        write_CharString = stream_write_encrypted;
1024
16
    }
1025
13.1k
    if (options & WRITE_TYPE1_EEXEC) {
1026
13.1k
        stream_puts(s, "currentfile eexec\n");
1027
13.1k
        lengths[0] = (int)(stell(s) - start);
1028
13.1k
        start = stell(s);
1029
13.1k
        if (options & WRITE_TYPE1_ASCIIHEX) {
1030
13.1k
            s_init(&AXE_stream, s->memory);
1031
13.1k
            s_init_state((stream_state *)&AXE_state, &s_AXE_template, NULL);
1032
13.1k
            s_init_filter(&AXE_stream, (stream_state *)&AXE_state,
1033
13.1k
                          AXE_buf, sizeof(AXE_buf), es);
1034
            /* We have to set this after s_init_filter() as that function
1035
             * sets it to true.
1036
             */
1037
13.1k
            AXE_state.EndOfData = false;
1038
13.1k
            es = &AXE_stream;
1039
13.1k
        }
1040
13.1k
        s_init(&exE_stream, s->memory);
1041
13.1k
        s_init_state((stream_state *)&exE_state, &s_exE_template, NULL);
1042
13.1k
        exE_state.cstate = 55665;
1043
13.1k
        s_init_filter(&exE_stream, (stream_state *)&exE_state,
1044
13.1k
                      exE_buf, sizeof(exE_buf), es);
1045
13.1k
        es = &exE_stream;
1046
        /*
1047
         * Note: eexec encryption always writes/skips 4 initial bytes, not
1048
         * the number of initial bytes given by pdata->lenIV.
1049
         */
1050
13.1k
        stream_puts(es, "****");
1051
13.1k
    }
1052
13.1k
    code = write_Private(es, pfont, glyphs.subset_glyphs, glyphs.subset_size,
1053
13.1k
                         glyphs.notdef, lenIV, write_CharString, &ppp, options);
1054
13.1k
    if (code < 0)
1055
0
        return code;
1056
13.1k
    stream_puts(es, "dup/FontName get exch definefont pop\n");
1057
13.1k
    if (options & WRITE_TYPE1_EEXEC) {
1058
13.1k
        if (options & (WRITE_TYPE1_EEXEC_PAD | WRITE_TYPE1_EEXEC_MARK))
1059
13.1k
            stream_puts(es, "mark ");
1060
13.1k
        stream_puts(es, "currentfile closefile\n");
1061
13.1k
        s_close_filters(&es, s);
1062
13.1k
        lengths[1] = (int)(stell(s) - start);
1063
13.1k
        start = stell(s);
1064
13.1k
        if (options & WRITE_TYPE1_EEXEC_PAD) {
1065
13.1k
            int i;
1066
1067
118k
            for (i = 0; i < 8; ++i)
1068
105k
                stream_puts(s, "\n0000000000000000000000000000000000000000000000000000000000000000");
1069
13.1k
            stream_puts(s, "\ncleartomark\n");
1070
13.1k
        }
1071
13.1k
        lengths[2] = (int)(stell(s) - start);
1072
13.1k
    } else {
1073
0
        lengths[0] = (int)(stell(s) - start);
1074
0
        lengths[1] = lengths[2] = 0;
1075
0
    }
1076
1077
    /* Wrap up. */
1078
1079
13.1k
    s_release_param_printer(&rlist);
1080
13.1k
    return 0;
1081
13.1k
}