Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gsicc_profilecache.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
/*  A cache for icc colorspaces that  were created from PS CIE color
17
    spaces or from PDF cal color spaces.
18
*/
19
20
#include "std.h"
21
#include "stdpre.h"
22
#include "gstypes.h"
23
#include "gsmemory.h"
24
#include "gsstruct.h"
25
#include "scommon.h"
26
#include "gx.h"
27
#include "gzstate.h"
28
#include "gscms.h"
29
#include "gsicc_profilecache.h"
30
#include "gserrors.h"
31
#include "assert_.h"
32
33
14.2k
#define ICC_CACHE_MAXPROFILE 50
34
35
/* Static prototypes */
36
static void rc_gsicc_profile_cache_free(gs_memory_t * mem, void *ptr_in,
37
                                        client_name_t cname);
38
static void gsicc_remove_cs_entry(gsicc_profile_cache_t *profile_cache);
39
40
gs_private_st_ptrs2(st_profile_entry, gsicc_profile_entry_t,
41
                    "gsicc_profile_entry", profile_entry_enum_ptrs,
42
                    profile_entry_reloc_ptrs, color_space, next);
43
gs_private_st_ptrs1(st_profile_cache, gsicc_profile_cache_t,
44
                    "gsicc_profile_cache", profile_list_enum_ptrs,
45
                    profile_list_reloc_ptrs, head);
46
47
/**
48
 * gsicc_cache_new: Allocate a new ICC cache manager
49
 * Return value: Pointer to allocated manager, or NULL on failure.
50
 **/
51
gsicc_profile_cache_t *
52
gsicc_profilecache_new(gs_memory_t *memory)
53
821k
{
54
821k
    gsicc_profile_cache_t *result;
55
56
    /* We want this to be maintained in stable_memory.  It should not be effected by the
57
       save and restores */
58
821k
    memory = memory->stable_memory;
59
821k
    result = gs_alloc_struct(memory, gsicc_profile_cache_t,
60
821k
                             &st_profile_cache, "gsicc_profilecache_new");
61
821k
    if ( result == NULL )
62
0
        return(NULL);
63
821k
    rc_init_free(result, memory, 1, rc_gsicc_profile_cache_free);
64
821k
    result->head = NULL;
65
821k
    result->num_entries = 0;
66
821k
    result->memory = memory;
67
821k
    return(result);
68
821k
}
69
70
static void
71
rc_gsicc_profile_cache_free(gs_memory_t * mem, void *ptr_in, client_name_t cname)
72
821k
{
73
821k
    gsicc_profile_cache_t *profile_cache = (gsicc_profile_cache_t * ) ptr_in;
74
821k
    gsicc_profile_entry_t *curr = profile_cache->head, *next;
75
76
821k
    assert(mem->stable_memory == profile_cache->memory);
77
835k
    while (curr != NULL ){
78
14.2k
        next = curr->next;
79
14.2k
        rc_decrement(curr->color_space, "rc_gsicc_profile_cache_free");
80
14.2k
        gs_free_object(profile_cache->memory, curr,
81
14.2k
                       "rc_gsicc_profile_cache_free");
82
14.2k
        profile_cache->num_entries--;
83
14.2k
        curr = next;
84
14.2k
    }
85
#ifdef DEBUG
86
    if (profile_cache->num_entries != 0)
87
        emprintf1(mem,"gsicc_profile_cache_free, num_entries is %d (should be 0).\n",
88
                  profile_cache->num_entries);
89
#endif
90
821k
    gs_free_object(profile_cache->memory, profile_cache,
91
821k
                   "rc_gsicc_profile_cache_free");
92
821k
}
93
94
void
95
gsicc_add_cs(gs_gstate * pgs, gs_color_space * colorspace, uint64_t dictkey)
96
14.3k
{
97
14.3k
    gsicc_profile_entry_t *result;
98
14.3k
    gsicc_profile_cache_t *profile_cache = pgs->icc_profile_cache;
99
14.3k
    gs_memory_t *memory =  profile_cache->memory;
100
101
14.3k
    if (dictkey == 0)
102
72
        return;
103
104
    /* The entry has to be added in stable memory. We want them
105
       to be maintained across the gsave and grestore process */
106
14.2k
    result = gs_alloc_struct(memory, gsicc_profile_entry_t,
107
14.2k
                             &st_profile_entry, "gsicc_add_cs");
108
14.2k
    if (result == NULL)
109
0
        return;     /* FIXME */
110
111
    /* If needed, remove an entry (the last one) */
112
14.2k
    if (profile_cache->num_entries >= ICC_CACHE_MAXPROFILE) {
113
0
        gsicc_remove_cs_entry(profile_cache);
114
0
    }
115
    /* Add to the top of the list. That way we find the MRU enty right away.
116
       Last entry stays the same. */
117
14.2k
    result->next = profile_cache->head;
118
14.2k
    profile_cache->head = result; /* MRU */
119
14.2k
    result->color_space = colorspace;
120
14.2k
    rc_increment(colorspace);
121
14.2k
    result->key = dictkey;
122
14.2k
    if_debug2m(gs_debug_flag_icc, memory,
123
14.2k
               "[icc] Add cs to cache = "PRI_INTPTR", hash = %"PRIu64"\n",
124
14.2k
               (intptr_t)result->color_space, (uint64_t)result->key);
125
14.2k
    profile_cache->num_entries++;
126
14.2k
}
127
128
gs_color_space*
129
gsicc_find_cs(uint64_t key_test, gs_gstate * pgs)
130
76.6k
{
131
76.6k
    gsicc_profile_cache_t *profile_cache = pgs->icc_profile_cache;
132
76.6k
    gsicc_profile_entry_t *prev = NULL, *curr = profile_cache->head;
133
134
76.6k
    if (key_test == 0)
135
72
        return NULL;
136
137
    /* Look through the cache for the key. If found, move to MRU */
138
109k
    while (curr != NULL ){
139
90.0k
        if (curr->key == key_test){
140
56.7k
            if_debug2m(gs_debug_flag_icc, pgs->memory,
141
56.7k
                       "[icc] Found cs = "PRI_INTPTR", hash = %"PRIu64"\n",
142
56.7k
                       (intptr_t)curr->color_space, (uint64_t)curr->key);
143
            /* If not already at head of list, move this one there */
144
56.7k
            if (curr != profile_cache->head) {
145
                /* We need to move found one to the top of the list. */
146
13.2k
                prev->next = curr->next;
147
13.2k
                curr->next = profile_cache->head;
148
13.2k
                profile_cache->head = curr;
149
13.2k
            }
150
56.7k
            return(curr->color_space);
151
56.7k
        }
152
33.2k
        prev = curr;
153
33.2k
        curr = curr->next;
154
33.2k
    }
155
19.8k
    return(NULL);
156
76.5k
}
157
158
/* Remove the LRU entry, which ideally is at the bottom. Note that there
159
   is no need to have a ref_count in this structure since the color
160
   space objects that are the member variables are reference counted themselves */
