Coverage Report

Created: 2026-10-28 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cairo/util/cairo-script/cairo-script-objects.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 <limits.h> /* INT_MAX */
40
#include <string.h>
41
42
csi_status_t
43
csi_array_new (csi_t *ctx,
44
         csi_integer_t initial_size,
45
         csi_object_t *obj)
46
47
2.71M
{
48
2.71M
    csi_array_t *array;
49
50
2.71M
    if (ctx->free_array == NULL ||
51
1.06k
  ctx->free_array->stack.size <= initial_size)
52
2.70M
    {
53
2.70M
  csi_status_t status;
54
55
2.70M
  array = _csi_slab_alloc (ctx, sizeof (csi_array_t));
56
2.70M
  if (_csi_unlikely (array == NULL))
57
0
      return _csi_error (CSI_STATUS_NO_MEMORY);
58
59
2.70M
  status = _csi_stack_init (ctx, &array->stack,
60
2.70M
          initial_size ? initial_size : 32);
61
2.70M
  if (_csi_unlikely (status)) {
62
0
      _csi_slab_free (ctx, array, sizeof (csi_array_t));
63
0
      return status;
64
0
  }
65
2.70M
    } else {
66
553
  array = ctx->free_array;
67
553
  ctx->free_array = NULL;
68
553
    }
69
70
2.71M
    array->base.type = CSI_OBJECT_TYPE_ARRAY;
71
2.71M
    array->base.ref = 1;
72
73
2.71M
    obj->type = CSI_OBJECT_TYPE_ARRAY;
74
2.71M
    obj->datum.array = array;
75
76
2.71M
    return CSI_STATUS_SUCCESS;
77
2.71M
}
78
79
csi_status_t
80
csi_array_put (csi_t *ctx,
81
         csi_array_t *array,
82
         csi_integer_t elem,
83
         csi_object_t *value)
84
0
{
85
0
    if (_csi_unlikely (elem < 0))
86
0
  return _csi_error (CSI_STATUS_INVALID_SCRIPT);
87
88
0
    if (_csi_unlikely (elem >= array->stack.len)) {
89
0
  csi_status_t status;
90
91
0
  status = _csi_stack_grow (ctx, &array->stack, elem + 1);
92
0
  if (_csi_unlikely (status))
93
0
      return status;
94
95
0
  memset (array->stack.objects + array->stack.len,
96
0
    0, (elem - array->stack.len + 1) * sizeof (csi_object_t));
97
0
  array->stack.len = elem + 1;
98
0
    }
99
100
0
    csi_object_free (ctx, &array->stack.objects[elem]);
101
0
    array->stack.objects[elem] = *csi_object_reference (value);
102
103
0
    return CSI_STATUS_SUCCESS;
104
0
}
105
106
csi_status_t
107
csi_array_get (csi_t *ctx,
108
         csi_array_t *array,
109
         csi_integer_t elem,
110
         csi_object_t *value)
111
1
{
112
1
    if (_csi_unlikely (elem < 0))
113
0
  return _csi_error (CSI_STATUS_INVALID_SCRIPT);
114
115
1
    if (_csi_unlikely (elem > array->stack.len))
116
1
  return _csi_error (CSI_STATUS_INVALID_SCRIPT);
117
118
0
    *value = array->stack.objects[elem];
119
0
    return CSI_STATUS_SUCCESS;
120
1
}
121
122
csi_status_t
123
csi_array_append (csi_t *ctx,
124
      csi_array_t *array,
125
      csi_object_t *obj)
