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
	uLongf len = src->deflate;
166
	csi_object_t tmp_obj;
167
	csi_string_t *tmp_str;
168
	csi_status_t status;
169

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

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

            
181
	case ZLIB:
182
#if HAVE_ZLIB
183
	    if (uncompress ((Bytef *) tmp_str->string, &len,
184
			    (Bytef *) src->string, src->len) != Z_OK)
185
#endif
186
		status = _csi_error (CAIRO_STATUS_NO_MEMORY);
187
	    break;
188
	case LZO:
189
#if HAVE_LZO
190
	    if (lzo2a_decompress ((lzo_bytep) src->string, src->len,
191
				  (lzo_bytep) tmp_str->string, &len,
192
				  NULL))
193
#endif
194
		status = _csi_error (CAIRO_STATUS_NO_MEMORY);
195
	    break;
196
	}
197
	if (_csi_unlikely (status)) {
198
	    csi_string_free (ctx, tmp_str);
199
	    _csi_slab_free (ctx, file, sizeof (csi_file_t));
200
	    return status;
201
	}
202

            
203
	file->src  = tmp_str;
204
	file->data = tmp_str->string;
205
	file->rem  = tmp_str->len;
206
    } else {
207
	file->src  = src; src->base.ref++;
208
	file->data = src->string;
209
	file->rem  = src->len;
210
    }
211
    file->type = BYTES;
212
    file->bp   = file->data;
213

            
214
    obj->type = CSI_OBJECT_TYPE_FILE;
215
    obj->datum.file = file;
216
    return CAIRO_STATUS_SUCCESS;
217
}
218

            
219
static csi_status_t
220
_csi_file_new_filter (csi_t *ctx,
221
		      csi_object_t *obj,
222
		      csi_object_t *src,
223
		      const csi_filter_funcs_t *funcs,
224
		      void *data)
225
{
226
    csi_file_t *file;
227
    csi_object_t src_file;
228
    csi_status_t status;
229

            
230
    file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
231
    if (file == NULL)
232
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
233

            
234
    obj->type = CSI_OBJECT_TYPE_FILE;
235
    obj->datum.file = file;
236

            
237
    file->base.type = CSI_OBJECT_TYPE_FILE;
238
    file->base.ref = 1;
239

            
240
    file->type = FILTER;
241
    file->data = data;
242
    file->filter = funcs;
243
    status = csi_object_as_file (ctx, src, &src_file);
244
    if (status) {
245
	csi_object_free (ctx, obj);
246
	return status;
247
    }
248
    file->src = src_file.datum.file;
249

            
250
    return CAIRO_STATUS_SUCCESS;
251
}
252

            
253

            
254
#if 0
255
csi_status_t
256
csi_file_new_from_stream (csi_t *ctx,
257
			  FILE *file,
258
			  csi_object_t **out)
259
{
260
    csi_file_t *obj;
261

            
262
    obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE);
263
    if (obj == NULL)
264
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
265

            
266
    obj->type = STDIO;
267
    obj->src = file;
268
    obj->data = _csi_alloc (ctx, CHUNK_SIZE);
269
    if (obj->data == NULL) {
270
	csi_object_free (&obj->base);
271
	return _csi_error (CAIRO_STATUS_UNDEFINED_FILENAME_ERROR);
272
    }
273
    obj->bp = obj->data;
274
    obj->rem = 0;
275

            
276
    *out = &obj->base;
277
    return CAIRO_STATUS_SUCCESS;
278
}
279

            
280
static csi_object_t *
281
_csi_file_new_from_procedure (csi_t *ctx, csi_object_t *src)
282
{
283
    csi_file_t *obj;
284

            
285
    obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE);
286
    if (obj == NULL)
287
	return NULL;
288

            
289
    obj->type = PROCEDURE;
290
    obj->src = csi_object_reference (src);
291
    obj->data = NULL;
292

            
293
    return &obj->base;
