Coverage Report

Created: 2026-05-23 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cairo/util/cairo-script/cairo-script-file.c
Line
Count
Source
1
/*
2
 * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it either under the terms of the GNU Lesser General Public
6
 * License version 2.1 as published by the Free Software Foundation
7
 * (the "LGPL") or, at your option, under the terms of the Mozilla
8
 * Public License Version 1.1 (the "MPL"). If you do not alter this
9
 * notice, a recipient may use your version of this file under either
10
 * the MPL or the LGPL.
11
 *
12
 * You should have received a copy of the LGPL along with this library
13
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
15
 * You should have received a copy of the MPL along with this library
16
 * in the file COPYING-MPL-1.1
17
 *
18
 * The contents of this file are subject to the Mozilla Public License
19
 * Version 1.1 (the "License"); you may not use this file except in
20
 * compliance with the License. You may obtain a copy of the License at
21
 * http://www.mozilla.org/MPL/
22
 *
23
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
24
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
25
 * the specific language governing rights and limitations.
26
 *
27
 * The Original Code is the cairo graphics library.
28
 *
29
 * The Initial Developer of the Original Code is Chris Wilson.
30
 *
31
 * Contributor(s):
32
 *  Chris Wilson <chris@chris-wilson.co.uk>
33
 */
34
35
#include "config.h"
36
37
#include "cairo-script-private.h"
38
39
#include <stdio.h>
40
#include <limits.h> /* INT_MAX */
41
#include <string.h>
42
#include <zlib.h>
43
44
#if HAVE_LZO
45
#include <lzo2a.h>
46
#endif
47
48
0
#define CHUNK_SIZE 32768
49
50
0
#define OWN_STREAM 0x1
51
52
csi_status_t
53
csi_file_new (csi_t *ctx,
54
        csi_object_t *obj,
55
        const char *path, const char *mode)
56
0
{
57
0
    csi_file_t *file;
58
59
0
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
60
0
    if (file == NULL)
61
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
62
63
0
    file->base.type = CSI_OBJECT_TYPE_FILE;
64
0
    file->base.ref = 1;
65
66
0
    file->data = NULL;
67
0
    file->type = STDIO;
68
0
    file->flags = OWN_STREAM;
69
0
    file->src = fopen (path, mode);
70
0
    if (file->src == NULL) {
71
0
  _csi_slab_free (ctx, file, sizeof (csi_file_t));
72
0
  return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
73
0
    }
74
75
0
    file->data = _csi_alloc (ctx, CHUNK_SIZE);
76
0
    if (file->data == NULL) {
77
0
  _csi_slab_free (ctx, file, sizeof (csi_file_t));
78
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
79
0
    }
80
0
    file->bp = file->data;
81
0
    file->rem = 0;
82
83
0
    obj->type = CSI_OBJECT_TYPE_FILE;
84
0
    obj->datum.file = file;
85
0
    return CAIRO_STATUS_SUCCESS;
86
0
}
87
88
csi_status_t
89
csi_file_new_for_stream (csi_t *ctx,
90
                   csi_object_t *obj,
91
       FILE *stream)
92
0
{
93
0
    csi_file_t *file;
94
95
0
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
96
0
    if (file == NULL)
97
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
98
99
0
    file->base.type = CSI_OBJECT_TYPE_FILE;
100
0
    file->base.ref = 1;
101
102
0
    file->data = NULL;
103
0
    file->type = STDIO;
104
0
    file->flags = 0;
105
0
    file->src = stream;
106
0
    if (file->src == NULL) {
107
0
  _csi_slab_free (ctx, file, sizeof (csi_file_t));
108
0
  return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
109
0
    }
110
111
0
    file->data = _csi_alloc (ctx, CHUNK_SIZE);
112
0
    if (file->data == NULL) {
113
0
  _csi_slab_free (ctx, file, sizeof (csi_file_t));
114
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
115
0
    }
116
0
    file->bp = file->data;
117
0
    file->rem = 0;
118
119
0
    obj->type = CSI_OBJECT_TYPE_FILE;
120
0
    obj->datum.file = file;
121
0
    return CAIRO_STATUS_SUCCESS;
122
0
}
123
124
csi_status_t
125
csi_file_new_for_bytes (csi_t *ctx,
126
      csi_object_t *obj,
127
      const char *bytes,
128
      unsigned int length)