126
908k
{
127
908k
    return _csi_stack_push (ctx, &array->stack, csi_object_reference (obj));
128
908k
}
129
130
inline csi_status_t
131
_csi_array_execute (csi_t *ctx, csi_array_t *array)
132
0
{
133
0
    csi_integer_t i;
134
0
    csi_status_t status;
135
136
0
    if (_csi_unlikely (array->stack.len == 0))
137
0
  return CSI_STATUS_SUCCESS;
138
139
0
    for (i = 0; i < array->stack.len; i++) {
140
0
  csi_object_t *obj = &array->stack.objects[i];
141
142
0
  if (obj->type & CSI_OBJECT_ATTR_EXECUTABLE) {
143
0
      if (obj->type == (CSI_OBJECT_TYPE_ARRAY |
144
0
            CSI_OBJECT_ATTR_EXECUTABLE))
145
0
      {
146
0
    status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
147
0
      }
148
0
      else
149
0
    status = csi_object_execute (ctx, &array->stack.objects[i]);
150
0
  } else
151
0
      status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
152
0
  if (_csi_unlikely (status))
153
0
      return status;
154
0
    }
155
156
0
    return CSI_STATUS_SUCCESS;
157
0
}
158
159
void
160
csi_array_free (csi_t *ctx, csi_array_t *array)
161
2.68M
{
162
#if CSI_DEBUG_MALLOC
163
    _csi_stack_fini (ctx, &array->stack);
164
    _csi_slab_free (ctx, array, sizeof (csi_array_t));
165
#else
166
2.68M
    csi_integer_t n;
167
168
3.87M
    for (n = 0; n < array->stack.len; n++)
169
1.18M
  csi_object_free (ctx, &array->stack.objects[n]);
170
2.68M
    array->stack.len = 0;
171
172
2.68M
    if (ctx->free_array != NULL) {
173
2.68M
  if (array->stack.size > ctx->free_array->stack.size) {
174
78
      csi_array_t *tmp = ctx->free_array;
175
78
      ctx->free_array = array;
176
78
      array = tmp;
177
78
  }
178
179
2.68M
  _csi_stack_fini (ctx, &array->stack);
180
2.68M
  _csi_slab_free (ctx, array, sizeof (csi_array_t));
181
2.68M
    } else
182
1.38k
  ctx->free_array = array;
183
2.68M
#endif
184
2.68M
}
185
186
static cairo_bool_t
187
_dictionary_name_equal (const void *_a, const void *_b)
188
5.26M
{
189
5.26M
    return TRUE;
190
5.26M
}
191
192
csi_status_t
193
csi_dictionary_new (csi_t *ctx,
194
        csi_object_t *obj)
195
196
166k
{
197
166k
    csi_dictionary_t *dict;
198
199
166k
    if (ctx->free_dictionary != NULL) {
200
6.97k
  dict = ctx->free_dictionary;
201
6.97k
  ctx->free_dictionary = NULL;
202
159k
    } else {
203
159k
  csi_status_t status;
204
205
159k
  dict = _csi_slab_alloc (ctx, sizeof (csi_dictionary_t));
206
159k
  if (_csi_unlikely (dict == NULL))
207
0
      return _csi_error (CSI_STATUS_NO_MEMORY);
208
209
159k
  status = _csi_hash_table_init (&dict->hash_table,
210
159k
               _dictionary_name_equal);
211
159k
  if (_csi_unlikely (status)) {
212
0
      _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
213
0
      return status;
214
0
  }
215
159k
    }
216
217
166k
    dict->base.type = CSI_OBJECT_TYPE_DICTIONARY;
218
166k
    dict->base.ref = 1;
219
220
166k
    obj->type = CSI_OBJECT_TYPE_DICTIONARY;
221
166k
    obj->datum.dictionary = dict;
222
223
166k
    return CSI_STATUS_SUCCESS;
224
166k
}
225
226
struct _dictionary_entry_pluck {
227
    csi_t *ctx;
228
    csi_hash_table_t *hash_table;
229
};
230
231
static void
232
_dictionary_entry_pluck (void *entry, void *data)
233
2.63M
{
234
2.63M
    csi_dictionary_entry_t *dict_entry;
235
2.63M
    struct _dictionary_entry_pluck *pluck_data;
236
237
2.63M
    dict_entry = entry;
238
2.63M
    pluck_data = data;
239
240
2.63M
    _csi_hash_table_remove (pluck_data->hash_table, entry);
241
2.63M
    csi_object_free (pluck_data->ctx, &dict_entry->value);
242
2.63M
    _csi_slab_free (pluck_data->ctx, entry, sizeof (csi_dictionary_entry_t));
243
2.63M
}
244
245
void
246
csi_dictionary_free (csi_t *ctx,
247
         csi_dictionary_t *dict)
248
172k
{
249
172k
    struct _dictionary_entry_pluck data;
250
251
172k
    data.ctx = ctx;
252
172k
    data.hash_table = &dict->hash_table;
253
172k
    _csi_hash_table_foreach (&dict->hash_table,
254
172k
           _dictionary_entry_pluck,
255
172k
           &data);
256
257
#if CSI_DEBUG_MALLOC
258
    _csi_hash_table_fini (&dict->hash_table);
259
    _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
260
#else
261
172k
    if (ctx->free_dictionary != NULL) {
262
159k
  _csi_hash_table_fini (&dict->hash_table);
263
159k
  _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
264
159k
    } else
265
13.1k
  ctx->free_dictionary = dict;
266
172k
#endif
267
172k
}
268
269
csi_status_t
270
csi_dictionary_put (csi_t *ctx,
271
        csi_dictionary_t *dict,
272
        csi_name_t name,
273
        csi_object_t *value)