294
}
295
#endif
296

            
297
typedef struct _ascii85_decode_data {
298
    uint8_t buf[CHUNK_SIZE];
299
    uint8_t *bp;
300
    short bytes_available;
301
    short eod;
302
} _ascii85_decode_data_t;
303

            
304
static int
305
_getc_skip_whitespace (csi_file_t *src)
306
{
307
    int c;
308

            
309
    do switch ((c = csi_file_getc (src))) {
310
    case 0x0:
311
    case 0x9:
312
    case 0xa:
313
    case 0xc:
314
    case 0xd:
315
    case 0x20:
316
	continue;
317

            
318
    default:
319
	return c;
320
    } while (TRUE);
321

            
322
    return c;
323
}
324

            
325
static void
326
_ascii85_decode (csi_file_t *file)
327
{
328
    _ascii85_decode_data_t *data = file->data;
329
    unsigned int n;
330

            
331
    if (data->eod)
332
	return;
333

            
334
    data->bp = data->buf;
335

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

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

            
387
	    data->buf[n+0] = v >> 24 & 0xff;
388
	    data->buf[n+1] = v >> 16 & 0xff;
389
	    data->buf[n+2] = v >> 8 & 0xff;
390
	    data->buf[n+3] = v >> 0 & 0xff;
391
	}
392
	n += 4;
393
    } while (n < sizeof (data->buf) && data->eod == FALSE);
394

            
395
    data->bytes_available = n;
396
}
397

            
398
static int
399
_ascii85_decode_getc (csi_file_t *file)
400
{
401
    _ascii85_decode_data_t *data = file->data;
402

            
403
    if (data->bytes_available == 0) {
404
	_ascii85_decode (file);
405

            
406
	if (data->bytes_available == 0)
407
	    return EOF;
408
    }
409

            
410
    data->bytes_available--;
411
    return *data->bp++;
412
}
413

            
414
static void
415
_ascii85_decode_putc (csi_file_t *file, int c)
416
{
417
    _ascii85_decode_data_t *data = file->data;
418
    data->bytes_available++;
419
    data->bp--;
420
}
421

            
422
static int
423
_ascii85_decode_read (csi_file_t *file, uint8_t *buf, int len)
424
{
425
    _ascii85_decode_data_t *data = file->data;
426

            
427
    if (data->bytes_available == 0) {
428
	_ascii85_decode (file);
429

            
430
	if (data->bytes_available == 0)
431
	    return 0;
432
    }
433

            
434
    if (len > data->bytes_available)
435
	len = data->bytes_available;
436
    memcpy (buf, data->bp, len);
437
    data->bp += len;
438
    data->bytes_available -= len;
439
    return len;
440
}
441

            
442
csi_status_t
443
csi_file_new_ascii85_decode (csi_t *ctx,
444
			     csi_object_t *obj,
445
			     csi_dictionary_t *dict,
446
			     csi_object_t *src)
447
{
448
    static const csi_filter_funcs_t funcs = {
449
	_ascii85_decode_getc,
450
	_ascii85_decode_putc,
451
	_ascii85_decode_read,
452
	_csi_free,
453
    };
454
    _ascii85_decode_data_t *data;
455

            
456
    data = _csi_alloc0 (ctx, sizeof (_ascii85_decode_data_t));
457
    if (data == NULL)
458
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
459

            
460
    return _csi_file_new_filter (ctx, obj, src, &funcs, data);
461
}
462

            
463
#if HAVE_ZLIB
464
#include <zlib.h>
465

            
466
typedef struct _deflate_decode_data {
467
    z_stream zlib_stream;
468

            
469
    uint8_t in[CHUNK_SIZE];
470
    uint8_t out[CHUNK_SIZE];
471

            
472
    int bytes_available;
473
    uint8_t *bp;
474
} _deflate_decode_data_t;
475

            
476
static void
477
_deflate_decode (csi_file_t *file)
478
{
479
    _deflate_decode_data_t *data = file->data;
480
    uint8_t *bp;
481
    int len;
482

            
483
    data->zlib_stream.next_out = data->out;
484
    data->zlib_stream.avail_out = sizeof (data->out);
485

            
486
    bp = data->in;
487
    len = sizeof (data->in);
488
    if (data->zlib_stream.avail_in) {
489
	memmove (data->in,
490
		 data->zlib_stream.next_in,
491
		 data->zlib_stream.avail_in);
492
	len -= data->zlib_stream.avail_in;
493
	bp += data->zlib_stream.avail_in;
494
    }
495

            
496
    len = csi_file_read (file->src, bp, len);
497

            
498
    data->zlib_stream.next_in = data->in;
499
    data->zlib_stream.avail_in += len;
500

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

            
503
    data->bytes_available = data->zlib_stream.next_out - data->out;
504
    data->bp = data->out;
505
}
506

            
507
static int
508
_deflate_decode_getc (csi_file_t *file)
509
{
510
    _deflate_decode_data_t *data = file->data;
511

            
512
    if (data->bytes_available == 0) {
513
	_deflate_decode (file);
514

            
515
	if (data->bytes_available == 0)
516
	    return EOF;
517
    }
518

            
519
    data->bytes_available--;
520
    return *data->bp++;
521
}
522

            
523
static void
524
_deflate_decode_putc (csi_file_t *file, int c)
525
{
526
    _deflate_decode_data_t *data = file->data;
527
    data->bytes_available++;
528
    data->bp--;
529
}
530

            
531
static int
532
_deflate_decode_read (csi_file_t *file, uint8_t *buf, int len)
533
{
534
    _deflate_decode_data_t *data = file->data;
535

            
536
    if (data->bytes_available == 0) {
537
	_deflate_decode (file);
538

            
539
	if (data->bytes_available == 0)
540
	    return 0;
541
    }
542

            
543
    if (len > (int) data->bytes_available)
544
	len = data->bytes_available;
545
    memcpy (buf, data->bp, len);
546
    data->bp += len;
547
    data->bytes_available -= len;
548
    return len;
549
}
550

            
551
static void
552
_deflate_destroy (csi_t *ctx, void *closure)
553
{
554
    _deflate_decode_data_t *data;
555

            
556
    data = closure;
557

            
558
    inflateEnd (&data->zlib_stream);
559

            
560
    _csi_free (ctx, data);
561
}
562

            
563
csi_status_t
564
csi_file_new_deflate_decode (csi_t *ctx,
565
			     csi_object_t *obj,
566
			     csi_dictionary_t *dict,
567
			     csi_object_t *src)