161
static void
162
gsicc_remove_cs_entry(gsicc_profile_cache_t *profile_cache)
163
0
{
164
0
    gs_memory_t *memory = profile_cache->memory;
165
0
    gsicc_profile_entry_t *prev = NULL, *curr = profile_cache->head;
166
167
#ifdef DEBUG
168
    if (curr == NULL) {
169
        emprintf(memory, " attempt to remove from an empty profile cache.\n");
170
        return; /* gs_abort(); */
171
    }
172
#endif
173
0
    while (curr->next != NULL) {
174
0
        prev = curr;
175
0
        curr = curr->next;
176
0
    }
177
0
    profile_cache->num_entries--;
178
0
    if (prev == NULL) {
179
        /* No more entries */
180
0
        profile_cache->head = NULL;
181
#ifdef DEBUG
182
    if (profile_cache->num_entries != 0) {
183
        emprintf1(memory, "profile cache list empty, but list has num_entries=%d.\n",
184
                  profile_cache->num_entries);
185
    }
186
#endif
187
0
    } else {
188
0
        prev->next = NULL;  /* new tail */
189
0
    }
190
    /* Decremented, but someone could still be referencing this */
191
    /* If found again in the source document, it will be regenerated
192
       and added back into the cache. */
193
0
    if_debug2m(gs_debug_flag_icc, memory,
194
0
               "[icc] Remove cs from cache = "PRI_INTPTR", hash = %"PRIu64"\n",
195
0
               (intptr_t)curr->color_space, (uint64_t)curr->key);
196
0
    rc_decrement(curr->color_space, "gsicc_remove_cs_entry");
197
0
    gs_free_object(memory, curr, "gsicc_remove_cs_entry");
198
0
}