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
#define CHUNK_SIZE 32768
49

            
50
#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
{
57
    csi_file_t *file;
58

            
59
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
60
    if (file == NULL)
61
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
62

            
63
    file->base.type = CSI_OBJECT_TYPE_FILE;
64
    file->base.ref = 1;
65

            
66
    file->data = NULL;
67
    file->type = STDIO;
68
    file->flags = OWN_STREAM;
69
    file->src = fopen (path, mode);
70
    if (file->src == NULL) {
71
	_csi_slab_free (ctx, file, sizeof (csi_file_t));
72
	return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
73
    }
74

            
75
    file->data = _csi_alloc (ctx, CHUNK_SIZE);
76
    if (file->data == NULL) {
77
	_csi_slab_free (ctx, file, sizeof (csi_file_t));
78
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
79
    }
80
    file->bp = file->data;
81
    file->rem = 0;
82

            
83
    obj->type = CSI_OBJECT_TYPE_FILE;
84
    obj->datum.file = file;
85
    return CAIRO_STATUS_SUCCESS;
86
}
87

            
88
csi_status_t
89
csi_file_new_for_stream (csi_t *ctx,
90
	                 csi_object_t *obj,
91
			 FILE *stream)
92
{
93
    csi_file_t *file;
94

            
95
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
96
    if (file == NULL)
97
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
98

            
99
    file->base.type = CSI_OBJECT_TYPE_FILE;
100
    file->base.ref = 1;
101

            
102
    file->data = NULL;
103
    file->type = STDIO;
104
    file->flags = 0;
105
    file->src = stream;
106
    if (file->src == NULL) {
107
	_csi_slab_free (ctx, file, sizeof (csi_file_t));
108
	return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
109
    }
110

            
111
    file->data = _csi_alloc (ctx, CHUNK_SIZE);
112
    if (file->data == NULL) {
113
	_csi_slab_free (ctx, file, sizeof (csi_file_t));
114
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
115
    }
116
    file->bp = file->data;
117
    file->rem = 0;
118

            
119
    obj->type = CSI_OBJECT_TYPE_FILE;
120
    obj->datum.file = file;
121
    return CAIRO_STATUS_SUCCESS;
122
}
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
{
130
    csi_file_t *file;
131

            
132
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
133
    if (file == NULL)
134
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
135

            
136
    file->base.type = CSI_OBJECT_TYPE_FILE;
137
    file->base.ref = 1;
138

            
139
    file->type = BYTES;
140
    file->src  = (uint8_t *) bytes;
141
    file->data = (uint8_t *) bytes;
142
    file->bp   = (uint8_t *) bytes;
143
    file->rem  = length;
144

            
145
    obj->type = CSI_OBJECT_TYPE_FILE;
146
    obj->datum.file = file;
147
    return CAIRO_STATUS_SUCCESS;
148
}
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
{
155
    csi_file_t *file;
156

            
157
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
158
    if (_csi_unlikely (file == NULL))
159
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
160

            
161
    file->base.type = CSI_OBJECT_TYPE_FILE;
162
    file->base.ref = 1;
163

            
164
    if (src->deflate) {
165
	csi_object_t tmp_obj;
166
	csi_string_t *tmp_str;
167
	csi_status_t status;
168

            
169
	status = csi_string_new (ctx, &tmp_obj,  NULL, src->deflate);
170
	if (_csi_unlikely (status))
171
	    return status;
172

            
173
	tmp_str = tmp_obj.datum.string;
174
	switch (src->method) {
175
	case NONE:
176
	default:
177
	    status = _csi_error (CAIRO_STATUS_NO_MEMORY);
178
	    break;
179

            
180
	case ZLIB:
181
        {
182
#if HAVE_ZLIB
183
            uLongf len = src->deflate;
184
	    if (uncompress ((Bytef *) tmp_str->string, &len,
185
			    (Bytef *) src->string, src->len) != Z_OK)
186
#endif
187
		status = _csi_error (CAIRO_STATUS_NO_MEMORY);
188
	    break;
189
        }
190
	case LZO:
191
        {
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
		status = _csi_error (CAIRO_STATUS_NO_MEMORY);
199
	    break;
200
        }
201
	}
202
	if (_csi_unlikely (status)) {
203
	    csi_string_free (ctx, tmp_str);
204
	    _csi_slab_free (ctx, file, sizeof (csi_file_t));
205
	    return status;
206
	}
207

            
208
	file->src  = tmp_str;
209
	file->data = tmp_str->string;
210
	file->rem  = tmp_str->len;
211
    } else {
212
	file->src  = src; src->base.ref++;
213
	file->data = src->string;
214
	file->rem  = src->len;
215
    }
216
    file->type = BYTES;
217
    file->bp   = file->data;
218

            
219
    obj->type = CSI_OBJECT_TYPE_FILE;
220
    obj->datum.file = file;
221
    return CAIRO_STATUS_SUCCESS;
222
}
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
{
231
    csi_file_t *file;
232
    csi_object_t src_file;
233
    csi_status_t status;
234

            
235
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
236
    if (file == NULL)
237
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
238

            
239
    obj->type = CSI_OBJECT_TYPE_FILE;
240
    obj->datum.file = file;
241

            
242
    file->base.type = CSI_OBJECT_TYPE_FILE;
243
    file->base.ref = 1;
244

            
245
    file->type = FILTER;
246
    file->data = data;
247
    file->filter = funcs;
248
    status = csi_object_as_file (ctx, src, &src_file);
249
    if (status) {
250
	csi_object_free (ctx, obj);
251
	return status;
252
    }
253
    file->src = src_file.datum.file;
254

            
255
    return CAIRO_STATUS_SUCCESS;
256
}
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
{
312
    int c;
313

            
314
    do switch ((c = csi_file_getc (src))) {
315
    case 0x0:
316
    case 0x9:
317
    case 0xa:
318
    case 0xc:
319
    case 0xd:
320
    case 0x20:
321
	continue;
322

            
323
    default:
324
	return c;
325
    } while (TRUE);
326

            
327
    return c;
328
}
329

            
330
static void
331
_ascii85_decode (csi_file_t *file)
332
{
333
    _ascii85_decode_data_t *data = file->data;
334
    unsigned int n;
335

            
336
    if (data->eod)
337
	return;
338

            
339
    data->bp = data->buf;
340

            
341
    n = 0;
342
    do {
343
	unsigned int v = _getc_skip_whitespace (file->src);
344
	if (v == 'z') {
345
	    data->buf[n+0] = 0;
346
	    data->buf[n+1] = 0;
347
	    data->buf[n+2] = 0;
348
	    data->buf[n+3] = 0;
349
	} else if (v == '~') {
350
	    _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */
351
	    data->eod = TRUE;
352
	    break;
353
	} else if (v < '!' || v > 'u') {
354
	    /* IO_ERROR */
355
	    data->eod = TRUE;
356
	    break;
357
	} else {
358
	    unsigned int i;
359

            
360
	    v -= '!';
361
	    for (i = 1; i < 5; i++) {
362
		int c = _getc_skip_whitespace (file->src);
363
		if (c == '~') { /* short tuple */
364
		    _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */
365
		    data->eod = TRUE;
366
		    switch (i) {
367
		    case 0:
368
		    case 1:
369
			/* IO_ERROR */
370
			break;
371
		    case 2:
372
			v = v * (85*85*85) + 85*85*85 -1;
373
			goto odd1;
374
		    case 3:
375
			v = v * (85*85) + 85*85 -1;
376
			goto odd2;
377
		    case 4:
378
			v = v * 85 + 84;
379
			data->buf[n+2] = v >> 8 & 0xff;
380
odd2:
381
			data->buf[n+1] = v >> 16 & 0xff;
382
odd1:
383
			data->buf[n+0] = v >> 24 & 0xff;
384
			data->bytes_available = n + i - 1;
385
			return;
386
		    }
387
		    break;
388
		}
389
		v = 85*v + c-'!';
390
	    }
391

            
392
	    data->buf[n+0] = v >> 24 & 0xff;
393
	    data->buf[n+1] = v >> 16 & 0xff;
394
	    data->buf[n+2] = v >> 8 & 0xff;
395
	    data->buf[n+3] = v >> 0 & 0xff;
396
	}
397
	n += 4;
398
    } while (n < sizeof (data->buf) && data->eod == FALSE);
399

            
400
    data->bytes_available = n;
401
}
402

            
403
static int
404
_ascii85_decode_getc (csi_file_t *file)
405
{
406
    _ascii85_decode_data_t *data = file->data;
407

            
408
    if (data->bytes_available == 0) {
409
	_ascii85_decode (file);
410

            
411
	if (data->bytes_available == 0)
412
	    return EOF;
413
    }
414

            
415
    data->bytes_available--;
416
    return *data->bp++;
417
}
418

            
419
static void
420
_ascii85_decode_putc (csi_file_t *file, int c)
421
{
422
    _ascii85_decode_data_t *data = file->data;
423
    data->bytes_available++;
424
    data->bp--;
425
}
426

            
427
static int
428
_ascii85_decode_read (csi_file_t *file, uint8_t *buf, int len)
429
{
430
    _ascii85_decode_data_t *data = file->data;
431

            
432
    if (data->bytes_available == 0) {
433
	_ascii85_decode (file);
434

            
435
	if (data->bytes_available == 0)
436
	    return 0;
437
    }
438

            
439
    if (len > data->bytes_available)
440
	len = data->bytes_available;
441
    memcpy (buf, data->bp, len);
442
    data->bp += len;
443
    data->bytes_available -= len;
444
    return len;
445
}
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
{
453
    static const csi_filter_funcs_t funcs = {
454
	_ascii85_decode_getc,
455
	_ascii85_decode_putc,
456
	_ascii85_decode_read,
457
	_csi_free,
458
    };
459
    _ascii85_decode_data_t *data;
460

            
461
    data = _csi_alloc0 (ctx, sizeof (_ascii85_decode_data_t));
462
    if (data == NULL)
463
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
464

            
465
    return _csi_file_new_filter (ctx, obj, src, &funcs, data);
466
}
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
{
484
    _deflate_decode_data_t *data = file->data;
485
    uint8_t *bp;
486
    int len;
487

            
488
    data->zlib_stream.next_out = data->out;
489
    data->zlib_stream.avail_out = sizeof (data->out);
490

            
491
    bp = data->in;
492
    len = sizeof (data->in);
493
    if (data->zlib_stream.avail_in) {
494
	memmove (data->in,
495
		 data->zlib_stream.next_in,
496
		 data->zlib_stream.avail_in);
497
	len -= data->zlib_stream.avail_in;
498
	bp += data->zlib_stream.avail_in;
499
    }
500

            
501
    len = csi_file_read (file->src, bp, len);
502

            
503
    data->zlib_stream.next_in = data->in;
504
    data->zlib_stream.avail_in += len;
505

            
506
    inflate (&data->zlib_stream, len == 0 ? Z_FINISH : Z_NO_FLUSH);
507

            
508
    data->bytes_available = data->zlib_stream.next_out - data->out;
509
    data->bp = data->out;
510
}
511

            
512
static int
513
_deflate_decode_getc (csi_file_t *file)
514
{
515
    _deflate_decode_data_t *data = file->data;
516

            
517
    if (data->bytes_available == 0) {
518
	_deflate_decode (file);
519

            
520
	if (data->bytes_available == 0)
521
	    return EOF;
522
    }
523

            
524
    data->bytes_available--;
525
    return *data->bp++;
526
}
527

            
528
static void
529
_deflate_decode_putc (csi_file_t *file, int c)
530
{
531
    _deflate_decode_data_t *data = file->data;
532
    data->bytes_available++;
533
    data->bp--;
534
}
535

            
536
static int
537
_deflate_decode_read (csi_file_t *file, uint8_t *buf, int len)
538
{
539
    _deflate_decode_data_t *data = file->data;
540

            
541
    if (data->bytes_available == 0) {
542
	_deflate_decode (file);
543

            
544
	if (data->bytes_available == 0)
545
	    return 0;
546
    }
547

            
548
    if (len > (int) data->bytes_available)
549
	len = data->bytes_available;
550
    memcpy (buf, data->bp, len);
551
    data->bp += len;
552
    data->bytes_available -= len;
553
    return len;
554
}
555

            
556
static void
557
_deflate_destroy (csi_t *ctx, void *closure)
558
{
559
    _deflate_decode_data_t *data;
560

            
561
    data = closure;
562

            
563
    inflateEnd (&data->zlib_stream);
564

            
565
    _csi_free (ctx, data);
566
}
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
{
574
    static const csi_filter_funcs_t funcs = {
575
	_deflate_decode_getc,
576
	_deflate_decode_putc,
577
	_deflate_decode_read,
578
	_deflate_destroy,
579
    };
580
    _deflate_decode_data_t *data;
581

            
582
    data = _csi_alloc (ctx, sizeof (_deflate_decode_data_t));
583
    if (data == NULL)
584
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
585

            
586
    data->zlib_stream.zalloc = Z_NULL;
587
    data->zlib_stream.zfree = Z_NULL;
588
    data->zlib_stream.opaque = Z_NULL;
589
    data->zlib_stream.next_in = data->in;
590
    data->zlib_stream.avail_in = 0;
591
    data->zlib_stream.next_out = data->out;
592
    data->zlib_stream.avail_out = sizeof (data->out);
593
    data->bytes_available = 0;
594

            
595
    if (inflateInit (&data->zlib_stream) != Z_OK) {
596
	_csi_free (ctx, data);
597
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
598
    }
599

            
600
    return _csi_file_new_filter (ctx, obj, src, &funcs, data);
601
}
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
{
823
    return _csi_scan_file (ctx, obj);
824
}
825

            
826
int
827
csi_file_getc (csi_file_t *file)
828
{
829
    int c;
830

            
831
    if (_csi_unlikely (file->src == NULL))
832
	return EOF;
833

            
834
    switch (file->type) {
835
    case STDIO:
836
	if (_csi_likely (file->rem)) {
837
	    c = *file->bp++;
838
	    file->rem--;
839
	} else {
840
	    file->rem = fread (file->bp = file->data, 1, CHUNK_SIZE, file->src);
841
	    /* fall through */
842
    case BYTES:
843
	    if (_csi_likely (file->rem)) {
844
		c = *file->bp++;
845
		file->rem--;
846
	    } else
847
		c = EOF;
848
	}
849
	break;
850

            
851
    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
	c = EOF;
878
#endif
879
	break;
880

            
881
    case FILTER:
882
	c = file->filter->filter_getc (file);
883
	break;
884

            
885
    default:
886
	c = EOF;
887
	break;
888
    }
889

            
890
    return c;
891
}
892

            
893
int
894
csi_file_read (csi_file_t *file, void *buf, int len)
895
{
896
    int ret;
897

            
898
    if (file->src == NULL)
899
	return 0;
900

            
901
    switch (file->type) {
902
    case STDIO:
903
	if (file->rem > 0) {
904
	    ret = len;
905
	    if (file->rem < ret)
906
		ret = file->rem;
907
	    memcpy (buf, file->bp, ret);
908
	    file->bp  += ret;
909
	    file->rem -= ret;
910
	} else
911
	    ret = fread (buf, 1, len, file->src);
912
	break;
913

            
914
    case BYTES:
915
	if (file->rem > 0) {
916
	    ret = len;
917
	    if (file->rem < ret)
918
		ret = file->rem;
919
	    memcpy (buf, file->bp, ret);
920
	    file->bp  += ret;
921
	    file->rem -= ret;
922
	} else
923
	    ret = 0;
924
	break;
925

            
926
    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
	ret = 0;
953
#endif
954
	break;
955

            
956
    case FILTER:
957
	ret = file->filter->filter_read (file, buf, len);
958
	break;
959

            
960
    default:
961
	ret = 0;
962
	break;
963
    }
964

            
965
    return ret;
966
}
967

            
968
void
969
csi_file_putc (csi_file_t *file, int c)
970
{
971
    if (file->src == NULL)
972
	return;
973

            
974
    switch ((int) file->type) {
975
    case STDIO:
976
    case BYTES:
977
	file->bp--;
978
	file->rem++;
979
	break;
980
    case FILTER:
981
	file->filter->filter_putc (file, c);
982
	break;
983
    default:
984
	break;
985
    }
986
}
987

            
988
void
989
csi_file_flush (csi_file_t *file)
990
{
991
    if (file->src == NULL)
992
	return;
993

            
994
    switch ((int) file->type) {
995
    case FILTER: /* need to eat EOD */
996
	while (csi_file_getc (file) != EOF)
997
	    ;
998
	break;
999
    default:
	break;
    }
}
void
csi_file_close (csi_t *ctx, csi_file_t *file)
{
    if (file->src == NULL)
	return;
    switch (file->type) {
    case STDIO:
	if (file->flags & OWN_STREAM)
	    fclose (file->src);
	break;
    case BYTES:
	if (file->src != file->data) {
	    csi_string_t *src = file->src;
	    if (src != NULL && --src->base.ref == 0)
		csi_string_free (ctx, src);
	}
	break;
    case FILTER:
	{
	    csi_file_t *src = file->src;
	    if (src != NULL && --src->base.ref == 0)
		_csi_file_free (ctx, src);
	}
	break;
    case PROCEDURE:
    default:
	break;
    }
    file->src = NULL;
}
void
_csi_file_free (csi_t *ctx, csi_file_t *file)
{
    csi_file_flush (file);
    /* XXX putback */
    csi_file_close (ctx, file);
    switch (file->type) {
    case BYTES:
	break;
    case PROCEDURE:
#if 0
	csi_object_free (ctx, file->data);
#endif
	break;
    case STDIO:
	_csi_free (ctx, file->data);
	break;
    case FILTER:
	file->filter->filter_destroy (ctx, file->data);
	break;
    default:
	break;
    }
    _csi_slab_free (ctx, file, sizeof (csi_file_t));
}
csi_status_t
_csi_file_as_string (csi_t *ctx,
		     csi_file_t *file,
		     csi_object_t *obj)
{
    char *bytes;
    unsigned int len;
    unsigned int allocated;
    csi_status_t status;
    allocated = 16384;
    bytes = _csi_alloc (ctx, allocated);
    if (bytes == NULL)
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
    len = 0;
    do {
	int ret;
	ret = csi_file_read (file, bytes + len, allocated - len);
	if (ret == 0)
	    break;
	len += ret;
	if (len + 1 > allocated / 2) {
	    char *newbytes;
	    int newlen;
	    if (_csi_unlikely (allocated > INT_MAX / 2))
		return _csi_error (CAIRO_STATUS_NO_MEMORY);
	    newlen = allocated * 2;
	    newbytes = _csi_realloc (ctx, bytes, newlen);
	    if (_csi_unlikely (newbytes == NULL)) {
		_csi_free (ctx, bytes);
		return _csi_error (CAIRO_STATUS_NO_MEMORY);
	    }
	    bytes = newbytes;
	    allocated = newlen;
	}
    } while (TRUE);
    bytes[len] = '\0'; /* better safe than sorry! */
    status = csi_string_new_from_bytes (ctx, obj, bytes, len);
    if (status) {
	_csi_free (ctx, bytes);
	return status;
    }
    return CAIRO_STATUS_SUCCESS;
}