568
{
569
    static const csi_filter_funcs_t funcs = {
570
	_deflate_decode_getc,
571
	_deflate_decode_putc,
572
	_deflate_decode_read,
573
	_deflate_destroy,
574
    };
575
    _deflate_decode_data_t *data;
576

            
577
    data = _csi_alloc (ctx, sizeof (_deflate_decode_data_t));
578
    if (data == NULL)
579
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
580

            
581
    data->zlib_stream.zalloc = Z_NULL;
582
    data->zlib_stream.zfree = Z_NULL;
583
    data->zlib_stream.opaque = Z_NULL;
584
    data->zlib_stream.next_in = data->in;
585
    data->zlib_stream.avail_in = 0;
586
    data->zlib_stream.next_out = data->out;
587
    data->zlib_stream.avail_out = sizeof (data->out);
588
    data->bytes_available = 0;
589

            
590
    if (inflateInit (&data->zlib_stream) != Z_OK) {
591
	_csi_free (ctx, data);
592
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
593
    }
594

            
595
    return _csi_file_new_filter (ctx, obj, src, &funcs, data);
596
}
597
#endif
598

            
599
#if 0
600
static int
601
hex_value (int c)
602
{
603
    if (c < '0')
604
	return EOF;
605
    if (c <= '9')
606
	return c - '0';
607
    c |= 32;
608
    if (c < 'a')
609
	return EOF;
610
    if (c <= 'f')
611
	return c - 'a' + 0xa;
612
    return EOF;
613
}
614

            
615
/* Adobe Type 1 Font Format book: p63 */
616
typedef struct _decrypt_data {
617
    uint8_t putback[32];
618
    uint8_t nputback;
619
    csi_bool_t is_hexadecimal;
620
    unsigned short R;
621
    int eod;
622
} _decrypt_data_t;
623

            
624
static uint8_t
625
_decrypt (unsigned short *R, uint8_t cypher)
626
{
627
#define c1 52845
628
#define c2 22719
629
    uint8_t plain;
630

            
631
    plain = cypher ^ (*R >> 8);
632
    *R = (cypher + *R) * c1 + c2;
633
    return plain;
634
#undef c1
635
#undef c2
636
}
637

            
638
int
639
csi_decrypt (uint8_t *in, int length,
640
	     unsigned short salt, int binary,
641
	     uint8_t *out)