274
2.64M
{
275
2.64M
    csi_dictionary_entry_t *entry;
276
2.64M
    csi_status_t status;
277
278
2.64M
    entry = _csi_hash_table_lookup (&dict->hash_table,
279
2.64M
            (csi_hash_entry_t *) &name);
280
2.64M
    if (entry != NULL) {
281
  /* replace the existing entry */
282
7.92k
  csi_object_free (ctx, &entry->value);
283
7.92k
  entry->value = *csi_object_reference (value);
284
7.92k
  return CSI_STATUS_SUCCESS;
285
7.92k
    }
286
287
2.63M
    entry = _csi_slab_alloc (ctx, sizeof (*entry));
288
2.63M
    if (_csi_unlikely (entry == NULL))
289
0
  return _csi_error (CSI_STATUS_NO_MEMORY);
290
291
2.63M
    entry->hash_entry.hash = name;
292
2.63M
    status = _csi_hash_table_insert (&dict->hash_table, &entry->hash_entry);
293
2.63M
    if (_csi_unlikely (status)) {
294
0
  _csi_slab_free (ctx, entry, sizeof (*entry));
295
0
  return status;
296
0
    }
297
298
2.63M
    entry->value = *csi_object_reference (value);
299
300
2.63M
    return CSI_STATUS_SUCCESS;
301
2.63M
}
302
303
csi_status_t
304
csi_dictionary_get (csi_t *ctx,
305
        csi_dictionary_t *dict,
306
        csi_name_t name,
307
        csi_object_t *value)
308
4
{
309
4
    csi_dictionary_entry_t *entry;
310
311
4
    entry = _csi_hash_table_lookup (&dict->hash_table,
312
4
            (csi_hash_entry_t *) &name);
313
4
    if (_csi_unlikely (entry == NULL))
314
4
  return _csi_error (CSI_STATUS_INVALID_SCRIPT);
315
316
0
    *value = entry->value;
317
0
    return CSI_STATUS_SUCCESS;
318
4
}
319
320
csi_boolean_t
321
csi_dictionary_has (csi_dictionary_t *dict,
322
        csi_name_t name)
323
1.21M
{
324
1.21M
    return _csi_hash_table_lookup (&dict->hash_table,
325
1.21M
           (csi_hash_entry_t *) &name) != NULL;
326
1.21M
}
327
328
void
329
csi_dictionary_remove (csi_t *ctx,
330
           csi_dictionary_t *dict,
331
           csi_name_t name)
332
0
{
333
0
    csi_dictionary_entry_t *entry;
334
335
0
    entry = _csi_hash_table_lookup (&dict->hash_table,
336
0
            (csi_hash_entry_t *) &name);
337
0
    if (entry != NULL) {
338
0
  _csi_hash_table_remove (&dict->hash_table, &entry->hash_entry);
339
0
  csi_object_free (ctx, &entry->value);
340
0
  _csi_slab_free (ctx, entry, sizeof (csi_dictionary_entry_t));
341
0
    }
342
0
}
343
344
csi_status_t
345
csi_matrix_new (csi_t *ctx,
346
    csi_object_t *obj)
347
2.57k
{
348
2.57k
    csi_matrix_t *matrix;
349
350
2.57k
    matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
351
2.57k
    if (_csi_unlikely (matrix == NULL))
352
0
  return _csi_error (CSI_STATUS_NO_MEMORY);
353
354
2.57k
    matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
355
2.57k
    matrix->base.ref = 1;
356
2.57k
    cairo_matrix_init_identity (&matrix->matrix);
357
358
2.57k
    obj->type = CSI_OBJECT_TYPE_MATRIX;
359
2.57k
    obj->datum.matrix = matrix;
360
361
2.57k
    return CSI_STATUS_SUCCESS;
362
2.57k
}
363
364
csi_status_t
365
csi_matrix_new_from_array (csi_t *ctx,
366
         csi_object_t *obj,
367
         csi_array_t *array)
368
1
{
369
1
    csi_matrix_t *matrix;
370
371
1
    if (_csi_unlikely (array->stack.len != 6))
372
1
  return _csi_error (CSI_STATUS_INVALID_SCRIPT);
373
374
0
    matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
375
0
    if (_csi_unlikely (matrix == NULL))
376
0
  return _csi_error (CSI_STATUS_NO_MEMORY);
377
378
0
    matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
379
0
    matrix->base.ref = 1;
380
0
    cairo_matrix_init (&matrix->matrix,
381
0
           csi_number_get_value (&array->stack.objects[0]),
382
0
           csi_number_get_value (&array->stack.objects[1]),
383
0
           csi_number_get_value (&array->stack.objects[2]),
384
0
           csi_number_get_value (&array->stack.objects[3]),
385
0
           csi_number_get_value (&array->stack.objects[4]),
386
0
           csi_number_get_value (&array->stack.objects[5]));
387
388
0
    obj->type = CSI_OBJECT_TYPE_MATRIX;
389
0
    obj->datum.matrix = matrix;
390
391
0
    return CSI_STATUS_SUCCESS;
392
0
}
393
394
csi_status_t
395
csi_matrix_new_from_matrix (csi_t *ctx,
396
          csi_object_t *obj,
397
          const cairo_matrix_t *m)
