/src/ghostpdl/psi/zstring.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 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 | | |
17 | | /* String operators */ |
18 | | #include "memory_.h" |
19 | | #include "ghost.h" |
20 | | #include "gsutil.h" |
21 | | #include "ialloc.h" |
22 | | #include "iname.h" |
23 | | #include "ivmspace.h" |
24 | | #include "oper.h" |
25 | | #include "store.h" |
26 | | |
27 | | /* The generic operators (copy, get, put, getinterval, putinterval, */ |
28 | | /* length, and forall) are implemented in zgeneric.c. */ |
29 | | |
30 | | /* <int> .bytestring <bytestring> */ |
31 | | static int |
32 | | zbytestring(i_ctx_t *i_ctx_p) |
33 | 0 | { |
34 | 0 | os_ptr op = osp; |
35 | 0 | byte *sbody; |
36 | 0 | uint size; |
37 | |
|
38 | 0 | check_int_leu(*op, max_int); |
39 | 0 | size = (uint)op->value.intval; |
40 | 0 | sbody = ialloc_bytes(size, ".bytestring"); |
41 | 0 | if (sbody == 0) |
42 | 0 | return_error(gs_error_VMerror); |
43 | 0 | make_astruct(op, a_all | icurrent_space, sbody); |
44 | 0 | memset(sbody, 0, size); |
45 | 0 | return 0; |
46 | 0 | } |
47 | | |
48 | | /* <int> string <string> */ |
49 | | int |
50 | | zstring(i_ctx_t *i_ctx_p) |
51 | 136M | { |
52 | 136M | os_ptr op = osp; |
53 | 136M | byte *sbody; |
54 | 136M | uint size; |
55 | | |
56 | 136M | check_type(*op, t_integer); |
57 | 136M | if (op->value.intval < 0 ) |
58 | 7 | return_error(gs_error_rangecheck); |
59 | 136M | if (op->value.intval > max_string_size ) |
60 | 8 | return_error(gs_error_limitcheck); /* to match Distiller */ |
61 | 136M | size = op->value.intval; |
62 | 136M | sbody = ialloc_string(size, "string"); |
63 | 136M | if (sbody == 0) |
64 | 0 | return_error(gs_error_VMerror); |
65 | 136M | make_string(op, a_all | icurrent_space, size, sbody); |
66 | 136M | memset(sbody, 0, size); |
67 | 136M | return 0; |
68 | 136M | } |
69 | | |
70 | | /* <name> .namestring <string> */ |
71 | | static int |
72 | | znamestring(i_ctx_t *i_ctx_p) |
73 | 100M | { |
74 | 100M | os_ptr op = osp; |
75 | | |
76 | 100M | check_type(*op, t_name); |
77 | 100M | name_string_ref(imemory, op, op); |
78 | 100M | return 0; |
79 | 100M | } |
80 | | |
81 | | /* <string> <pattern> anchorsearch <post> <match> -true- */ |
82 | | /* <string> <pattern> anchorsearch <string> -false- */ |
83 | | static int |
84 | | zanchorsearch(i_ctx_t *i_ctx_p) |
85 | 2.56M | { |
86 | 2.56M | os_ptr op = osp; |
87 | 2.56M | os_ptr op1 = op - 1; |
88 | 2.56M | uint size = r_size(op); |
89 | | |
90 | 2.56M | check_read_type(*op, t_string); |
91 | 2.56M | check_read_type(*op1, t_string); |
92 | 2.56M | if (size <= r_size(op1) && !memcmp(op1->value.bytes, op->value.bytes, size)) { |
93 | 1.26M | os_ptr op0 = op; |
94 | | |
95 | 1.26M | push(1); |
96 | 1.26M | *op0 = *op1; |
97 | 1.26M | r_set_size(op0, size); |
98 | 1.26M | op1->value.bytes += size; |
99 | 1.26M | r_dec_size(op1, size); |
100 | 1.26M | make_true(op); |
101 | 1.26M | } else |
102 | 2.56M | make_false(op); |
103 | 2.56M | return 0; |
104 | 2.56M | } |
105 | | |
106 | | /* <string> <pattern> (r)search <post> <match> <pre> -true- */ |
107 | | /* <string> <pattern> (r)search <string> -false- */ |
108 | | static int |
109 | | search_impl(i_ctx_t *i_ctx_p, bool forward) |
110 | 20.4M | { |
111 | 20.4M | os_ptr op = osp; |
112 | 20.4M | os_ptr op1 = op - 1; |
113 | 20.4M | uint size = r_size(op); |
114 | 20.4M | uint count; |
115 | 20.4M | byte *pat; |
116 | 20.4M | byte *ptr; |
117 | 20.4M | byte ch; |
118 | 20.4M | int incr = forward ? 1 : -1; |
119 | | |
120 | 20.4M | check_read_type(*op1, t_string); |
121 | 20.4M | check_read_type(*op, t_string); |
122 | 20.4M | if (size > r_size(op1)) { /* can't match */ |
123 | 1.84M | make_false(op); |
124 | 1.84M | return 0; |
125 | 1.84M | } |
126 | 18.5M | count = r_size(op1) - size; |
127 | 18.5M | ptr = op1->value.bytes; |
128 | 18.5M | if (size == 0) |
129 | 1 | goto found; |
130 | 18.5M | if (!forward) |
131 | 17.8M | ptr += count; |
132 | 18.5M | pat = op->value.bytes; |
133 | 18.5M | ch = pat[0]; |
134 | 216M | do { |
135 | 216M | if (*ptr == ch && (size == 1 || !memcmp(ptr, pat, size))) |
136 | 667k | goto found; |
137 | 215M | ptr += incr; |
138 | 215M | } |
139 | 215M | while (count--); |
140 | | /* No match */ |
141 | 17.9M | make_false(op); |
142 | 17.9M | return 0; |
143 | 667k | found: |
144 | 667k | op->tas.type_attrs = op1->tas.type_attrs; |
145 | 667k | op->value.bytes = ptr; /* match */ |
146 | 667k | op->tas.rsize = size; /* match */ |
147 | 667k | push(2); |
148 | 667k | op[-1] = *op1; /* pre */ |
149 | 667k | op[-3].value.bytes = ptr + size; /* post */ |
150 | 667k | if (forward) { |
151 | 399k | op[-1].tas.rsize = ptr - op[-1].value.bytes; /* pre */ |
152 | 399k | op[-3].tas.rsize = count; /* post */ |
153 | 399k | } else { |
154 | 267k | op[-1].tas.rsize = count; /* pre */ |
155 | 267k | op[-3].tas.rsize -= count + size; /* post */ |
156 | 267k | } |
157 | 667k | make_true(op); |
158 | 667k | return 0; |
159 | 667k | } |
160 | | |
161 | | /* Search from the start of the string */ |
162 | | static int |
163 | | zsearch(i_ctx_t *i_ctx_p) |
164 | 2.57M | { |
165 | 2.57M | return search_impl(i_ctx_p, true); |
166 | 2.57M | } |
167 | | |
168 | | /* Search from the end of the string */ |
169 | | static int |
170 | | zrsearch(i_ctx_t *i_ctx_p) |
171 | 17.8M | { |
172 | 17.8M | return search_impl(i_ctx_p, false); |
173 | 17.8M | } |
174 | | |
175 | | /* <string> <charstring> .stringbreak <int|null> */ |
176 | | static int |
177 | | zstringbreak(i_ctx_t *i_ctx_p) |
178 | 0 | { |
179 | 0 | os_ptr op = osp; |
180 | 0 | uint i, j; |
181 | |
|
182 | 0 | check_read_type(op[-1], t_string); |
183 | 0 | check_read_type(*op, t_string); |
184 | | /* We can't use strpbrk here, because C doesn't allow nulls in strings. */ |
185 | 0 | for (i = 0; i < r_size(op - 1); ++i) |
186 | 0 | for (j = 0; j < r_size(op); ++j) |
187 | 0 | if (op[-1].value.const_bytes[i] == op->value.const_bytes[j]) { |
188 | 0 | make_int(op - 1, i); |
189 | 0 | goto done; |
190 | 0 | } |
191 | 0 | make_null(op - 1); |
192 | 0 | done: |
193 | 0 | pop(1); |
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | | /* <obj> <pattern> .stringmatch <bool> */ |
198 | | static int |
199 | | zstringmatch(i_ctx_t *i_ctx_p) |
200 | 0 | { |
201 | 0 | os_ptr op = osp; |
202 | 0 | os_ptr op1 = op - 1; |
203 | 0 | bool result; |
204 | |
|
205 | 0 | check_read_type(*op, t_string); |
206 | 0 | switch (r_type(op1)) { |
207 | 0 | case t_string: |
208 | 0 | check_read(*op1); |
209 | 0 | goto cmp; |
210 | 0 | case t_name: |
211 | 0 | name_string_ref(imemory, op1, op1); /* can't fail */ |
212 | 0 | cmp: |
213 | 0 | result = string_match(op1->value.const_bytes, r_size(op1), |
214 | 0 | op->value.const_bytes, r_size(op), |
215 | 0 | NULL); |
216 | 0 | break; |
217 | 0 | default: |
218 | 0 | result = (r_size(op) == 1 && *op->value.bytes == '*'); |
219 | 0 | } |
220 | 0 | make_bool(op1, result); |
221 | 0 | pop(1); |
222 | 0 | return 0; |
223 | 0 | } |
224 | | |
225 | | /* ------ Initialization procedure ------ */ |
226 | | |
227 | | const op_def zstring_op_defs[] = |
228 | | { |
229 | | {"1.bytestring", zbytestring}, |
230 | | {"2anchorsearch", zanchorsearch}, |
231 | | {"1.namestring", znamestring}, |
232 | | {"2search", zsearch}, |
233 | | {"2rsearch", zrsearch}, |
234 | | {"1string", zstring}, |
235 | | {"2.stringbreak", zstringbreak}, |
236 | | {"2.stringmatch", zstringmatch}, |
237 | | op_def_end(0) |
238 | | }; |