642
{
643
    const uint8_t * const end = in + length;
644
    uint8_t *base = out;
645

            
646
    while (in < end) {
647
	int c;
648

            
649
	if (! binary) {
650
	    int c_hi = -1, c_lo = 0;
651

            
652
	    while (in < end && (c_hi = *in++)) {
653
		switch (c_hi) {
654
		case 0x0:
655
		case 0x9:
656
		case 0xa:
657
		case 0xc:
658
		case 0xd:
659
		case 0x20:
660
		    continue;
661

            
662
		default:
663
		    break;
664
		}
665
	    }
666
	    if (c_hi < 0)
667
		break;
668

            
669
	    while (in < end && (c_lo = *in++)) {
670
		switch (c_lo) {
671
		case 0x0:
672
		case 0x9:
673
		case 0xa:
674
		case 0xc:
675
		case 0xd:
676
		case 0x20:
677
		    continue;
678

            
679
		default:
680
		    break;
681
		}
682
	    }
683

            
684
	    c = (hex_value (c_hi) << 4) | hex_value (c_lo);
685
	} else
686
	    c = *in++;
687

            
688
	*out++ = _decrypt (&salt, c);
689
    }
690

            
691
    return out - base;
692
}
693

            
694
static uint8_t
695
_encrypt (unsigned short *R, uint8_t plain)
696
{
697
#define c1 52845
698
#define c2 22719
699
    uint8_t cypher;
700

            
701
    cypher = plain ^ (*R >> 8);
702
    *R = (cypher + *R) * c1 + c2;
703
    return cypher;
704
#undef c1
705
#undef c2
706
}
707

            
708
int
709
csi_encrypt (uint8_t *in, int length,
710
	     unsigned short salt, int discard, int binary,
711
	     uint8_t *out)
712
{
713
    const char hex[]="0123456789abcdef";
714
    const uint8_t * const end = in + length;
715
    uint8_t *base = out;
716
    int col = 0;
717

            
718
    while (discard--) {
719
	if (! binary) {
720
	    int c = _encrypt (&salt, ' ');
721
	    *out++ = hex[(c >> 4) & 0xf];
722
	    *out++ = hex[(c >> 0) & 0xf];
723
	} else
724
	    *out++ = _encrypt (&salt, 0);
725
    }
726

            
727
    while (in < end) {
728
	int c;
729

            
730
	c = _encrypt (&salt, *in++);
731
	if (! binary) {
732
	    if (col == 78) {
733
		*out++ = '\n';
734
		col = 0;
735
	    }
736
	    *out++ = hex[(c >> 4) & 0xf];
737
	    *out++ = hex[(c >> 0) & 0xf];
738
	    col += 2;
739
	} else
740
	    *out++ = c;
741
    }
742

            
743
    return out - base;
744
}
745

            
746
static int
747
_decrypt_getc (csi_file_t *file)
748
{
749
    _decrypt_data_t *data = file->data;
750
    int c;
751

            
752
    if (data->nputback)
753
	return data->putback[--data->nputback];
754

            
755
    if (data->is_hexadecimal) {
756
	int c_hi, c_lo;
757

            
758
	c_hi = _getc_skip_whitespace (file->src);
759
	c_lo = _getc_skip_whitespace (file->src);
760
	c = (hex_value (c_hi) << 4) | hex_value (c_lo);
761
    } else
762
	c = csi_file_getc (file->src);
763

            
764
    if (c == EOF)
765
	return EOF;
766

            
767
    return _decrypt (&data->R, c);
768
}
769

            
770
static void
771
_decrypt_putc (csi_file_t *file, int c)
772
{
773
    _decrypt_data_t *data;
774

            
775
    data = file->data;
776

            
777
    data->putback[data->nputback++] = c;
778
}
779

            
780
csi_object_t *
781
csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard)
782
{
783
    csi_object_t *obj;
784
    _decrypt_data_t *data;
785
    int n;
786

            
787
    data = _csi_alloc0 (ctx, sizeof (_decrypt_data_t));
788
    if (data == NULL)
789
	return NULL;
790

            
791
    data->R = salt;
792

            
793
    obj = _csi_file_new_filter (ctx, src,
794
				_decrypt_getc,
795
				_decrypt_putc,
796
				NULL,
797
				_csi_free,
798
				data);
799
    if (obj == NULL)
800
	return NULL;
801

            
802
    /* XXX determine encoding, eexec only? */
803
    data->is_hexadecimal = salt != 4330;
804
    for (n = 0; n < discard; n++) {
805
	int c;
806
	c = csi_file_getc (obj);
807
	if (c == EOF) {
808
	    return obj;
809
	}
810
    }
811
    return obj;
812
}
813
#endif
814

            
815
csi_status_t
816
_csi_file_execute (csi_t *ctx, csi_file_t *obj)
817
{
818
    return _csi_scan_file (ctx, obj);
819
}
820

            
821
int
822
csi_file_getc (csi_file_t *file)
823
{
824
    int c;
825

            
826
    if (_csi_unlikely (file->src == NULL))
827
	return EOF;
828

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

            
846
    case PROCEDURE:
847
#if 0
848
	if (file->data == NULL) {
849
	    csi_status_t status;
850
	    csi_object_t *string;
851

            
852
RERUN_PROCEDURE:
853
	    status = csi_object_execute (file->src);
854
	    if (status)
855
		return EOF;
856

            
857
	    string = csi_pop_operand (file->base.ctx);
858
	    if (string == NULL)
859
		return EOF;
860
	    file->data = csi_object_as_file (file->base.ctx, string);
861
	    csi_object_free (string);
862
	    if (file->data == NULL)
863
		return EOF;
864
	}
865
	c = csi_file_getc (file->data);
866
	if (c == EOF) {
867
	    csi_object_free (file->data);
868
	    file->data = NULL;
869
	    goto RERUN_PROCEDURE;
870
	}
871
#else
872
	c = EOF;
873
#endif
874
	break;
875

            
876
    case FILTER:
877
	c = file->filter->filter_getc (file);
878
	break;
879

            
880
    default:
881
	c = EOF;
882
	break;
883
    }