398
1
{
399
1
    csi_matrix_t *matrix;
400
401
1
    matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
402
1
    if (_csi_unlikely (matrix == NULL))
403
0
  return _csi_error (CSI_STATUS_NO_MEMORY);
404
405
1
    matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
406
1
    matrix->base.ref = 1;
407
1
    matrix->matrix = *m;
408
409
1
    obj->type = CSI_OBJECT_TYPE_MATRIX;
410
1
    obj->datum.matrix = matrix;
411
412
1
    return CSI_STATUS_SUCCESS;
413
1
}
414
415
csi_status_t
416
csi_matrix_new_from_values (csi_t *ctx,
417
          csi_object_t *obj,
418
          double v[6])
419
1.76k
{
420
1.76k
    csi_matrix_t *matrix;
421
422
1.76k
    matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
423
1.76k
    if (_csi_unlikely (matrix == NULL))
424
0
  return _csi_error (CSI_STATUS_NO_MEMORY);
425
426
1.76k
    matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
427
1.76k
    matrix->base.ref = 1;
428
1.76k
    cairo_matrix_init (&matrix->matrix, v[0], v[1], v[2], v[3], v[4], v[5]);
429
430
1.76k
    obj->type = CSI_OBJECT_TYPE_MATRIX;
431
1.76k
    obj->datum.matrix = matrix;
432
433
1.76k
    return CSI_STATUS_SUCCESS;
434
1.76k
}
435
436
void
437
csi_matrix_free (csi_t *ctx,
438
     csi_matrix_t *obj)
439
4.34k
{
440
4.34k
    _csi_slab_free (ctx, obj, sizeof (csi_matrix_t));
441
4.34k
}
442
443
444
csi_status_t
445
csi_name_new (csi_t *ctx,
446
        csi_object_t *obj,
447
        const char *str,
448
        int len)
449
5.80M
{
450
5.80M
    csi_status_t status;
451
452
5.80M
    status = _csi_intern_string (ctx, &str, len);
453
5.80M
    if (_csi_unlikely (status))
454
0
  return status;
455
456
5.80M
    obj->type = CSI_OBJECT_TYPE_NAME;
457
5.80M
    obj->datum.name = (csi_name_t) str;
458
459
5.80M
    return CSI_STATUS_SUCCESS;
460
5.80M
}
461
462
csi_status_t
463
csi_name_new_static (csi_t *ctx,
464
         csi_object_t *obj,
465
         const char *str)
466
1.76M
{
467
1.76M
    csi_status_t status;
468
469
1.76M
    status = _csi_intern_string (ctx, &str, strlen (str));
470
1.76M
    if (_csi_unlikely (status))
471
0
  return status;
472
473
1.76M
    obj->type = CSI_OBJECT_TYPE_NAME;
474
1.76M
    obj->datum.name = (csi_name_t) str;
475
476
1.76M
    return CSI_STATUS_SUCCESS;
477
1.76M
}
478
479
csi_status_t
480
csi_string_new (csi_t *ctx,
481
    csi_object_t *obj,
482
    const char *str,
483
    int len)
484
507k
{
485
507k
    csi_string_t *string;
486
487
507k
    if (len < 0)
488
616
  len = strlen (str);
489
507k
    if (_csi_unlikely (len >= INT_MAX))
490
1
  return _csi_error (CSI_STATUS_NO_MEMORY);
491
492
507k
    if (ctx->free_string == NULL || ctx->free_string->len <= len) {
493
502k
  string = _csi_slab_alloc (ctx, sizeof (csi_string_t));
494
502k
  if (_csi_unlikely (string == NULL))
495
0
      return _csi_error (CSI_STATUS_NO_MEMORY);
496
497
502k
  string->string = _csi_alloc (ctx, len + 1);
498
502k
  if (_csi_unlikely (string->string == NULL)) {
499
0
      _csi_slab_free (ctx, string, sizeof (csi_string_t));
500
0
      return _csi_error (CSI_STATUS_NO_MEMORY);
501
0
  }
502
502k
    } else {
503
4.62k
  string = ctx->free_string;
504
4.62k
  ctx->free_string = NULL;
505
4.62k
    }
506
507
507k
    if (str != NULL) {
508
502k
  memcpy (string->string, str, len);
509
502k
  string->string[len] = '\0';
510
502k
    }
511
507k
    string->len = len;
512
507k
    string->deflate = 0;
513
507k
    string->method = NONE;
514
515
507k
    string->base.type = CSI_OBJECT_TYPE_STRING;
516
507k
    string->base.ref = 1;
517
518
507k
    obj->type = CSI_OBJECT_TYPE_STRING;
519
507k
    obj->datum.string = string;
520
521
507k
    return CSI_STATUS_SUCCESS;
522
507k
}
523
524
csi_status_t
525
csi_string_deflate_new (csi_t *ctx,
526
      csi_object_t *obj,
527
      void *bytes,
528
      int in_len,
529
      int out_len)