129
2.98k
{
130
2.98k
    csi_file_t *file;
131
132
2.98k
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
133
2.98k
    if (file == NULL)
134
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
135
136
2.98k
    file->base.type = CSI_OBJECT_TYPE_FILE;
137
2.98k
    file->base.ref = 1;
138
139
2.98k
    file->type = BYTES;
140
2.98k
    file->src  = (uint8_t *) bytes;
141
2.98k
    file->data = (uint8_t *) bytes;
142
2.98k
    file->bp   = (uint8_t *) bytes;
143
2.98k
    file->rem  = length;
144
145
2.98k
    obj->type = CSI_OBJECT_TYPE_FILE;
146
2.98k
    obj->datum.file = file;
147
2.98k
    return CAIRO_STATUS_SUCCESS;
148
2.98k
}
149
150
csi_status_t
151
csi_file_new_from_string (csi_t *ctx,
152
        csi_object_t *obj,
153
        csi_string_t *src)
154
0
{
155
0
    csi_file_t *file;
156
157
0
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
158
0
    if (_csi_unlikely (file == NULL))
159
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
160
161
0
    file->base.type = CSI_OBJECT_TYPE_FILE;
162
0
    file->base.ref = 1;
163
164
0
    if (src->deflate) {
165
0
  csi_object_t tmp_obj;
166
0
  csi_string_t *tmp_str;
167
0
  csi_status_t status;
168
169
0
  status = csi_string_new (ctx, &tmp_obj,  NULL, src->deflate);
170
0
  if (_csi_unlikely (status))
171
0
      return status;
172
173
0
  tmp_str = tmp_obj.datum.string;
174
0
  switch (src->method) {
175
0
  case NONE:
176
0
  default:
177
0
      status = _csi_error (CAIRO_STATUS_NO_MEMORY);
178
0
      break;
179
180
0
  case ZLIB:
181
0
        {
182
0
#if HAVE_ZLIB
183
0
            uLongf len = src->deflate;
184
0
      if (uncompress ((Bytef *) tmp_str->string, &len,
185
0
          (Bytef *) src->string, src->len) != Z_OK)
186
0
#endif
187
0
    status = _csi_error (CAIRO_STATUS_NO_MEMORY);
188
0
      break;
189
0
        }
190
0
  case LZO:
191
0
        {
192
#if HAVE_LZO
193
            lzo_uint len = src->deflate;
194
      if (lzo2a_decompress ((lzo_bytep) src->string, src->len,
195
          (lzo_bytep) tmp_str->string, &len,
196
          NULL))
197
#endif
198
0
    status = _csi_error (CAIRO_STATUS_NO_MEMORY);
199
0
      break;
200
0
        }
201
0
  }
202
0
  if (_csi_unlikely (status)) {
203
0
      csi_string_free (ctx, tmp_str);
204
0
      _csi_slab_free (ctx, file, sizeof (csi_file_t));
205
0
      return status;
206
0
  }
207
208
0
  file->src  = tmp_str;
209
0
  file->data = tmp_str->string;
210
0
  file->rem  = tmp_str->len;
211
0
    } else {
212
0
  file->src  = src; src->base.ref++;
213
0
  file->data = src->string;
214
0
  file->rem  = src->len;
215
0
    }
216
0
    file->type = BYTES;
217
0
    file->bp   = file->data;
218
219
0
    obj->type = CSI_OBJECT_TYPE_FILE;
220
0
    obj->datum.file = file;
221
0
    return CAIRO_STATUS_SUCCESS;
222
0
}
223
224
static csi_status_t
225
_csi_file_new_filter (csi_t *ctx,
226
          csi_object_t *obj,
227
          csi_object_t *src,
228
          const csi_filter_funcs_t *funcs,
229
          void *data)
230
0
{
231
0
    csi_file_t *file;
232
0
    csi_object_t src_file;
233
0
    csi_status_t status;
234
235
0
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
236
0
    if (file == NULL)
237
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
238
239
0
    obj->type = CSI_OBJECT_TYPE_FILE;
240
0
    obj->datum.file = file;
241
242
0
    file->base.type = CSI_OBJECT_TYPE_FILE;
243
0
    file->base.ref = 1;
244
245
0
    file->type = FILTER;
246
0
    file->data = data;
247
0
    file->filter = funcs;
248
0
    status = csi_object_as_file (ctx, src, &src_file);
249
0
    if (status) {
250
0
  csi_object_free (ctx, obj);
251
0
  return status;
252
0
    }
253
0
    file->src = src_file.datum.file;
254
255
0
    return CAIRO_STATUS_SUCCESS;
256
0
}
257
258
259
#if 0
260
csi_status_t
261
csi_file_new_from_stream (csi_t *ctx,
262
        FILE *file,
263
        csi_object_t **out)
