Coverage Report

Created: 2026-10-28 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cairo/util/cairo-script/cairo-script-interpreter.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.h"
38
39
#include "cairo-script-private.h"
40
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <math.h>
45
#include <assert.h>
46
47
#ifndef MAX
48
33.7k
#define MAX(a,b) (((a)>=(b))?(a):(b))
49
#endif
50
51
csi_status_t
52
_csi_error (csi_status_t status)
53
3.87k
{
54
3.87k
    return status;
55
3.87k
}
56
57
/* XXX track global/local memory, cap etc, mark/sweep GC */
58
void *
59
_csi_alloc (csi_t *ctx, int size)
60
3.28M
{
61
3.28M
    return malloc (size);
62
3.28M
}
63
64
void *
65
_csi_alloc0 (csi_t *ctx, int size)
66
0
{
67
0
    void *ptr;
68
69
0
    ptr = _csi_alloc (ctx, size);
70
0
    if (_csi_likely (ptr != NULL))
71
0
  memset (ptr, 0, size);
72
73
0
    return ptr;
74
0
}
75
76
void *
77
_csi_realloc (csi_t *ctx, void *ptr, int size)
78
3.20k
{
79
3.20k
    return realloc (ptr, size);
80
3.20k
}
81
82
void
83
_csi_free (csi_t *ctx, void *ptr)
84
3.25M
{
85
3.25M
    if (_csi_unlikely (ptr == NULL))
86
0
  return;
87
88
3.25M
    free (ptr);
89
3.25M
}
90
91
void *
92
_csi_perm_alloc (csi_t *ctx, int size)
93
1.77M
{
94
1.77M
    csi_chunk_t *chunk;
95
1.77M
    void *ptr;
96
97
1.77M
    size = (size + sizeof (void *)-1) & -sizeof (void *);
98
99
1.77M
    chunk = ctx->perm_chunk;
100
1.77M
    if (chunk == NULL || chunk->rem < size) {
101
12.5k
  int chunk_size = (size + 8191) & -8192;
102
12.5k
  chunk = _csi_alloc (ctx, sizeof (csi_chunk_t) + chunk_size);
103
12.5k
  if (_csi_unlikely (chunk == NULL))
104
0
      return NULL;
105
106
12.5k
  chunk->rem = chunk_size;
107
12.5k
  chunk->ptr = (char *) (chunk + 1);
108
12.5k
  chunk->next = ctx->perm_chunk;
109
12.5k
  ctx->perm_chunk = chunk;
110
12.5k
    }
111
112
1.77M
    ptr = chunk->ptr;
113
1.77M
    chunk->ptr += size;
114
1.77M
    chunk->rem -= size;
115
116
1.77M
    return ptr;
117
1.77M
}
118
119
void *
120
_csi_slab_alloc (csi_t *ctx, int size)
121
6.02M
{
122
#if CSI_DEBUG_MALLOC
123
    return malloc (size);
124
#else
125
6.02M
    int chunk_size;
126
6.02M
    csi_chunk_t *chunk;
127
6.02M
    void *ptr;
128
129
6.02M
    chunk_size = 2 * sizeof (void *);
130
6.02M
    chunk_size = (size + chunk_size - 1) / chunk_size;
131
132
6.02M
    if (ctx->slabs[chunk_size].free_list) {
133
594k
  ptr = ctx->slabs[chunk_size].free_list;
134
594k
  ctx->slabs[chunk_size].free_list = *(void **) ptr;
135
594k
  return ptr;
136
594k
    }
137
138
5.42M
    chunk = ctx->slabs[chunk_size].chunk;
139
5.42M
    if (chunk == NULL || ! chunk->rem) {
140
33.7k
  int cnt = MAX (128, 8192 / (chunk_size * 2 * sizeof (void *)));
141
142
33.7k
  chunk = _csi_alloc (ctx,
143
33.7k
          sizeof (csi_chunk_t) +
144
33.7k
          cnt * chunk_size * 2 * sizeof (void *));
145
33.7k
  if (_csi_unlikely (chunk == NULL))
146
0
      return NULL;
147
148
33.7k
  chunk->rem = cnt;
149
33.7k
  chunk->ptr = (char *) (chunk + 1);
150
33.7k
  chunk->next = ctx->slabs[chunk_size].chunk;
151
33.7k
  ctx->slabs[chunk_size].chunk = chunk;
152
33.7k
    }
153
154
5.42M
    ptr = chunk->ptr;
155
5.42M
    chunk->ptr += chunk_size * 2 * sizeof (void *);
156
5.42M
    chunk->rem--;
157
158
5.42M
    return ptr;
159
5.42M
#endif
160
5.42M
}
161
162
void
163
_csi_slab_free (csi_t *ctx, void *ptr, int size)
164
5.99M
{
165
5.99M
    int chunk_size;
166
5.99M
    void **free_list;
167
168
5.99M
    if (_csi_unlikely (ptr == NULL))
169
0
  return;
170
171
#if CSI_DEBUG_MALLOC
172
    free (ptr);
173
#else
174
5.99M
    chunk_size = 2 * sizeof (void *);
175
5.99M
    chunk_size = (size + chunk_size - 1) / chunk_size;
176
177
5.99M
    free_list = ptr;
178
5.99M
    *free_list = ctx->slabs[chunk_size].free_list;
179
5.99M
    ctx->slabs[chunk_size].free_list = ptr;
180
5.99M
#endif
181
5.99M
}
182
183
csi_status_t
184
_csi_stack_push (csi_t *ctx, csi_stack_t *stack,
185
     const csi_object_t *obj)