530
616
{
531
616
    csi_status_t status;
532
616
    csi_string_t *string;
533
534
616
    status = csi_string_new (ctx, obj, bytes, in_len);
535
616
    if (_csi_unlikely (status))
536
0
  return status;
537
538
616
    string = obj->datum.string;
539
616
    string->deflate = out_len;
540
616
    string->method = ZLIB;
541
542
616
    return CSI_STATUS_SUCCESS;
543
616
}
544
545
csi_status_t
546
csi_string_new_from_bytes (csi_t *ctx,
547
                     csi_object_t *obj,
548
         char *bytes,
549
         unsigned int len)
550
0
{
551
0
    csi_string_t *string;
552
553
0
    if (_csi_unlikely (len >= INT_MAX))
554
0
  return _csi_error (CSI_STATUS_NO_MEMORY);
555
556
0
    string = _csi_slab_alloc (ctx, sizeof (csi_string_t));
557
0
    if (_csi_unlikely (string == NULL))
558
0
  return _csi_error (CSI_STATUS_NO_MEMORY);
559
560
0
    string->string = bytes;
561
0
    string->len = len;
562
0
    string->deflate = 0;
563
0
    string->method = NONE;
564
565
0
    string->base.type = CSI_OBJECT_TYPE_STRING;
566
0
    string->base.ref = 1;
567
568
0
    obj->type = CSI_OBJECT_TYPE_STRING;
569
0
    obj->datum.string = string;
570
571
0
    return CSI_STATUS_SUCCESS;
572
0
}
573
574
static inline csi_status_t
575
_csi_string_execute (csi_t *ctx, csi_string_t *string)
576
0
{
577
0
    csi_status_t status;
578
0
    csi_object_t obj;
579
580
0
    if (_csi_unlikely (string->len == 0))
581
0
  return CSI_STATUS_SUCCESS;
582
583
0
    status = csi_file_new_for_bytes (ctx, &obj, string->string, string->len);
584
0
    if (_csi_unlikely (status))
585
0
  return status;
586
587
0
    status = _csi_scan_file (ctx, obj.datum.file);
588
0
    csi_object_free (ctx, &obj);
589
590
0
    return status;
591
0
}
592
593
void
594
csi_string_free (csi_t *ctx, csi_string_t *string)
595
501k
{
596
#if CSI_DEBUG_MALLOC
597
    _csi_free (ctx, string->string);
598
    _csi_slab_free (ctx, string, sizeof (csi_string_t));
599
#else
600
501k
    if (ctx->free_string != NULL) {
601
496k
  if (string->len > ctx->free_string->len) {
602
1.20k
      csi_string_t *tmp = ctx->free_string;
603
1.20k
      ctx->free_string = string;
604
1.20k
      string = tmp;
605
1.20k
  }
606
607
496k
  _csi_free (ctx, string->string);
608
496k
  _csi_slab_free (ctx, string, sizeof (csi_string_t));
609
496k
    } else
610
5.20k
  ctx->free_string = string;
611
501k
#endif
612
501k
}
613
614
csi_status_t
615
csi_object_execute (csi_t *ctx, csi_object_t *obj)
616
5.92M
{
617
5.92M
    csi_status_t status;
618
5.92M
    csi_object_t indirect;
619
620
10.8M
 INDIRECT:
621
10.8M
    switch (obj->type & CSI_OBJECT_TYPE_MASK) {
622
4.90M
    case CSI_OBJECT_TYPE_NAME:
623
4.90M
  status = _csi_name_lookup (ctx, obj->datum.name, &indirect);
624
4.90M
  if (_csi_unlikely (status))
625
994
      return status;
626
4.90M
  if (indirect.type & CSI_OBJECT_ATTR_EXECUTABLE) {
627
4.90M
      obj = &indirect;
628
4.90M
      goto INDIRECT;
629
4.90M
  } else
630
1
      return _csi_push_ostack_copy (ctx, &indirect);
631
632
5.91M
    case CSI_OBJECT_TYPE_OPERATOR:
633
5.91M
  return obj->datum.op (ctx);
634
635
0
    case CSI_OBJECT_TYPE_ARRAY:
636
0
  return _csi_array_execute (ctx, obj->datum.array);
637
6.20k
    case CSI_OBJECT_TYPE_FILE:
638
6.20k
  return _csi_file_execute (ctx, obj->datum.file);
639
0
    case CSI_OBJECT_TYPE_STRING:
640
0
  return _csi_string_execute (ctx, obj->datum.string);
641
642
0
    default:
643
0
  return _csi_push_ostack_copy (ctx, obj);
644
10.8M
    }
645
10.8M
}
646
647
csi_object_t *
648
csi_object_reference (csi_object_t *obj)
649
3.58M
{
650
3.58M
    if (CSI_OBJECT_IS_CAIRO (obj)) {
651
58
  switch (obj->type & CSI_OBJECT_TYPE_MASK) {
652
0
  case CSI_OBJECT_TYPE_CONTEXT:
653
0
      cairo_reference (obj->datum.cr);
654
0
      break;
655
0
  case CSI_OBJECT_TYPE_FONT:
656
0
      cairo_font_face_reference (obj->datum.font_face);
657
0
      break;
658
58
  case CSI_OBJECT_TYPE_PATTERN:
659
58
      cairo_pattern_reference (obj->datum.pattern);
660
58
      break;
661
0
  case CSI_OBJECT_TYPE_SCALED_FONT:
662
0
      cairo_scaled_font_reference (obj->datum.scaled_font);
663
0
      break;
664
0
  case CSI_OBJECT_TYPE_SURFACE:
665
0
      cairo_surface_reference (obj->datum.surface);
666
0
      break;
667
58
  }
668
3.58M
    } else if (CSI_OBJECT_IS_COMPOUND (obj)) {
669
33.6k
  obj->datum.object->ref++;
670
33.6k
    }
671
672
3.58M
    return obj;
673
3.58M
}
674
675
void
676
csi_object_free (csi_t *ctx,
677
     csi_object_t *obj)