264
{
265
    csi_file_t *obj;
266
267
    obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE);
268
    if (obj == NULL)
269
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
270
271
    obj->type = STDIO;
272
    obj->src = file;
273
    obj->data = _csi_alloc (ctx, CHUNK_SIZE);
274
    if (obj->data == NULL) {
275
  csi_object_free (&obj->base);
276
  return _csi_error (CAIRO_STATUS_UNDEFINED_FILENAME_ERROR);
277
    }
278
    obj->bp = obj->data;
279
    obj->rem = 0;
280
281
    *out = &obj->base;
282
    return CAIRO_STATUS_SUCCESS;
283
}
284
285
static csi_object_t *
286
_csi_file_new_from_procedure (csi_t *ctx, csi_object_t *src)
287
{
288
    csi_file_t *obj;
289
290
    obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE);
291
    if (obj == NULL)
292
  return NULL;
293
294
    obj->type = PROCEDURE;
295
    obj->src = csi_object_reference (src);
296
    obj->data = NULL;
297
298
    return &obj->base;
299
}
300
#endif
301
302
typedef struct _ascii85_decode_data {
303
    uint8_t buf[CHUNK_SIZE];
304
    uint8_t *bp;
305
    short bytes_available;
306
    short eod;
307
} _ascii85_decode_data_t;
308
309
static int
310
_getc_skip_whitespace (csi_file_t *src)
311
0
{
312
0
    int c;
313
314
0
    do switch ((c = csi_file_getc (src))) {
315
0
    case 0x0:
316
0
    case 0x9:
317
0
    case 0xa:
318
0
    case 0xc:
319
0
    case 0xd:
320
0
    case 0x20:
321
0
  continue;
322
323
0
    default:
324
0
  return c;
325
0
    } while (TRUE);
326
327
0
    return c;
328
0
}
329
330
static void
331
_ascii85_decode (csi_file_t *file)
332
0
{
333
0
    _ascii85_decode_data_t *data = file->data;
334
0
    unsigned int n;
335
336
0
    if (data->eod)
337
0
  return;
338
339
0
    data->bp = data->buf;
340
341
0
    n = 0;
342
0
    do {
343
0
  unsigned int v = _getc_skip_whitespace (file->src);
344
0
  if (v == 'z') {
345
0
      data->buf[n+0] = 0;
346
0
      data->buf[n+1] = 0;
347
0
      data->buf[n+2] = 0;
348
0
      data->buf[n+3] = 0;
349
0
  } else if (v == '~') {
350
0
      _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */
351
0
      data->eod = TRUE;
352
0
      break;
353
0
  } else if (v < '!' || v > 'u') {
354
      /* IO_ERROR */
355
0
      data->eod = TRUE;
356
0
      break;
357
0
  } else {
358
0
      unsigned int i;
359
360
0
      v -= '!';
361
0
      for (i = 1; i < 5; i++) {
362
0
    int c = _getc_skip_whitespace (file->src);
363
0
    if (c == '~') { /* short tuple */
364
0
        _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */
365
0
        data->eod = TRUE;
366
0
        switch (i) {
367
0
        case 0:
368
0
        case 1:
369
      /* IO_ERROR */
370
0
      break;
371
0
        case 2:
372
0
      v = v * (85*85*85) + 85*85*85 -1;
373
0
      goto odd1;
374
0
        case 3:
375
0
      v = v * (85*85) + 85*85 -1;
376
0
      goto odd2;
377
0
        case 4:
378
0
      v = v * 85 + 84;
379
0
      data->buf[n+2] = v >> 8 & 0xff;
380
0
odd2:
381
0
      data->buf[n+1] = v >> 16 & 0xff;
382
0
odd1:
383
0
      data->buf[n+0] = v >> 24 & 0xff;
384
0
      data->bytes_available = n + i - 1;
385
0
      return;
386
0
        }
387
0
        break;
388
0
    }
389
0
    v = 85*v + c-'!';
390
0
      }
391
392
0
      data->buf[n+0] = v >> 24 & 0xff;
393
0
      data->buf[n+1] = v >> 16 & 0xff;
394
0
      data->buf[n+2] = v >> 8 & 0xff;
395
0
      data->buf[n+3] = v >> 0 & 0xff;
396
0
  }
397
0
  n += 4;
398
0
    } while (n < sizeof (data->buf) && data->eod == FALSE);
399
400
0
    data->bytes_available = n;
401
0
}
402
403
static int
404
_ascii85_decode_getc (csi_file_t *file)
405
0
{
406
0
    _ascii85_decode_data_t *data = file->data;
407
408
0
    if (data->bytes_available == 0) {
409
0
  _ascii85_decode (file);
410
411
0
  if (data->bytes_available == 0)
412
0
      return EOF;
413
0
    }
414
415
0
    data->bytes_available--;
416
0
    return *data->bp++;
417
0
}
418
419
static void
420
_ascii85_decode_putc (csi_file_t *file, int c)
421
0
{
422
0
    _ascii85_decode_data_t *data = file->data;
423
0
    data->bytes_available++;
424
0
    data->bp--;
425
0
}
426
427
static int
428
_ascii85_decode_read (csi_file_t *file, uint8_t *buf, int len)
429
0
{
430
0
    _ascii85_decode_data_t *data = file->data;
431
432
0
    if (data->bytes_available == 0) {
433
0
  _ascii85_decode (file);
434
435
0
  if (data->bytes_available == 0)
436
0
      return 0;
437
0
    }
438
439
0
    if (len > data->bytes_available)
440
0
  len = data->bytes_available;
441
0
    memcpy (buf, data->bp, len);
442
0
    data->bp += len;
443
0
    data->bytes_available -= len;
444
0
    return len;
445
0
}
446
447
csi_status_t
448
csi_file_new_ascii85_decode (csi_t *ctx,
449
           csi_object_t *obj,
450
           csi_dictionary_t *dict,
451
           csi_object_t *src)