884

            
885
    return c;
886
}
887

            
888
int
889
csi_file_read (csi_file_t *file, void *buf, int len)
890
{
891
    int ret;
892

            
893
    if (file->src == NULL)
894
	return 0;
895

            
896
    switch (file->type) {
897
    case STDIO:
898
	if (file->rem > 0) {
899
	    ret = len;
900
	    if (file->rem < ret)
901
		ret = file->rem;
902
	    memcpy (buf, file->bp, ret);
903
	    file->bp  += ret;
904
	    file->rem -= ret;
905
	} else
906
	    ret = fread (buf, 1, len, file->src);
907
	break;
908

            
909
    case BYTES:
910
	if (file->rem > 0) {
911
	    ret = len;
912
	    if (file->rem < ret)
913
		ret = file->rem;
914
	    memcpy (buf, file->bp, ret);
915
	    file->bp  += ret;
916
	    file->rem -= ret;
917
	} else
918
	    ret = 0;
919
	break;
920

            
921
    case PROCEDURE:
922
#if 0
923
	if (file->data == NULL) {
924
	    csi_status_t status;
925
	    csi_object_t *string;
926

            
927
RERUN_PROCEDURE:
928
	    status = csi_object_execute (file->src);
929
	    if (status)
930
		return 0;
931

            
932
	    string = csi_pop_operand (file->base.ctx);
933
	    if (string == NULL)
934
		return 0;
935
	    file->data = csi_object_as_file (file->base.ctx, string);
936
	    csi_object_free (string);
937
	    if (file->data == NULL)
938
		return 0;
939
	}
940
	ret = csi_file_read (file->data, buf, len);
941
	if (ret == 0) {
942
	    csi_object_free (file->data);
943
	    file->data = NULL;
944
	    goto RERUN_PROCEDURE;
945
	}
946
#else
947
	ret = 0;
948
#endif
949
	break;
950

            
951
    case FILTER:
952
	ret = file->filter->filter_read (file, buf, len);
953
	break;
954

            
955
    default:
956
	ret = 0;
957
	break;
958
    }
959

            
960
    return ret;
961
}
962

            
963
void
964
csi_file_putc (csi_file_t *file, int c)
965
{
966
    if (file->src == NULL)
967
	return;
968

            
969
    switch ((int) file->type) {
970
    case STDIO:
971
    case BYTES:
972
	file->bp--;
973
	file->rem++;
974
	break;
975
    case FILTER:
976
	file->filter->filter_putc (file, c);
977
	break;
978
    default:
979
	break;
980
    }
981
}
982

            
983
void
984
csi_file_flush (csi_file_t *file)
985
{
986
    if (file->src == NULL)
987
	return;
988

            
989
    switch ((int) file->type) {
990
    case FILTER: /* need to eat EOD */
991
	while (csi_file_getc (file) != EOF)
992
	    ;
993
	break;
994
    default:
995
	break;
996
    }
997
}
998

            
999
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;
}