678
19.0M
{
679
19.0M
    if (CSI_OBJECT_IS_CAIRO (obj)) {
680
87.5k
  switch (obj->type & CSI_OBJECT_TYPE_MASK) {
681
0
  case CSI_OBJECT_TYPE_CONTEXT:
682
0
      cairo_destroy (obj->datum.cr);
683
0
      break;
684
0
  case CSI_OBJECT_TYPE_FONT:
685
0
      cairo_font_face_destroy (obj->datum.font_face);
686
0
      break;
687
87.5k
  case CSI_OBJECT_TYPE_PATTERN:
688
87.5k
      cairo_pattern_destroy (obj->datum.pattern);
689
87.5k
      break;
690
0
  case CSI_OBJECT_TYPE_SCALED_FONT:
691
0
      cairo_scaled_font_destroy (obj->datum.scaled_font);
692
0
      break;
693
2
  case CSI_OBJECT_TYPE_SURFACE:
694
2
      cairo_surface_destroy (obj->datum.surface);
695
2
      break;
696
87.5k
  }
697
19.0M
    } else if (CSI_OBJECT_IS_COMPOUND (obj)) {
698
3.39M
  if (--obj->datum.object->ref)
699
33.6k
      return;
700
701
3.35M
  switch (obj->type & CSI_OBJECT_TYPE_MASK) {
702
2.68M
  case CSI_OBJECT_TYPE_ARRAY:
703
2.68M
      csi_array_free (ctx, obj->datum.array);
704
2.68M
      break;
705
160k
  case CSI_OBJECT_TYPE_DICTIONARY:
706
160k
      csi_dictionary_free (ctx, obj->datum.dictionary);
707
160k
      break;
708
6.20k
  case CSI_OBJECT_TYPE_FILE:
709
6.20k
      _csi_file_free (ctx, obj->datum.file);
710
6.20k
      break;
711
4.34k
  case CSI_OBJECT_TYPE_MATRIX:
712
4.34k
      csi_matrix_free (ctx, obj->datum.matrix);
713
4.34k
      break;
714
500k
  case CSI_OBJECT_TYPE_STRING:
715
500k
      csi_string_free (ctx, obj->datum.string);
716
500k
      break;
717
0
  default:
718
0
      break;
719
3.35M
  }
720
3.35M
    }
721
19.0M
}
722
723
csi_status_t
724
csi_object_as_file (csi_t *ctx,
725
        csi_object_t *src,
726
        csi_object_t *file)
727
0
{
728
0
    int type = csi_object_get_type (src);
729
0
    switch (type) {
730
0
    case CSI_OBJECT_TYPE_FILE:
731
0
  *file = *csi_object_reference (src);
732
0
  return CSI_STATUS_SUCCESS;
733
0
    case CSI_OBJECT_TYPE_STRING:
734
0
   return csi_file_new_from_string (ctx, file, src->datum.string);
735
0
    case CSI_OBJECT_TYPE_ARRAY:
736
#if 0
737
  if (src->type & CSI_OBJECT_ATTR_EXECUTABLE)
738
      return _csi_file_new_from_procedure (cs, src);
739
#endif
740
0
    default:
741
0
  return _csi_error (CSI_STATUS_INVALID_SCRIPT);
742
0
    }
743
0
}
744
745
static int
746
lexcmp (void const *a, size_t alen,
747
  void const *b, size_t blen)