452
0
{
453
0
    static const csi_filter_funcs_t funcs = {
454
0
  _ascii85_decode_getc,
455
0
  _ascii85_decode_putc,
456
0
  _ascii85_decode_read,
457
0
  _csi_free,
458
0
    };
459
0
    _ascii85_decode_data_t *data;
460
461
0
    data = _csi_alloc0 (ctx, sizeof (_ascii85_decode_data_t));
462
0
    if (data == NULL)
463
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
464
465
0
    return _csi_file_new_filter (ctx, obj, src, &funcs, data);
466
0
}
467
468
#if HAVE_ZLIB
469
#include <zlib.h>
470
471
typedef struct _deflate_decode_data {
472
    z_stream zlib_stream;
473
474
    uint8_t in[CHUNK_SIZE];
475
    uint8_t out[CHUNK_SIZE];
476
477
    int bytes_available;
478
    uint8_t *bp;
479
} _deflate_decode_data_t;
480
481
static void
482
_deflate_decode (csi_file_t *file)
483
0
{
484
0
    _deflate_decode_data_t *data = file->data;
485
0
    uint8_t *bp;
486
0
    int len;
487
488
0
    data->zlib_stream.next_out = data->out;
489
0
    data->zlib_stream.avail_out = sizeof (data->out);
490
491
0
    bp = data->in;
492
0
    len = sizeof (data->in);
493
0
    if (data->zlib_stream.avail_in) {
494
0
  memmove (data->in,
495
0
     data->zlib_stream.next_in,
496
0
     data->zlib_stream.avail_in);
497
0
  len -= data->zlib_stream.avail_in;
498
0
  bp += data->zlib_stream.avail_in;
499
0
    }
500
501
0
    len = csi_file_read (file->src, bp, len);
502
503
0
    data->zlib_stream.next_in = data->in;
504
0
    data->zlib_stream.avail_in += len;
505
506
0
    inflate (&data->zlib_stream, len == 0 ? Z_FINISH : Z_NO_FLUSH);
507
508
0
    data->bytes_available = data->zlib_stream.next_out - data->out;
509
0
    data->bp = data->out;
510
0
}
511
512
static int
513
_deflate_decode_getc (csi_file_t *file)
514
0
{
515
0
    _deflate_decode_data_t *data = file->data;
516
517
0
    if (data->bytes_available == 0) {
518
0
  _deflate_decode (file);
519
520
0
  if (data->bytes_available == 0)
521
0
      return EOF;
522
0
    }
523
524
0
    data->bytes_available--;
525
0
    return *data->bp++;
526
0
}
527
528
static void
529
_deflate_decode_putc (csi_file_t *file, int c)
530
0
{
531
0
    _deflate_decode_data_t *data = file->data;
532
0
    data->bytes_available++;
533
0
    data->bp--;
534
0
}
535
536
static int
537
_deflate_decode_read (csi_file_t *file, uint8_t *buf, int len)
538
0
{
539
0
    _deflate_decode_data_t *data = file->data;
540
541
0
    if (data->bytes_available == 0) {
542
0
  _deflate_decode (file);
543
544
0
  if (data->bytes_available == 0)
545
0
      return 0;
546
0
    }
547
548
0
    if (len > (int) data->bytes_available)
549
0
  len = data->bytes_available;
550
0
    memcpy (buf, data->bp, len);
551
0
    data->bp += len;
552
0
    data->bytes_available -= len;
553
0
    return len;
554
0
}
555
556
static void
557
_deflate_destroy (csi_t *ctx, void *closure)
558
0
{
559
0
    _deflate_decode_data_t *data;
560
561
0
    data = closure;
562
563
0
    inflateEnd (&data->zlib_stream);
564
565
0
    _csi_free (ctx, data);
566
0
}
567
568
csi_status_t
569
csi_file_new_deflate_decode (csi_t *ctx,
570
           csi_object_t *obj,
571
           csi_dictionary_t *dict,
572
           csi_object_t *src)