186
11.0M
{
187
11.0M
    if (_csi_unlikely (stack->len == stack->size))
188
2.80k
  return _csi_stack_push_internal (ctx, stack, obj);
189
190
11.0M
    stack->objects[stack->len++] = *obj;
191
11.0M
    return CSI_STATUS_SUCCESS;
192
11.0M
}
193
194
static void
195
_csi_perm_fini (csi_t *ctx)
196
6.20k
{
197
18.7k
    while (ctx->perm_chunk != NULL) {
198
12.5k
  csi_chunk_t *chunk = ctx->perm_chunk;
199
12.5k
  ctx->perm_chunk = chunk->next;
200
12.5k
  _csi_free (ctx, chunk);
201
12.5k
    }
202
6.20k
}
203
204
static void
205
_csi_slab_fini (csi_t *ctx)
206
6.20k
{
207
6.20k
    unsigned int i;
208
209
105k
    for (i = 0; i < sizeof (ctx->slabs) / sizeof (ctx->slabs[0]); i++) {
210
133k
  while (ctx->slabs[i].chunk != NULL) {
211
33.7k
      csi_chunk_t *chunk = ctx->slabs[i].chunk;
212
33.7k
      ctx->slabs[i].chunk = chunk->next;
213
33.7k
      _csi_free (ctx, chunk);
214
33.7k
  }
215
99.3k
    }
216
6.20k
}
217
218
static csi_status_t
219
_add_operator (csi_t *ctx,
220
         csi_dictionary_t *dict,
221
         const csi_operator_def_t *def)
222
1.21M
{
223
1.21M
    csi_object_t name;
224
1.21M
    csi_object_t operator;
225
1.21M
    csi_status_t status;
226
227
1.21M
    status = csi_name_new_static (ctx, &name, def->name);
228
1.21M
    if (status)
229
0
  return status;
230
231
1.21M
    csi_operator_new (&operator, def->op);
232
233
1.21M
    return csi_dictionary_put (ctx, dict, name.datum.name, &operator);
234
1.21M
}
235
236
static csi_status_t
237
_add_integer_constant (csi_t *ctx,
238
           csi_dictionary_t *dict,
239
           const csi_integer_constant_def_t *def)
240
533k
{
241
533k
    csi_object_t name;
242
533k
    csi_object_t constant;
243
533k
    csi_status_t status;
244
245
533k
    status = csi_name_new_static (ctx, &name, def->name);
246
533k
    if (status)
247
0
  return status;
248
249
533k
    csi_integer_new (&constant, def->value);
250
251
533k
    return csi_dictionary_put (ctx, dict, name.datum.name, &constant);
252
533k
}
253
254
static csi_status_t
255
_add_real_constant (csi_t *ctx,
256
        csi_dictionary_t *dict,
257
        const csi_real_constant_def_t *def)