748
9.73k
{
749
9.73k
    size_t len = alen < blen ? alen : blen;
750
9.73k
    int cmp = memcmp (a, b, len);
751
9.73k
    if (cmp)
752
2.18k
  return cmp;
753
7.55k
    if (alen == blen)
754
3.96k
  return 0;
755
3.58k
    return alen < blen ? -1 : +1;
756
7.55k
}
757
758
csi_boolean_t
759
csi_object_eq (csi_object_t *a,
760
         csi_object_t *b)
761
381k
{
762
381k
    csi_object_type_t atype = csi_object_get_type (a);
763
381k
    csi_object_type_t btype = csi_object_get_type (b);
764
765
381k
    if (atype == btype) {
766
332k
  switch (atype) {
767
20.4k
  case CSI_OBJECT_TYPE_BOOLEAN:
768
20.4k
      return a->datum.boolean == b->datum.boolean;
769
58.1k
  case CSI_OBJECT_TYPE_INTEGER:
770
58.1k
      return a->datum.integer == b->datum.integer;
771
244k
  case CSI_OBJECT_TYPE_REAL:
772
244k
      return a->datum.real == b->datum.real;
773
54
  case CSI_OBJECT_TYPE_NAME:
774
54
      return a->datum.name == b->datum.name;
775
8.19k
  case CSI_OBJECT_TYPE_STRING:
776
8.19k
      return 0 == lexcmp (a->datum.string->string,
777
8.19k
        a->datum.string->len,
778
8.19k
        b->datum.string->string,
779
8.19k
        b->datum.string->len);
780
3
  case CSI_OBJECT_TYPE_NULL:
781
719
  case CSI_OBJECT_TYPE_MARK:
782
719
      return TRUE;
783
24
  case CSI_OBJECT_TYPE_OPERATOR:
784
24
      return a->datum.op == b->datum.op;
785
85
  case CSI_OBJECT_TYPE_ARRAY:
786
703
  case CSI_OBJECT_TYPE_DICTIONARY:
787
703
  case CSI_OBJECT_TYPE_FILE:
788
704
  case CSI_OBJECT_TYPE_MATRIX:
789
704
  case CSI_OBJECT_TYPE_CONTEXT:
790
704
  case CSI_OBJECT_TYPE_FONT:
791
1.17k
  case CSI_OBJECT_TYPE_PATTERN:
792
1.17k
  case CSI_OBJECT_TYPE_SCALED_FONT:
793
1.17k
  case CSI_OBJECT_TYPE_SURFACE:
794
1.17k
      return a->datum.ptr == b->datum.ptr;
795
332k
  }
796
332k
    }
797
798
48.6k
    if (atype < btype) {
799
33.4k
  csi_object_t *c;
800
33.4k
  csi_object_type_t ctype;
801
33.4k
  c = a; a = b; b = c;
802
33.4k
  ctype = atype; atype = btype; btype = ctype;
803
33.4k
    }
804
805
48.6k
    switch ((int) atype) {
806
10.1k
    case CSI_OBJECT_TYPE_INTEGER:
807
10.1k
  if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
808
10.1k
      return a->datum.integer == b->datum.boolean;
809
10.1k
  }
810
1
  break;
811
31.3k
    case CSI_OBJECT_TYPE_REAL:
812
31.3k
  if (btype == CSI_OBJECT_TYPE_INTEGER) {
813
14.2k
      return a->datum.real == b->datum.integer;
814
14.2k
  }
815
17.0k
  else if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
816
15.1k
      return a->datum.real == b->datum.boolean;
817
15.1k
  }
818
1.95k
  break;
819
820
5.48k
    case CSI_OBJECT_TYPE_STRING:
821
5.48k
  if (btype == CSI_OBJECT_TYPE_NAME) {
822
1.46k
      const char *bstr = (const char *) b->datum.name;
823
1.46k
      return 0 == lexcmp (a->datum.string->string,
824
1.46k
        a->datum.string->len,
825
1.46k
        bstr,
826
1.46k
        strlen (bstr));
827
1.46k
  }
828
4.02k
  break;
829
830
4.02k
    default:
831
1.66k
  break;
832
48.6k
    }
833
834
7.65k
    return FALSE;
835
48.6k
}
836
837
csi_status_t
838
csi_object_compare (csi_object_t *a,
839
        csi_object_t *b,
840
        int *out)