573
0
{
574
0
    static const csi_filter_funcs_t funcs = {
575
0
  _deflate_decode_getc,
576
0
  _deflate_decode_putc,
577
0
  _deflate_decode_read,
578
0
  _deflate_destroy,
579
0
    };
580
0
    _deflate_decode_data_t *data;
581
582
0
    data = _csi_alloc (ctx, sizeof (_deflate_decode_data_t));
583
0
    if (data == NULL)
584
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
585
586
0
    data->zlib_stream.zalloc = Z_NULL;
587
0
    data->zlib_stream.zfree = Z_NULL;
588
0
    data->zlib_stream.opaque = Z_NULL;
589
0
    data->zlib_stream.next_in = data->in;
590
0
    data->zlib_stream.avail_in = 0;
591
0
    data->zlib_stream.next_out = data->out;
592
0
    data->zlib_stream.avail_out = sizeof (data->out);
593
0
    data->bytes_available = 0;
594
595
0
    if (inflateInit (&data->zlib_stream) != Z_OK) {
596
0
  _csi_free (ctx, data);
597
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
598
0
    }
599
600
0
    return _csi_file_new_filter (ctx, obj, src, &funcs, data);
601
0
}
602
#endif
603
604
#if 0
605
static int
606
hex_value (int c)
607
{
608
    if (c < '0')
609
  return EOF;
610
    if (c <= '9')
611
  return c - '0';
612
    c |= 32;
613
    if (c < 'a')
614
  return EOF;
615
    if (c <= 'f')
616
  return c - 'a' + 0xa;
617
    return EOF;
618
}
619
620
/* Adobe Type 1 Font Format book: p63 */
621
typedef struct _decrypt_data {
622
    uint8_t putback[32];
623
    uint8_t nputback;
624
    csi_bool_t is_hexadecimal;
625
    unsigned short R;
626
    int eod;
627
} _decrypt_data_t;
628
629
static uint8_t
630
_decrypt (unsigned short *R, uint8_t cypher)
631
{
632
#define c1 52845
633
#define c2 22719
634
    uint8_t plain;
635
636
    plain = cypher ^ (*R >> 8);
637
    *R = (cypher + *R) * c1 + c2;
638
    return plain;
639
#undef c1
640
#undef c2
641
}
642
643
int
644
csi_decrypt (uint8_t *in, int length,
645
       unsigned short salt, int binary,
646
       uint8_t *out)