258
24.8k
{
259
24.8k
    csi_object_t name;
260
24.8k
    csi_object_t constant;
261
24.8k
    csi_status_t status;
262
263
24.8k
    status = csi_name_new_static (ctx, &name, def->name);
264
24.8k
    if (status)
265
0
  return status;
266
267
24.8k
    csi_real_new (&constant, def->value);
268
269
24.8k
    return csi_dictionary_put (ctx, dict, name.datum.name, &constant);
270
24.8k
}
271
272
static csi_status_t
273
_init_dictionaries (csi_t *ctx)
274
6.20k
{
275
6.20k
    csi_status_t status;
276
6.20k
    csi_stack_t *stack;
277
6.20k
    csi_object_t obj;
278
6.20k
    csi_dictionary_t *dict, *opcodes;
279
6.20k
    const csi_operator_def_t *odef;
280
6.20k
    const csi_integer_constant_def_t *idef;
281
6.20k
    const csi_real_constant_def_t *rdef;
282
6.20k
    unsigned n;
283
284
6.20k
    stack = &ctx->dstack;
285
286
6.20k
    status = _csi_stack_init (ctx, stack, 4);
287
6.20k
    if (_csi_unlikely (status))
288
0
  return status;
289
290
    /* systemdict */
291
6.20k
    status = csi_dictionary_new (ctx, &obj);
292
6.20k
    if (_csi_unlikely (status))
293
0
  return status;
294
295
6.20k
    status = _csi_stack_push (ctx, stack, &obj);
296
6.20k
    if (_csi_unlikely (status))
297
0
  return status;
298
299
6.20k
    dict = obj.datum.dictionary;
300
301
6.20k
    status = csi_dictionary_new (ctx, &obj);
302
6.20k
    if (_csi_unlikely (status))
303
0
  return status;
304
305
6.20k
    opcodes = obj.datum.dictionary;
306
307
6.20k
    n = 0;
308
6.20k
    csi_integer_new (&obj, n);
309
6.20k
    status = csi_dictionary_put (ctx, opcodes, 0, &obj);
310
6.20k
    if (_csi_unlikely (status))
311
0
  return status;
312
6.20k
    ctx->opcode[n++] = NULL;
313
314
    /* fill systemdict with operators */
315
1.21M
    for (odef = _csi_operators (); odef->name != NULL; odef++) {
316
1.21M
  status = _add_operator (ctx, dict, odef);
317
1.21M
  if (_csi_unlikely (status))
318
0
      return status;
319
320
1.21M
  if (! csi_dictionary_has (opcodes, (csi_name_t) odef->op)) {
321
863k
      csi_integer_new (&obj, n);
322
863k
      status = csi_dictionary_put (ctx,
323
863k
                             opcodes, (csi_name_t) odef->op, &obj);
324
863k
      if (_csi_unlikely (status))
325
0
    return status;
326
327
863k
      assert (n < sizeof (ctx->opcode) / sizeof (ctx->opcode[0]));
328
863k
      ctx->opcode[n++] = odef->op;
329
863k
  }
330
1.21M
    }
331
6.20k
    csi_dictionary_free (ctx, opcodes);
332
333
    /* add constants */
334
540k
    for (idef = _csi_integer_constants (); idef->name != NULL; idef++) {
335
533k
  status = _add_integer_constant (ctx, dict, idef);
336
533k
  if (_csi_unlikely (status))
337
0
      return status;
338
533k
    }
339
31.0k
    for (rdef = _csi_real_constants (); rdef->name != NULL; rdef++) {
340
24.8k
  status = _add_real_constant (ctx, dict, rdef);
341
24.8k
  if (_csi_unlikely (status))
342
0
      return status;
343
24.8k
    }
344
345
    /* and seal */
346
    //dict.type &= ~CSI_OBJECT_ATTR_WRITABLE;
347
348
349
    /* globaldict */
350
6.20k
    status = csi_dictionary_new (ctx, &obj);
351
6.20k
    if (_csi_unlikely (status))
352
0
  return status;
353
6.20k
    status = _csi_stack_push (ctx, stack, &obj);
354
6.20k
    if (_csi_unlikely (status))
355
0
  return status;
356
357
    /* userdict */
358
6.20k
    status = csi_dictionary_new (ctx, &obj);
359
6.20k
    if (_csi_unlikely (status))
360
0
  return status;
361
6.20k
    status = _csi_stack_push (ctx, stack, &obj);
362
6.20k
    if (_csi_unlikely (status))
363
0
  return status;
364
365
6.20k
    return CSI_STATUS_SUCCESS;
366
6.20k
}
367
368
/* intern string */
369
370
typedef struct _cairo_intern_string {
371
    csi_hash_entry_t hash_entry;
372
    int len;
373
    char *string;
374
} csi_intern_string_t;
375
376
static unsigned long
377
_intern_string_hash (const char *str, int len)
378
7.57M
{
379
7.57M
    const signed char *p = (const signed char *) str;
380
7.57M
    if (len > 0) {
381
7.56M
  unsigned int h = *p;
382
383
35.6M
  while (--len)
384
28.0M
      h = (h << 5) - h + *++p;
385
386
7.56M
  return h;
387
7.56M
    }
388
1.25k
    return 0;
389
7.57M
}
390
391
static cairo_bool_t
392
_intern_string_equal (const void *_a, const void *_b)
393
5.79M
{
394
5.79M
    const csi_intern_string_t *a = _a;
395
5.79M
    const csi_intern_string_t *b = _b;
396
397
5.79M
    if (a->len != b->len)
398
1.91k
  return FALSE;
399
400
5.79M
    return memcmp (a->string, b->string, a->len) == 0;
401
5.79M
}
402
403
static void
404
_csi_init (csi_t *ctx)
405
6.20k
{
406
6.20k
    csi_status_t status;
407
408
6.20k
    memset (ctx, 0, sizeof (*ctx));
409
410
6.20k
    ctx->status = CSI_STATUS_SUCCESS;
411
6.20k
    ctx->ref_count = 1;
412
6.20k
    ctx->scanner.line_number = -1;
413
414
6.20k
    status = _csi_hash_table_init (&ctx->strings, _intern_string_equal);
415
6.20k
    if (status)
416
0
  goto FAIL;
417
418
6.20k
    status = _csi_stack_init (ctx, &ctx->ostack, 2048);
419
6.20k
    if (status)
420
0
  goto FAIL;
421
6.20k
    status = _init_dictionaries (ctx);
422
6.20k
    if (status)
423
0
  goto FAIL;
424
425
6.20k
    status = _csi_scanner_init (ctx, &ctx->scanner);
426
6.20k
    if (status)
427
0
  goto FAIL;
428
429
6.20k
    return;
430
431
6.20k
FAIL:
432
0
    if (ctx->status == CSI_STATUS_SUCCESS)
433
0
  ctx->status = status;
434
0
}
435
436
static void
437
_csi_finish (csi_t *ctx)
438
6.20k
{
439
6.20k
    _csi_stack_fini (ctx, &ctx->ostack);
440
6.20k
    _csi_stack_fini (ctx, &ctx->dstack);
441
6.20k
    _csi_scanner_fini (ctx, &ctx->scanner);
442
443
6.20k
    _csi_hash_table_fini (&ctx->strings);
444
6.20k
}
445
446
csi_status_t
447
_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj)
448
7.92k
{
449
7.92k
    return csi_dictionary_put (ctx,
450
7.92k
      ctx->dstack.objects[ctx->dstack.len-1].datum.dictionary,
451
7.92k
      name,
452
7.92k
      obj);
453
7.92k
}
454
455
csi_status_t
456
_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj)
457
4.91M
{
458
4.91M
    int i;
459
460
14.7M
    for (i = ctx->dstack.len; i--; ) {
461
14.7M
  csi_dictionary_t *dict;
462
14.7M
  csi_dictionary_entry_t *entry;
463
464
14.7M
  dict = ctx->dstack.objects[i].datum.dictionary;
465
14.7M
  entry = _csi_hash_table_lookup (&dict->hash_table,
466
14.7M
          (csi_hash_entry_t *) &name);
467
14.7M
  if (entry != NULL) {
468
4.90M
      *obj = entry->value;
469
4.90M
      return CSI_STATUS_SUCCESS;
470
4.90M
  }
471
14.7M
    }
472
473
1.00k
    return _csi_error (CSI_STATUS_INVALID_SCRIPT);
474
4.91M
}
475
476
csi_status_t
477
_csi_name_undefine (csi_t *ctx, csi_name_t name)
478
1
{
479
1
    unsigned int i;
480
481
3
    for (i = ctx->dstack.len; --i; ) {
482
2
  if (csi_dictionary_has (ctx->dstack.objects[i].datum.dictionary,
483
2
        name))
484
0
  {
485
0
      csi_dictionary_remove (ctx,
486
0
           ctx->dstack.objects[i].datum.dictionary,
487
0
           name);
488
0
      return CSI_STATUS_SUCCESS;
489
0
  }
490
2
    }
491
492
1
    return _csi_error (CSI_STATUS_INVALID_SCRIPT);
493
1
}
494
495
csi_status_t
496
_csi_intern_string (csi_t *ctx, const char **str_inout, int len)
497
7.57M
{
498
7.57M
    char *str = (char *) *str_inout;
499
7.57M
    csi_intern_string_t tmpl, *istring;
500
7.57M
    csi_status_t status = CSI_STATUS_SUCCESS;
501
502
7.57M
    tmpl.hash_entry.hash = _intern_string_hash (str, len);
503
7.57M
    tmpl.len = len;
504
7.57M
    tmpl.string = (char *) str;
505
506
7.57M
    istring = _csi_hash_table_lookup (&ctx->strings, &tmpl.hash_entry);
507
7.57M
    if (istring == NULL) {
508
1.77M
  istring = _csi_perm_alloc (ctx,
509
1.77M
           sizeof (csi_intern_string_t) + len + 1);
510
1.77M
  if (istring != NULL) {
511
1.77M
      istring->hash_entry.hash = tmpl.hash_entry.hash;
512
1.77M
      istring->len = tmpl.len;
513
1.77M
      istring->string = (char *) (istring + 1);
514
1.77M
      memcpy (istring->string, str, len);
515
1.77M
      istring->string[len] = '\0';
516
517
1.77M
      status = _csi_hash_table_insert (&ctx->strings,
518
1.77M
               &istring->hash_entry);
519
1.77M
      if (_csi_unlikely (status)) {
520
0
    _csi_free (ctx, istring);
521
0
    return status;
522
0
      }
523
1.77M
  } else
524
0
      return _csi_error (CSI_STATUS_NO_MEMORY);
525
1.77M
    }
526
527
7.57M
    *str_inout = istring->string;
528
7.57M
    return CSI_STATUS_SUCCESS;
529
7.57M
}
530
531
/* Public */
532
533
static csi_t _csi_nil = { -1, CSI_STATUS_NO_MEMORY };
534
535
csi_t *
536
cairo_script_interpreter_create (void)
537
6.20k
{
538
6.20k
    csi_t *ctx;
539
540
6.20k
    ctx = malloc (sizeof (csi_t));
541
6.20k
    if (ctx == NULL)
542
0
  return (csi_t *) &_csi_nil;
543
544
6.20k
    _csi_init (ctx);
545
546
6.20k
    return ctx;
547
6.20k
}
548
549
void
550
cairo_script_interpreter_install_hooks (csi_t *ctx,
551
          const csi_hooks_t *hooks)
