/src/imagemagick/MagickCore/token.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % TTTTT OOO K K EEEEE N N % |
7 | | % T O O K K E NN N % |
8 | | % T O O KKK EEE N N N % |
9 | | % T O O K K E N NN % |
10 | | % T OOO K K EEEEE N N % |
11 | | % % |
12 | | % % |
13 | | % MagickCore Token Methods % |
14 | | % % |
15 | | % Software Design % |
16 | | % Cristy % |
17 | | % January 1993 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/license/ % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | % |
38 | | */ |
39 | | |
40 | | /* |
41 | | Include declarations. |
42 | | */ |
43 | | #include "MagickCore/studio.h" |
44 | | #include "MagickCore/exception.h" |
45 | | #include "MagickCore/exception-private.h" |
46 | | #include "MagickCore/image.h" |
47 | | #include "MagickCore/image-private.h" |
48 | | #include "MagickCore/locale-private.h" |
49 | | #include "MagickCore/memory_.h" |
50 | | #include "MagickCore/memory-private.h" |
51 | | #include "MagickCore/string_.h" |
52 | | #include "MagickCore/string-private.h" |
53 | | #include "MagickCore/token.h" |
54 | | #include "MagickCore/token-private.h" |
55 | | #include "MagickCore/utility.h" |
56 | | #include "MagickCore/utility-private.h" |
57 | | |
58 | | /* |
59 | | Typedef declarations. |
60 | | */ |
61 | | struct _TokenInfo |
62 | | { |
63 | | int |
64 | | state; |
65 | | |
66 | | MagickStatusType |
67 | | flag; |
68 | | |
69 | | ssize_t |
70 | | offset; |
71 | | |
72 | | char |
73 | | quote; |
74 | | |
75 | | size_t |
76 | | signature; |
77 | | }; |
78 | | |
79 | | /* |
80 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
81 | | % % |
82 | | % % |
83 | | % % |
84 | | % A c q u i r e T o k e n I n f o % |
85 | | % % |
86 | | % % |
87 | | % % |
88 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
89 | | % |
90 | | % AcquireTokenInfo() allocates the TokenInfo structure. |
91 | | % |
92 | | % The format of the AcquireTokenInfo method is: |
93 | | % |
94 | | % TokenInfo *AcquireTokenInfo() |
95 | | % |
96 | | */ |
97 | | MagickExport TokenInfo *AcquireTokenInfo(void) |
98 | 187 | { |
99 | 187 | TokenInfo |
100 | 187 | *token_info; |
101 | | |
102 | 187 | token_info=(TokenInfo *) AcquireCriticalMemory(sizeof(*token_info)); |
103 | 187 | token_info->signature=MagickCoreSignature; |
104 | 187 | return(token_info); |
105 | 187 | } |
106 | | |
107 | | /* |
108 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
109 | | % % |
110 | | % % |
111 | | % % |
112 | | % D e s t r o y T o k e n I n f o % |
113 | | % % |
114 | | % % |
115 | | % % |
116 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
117 | | % |
118 | | % DestroyTokenInfo() deallocates memory associated with an TokenInfo |
119 | | % structure. |
120 | | % |
121 | | % The format of the DestroyTokenInfo method is: |
122 | | % |
123 | | % TokenInfo *DestroyTokenInfo(TokenInfo *token_info) |
124 | | % |
125 | | % A description of each parameter follows: |
126 | | % |
127 | | % o token_info: Specifies a pointer to an TokenInfo structure. |
128 | | % |
129 | | */ |
130 | | MagickExport TokenInfo *DestroyTokenInfo(TokenInfo *token_info) |
131 | 187 | { |
132 | 187 | assert(token_info != (TokenInfo *) NULL); |
133 | 187 | assert(token_info->signature == MagickCoreSignature); |
134 | 187 | if (IsEventLogging() != MagickFalse) |
135 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); |
136 | 187 | token_info->signature=(~MagickCoreSignature); |
137 | 187 | token_info=(TokenInfo *) RelinquishMagickMemory(token_info); |
138 | 187 | return(token_info); |
139 | 187 | } |
140 | | |
141 | | /* |
142 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
143 | | % % |
144 | | % % |
145 | | % % |
146 | | + G e t N e x t T o k e n % |
147 | | % % |
148 | | % % |
149 | | % % |
150 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
151 | | % |
152 | | % GetNextToken() gets a token from the token stream. A token is defined as |
153 | | % a sequence of characters delimited by whitespace (e.g. clip-path), a |
154 | | % sequence delimited with quotes (.e.g "Quote me"), or a sequence enclosed in |
155 | | % parenthesis (e.g. rgb(0,0,0)). GetNextToken() also recognizes these |
156 | | % separator characters: ':', '=', ',', and ';'. GetNextToken() returns the |
157 | | % length of the consumed token. |
158 | | % |
159 | | % The format of the GetNextToken method is: |
160 | | % |
161 | | % size_t GetNextToken(const char *magick_restrict start, |
162 | | % const char **magick_restrict end,const size_t extent, |
163 | | % char *magick_restrict token) |
164 | | % |
165 | | % A description of each parameter follows: |
166 | | % |
167 | | % o start: the start of the token sequence. |
168 | | % |
169 | | % o end: point to the end of the token sequence. |
170 | | % |
171 | | % o extent: maximum extent of the token. |
172 | | % |
173 | | % o token: copy the token to this buffer. |
174 | | % |
175 | | */ |
176 | | MagickExport magick_hot_spot size_t GetNextToken( |
177 | | const char *magick_restrict start,const char **magick_restrict end, |
178 | | const size_t extent,char *magick_restrict token) |
179 | 77.3M | { |
180 | 77.3M | char |
181 | 77.3M | *magick_restrict q; |
182 | | |
183 | 77.3M | const char |
184 | 77.3M | *magick_restrict p; |
185 | | |
186 | 77.3M | double |
187 | 77.3M | value; |
188 | | |
189 | 77.3M | ssize_t |
190 | 77.3M | i; |
191 | | |
192 | 77.3M | assert(start != (const char *) NULL); |
193 | 77.3M | assert(token != (char *) NULL); |
194 | 77.3M | i=0; |
195 | 77.3M | p=start; |
196 | 77.8M | while ((isspace((int) ((unsigned char) *p)) != 0) && (*p != '\0')) |
197 | 511k | p++; |
198 | 77.3M | switch (*p) |
199 | 77.3M | { |
200 | 22.0k | case '\0': |
201 | 22.0k | break; |
202 | 3.54M | case '"': |
203 | 3.81M | case '\'': |
204 | 3.85M | case '`': |
205 | 3.99M | case '{': |
206 | 3.99M | { |
207 | 3.99M | char |
208 | 3.99M | escape; |
209 | | |
210 | 3.99M | switch (*p) |
211 | 3.99M | { |
212 | 3.54M | case '"': escape='"'; break; |
213 | 267k | case '\'': escape='\''; break; |
214 | 42.1k | case '`': escape='\''; break; |
215 | 145k | case '{': escape='}'; break; |
216 | 0 | default: escape=(*p); break; |
217 | 3.99M | } |
218 | 398M | for (p++; *p != '\0'; p++) |
219 | 397M | { |
220 | 397M | if ((*p == '\\') && ((*(p+1) == escape) || (*(p+1) == '\\'))) |
221 | 9.48M | p++; |
222 | 388M | else |
223 | 388M | if (*p == escape) |
224 | 3.48M | { |
225 | 3.48M | p++; |
226 | 3.48M | break; |
227 | 3.48M | } |
228 | 394M | if (i < (ssize_t) (extent-1)) |
229 | 394M | token[i++]=(*p); |
230 | 394M | if ((size_t) (p-start) >= (extent-1)) |
231 | 1.20k | break; |
232 | 394M | } |
233 | 3.99M | break; |
234 | 3.99M | } |
235 | 73.0k | case '/': |
236 | 73.0k | { |
237 | 73.0k | if (i < (ssize_t) (extent-1)) |
238 | 73.0k | token[i++]=(*p); |
239 | 73.0k | p++; |
240 | 73.0k | if ((*p == '>') || (*p == '/')) |
241 | 10.8k | { |
242 | 10.8k | if (i < (ssize_t) (extent-1)) |
243 | 10.8k | token[i++]=(*p); |
244 | 10.8k | p++; |
245 | 10.8k | } |
246 | 73.0k | break; |
247 | 3.99M | } |
248 | 73.2M | default: |
249 | 73.2M | { |
250 | 73.2M | value=StringToDouble(p,&q); |
251 | 73.2M | (void) value; |
252 | 73.2M | if ((p != q) && (*p != ',')) |
253 | 8.66M | { |
254 | 26.8M | for ( ; (p < q) && (*p != ','); p++) |
255 | 18.1M | { |
256 | 18.1M | if (i < (ssize_t) (extent-1)) |
257 | 18.1M | token[i++]=(*p); |
258 | 18.1M | if ((size_t) (p-start) >= (extent-1)) |
259 | 0 | break; |
260 | 18.1M | } |
261 | 8.66M | if (*p == '%') |
262 | 77.0k | { |
263 | 77.0k | if (i < (ssize_t) (extent-1)) |
264 | 77.0k | token[i++]=(*p); |
265 | 77.0k | p++; |
266 | 77.0k | } |
267 | 8.66M | break; |
268 | 8.66M | } |
269 | 64.5M | if ((*p != '\0') && (isalpha((int) ((unsigned char) *p)) == 0) && |
270 | 49.0M | (*p != *DirectorySeparator) && (*p != '#') && (*p != '<')) |
271 | 46.5M | { |
272 | 46.5M | if (i < (ssize_t) (extent-1)) |
273 | 46.5M | token[i++]=(*p); |
274 | 46.5M | p++; |
275 | 46.5M | break; |
276 | 46.5M | } |
277 | 197M | for ( ; *p != '\0'; p++) |
278 | 197M | { |
279 | 197M | if (((isspace((int) ((unsigned char) *p)) != 0) || (*p == '=') || |
280 | 183M | (*p == ',') || (*p == ':') || (*p == ';')) && (*(p-1) != '\\')) |
281 | 17.7M | break; |
282 | 179M | if ((i > 0) && (*p == '<')) |
283 | 53.9k | break; |
284 | 179M | if (i < (ssize_t) (extent-1)) |
285 | 179M | token[i++]=(*p); |
286 | 179M | if (*p == '>') |
287 | 79.3k | break; |
288 | 179M | if (*p == '(') |
289 | 160k | { |
290 | 50.4M | for (p++; *p != '\0'; p++) |
291 | 50.4M | { |
292 | 50.4M | if (i < (ssize_t) (extent-1)) |
293 | 50.4M | token[i++]=(*p); |
294 | 50.4M | if ((*p == ')') && (*(p-1) != '\\')) |
295 | 154k | break; |
296 | 50.3M | if ((size_t) (p-start) >= (extent-1)) |
297 | 30 | break; |
298 | 50.3M | } |
299 | 160k | if (*p == '\0') |
300 | 5.51k | break; |
301 | 160k | } |
302 | 179M | if ((size_t) (p-start) >= (extent-1)) |
303 | 57 | break; |
304 | 179M | } |
305 | 18.0M | break; |
306 | 64.5M | } |
307 | 77.3M | } |
308 | 77.3M | token[i]='\0'; |
309 | 77.3M | if (LocaleNCompare(token,"url(#",5) == 0) |
310 | 1.55k | { |
311 | 1.55k | q=strrchr(token,')'); |
312 | 1.55k | if (q != (char *) NULL) |
313 | 1.08k | { |
314 | 1.08k | *q='\0'; |
315 | 1.08k | (void) memmove(token,token+5,(size_t) (q-token-4)); |
316 | 1.08k | } |
317 | 1.55k | } |
318 | 104M | while (isspace((int) ((unsigned char) *p)) != 0) |
319 | 27.6M | p++; |
320 | 77.3M | if (end != (const char **) NULL) |
321 | 76.5M | *end=(const char *) p; |
322 | 77.3M | return((size_t) (p-start+1)); |
323 | 77.3M | } |
324 | | |
325 | | /* |
326 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
327 | | % % |
328 | | % % |
329 | | % % |
330 | | % G l o b E x p r e s s i o n % |
331 | | % % |
332 | | % % |
333 | | % % |
334 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
335 | | % |
336 | | % GlobExpression() returns MagickTrue if the expression matches the pattern. |
337 | | % |
338 | | % The format of the GlobExpression function is: |
339 | | % |
340 | | % MagickBooleanType GlobExpression(const char *magick_restrict expression, |
341 | | % const char *magick_restrict pattern, |
342 | | % const MagickBooleanType case_insensitive) |
343 | | % |
344 | | % A description of each parameter follows: |
345 | | % |
346 | | % o expression: Specifies a pointer to a text string containing a file name. |
347 | | % |
348 | | % o pattern: Specifies a pointer to a text string containing a pattern. |
349 | | % |
350 | | % o case_insensitive: set to MagickTrue to ignore the case when matching |
351 | | % an expression. |
352 | | % |
353 | | */ |
354 | | |
355 | | static MagickBooleanType GlobExpression_(const char *magick_restrict expression, |
356 | | const char *magick_restrict pattern,const MagickBooleanType case_insensitive, |
357 | | const size_t depth) |
358 | 1.02M | { |
359 | 1.02M | if (depth > MagickMaxRecursionDepth) |
360 | 0 | { |
361 | 0 | errno=EOVERFLOW; |
362 | 0 | return(MagickFalse); |
363 | 0 | } |
364 | | /* |
365 | | Empty pattern or single '*' always matches. |
366 | | */ |
367 | 1.02M | if (pattern == (const char *) NULL) |
368 | 0 | return(MagickTrue); |
369 | 1.02M | if (GetUTFCode(pattern) == 0) |
370 | 121 | return(MagickTrue); |
371 | 1.02M | if ((GetUTFCode(pattern) == '*') && |
372 | 25.1k | (GetUTFCode(pattern+GetUTFOctets(pattern)) == 0)) |
373 | 41 | return(MagickTrue); |
374 | 1.02M | if ((strchr(pattern,'{') == NULL) && |
375 | 588k | (strchr(pattern,'*') == NULL) && |
376 | 549k | (strchr(pattern,'?') == NULL)) |
377 | 460k | { |
378 | 460k | char |
379 | 460k | path[MagickPathExtent]= { 0 }; |
380 | | |
381 | | /* |
382 | | If no glob characters exist, ensure no subimage specifier. |
383 | | */ |
384 | 460k | GetPathComponent(pattern,SubimagePath,path); |
385 | 460k | if (*path != '\0') |
386 | 13.6k | return(MagickFalse); |
387 | 460k | } |
388 | 1.08M | while (GetUTFCode(pattern) != 0) |
389 | 1.08M | { |
390 | 1.08M | int |
391 | 1.08M | ecode = GetUTFCode(expression), |
392 | 1.08M | pcode = GetUTFCode(pattern); |
393 | | |
394 | 1.08M | if ((ecode == 0) && (pcode != '*') && (pcode != '{')) |
395 | 31.2k | break; |
396 | 1.05M | switch (pcode) |
397 | 1.05M | { |
398 | 38.0k | case '*': |
399 | 38.0k | { |
400 | 38.0k | do |
401 | 39.8k | { |
402 | | /* |
403 | | Skip consecutive '*'. |
404 | | */ |
405 | 39.8k | pattern+=GetUTFOctets(pattern); |
406 | 39.8k | } |
407 | 39.8k | while (GetUTFCode(pattern) == '*'); |
408 | 273k | while (1) |
409 | 273k | { |
410 | | /* |
411 | | Try to match at each position. |
412 | | */ |
413 | 273k | if (GlobExpression_(expression,pattern,case_insensitive,depth+1) != MagickFalse) |
414 | 391 | { |
415 | | /* |
416 | | Consume rest of expression and pattern. |
417 | | */ |
418 | 2.60k | while (GetUTFCode(expression) != 0) |
419 | 2.21k | expression+=GetUTFOctets(expression); |
420 | 5.27k | while (GetUTFCode(pattern) != 0) |
421 | 4.88k | pattern+=GetUTFOctets(pattern); |
422 | 391 | return(MagickTrue); |
423 | 391 | } |
424 | 272k | if (GetUTFCode(expression) == 0) |
425 | 37.6k | break; |
426 | 235k | expression+=GetUTFOctets(expression); |
427 | 235k | } |
428 | 37.6k | return(MagickFalse); |
429 | 38.0k | } |
430 | 72.7k | case '?': |
431 | 72.7k | { |
432 | 72.7k | if (ecode == 0) |
433 | 0 | return(MagickFalse); |
434 | 72.7k | pattern+=GetUTFOctets(pattern); |
435 | 72.7k | expression+=GetUTFOctets(expression); |
436 | 72.7k | break; |
437 | 72.7k | } |
438 | 15.3k | case '[': |
439 | 15.3k | { |
440 | 15.3k | const char |
441 | 15.3k | *p = pattern+GetUTFOctets(pattern), |
442 | 15.3k | *q = pattern+GetUTFOctets(pattern); |
443 | | |
444 | 15.3k | MagickBooleanType |
445 | 15.3k | matched = MagickFalse; |
446 | | |
447 | 15.3k | if (ecode == 0) |
448 | 0 | return(MagickFalse); |
449 | 1.01M | while ((GetUTFCode(q) != 0) && (GetUTFCode(q) != ']')) |
450 | 995k | q+=GetUTFOctets(q); |
451 | 15.3k | if (GetUTFCode(q) == 0) |
452 | 4.23k | return(MagickFalse); /* malformed */ |
453 | 601k | while (p < q) |
454 | 590k | { |
455 | 590k | const char |
456 | 590k | *next; |
457 | | |
458 | 590k | int |
459 | 590k | code = GetUTFCode(p); |
460 | | |
461 | 590k | size_t |
462 | 590k | octets = GetUTFOctets(p); |
463 | | |
464 | 590k | if (code == '\\') |
465 | 2.14k | { |
466 | 2.14k | p+=octets; |
467 | 2.14k | code=GetUTFCode(p); |
468 | 2.14k | octets=GetUTFOctets(p); |
469 | 2.14k | } |
470 | 590k | next=p+octets; |
471 | 590k | if ((next < q) && (GetUTFCode(next) == '-')) |
472 | 4.95k | { |
473 | 4.95k | int |
474 | 4.95k | ncode; |
475 | | |
476 | 4.95k | next+=GetUTFOctets(next); |
477 | 4.95k | ncode=GetUTFCode(next); |
478 | 4.95k | if (ncode == '\\') |
479 | 1.19k | { |
480 | 1.19k | next+=GetUTFOctets(next); |
481 | 1.19k | ncode=GetUTFCode(next); |
482 | 1.19k | } |
483 | 4.95k | if ((ecode >= code) && (ecode <= ncode)) |
484 | 878 | matched=MagickTrue; |
485 | 4.95k | p=next+GetUTFOctets(next); |
486 | 4.95k | } |
487 | 585k | else |
488 | 585k | { |
489 | 585k | if (ecode == code) |
490 | 8.06k | matched=MagickTrue; |
491 | 585k | p+=octets; |
492 | 585k | } |
493 | 590k | } |
494 | | /* |
495 | | Skip consecutive '*'. |
496 | | */ |
497 | 11.1k | if (matched == MagickFalse) |
498 | 9.18k | return(MagickFalse); |
499 | 1.92k | pattern=q+GetUTFOctets(q); /* skip ']' */ |
500 | 1.92k | expression+=GetUTFOctets(expression); |
501 | 1.92k | break; |
502 | 11.1k | } |
503 | 52.5k | case '{': |
504 | 52.5k | { |
505 | 52.5k | char |
506 | 52.5k | *a, |
507 | 52.5k | *alternative; |
508 | | |
509 | 52.5k | const char |
510 | 52.5k | *p, |
511 | 52.5k | *q; |
512 | | |
513 | 52.5k | size_t |
514 | 52.5k | remaining = MagickPathExtent; |
515 | | |
516 | 52.5k | pattern+=GetUTFOctets(pattern); /* Skip '{' */ |
517 | 52.5k | if (GetUTFCode(pattern) == 0) |
518 | 877 | return(MagickFalse); |
519 | | /* |
520 | | End of brace expression: append remaining pattern. |
521 | | */ |
522 | 51.6k | p=pattern; |
523 | 9.85M | while ((GetUTFCode(p) != 0) && (GetUTFCode(p) != '}')) |
524 | 9.80M | { |
525 | 9.80M | #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__) |
526 | 9.80M | if (GetUTFCode(p) == '\\') |
527 | 544k | { |
528 | 544k | p+=GetUTFOctets(p); |
529 | 544k | if (GetUTFCode(p) == 0) |
530 | 322 | break; |
531 | 544k | } |
532 | 9.80M | #endif |
533 | 9.80M | p+=GetUTFOctets(p); |
534 | 9.80M | } |
535 | 51.6k | if (GetUTFCode(p) != '}') |
536 | 11.6k | return(MagickFalse); /* malformed */ |
537 | 39.9k | q=p+GetUTFOctets(p); |
538 | 39.9k | alternative=AcquireString(pattern); |
539 | 39.9k | a=alternative; |
540 | 3.40M | while (1) |
541 | 3.40M | { |
542 | 3.40M | int |
543 | 3.40M | code = GetUTFCode(pattern); |
544 | | |
545 | 3.40M | size_t |
546 | 3.40M | octets; |
547 | | |
548 | 3.40M | if ((code == 0) || (code == ',') || (code == '}')) |
549 | 42.4k | { |
550 | 42.4k | char |
551 | 42.4k | *subpattern; |
552 | | |
553 | 42.4k | MagickBooleanType |
554 | 42.4k | match; |
555 | | |
556 | | /* |
557 | | Try alternative as a full sub-pattern. |
558 | | */ |
559 | 42.4k | *a='\0'; |
560 | 42.4k | subpattern=AcquireString(alternative); |
561 | 42.4k | if (ConcatenateString(&subpattern,q) == MagickFalse) |
562 | 0 | { |
563 | 0 | subpattern=DestroyString(subpattern); |
564 | 0 | alternative=DestroyString(alternative); |
565 | 0 | return(MagickFalse); |
566 | 0 | } |
567 | 42.4k | match=GlobExpression_(expression,subpattern,case_insensitive, |
568 | 42.4k | depth+1); |
569 | 42.4k | subpattern=DestroyString(subpattern); |
570 | 42.4k | if (match != MagickFalse) |
571 | 268 | { |
572 | | /* |
573 | | Consume rest of expression and pattern. |
574 | | */ |
575 | 2.13k | while (GetUTFCode(expression) != 0) |
576 | 1.86k | expression+=GetUTFOctets(expression); |
577 | 268 | pattern=q; |
578 | 3.34k | while (GetUTFCode(pattern) != 0) |
579 | 3.07k | pattern+=GetUTFOctets(pattern); |
580 | 268 | alternative=DestroyString(alternative); |
581 | 268 | return(MagickTrue); |
582 | 268 | } |
583 | | /* |
584 | | Reset buffer for next alternative. |
585 | | */ |
586 | 42.1k | a=alternative; |
587 | 42.1k | remaining=MagickPathExtent; |
588 | 42.1k | if (code == ',') |
589 | 2.51k | { |
590 | 2.51k | pattern+=GetUTFOctets(pattern); /* skip ',' */ |
591 | 2.51k | continue; |
592 | 2.51k | } |
593 | 39.6k | break; /* '}' or end */ |
594 | 42.1k | } |
595 | | /* |
596 | | Copy UTF-8 sequence into alternative. |
597 | | */ |
598 | 3.36M | octets=GetUTFOctets(pattern); |
599 | 3.36M | if ((octets == 0) || (octets >= remaining)) |
600 | 0 | break; |
601 | 3.36M | (void) memcpy(a,pattern,octets); |
602 | 3.36M | a+=octets; |
603 | 3.36M | remaining-=octets; |
604 | 3.36M | pattern+=octets; |
605 | 3.36M | } |
606 | 39.6k | alternative=DestroyString(alternative); |
607 | 39.6k | return(MagickFalse); |
608 | 39.9k | } |
609 | 0 | #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__) |
610 | 6.64k | case '\\': |
611 | 6.64k | { |
612 | 6.64k | pattern+=GetUTFOctets(pattern); |
613 | 6.64k | if (GetUTFCode(pattern) == 0) |
614 | 329 | return(MagickFalse); |
615 | 6.31k | magick_fallthrough; |
616 | 6.31k | } |
617 | 0 | #endif |
618 | 877k | default: |
619 | 877k | { |
620 | 877k | int |
621 | 877k | ec = ecode, |
622 | 877k | pc = pcode; |
623 | | |
624 | 877k | if (ecode == 0) |
625 | 0 | return(MagickFalse); |
626 | 877k | if (case_insensitive != MagickFalse) |
627 | 26.3k | { |
628 | 26.3k | pc=LocaleToLowercase(pc); |
629 | 26.3k | ec=LocaleToLowercase(ec); |
630 | 26.3k | } |
631 | 877k | if (pc != ec) |
632 | 874k | return(MagickFalse); |
633 | 3.76k | pattern+=GetUTFOctets(pattern); |
634 | 3.76k | expression+=GetUTFOctets(expression); |
635 | 3.76k | break; |
636 | 877k | } |
637 | 1.05M | } |
638 | 1.05M | } |
639 | 32.1k | while (GetUTFCode(pattern) == '*') |
640 | 0 | pattern+=GetUTFOctets(pattern); |
641 | 32.1k | return(((GetUTFCode(expression) == 0) && |
642 | 32.0k | (GetUTFCode(pattern) == 0)) ? MagickTrue : MagickFalse); |
643 | 1.01M | } |
644 | | |
645 | | MagickExport MagickBooleanType GlobExpression( |
646 | | const char *magick_restrict expression,const char *magick_restrict pattern, |
647 | | const MagickBooleanType case_insensitive) |
648 | 708k | { |
649 | 708k | return(GlobExpression_(expression,pattern,case_insensitive,0)); |
650 | 708k | } |
651 | | |
652 | | /* |
653 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
654 | | % % |
655 | | % % |
656 | | % % |
657 | | + I s G l o b % |
658 | | % % |
659 | | % % |
660 | | % % |
661 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
662 | | % |
663 | | % IsGlob() returns MagickTrue if the path specification contains a globbing |
664 | | % pattern. |
665 | | % |
666 | | % The format of the IsGlob method is: |
667 | | % |
668 | | % MagickBooleanType IsGlob(const char *geometry) |
669 | | % |
670 | | % A description of each parameter follows: |
671 | | % |
672 | | % o path: the path. |
673 | | % |
674 | | */ |
675 | | MagickPrivate MagickBooleanType IsGlob(const char *path) |
676 | 169k | { |
677 | 169k | MagickBooleanType |
678 | 169k | status = MagickFalse; |
679 | | |
680 | 169k | const char |
681 | 169k | *p; |
682 | | |
683 | 169k | if (IsPathAccessible(path) != MagickFalse) |
684 | 32 | return(MagickFalse); |
685 | 11.0M | for (p=path; *p != '\0'; p++) |
686 | 10.8M | { |
687 | 10.8M | switch (*p) |
688 | 10.8M | { |
689 | 16.1k | case '*': |
690 | 41.7k | case '?': |
691 | 66.2k | case '{': |
692 | 69.9k | case '}': |
693 | 105k | case '[': |
694 | 157k | case ']': |
695 | 157k | { |
696 | 157k | status=MagickTrue; |
697 | 157k | break; |
698 | 105k | } |
699 | 10.7M | default: |
700 | 10.7M | break; |
701 | 10.8M | } |
702 | 10.8M | } |
703 | 169k | return(status); |
704 | 169k | } |
705 | | |
706 | | /* |
707 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
708 | | % % |
709 | | % % |
710 | | % % |
711 | | % T o k e n i z e r % |
712 | | % % |
713 | | % % |
714 | | % % |
715 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
716 | | % |
717 | | % Tokenizer() is a generalized, finite state token parser. It extracts tokens |
718 | | % one at a time from a string of characters. The characters used for white |
719 | | % space, for break characters, and for quotes can be specified. Also, |
720 | | % characters in the string can be preceded by a specifiable escape character |
721 | | % which removes any special meaning the character may have. |
722 | | % |
723 | | % Here is some terminology: |
724 | | % |
725 | | % o token: A single unit of information in the form of a group of |
726 | | % characters. |
727 | | % |
728 | | % o white space: Apace that gets ignored (except within quotes or when |
729 | | % escaped), like blanks and tabs. in addition, white space terminates a |
730 | | % non-quoted token. |
731 | | % |
732 | | % o break set: One or more characters that separates non-quoted tokens. |
733 | | % Commas are a common break character. The usage of break characters to |
734 | | % signal the end of a token is the same as that of white space, except |
735 | | % multiple break characters with nothing or only white space between |
736 | | % generate a null token for each two break characters together. |
737 | | % |
738 | | % For example, if blank is set to be the white space and comma is set to |
739 | | % be the break character, the line |
740 | | % |
741 | | % A, B, C , , DEF |
742 | | % |
743 | | % ... consists of 5 tokens: |
744 | | % |
745 | | % 1) "A" |
746 | | % 2) "B" |
747 | | % 3) "C" |
748 | | % 4) "" (the null string) |
749 | | % 5) "DEF" |
750 | | % |
751 | | % o Quote character: A character that, when surrounding a group of other |
752 | | % characters, causes the group of characters to be treated as a single |
753 | | % token, no matter how many white spaces or break characters exist in |
754 | | % the group. Also, a token always terminates after the closing quote. |
755 | | % For example, if ' is the quote character, blank is white space, and |
756 | | % comma is the break character, the following string |
757 | | % |
758 | | % A, ' B, CD'EF GHI |
759 | | % |
760 | | % ... consists of 4 tokens: |
761 | | % |
762 | | % 1) "A" |
763 | | % 2) " B, CD" (note the blanks & comma) |
764 | | % 3) "EF" |
765 | | % 4) "GHI" |
766 | | % |
767 | | % The quote characters themselves do not appear in the resultant |
768 | | % tokens. The double quotes are delimiters i use here for |
769 | | % documentation purposes only. |
770 | | % |
771 | | % o Escape character: A character which itself is ignored but which |
772 | | % causes the next character to be used as is. ^ and \ are often used |
773 | | % as escape characters. An escape in the last position of the string |
774 | | % gets treated as a "normal" (i.e., non-quote, non-white, non-break, |
775 | | % and non-escape) character. For example, assume white space, break |
776 | | % character, and quote are the same as in the above examples, and |
777 | | % further, assume that ^ is the escape character. Then, in the string |
778 | | % |
779 | | % ABC, ' DEF ^' GH' I ^ J K^ L ^ |
780 | | % |
781 | | % ... there are 7 tokens: |
782 | | % |
783 | | % 1) "ABC" |
784 | | % 2) " DEF ' GH" |
785 | | % 3) "I" |
786 | | % 4) " " (a lone blank) |
787 | | % 5) "J" |
788 | | % 6) "K L" |
789 | | % 7) "^" (passed as is at end of line) |
790 | | % |
791 | | % The format of the Tokenizer method is: |
792 | | % |
793 | | % int Tokenizer(TokenInfo *token_info,const unsigned flag,char *token, |
794 | | % const size_t max_token_length,const char *line,const char *white, |
795 | | % const char *break_set,const char *quote,const char escape, |
796 | | % char *breaker,int *next,char *quoted) |
797 | | % |
798 | | % A description of each parameter follows: |
799 | | % |
800 | | % o flag: right now, only the low order 3 bits are used. |
801 | | % |
802 | | % 1 => convert non-quoted tokens to upper case |
803 | | % 2 => convert non-quoted tokens to lower case |
804 | | % 0 => do not convert non-quoted tokens |
805 | | % |
806 | | % o token: a character string containing the returned next token |
807 | | % |
808 | | % o max_token_length: the maximum size of "token". Characters beyond |
809 | | % "max_token_length" are truncated. |
810 | | % |
811 | | % o string: the string to be parsed. |
812 | | % |
813 | | % o white: a string of the valid white spaces. example: |
814 | | % |
815 | | % char whitesp[]={" \t"}; |
816 | | % |
817 | | % blank and tab will be valid white space. |
818 | | % |
819 | | % o break: a string of the valid break characters. example: |
820 | | % |
821 | | % char breakch[]={";,"}; |
822 | | % |
823 | | % semicolon and comma will be valid break characters. |
824 | | % |
825 | | % o quote: a string of the valid quote characters. An example would be |
826 | | % |
827 | | % char whitesp[]={"'\""); |
828 | | % |
829 | | % (this causes single and double quotes to be valid) Note that a |
830 | | % token starting with one of these characters needs the same quote |
831 | | % character to terminate it. |
832 | | % |
833 | | % for example: |
834 | | % |
835 | | % "ABC ' |
836 | | % |
837 | | % is unterminated, but |
838 | | % |
839 | | % "DEF" and 'GHI' |
840 | | % |
841 | | % are properly terminated. Note that different quote characters |
842 | | % can appear on the same line; only for a given token do the quote |
843 | | % characters have to be the same. |
844 | | % |
845 | | % o escape: the escape character (NOT a string ... only one |
846 | | % allowed). Use zero if none is desired. |
847 | | % |
848 | | % o breaker: the break character used to terminate the current |
849 | | % token. If the token was quoted, this will be the quote used. If |
850 | | % the token is the last one on the line, this will be zero. |
851 | | % |
852 | | % o next: this variable points to the first character of the |
853 | | % next token. it gets reset by "tokenizer" as it steps through the |
854 | | % string. Set it to 0 upon initialization, and leave it alone |
855 | | % after that. You can change it if you want to jump around in the |
856 | | % string or re-parse from the beginning, but be careful. |
857 | | % |
858 | | % o quoted: set to True if the token was quoted and MagickFalse |
859 | | % if not. You may need this information (for example: in C, a |
860 | | % string with quotes around it is a character string, while one |
861 | | % without is an identifier). |
862 | | % |
863 | | % o result: 0 if we haven't reached EOS (end of string), and 1 |
864 | | % if we have. |
865 | | % |
866 | | */ |
867 | | |
868 | 46.7k | #define IN_WHITE 0 |
869 | 62.1k | #define IN_TOKEN 1 |
870 | 144k | #define IN_QUOTE 2 |
871 | 18.6k | #define IN_OZONE 3 |
872 | | |
873 | | static ssize_t sindex(int c,const char *string) |
874 | 259k | { |
875 | 259k | const char |
876 | 259k | *p; |
877 | | |
878 | 391k | for (p=string; *p != '\0'; p++) |
879 | 152k | if (c == (int) (*p)) |
880 | 20.8k | return((ssize_t) (p-string)); |
881 | 238k | return(-1); |
882 | 259k | } |
883 | | |
884 | | static void StoreToken(TokenInfo *token_info,char *string, |
885 | | size_t max_token_length,int c) |
886 | 76.6k | { |
887 | 76.6k | ssize_t |
888 | 76.6k | i; |
889 | | |
890 | 76.6k | if ((token_info->offset < 0) || |
891 | 76.6k | ((size_t) token_info->offset >= (max_token_length-1))) |
892 | 0 | return; |
893 | 76.6k | i=token_info->offset++; |
894 | 76.6k | string[i]=(char) c; |
895 | 76.6k | if (token_info->state == IN_QUOTE) |
896 | 30.0k | return; |
897 | 46.5k | switch (token_info->flag & 0x03) |
898 | 46.5k | { |
899 | 0 | case 1: |
900 | 0 | { |
901 | 0 | string[i]=(char) LocaleToUppercase(c); |
902 | 0 | break; |
903 | 0 | } |
904 | 0 | case 2: |
905 | 0 | { |
906 | 0 | string[i]=(char) LocaleToLowercase(c); |
907 | 0 | break; |
908 | 0 | } |
909 | 46.5k | default: |
910 | 46.5k | break; |
911 | 46.5k | } |
912 | 46.5k | } |
913 | | |
914 | | MagickExport int Tokenizer(TokenInfo *token_info,const unsigned flag, |
915 | | char *token,const size_t max_token_length,const char *line,const char *white, |
916 | | const char *break_set,const char *quote,const char escape,char *breaker, |
917 | | int *next,char *quoted) |
918 | 31.7k | { |
919 | 31.7k | int |
920 | 31.7k | c; |
921 | | |
922 | 31.7k | ssize_t |
923 | 31.7k | i; |
924 | | |
925 | 31.7k | *breaker='\0'; |
926 | 31.7k | *quoted='\0'; |
927 | 31.7k | if (line[*next] == '\0') |
928 | 8.34k | return(1); |
929 | 23.3k | token_info->state=IN_WHITE; |
930 | 23.3k | token_info->quote=(char) MagickFalse; |
931 | 23.3k | token_info->flag=flag; |
932 | 104k | for (token_info->offset=0; (int) line[*next] != 0; (*next)++) |
933 | 98.2k | { |
934 | 98.2k | c=(int) line[*next]; |
935 | 98.2k | i=sindex(c,break_set); |
936 | 98.2k | if (i >= 0) |
937 | 14.2k | { |
938 | 14.2k | switch (token_info->state) |
939 | 14.2k | { |
940 | 6.59k | case IN_WHITE: |
941 | 13.8k | case IN_TOKEN: |
942 | 14.0k | case IN_OZONE: |
943 | 14.0k | { |
944 | 14.0k | (*next)++; |
945 | 14.0k | *breaker=break_set[i]; |
946 | 14.0k | token[token_info->offset]='\0'; |
947 | 14.0k | return(0); |
948 | 13.8k | } |
949 | 202 | case IN_QUOTE: |
950 | 202 | { |
951 | 202 | StoreToken(token_info,token,max_token_length,c); |
952 | 202 | break; |
953 | 13.8k | } |
954 | 14.2k | } |
955 | 202 | continue; |
956 | 14.2k | } |
957 | 83.9k | i=sindex(c,quote); |
958 | 83.9k | if (i >= 0) |
959 | 6.61k | { |
960 | 6.61k | switch (token_info->state) |
961 | 6.61k | { |
962 | 2.97k | case IN_WHITE: |
963 | 2.97k | { |
964 | 2.97k | token_info->state=IN_QUOTE; |
965 | 2.97k | token_info->quote=quote[i]; |
966 | 2.97k | *quoted=(char) MagickTrue; |
967 | 2.97k | break; |
968 | 0 | } |
969 | 1.68k | case IN_QUOTE: |
970 | 1.68k | { |
971 | 1.68k | if (quote[i] != token_info->quote) |
972 | 0 | StoreToken(token_info,token,max_token_length,c); |
973 | 1.68k | else |
974 | 1.68k | { |
975 | 1.68k | token_info->state=IN_OZONE; |
976 | 1.68k | token_info->quote='\0'; |
977 | 1.68k | } |
978 | 1.68k | break; |
979 | 0 | } |
980 | 1.74k | case IN_TOKEN: |
981 | 1.95k | case IN_OZONE: |
982 | 1.95k | { |
983 | 1.95k | *breaker=(char) c; |
984 | 1.95k | token[token_info->offset]='\0'; |
985 | 1.95k | return(0); |
986 | 1.74k | } |
987 | 6.61k | } |
988 | 4.65k | continue; |
989 | 6.61k | } |
990 | 77.3k | i=sindex(c,white); |
991 | 77.3k | if (i >= 0) |
992 | 0 | { |
993 | 0 | switch (token_info->state) |
994 | 0 | { |
995 | 0 | case IN_WHITE: |
996 | 0 | case IN_OZONE: |
997 | 0 | break; |
998 | 0 | case IN_TOKEN: |
999 | 0 | { |
1000 | 0 | token_info->state=IN_OZONE; |
1001 | 0 | break; |
1002 | 0 | } |
1003 | 0 | case IN_QUOTE: |
1004 | 0 | { |
1005 | 0 | StoreToken(token_info,token,max_token_length,c); |
1006 | 0 | break; |
1007 | 0 | } |
1008 | 0 | } |
1009 | 0 | continue; |
1010 | 0 | } |
1011 | 77.3k | if (c == (int) escape) |
1012 | 0 | { |
1013 | 0 | if (line[(*next)+1] == '\0') |
1014 | 0 | { |
1015 | 0 | *breaker='\0'; |
1016 | 0 | StoreToken(token_info,token,max_token_length,c); |
1017 | 0 | (*next)++; |
1018 | 0 | token[token_info->offset]='\0'; |
1019 | 0 | return(0); |
1020 | 0 | } |
1021 | 0 | switch (token_info->state) |
1022 | 0 | { |
1023 | 0 | case IN_WHITE: |
1024 | 0 | { |
1025 | 0 | (*next)--; |
1026 | 0 | token_info->state=IN_TOKEN; |
1027 | 0 | break; |
1028 | 0 | } |
1029 | 0 | case IN_TOKEN: |
1030 | 0 | case IN_QUOTE: |
1031 | 0 | { |
1032 | 0 | (*next)++; |
1033 | 0 | c=(int) line[*next]; |
1034 | 0 | StoreToken(token_info,token,max_token_length,c); |
1035 | 0 | break; |
1036 | 0 | } |
1037 | 0 | case IN_OZONE: |
1038 | 0 | { |
1039 | 0 | token[token_info->offset]='\0'; |
1040 | 0 | return(0); |
1041 | 0 | } |
1042 | 0 | } |
1043 | 0 | continue; |
1044 | 0 | } |
1045 | 77.3k | switch (token_info->state) |
1046 | 77.3k | { |
1047 | 13.8k | case IN_WHITE: |
1048 | 13.8k | { |
1049 | 13.8k | token_info->state=IN_TOKEN; |
1050 | 13.8k | StoreToken(token_info,token,max_token_length,c); |
1051 | 13.8k | break; |
1052 | 0 | } |
1053 | 32.7k | case IN_TOKEN: |
1054 | 62.5k | case IN_QUOTE: |
1055 | 62.5k | { |
1056 | 62.5k | StoreToken(token_info,token,max_token_length,c); |
1057 | 62.5k | break; |
1058 | 32.7k | } |
1059 | 982 | case IN_OZONE: |
1060 | 982 | { |
1061 | 982 | token[token_info->offset]='\0'; |
1062 | 982 | return(0); |
1063 | 32.7k | } |
1064 | 77.3k | } |
1065 | 77.3k | } |
1066 | 6.41k | token[token_info->offset]='\0'; |
1067 | 6.41k | return(0); |
1068 | 23.3k | } |