647
{
648
    const uint8_t * const end = in + length;
649
    uint8_t *base = out;
650
651
    while (in < end) {
652
  int c;
653
654
  if (! binary) {
655
      int c_hi = -1, c_lo = 0;
656
657
      while (in < end && (c_hi = *in++)) {
658
    switch (c_hi) {
659
    case 0x0:
660
    case 0x9:
661
    case 0xa:
662
    case 0xc:
663
    case 0xd:
664
    case 0x20:
665
        continue;
666
667
    default:
668
        break;
669
    }
670
      }
671
      if (c_hi < 0)
672
    break;
673
674
      while (in < end && (c_lo = *in++)) {
675
    switch (c_lo) {
676
    case 0x0:
677
    case 0x9:
678
    case 0xa:
679
    case 0xc:
680
    case 0xd:
681
    case 0x20:
682
        continue;
683
684
    default:
685
        break;
686
    }
687
      }
688
689
      c = (hex_value (c_hi) << 4) | hex_value (c_lo);
690
  } else
691
      c = *in++;
692
693
  *out++ = _decrypt (&salt, c);
694
    }
695
696
    return out - base;
697
}
698
699
static uint8_t
700
_encrypt (unsigned short *R, uint8_t plain)
701
{
702
#define c1 52845
703
#define c2 22719
704
    uint8_t cypher;
705
706
    cypher = plain ^ (*R >> 8);
707
    *R = (cypher + *R) * c1 + c2;
708
    return cypher;
709
#undef c1
710
#undef c2
711
}
712
713
int
714
csi_encrypt (uint8_t *in, int length,
715
       unsigned short salt, int discard, int binary,
716
       uint8_t *out)