841
61.0k
{
842
61.0k
    csi_object_type_t atype = csi_object_get_type (a);
843
61.0k
    csi_object_type_t btype = csi_object_get_type (b);
844
61.0k
    int sign;
845
846
61.0k
    if (csi_object_eq (a, b)){
847
5.76k
  *out = 0;
848
5.76k
  return CSI_STATUS_SUCCESS;
849
5.76k
    }
850
851
55.2k
#define CMP(x,y) ((x) < (y) ? -1 : +1)
852
853
55.2k
    if (atype == btype) {
854
52.7k
  switch (atype) {
855
250
  case CSI_OBJECT_TYPE_BOOLEAN:
856
250
      *out = CMP (a->datum.boolean, b->datum.boolean);
857
250
      return CSI_STATUS_SUCCESS;
858
52.4k
  case CSI_OBJECT_TYPE_INTEGER:
859
52.4k
      *out = CMP (a->datum.integer, b->datum.integer);
860
52.4k
      return CSI_STATUS_SUCCESS;
861
21
  case CSI_OBJECT_TYPE_REAL:
862
21
      *out = CMP (a->datum.real, b->datum.real);
863
21
      return CSI_STATUS_SUCCESS;
864
53
  case CSI_OBJECT_TYPE_NAME: {
865
53
      const char *x = (char const *) a->datum.name;
866
53
      const char *y = (char const *) b->datum.name;
867
53
      *out = lexcmp (x, strlen(x), y, strlen (y));
868
53
      return CSI_STATUS_SUCCESS;
869
0
  }
870
2
  case CSI_OBJECT_TYPE_STRING:
871
2
      *out = lexcmp (a->datum.string->string,
872
2
         a->datum.string->len,
873
2
         b->datum.string->string,
874
2
         b->datum.string->len);
875
2
      return CSI_STATUS_SUCCESS;
876
0
  case CSI_OBJECT_TYPE_NULL:
877
0
  case CSI_OBJECT_TYPE_MARK:
878
2
  case CSI_OBJECT_TYPE_OPERATOR:
879
3
  case CSI_OBJECT_TYPE_ARRAY:
880
6
  case CSI_OBJECT_TYPE_DICTIONARY:
881
6
  case CSI_OBJECT_TYPE_FILE:
882
7
  case CSI_OBJECT_TYPE_MATRIX:
883
7
  case CSI_OBJECT_TYPE_CONTEXT:
884
7
  case CSI_OBJECT_TYPE_FONT:
885
10
  case CSI_OBJECT_TYPE_PATTERN:
886
10
  case CSI_OBJECT_TYPE_SCALED_FONT:
887
10
  case CSI_OBJECT_TYPE_SURFACE:
888
10
      goto TYPE_CHECK_ERROR;
889
52.7k
  }
890
52.7k
    }
891
892
2.55k
    sign = +1;
893
2.55k
    if (atype < btype) {
894
1.93k
  csi_object_t *c;
895
1.93k
  csi_object_type_t ctype;
896
1.93k
  c = a; a = b; b = c;
897
1.93k
  ctype = atype; atype = btype; btype = ctype;
898
1.93k
  sign = -1;
899
1.93k
    }
900
901
2.55k
    switch ((int) atype) {
902
2.03k
    case CSI_OBJECT_TYPE_INTEGER:
903
2.03k
  if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
904
2.03k
      *out = sign * CMP (a->datum.integer, !!b->datum.boolean);
905
2.03k
      return CSI_STATUS_SUCCESS;
906
2.03k
  }
907
1
  break;
908
487
    case CSI_OBJECT_TYPE_REAL:
909
487
  if (btype == CSI_OBJECT_TYPE_INTEGER) {
910
261
      *out = sign * CMP (a->datum.real, b->datum.integer);
911
261
      return CSI_STATUS_SUCCESS;
912
261
  }
913
226
  else if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
914
224
      *out = sign * CMP (a->datum.real, !!b->datum.boolean);
915
224
      return CSI_STATUS_SUCCESS;
916
224
  }
917
2
  break;
918
919
19
    case CSI_OBJECT_TYPE_STRING:
920
19
  if (btype == CSI_OBJECT_TYPE_NAME) {
921
18
      const char *bstr = (const char *) b->datum.name;
922
18
      *out = sign * lexcmp (a->datum.string->string,
923
18
          a->datum.string->len,
924
18
          bstr,
925
18
          strlen (bstr));
926
18
      return CSI_STATUS_SUCCESS;
927
18
  }
928
1
  break;
929
930
15
    default:
931
15
  break;
932
2.55k
    }
933
934
19
#undef CMP
935
936
29
 TYPE_CHECK_ERROR:
937
29
    return _csi_error (CSI_STATUS_SCRIPT_INVALID_TYPE);
938
2.55k
}