552
6.20k
{
553
6.20k
    if (ctx->status)
554
0
  return;
555
556
6.20k
    ctx->hooks = *hooks;
557
6.20k
}
558
559
cairo_status_t
560
cairo_script_interpreter_run (csi_t *ctx, const char *filename)
561
0
{
562
0
    csi_object_t file;
563
564
0
    if (ctx->status)
565
0
  return ctx->status;
566
0
    if (ctx->finished)
567
0
  return ctx->status = CSI_STATUS_INTERPRETER_FINISHED;
568
569
0
    ctx->status = csi_file_new (ctx, &file, filename, "r");
570
0
    if (ctx->status)
571
0
  return ctx->status;
572
573
0
    file.type |= CSI_OBJECT_ATTR_EXECUTABLE;
574
575
0
    ctx->status = csi_object_execute (ctx, &file);
576
0
    csi_object_free (ctx, &file);
577
578
0
    return ctx->status;
579
0
}
580
581
cairo_status_t
582
cairo_script_interpreter_feed_stream (csi_t *ctx, FILE *stream)
583
0
{
584
0
    csi_object_t file;
585
586
0
    if (ctx->status)
587
0
  return ctx->status;
588
0
    if (ctx->finished)
589
0
  return ctx->status = CSI_STATUS_INTERPRETER_FINISHED;
590
591
0
    ctx->status = csi_file_new_for_stream (ctx, &file, stream);
592
0
    if (ctx->status)
593
0
  return ctx->status;
594
595
0
    file.type |= CSI_OBJECT_ATTR_EXECUTABLE;
596
597
0
    ctx->status = csi_object_execute (ctx, &file);
598
0
    csi_object_free (ctx, &file);
599
600
0
    return ctx->status;
601
0
}
602
603
cairo_status_t
604
cairo_script_interpreter_feed_string (csi_t *ctx, const char *line, int len)
605
6.20k
{
606
6.20k
    csi_object_t file;
607
608
6.20k
    if (ctx->status)
609
0
  return ctx->status;
610
6.20k
    if (ctx->finished)
611
0
  return ctx->status = CSI_STATUS_INTERPRETER_FINISHED;
612
613
6.20k
    if (len < 0)
614
0
  len = strlen (line);
615
6.20k
    ctx->status = csi_file_new_for_bytes (ctx, &file, line, len);
616
6.20k
    if (ctx->status)
617
0
  return ctx->status;
618
619
6.20k
    file.type |= CSI_OBJECT_ATTR_EXECUTABLE;
620
621
6.20k
    ctx->status = csi_object_execute (ctx, &file);
622
6.20k
    csi_object_free (ctx, &file);
623
624
6.20k
    return ctx->status;
625
6.20k
}
626
627
unsigned int
628
cairo_script_interpreter_get_line_number (csi_t *ctx)
629
0
{
630
0
    return ctx->scanner.line_number + 1; /* 1 index based */
631
0
}
632
633
csi_t *
634
cairo_script_interpreter_reference (csi_t *ctx)
635
0
{
636
0
    ctx->ref_count++;
637
0
    return ctx;
638
0
}
639
640
cairo_status_t
641
cairo_script_interpreter_finish (csi_t *ctx)
642
6.20k
{
643
6.20k
    csi_status_t status;
644
645
6.20k
    status = ctx->status;
646
6.20k
    if (! ctx->finished) {
647
6.20k
  _csi_finish (ctx);
648
6.20k
  ctx->finished = 1;
649
6.20k
    } else if (status == CSI_STATUS_SUCCESS) {
650
0
  status = ctx->status = CSI_STATUS_INTERPRETER_FINISHED;
651
0
    }
652
653
6.20k
    return status;
654
6.20k
}
655
656
static void
657
_csi_fini (csi_t *ctx)
658
6.20k
{
659
6.20k
    if (! ctx->finished)
660
0
  _csi_finish (ctx);
661
662
6.20k
    if (ctx->free_array != NULL)
663
832
  csi_array_free (ctx, ctx->free_array);
664
6.20k
    if (ctx->free_dictionary != NULL)
665
6.20k
  csi_dictionary_free (ctx, ctx->free_dictionary);
666
6.20k
    if (ctx->free_string != NULL)
667
573
  csi_string_free (ctx, ctx->free_string);
668
669
6.20k
    _csi_slab_fini (ctx);
670
6.20k
    _csi_perm_fini (ctx);
671
6.20k
}
672
673
cairo_status_t
674
cairo_script_interpreter_destroy (csi_t *ctx)
675
6.20k
{
676
6.20k
    csi_status_t status;
677
678
6.20k
    status = ctx->status;
679
6.20k
    if (--ctx->ref_count)
680
0
  return status;
681
682
6.20k
    _csi_fini (ctx);
683
6.20k
    free (ctx);
684
685
6.20k
    return status;
686
6.20k
}
687
688
cairo_status_t
689
cairo_script_interpreter_translate_stream (FILE *stream,
690
                                     cairo_write_func_t write_func,
691
             void *closure)
692
0
{
693
0
    csi_t ctx;
694
0
    csi_object_t src;
695
0
    csi_status_t status;
696
697
0
    _csi_init (&ctx);
698
699
0
    status = csi_file_new_for_stream (&ctx, &src, stream);
700
0
    if (status)
701
0
  goto BAIL;
702
703
0
    status = _csi_translate_file (&ctx, src.datum.file, write_func, closure);
704
705
0
BAIL:
706
0
    csi_object_free (&ctx, &src);
707
0
    _csi_fini (&ctx);
708
709
0
    return status;
710
0
}