717
{
718
    const char hex[]="0123456789abcdef";
719
    const uint8_t * const end = in + length;
720
    uint8_t *base = out;
721
    int col = 0;
722
723
    while (discard--) {
724
  if (! binary) {
725
      int c = _encrypt (&salt, ' ');
726
      *out++ = hex[(c >> 4) & 0xf];
727
      *out++ = hex[(c >> 0) & 0xf];
728
  } else
729
      *out++ = _encrypt (&salt, 0);
730
    }
731
732
    while (in < end) {
733
  int c;
734
735
  c = _encrypt (&salt, *in++);
736
  if (! binary) {
737
      if (col == 78) {
738
    *out++ = '\n';
739
    col = 0;
740
      }
741
      *out++ = hex[(c >> 4) & 0xf];
742
      *out++ = hex[(c >> 0) & 0xf];
743
      col += 2;
744
  } else
745
      *out++ = c;
746
    }
747
748
    return out - base;
749
}
750
751
static int
752
_decrypt_getc (csi_file_t *file)
753
{
754
    _decrypt_data_t *data = file->data;
755
    int c;
756
757
    if (data->nputback)
758
  return data->putback[--data->nputback];
759
760
    if (data->is_hexadecimal) {
761
  int c_hi, c_lo;
762
763
  c_hi = _getc_skip_whitespace (file->src);
764
  c_lo = _getc_skip_whitespace (file->src);
765
  c = (hex_value (c_hi) << 4) | hex_value (c_lo);
766
    } else
767
  c = csi_file_getc (file->src);
768
769
    if (c == EOF)
770
  return EOF;
771
772
    return _decrypt (&data->R, c);
773
}
774
775
static void
776
_decrypt_putc (csi_file_t *file, int c)
777
{
778
    _decrypt_data_t *data;
779
780
    data = file->data;
781
782
    data->putback[data->nputback++] = c;
783
}
784
785
csi_object_t *
786
csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard)
787
{
788
    csi_object_t *obj;
789
    _decrypt_data_t *data;
790
    int n;
791
792
    data = _csi_alloc0 (ctx, sizeof (_decrypt_data_t));
793
    if (data == NULL)
794
  return NULL;
795
796
    data->R = salt;
797
798
    obj = _csi_file_new_filter (ctx, src,
799
        _decrypt_getc,
800
        _decrypt_putc,
801
        NULL,
802
        _csi_free,
803
        data);
804
    if (obj == NULL)
805
  return NULL;
806
807
    /* XXX determine encoding, eexec only? */
808
    data->is_hexadecimal = salt != 4330;
809
    for (n = 0; n < discard; n++) {
810
  int c;
811
  c = csi_file_getc (obj);
812
  if (c == EOF) {
813
      return obj;
814
  }
815
    }
816
    return obj;
817
}
818
#endif
819
820
csi_status_t
821
_csi_file_execute (csi_t *ctx, csi_file_t *obj)
822
2.98k
{
823
2.98k
    return _csi_scan_file (ctx, obj);
824
2.98k
}
825
826
int
827
csi_file_getc (csi_file_t *file)
828
24.6M
{
829
24.6M
    int c;
830
831
24.6M
    if (_csi_unlikely (file->src == NULL))
832
0
  return EOF;
833
834
24.6M
    switch (file->type) {
835
0
    case STDIO:
836
0
  if (_csi_likely (file->rem)) {
837
0
      c = *file->bp++;
838
0
      file->rem--;
839
0
  } else {
840
0
      file->rem = fread (file->bp = file->data, 1, CHUNK_SIZE, file->src);
841
      /* fall through */
842
24.6M
    case BYTES:
843
24.6M
      if (_csi_likely (file->rem)) {
844
24.6M
    c = *file->bp++;
845
24.6M
    file->rem--;
846
24.6M
      } else
847
2.19k
    c = EOF;
848
24.6M
  }
849
24.6M
  break;
850
851
24.6M
    case PROCEDURE:
852
#if 0
853
  if (file->data == NULL) {
854
      csi_status_t status;
855
      csi_object_t *string;
856
857
RERUN_PROCEDURE:
858
      status = csi_object_execute (file->src);
859
      if (status)
860
    return EOF;
861
862
      string = csi_pop_operand (file->base.ctx);
863
      if (string == NULL)
864
    return EOF;
865
      file->data = csi_object_as_file (file->base.ctx, string);
866
      csi_object_free (string);
867
      if (file->data == NULL)
868
    return EOF;
869
  }
870
  c = csi_file_getc (file->data);
871
  if (c == EOF) {
872
      csi_object_free (file->data);
873
      file->data = NULL;
874
      goto RERUN_PROCEDURE;
875
  }
876
#else
877
0
  c = EOF;
878
0
#endif
879
0
  break;
880
881
0
    case FILTER:
882
0
  c = file->filter->filter_getc (file);
883
0
  break;
884
885
0
    default:
886
0
  c = EOF;
887
0
  break;
888
24.6M
    }
889
890
24.6M
    return c;
891
24.6M
}
892
893
int
894
csi_file_read (csi_file_t *file, void *buf, int len)
895
37.7k
{
896
37.7k
    int ret;
897
898
37.7k
    if (file->src == NULL)
899
0
  return 0;
900
901
37.7k
    switch (file->type) {
902
0
    case STDIO:
903
0
  if (file->rem > 0) {
904
0
      ret = len;
905
0
      if (file->rem < ret)
906
0
    ret = file->rem;
907
0
      memcpy (buf, file->bp, ret);
908
0
      file->bp  += ret;
909
0
      file->rem -= ret;
910
0
  } else
911
0
      ret = fread (buf, 1, len, file->src);
912
0
  break;
913
914
37.7k
    case BYTES:
915
37.7k
  if (file->rem > 0) {
916
37.5k
      ret = len;
917
37.5k
      if (file->rem < ret)
918
122
    ret = file->rem;
919
37.5k
      memcpy (buf, file->bp, ret);
920
37.5k
      file->bp  += ret;
921
37.5k
      file->rem -= ret;
922
37.5k
  } else
923
224
      ret = 0;
924
37.7k
  break;
925
926
0
    case PROCEDURE:
927
#if 0
928
  if (file->data == NULL) {
929
      csi_status_t status;
930
      csi_object_t *string;
931
932
RERUN_PROCEDURE:
933
      status = csi_object_execute (file->src);
934
      if (status)
935
    return 0;
936
937
      string = csi_pop_operand (file->base.ctx);
938
      if (string == NULL)
939
    return 0;
940
      file->data = csi_object_as_file (file->base.ctx, string);
941
      csi_object_free (string);
942
      if (file->data == NULL)
943
    return 0;
944
  }
945
  ret = csi_file_read (file->data, buf, len);
946
  if (ret == 0) {
947
      csi_object_free (file->data);
948
      file->data = NULL;
949
      goto RERUN_PROCEDURE;
950
  }
951
#else
952
0
  ret = 0;
953
0
#endif
954
0
  break;
955
956
0
    case FILTER:
957
0
  ret = file->filter->filter_read (file, buf, len);
958
0
  break;
959
960
0
    default:
961
0
  ret = 0;
962
0
  break;
963
37.7k
    }
964
965
37.7k
    return ret;
966
37.7k
}
967
968
void
969
csi_file_putc (csi_file_t *file, int c)
970
15.2k
{
971
15.2k
    if (file->src == NULL)
972
0
  return;
973
974
15.2k
    switch ((int) file->type) {
975
0
    case STDIO:
976
15.2k
    case BYTES:
977
15.2k
  file->bp--;
978
15.2k
  file->rem++;
979
15.2k
  break;
980
0
    case FILTER:
981
0
  file->filter->filter_putc (file, c);
982
0
  break;
983
0
    default:
984
0
  break;
985
15.2k
    }
986
15.2k
}
987
988
void
989
csi_file_flush (csi_file_t *file)
990
2.98k
{
991
2.98k
    if (file->src == NULL)
992
0
  return;
993
994
2.98k
    switch ((int) file->type) {
995
0
    case FILTER: /* need to eat EOD */
996
0
  while (csi_file_getc (file) != EOF)
997
0
      ;
998
0
  break;
999
2.98k
    default:
1000
2.98k
  break;
1001
2.98k
    }
1002
2.98k
}
1003
1004
void
1005
csi_file_close (csi_t *ctx, csi_file_t *file)
1006
2.98k
{
1007
2.98k
    if (file->src == NULL)
1008
0
  return;
1009
1010
2.98k
    switch (file->type) {
1011
0
    case STDIO:
1012
0
  if (file->flags & OWN_STREAM)
1013
0
      fclose (file->src);
1014
0
  break;
1015
2.98k
    case BYTES:
1016
2.98k
  if (file->src != file->data) {
1017
0
      csi_string_t *src = file->src;
1018
0
      if (src != NULL && --src->base.ref == 0)
1019
0
    csi_string_free (ctx, src);
1020
0
  }
1021
2.98k
  break;
1022
0
    case FILTER:
1023
0
  {
1024
0
      csi_file_t *src = file->src;
1025
0
      if (src != NULL && --src->base.ref == 0)
1026
0
    _csi_file_free (ctx, src);
1027
0
  }
1028
0
  break;
1029
0
    case PROCEDURE:
1030
0
    default:
1031
0
  break;
1032
2.98k
    }
1033
2.98k
    file->src = NULL;
1034
2.98k
}
1035
1036
void
1037
_csi_file_free (csi_t *ctx, csi_file_t *file)
1038
2.98k
{
1039
2.98k
    csi_file_flush (file);
1040
    /* XXX putback */
1041
2.98k
    csi_file_close (ctx, file);
1042
1043
2.98k
    switch (file->type) {
1044
2.98k
    case BYTES:
1045
2.98k
  break;
1046
0
    case PROCEDURE:
1047
#if 0
1048
  csi_object_free (ctx, file->data);
1049
#endif
1050
0
  break;
1051
0
    case STDIO:
1052
0
  _csi_free (ctx, file->data);
1053
0
  break;
1054
0
    case FILTER:
1055
0
  file->filter->filter_destroy (ctx, file->data);
1056
0
  break;
1057
0
    default:
1058
0
  break;
1059
2.98k
    }
1060
1061
2.98k
    _csi_slab_free (ctx, file, sizeof (csi_file_t));
1062
2.98k
}
1063
1064
csi_status_t
1065
_csi_file_as_string (csi_t *ctx,
1066
         csi_file_t *file,
1067
         csi_object_t *obj)
1068
0
{
1069
0
    char *bytes;
1070
0
    unsigned int len;
1071
0
    unsigned int allocated;
1072
0
    csi_status_t status;
1073
1074
0
    allocated = 16384;
1075
0
    bytes = _csi_alloc (ctx, allocated);
1076
0
    if (bytes == NULL)
1077
0
  return _csi_error (CAIRO_STATUS_NO_MEMORY);
1078
1079
0
    len = 0;
1080
0
    do {
1081
0
  int ret;
1082
1083
0
  ret = csi_file_read (file, bytes + len, allocated - len);
1084
0
  if (ret == 0)
1085
0
      break;
1086
1087
0
  len += ret;
1088
0
  if (len + 1 > allocated / 2) {
1089
0
      char *newbytes;
1090
0
      int newlen;
1091
1092
0
      if (_csi_unlikely (allocated > INT_MAX / 2))
1093
0
    return _csi_error (CAIRO_STATUS_NO_MEMORY);
1094
1095
0
      newlen = allocated * 2;
1096
0
      newbytes = _csi_realloc (ctx, bytes, newlen);
1097
0
      if (_csi_unlikely (newbytes == NULL)) {
1098
0
    _csi_free (ctx, bytes);
1099
0
    return _csi_error (CAIRO_STATUS_NO_MEMORY);
1100
0
      }
1101
0
      bytes = newbytes;
1102
0
      allocated = newlen;
1103
0
  }
1104
0
    } while (TRUE);
1105
1106
0
    bytes[len] = '\0'; /* better safe than sorry! */
1107
0
    status = csi_string_new_from_bytes (ctx, obj, bytes, len);
1108
0
    if (status) {
1109
0
  _csi_free (ctx, bytes);
1110
0
  return status;
1111
0
    }
1112
1113
0
    return CAIRO_STATUS_SUCCESS;
1114
0
}
1115