/src/libgit2/deps/pcre2/pcre2_compile_cgroup.c
Line | Count | Source |
1 | | /************************************************* |
2 | | * Perl-Compatible Regular Expressions * |
3 | | *************************************************/ |
4 | | |
5 | | /* PCRE is a library of functions to support regular expressions whose syntax |
6 | | and semantics are as close as possible to those of the Perl 5 language. |
7 | | |
8 | | Written by Philip Hazel |
9 | | Original API code Copyright (c) 1997-2012 University of Cambridge |
10 | | New API code Copyright (c) 2016-2024 University of Cambridge |
11 | | |
12 | | ----------------------------------------------------------------------------- |
13 | | Redistribution and use in source and binary forms, with or without |
14 | | modification, are permitted provided that the following conditions are met: |
15 | | |
16 | | * Redistributions of source code must retain the above copyright notice, |
17 | | this list of conditions and the following disclaimer. |
18 | | |
19 | | * Redistributions in binary form must reproduce the above copyright |
20 | | notice, this list of conditions and the following disclaimer in the |
21 | | documentation and/or other materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the University of Cambridge nor the names of its |
24 | | contributors may be used to endorse or promote products derived from |
25 | | this software without specific prior written permission. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
28 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
29 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
30 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
31 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
32 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
33 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
34 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
35 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
36 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
37 | | POSSIBILITY OF SUCH DAMAGE. |
38 | | ----------------------------------------------------------------------------- |
39 | | */ |
40 | | |
41 | | |
42 | | #include "pcre2_compile.h" |
43 | | |
44 | | /************************************************* |
45 | | * Compute the hash code from a capture name * |
46 | | *************************************************/ |
47 | | |
48 | | /* This function returns with a simple hash code |
49 | | computed from the name of a capture group. |
50 | | |
51 | | Arguments: |
52 | | name name of the capture group |
53 | | length the length of the name |
54 | | |
55 | | Returns: hash code |
56 | | */ |
57 | | |
58 | | uint16_t |
59 | | PRIV(compile_get_hash_from_name)(PCRE2_SPTR name, uint32_t length) |
60 | 96.1k | { |
61 | 96.1k | uint16_t hash; |
62 | | |
63 | 96.1k | PCRE2_ASSERT(length > 0); |
64 | | |
65 | 96.1k | hash = (uint16_t)((name[0] & 0x7f) | ((name[length - 1] & 0xff) << 7)); |
66 | 96.1k | PCRE2_ASSERT(hash <= NAMED_GROUP_HASH_MASK); |
67 | 96.1k | return hash; |
68 | 96.1k | } |
69 | | |
70 | | |
71 | | /************************************************* |
72 | | * Get the descriptor of a known named capture * |
73 | | *************************************************/ |
74 | | |
75 | | /* This function returns the descriptor in the |
76 | | named group list of a known capture group. |
77 | | |
78 | | Arguments: |
79 | | name name of the capture group |
80 | | length the length of the name |
81 | | |
82 | | Returns: pointer to the descriptor when found, |
83 | | NULL otherwise |
84 | | */ |
85 | | |
86 | | named_group * |
87 | | PRIV(compile_find_named_group)(PCRE2_SPTR name, |
88 | | uint32_t length, compile_block *cb) |
89 | 9.85k | { |
90 | 9.85k | uint16_t hash = PRIV(compile_get_hash_from_name)(name, length); |
91 | 9.85k | named_group *ng; |
92 | 9.85k | named_group *end = cb->named_groups + cb->names_found; |
93 | | |
94 | 22.9k | for (ng = cb->named_groups; ng < end; ng++) |
95 | 21.1k | if (length == ng->length && hash == NAMED_GROUP_GET_HASH(ng) && |
96 | 8.61k | PRIV(strncmp)(name, ng->name, length) == 0) return ng; |
97 | | |
98 | 1.75k | return NULL; |
99 | 9.85k | } |
100 | | |
101 | | |
102 | | /************************************************* |
103 | | * Add an entry to the name/number table * |
104 | | *************************************************/ |
105 | | |
106 | | /* This function is called between compiling passes to add an entry to the |
107 | | name/number table, maintaining alphabetical order. Checking for permitted |
108 | | and forbidden duplicates has already been done. |
109 | | |
110 | | Arguments: |
111 | | cb the compile data block |
112 | | nb named group entry |
113 | | tablecount the count of names in the table so far |
114 | | |
115 | | Returns: new tablecount |
116 | | */ |
117 | | |
118 | | uint32_t |
119 | | PRIV(compile_add_name_to_table)(compile_block *cb, |
120 | | named_group *ng, uint32_t tablecount) |
121 | 1.29k | { |
122 | 1.29k | uint32_t i; |
123 | 1.29k | PCRE2_SPTR name = ng->name; |
124 | 1.29k | int length = ng->length; |
125 | 1.29k | uint32_t duplicate_count = 1; |
126 | | |
127 | 1.29k | PCRE2_UCHAR *slot = cb->name_table; |
128 | | |
129 | 1.29k | PCRE2_ASSERT(length > 0); |
130 | | |
131 | 1.29k | if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0) |
132 | 574 | { |
133 | 574 | named_group *ng_it; |
134 | 574 | named_group *end = cb->named_groups + cb->names_found; |
135 | | |
136 | 26.1k | for (ng_it = ng + 1; ng_it < end; ng_it++) |
137 | 25.6k | if (ng_it->name == name) duplicate_count++; |
138 | 574 | } |
139 | | |
140 | 16.9k | for (i = 0; i < tablecount; i++) |
141 | 16.1k | { |
142 | 16.1k | int crc = memcmp(name, slot + IMM2_SIZE, CU2BYTES(length)); |
143 | 16.1k | if (crc == 0 && slot[IMM2_SIZE + length] != 0) |
144 | 95 | crc = -1; /* Current name is a substring */ |
145 | | |
146 | | /* Make space in the table and break the loop for an earlier name. For a |
147 | | duplicate or later name, carry on. We do this for duplicates so that in the |
148 | | simple case (when ?(| is not used) they are in order of their numbers. In all |
149 | | cases they are in the order in which they appear in the pattern. */ |
150 | | |
151 | 16.1k | if (crc < 0) |
152 | 495 | { |
153 | 495 | (void)memmove(slot + cb->name_entry_size * duplicate_count, slot, |
154 | 495 | CU2BYTES((tablecount - i) * cb->name_entry_size)); |
155 | 495 | break; |
156 | 495 | } |
157 | | |
158 | | /* Continue the loop for a later or duplicate name */ |
159 | | |
160 | 15.6k | slot += cb->name_entry_size; |
161 | 15.6k | } |
162 | | |
163 | 1.29k | tablecount += duplicate_count; |
164 | | |
165 | 15.4k | while (TRUE) |
166 | 15.4k | { |
167 | 15.4k | PUT2(slot, 0, ng->number); |
168 | 15.4k | memcpy(slot + IMM2_SIZE, name, CU2BYTES(length)); |
169 | | |
170 | | /* Add a terminating zero and fill the rest of the slot with zeroes so that |
171 | | the memory is all initialized. Otherwise valgrind moans about uninitialized |
172 | | memory when saving serialized compiled patterns. */ |
173 | | |
174 | 15.4k | memset(slot + IMM2_SIZE + length, 0, |
175 | 15.4k | CU2BYTES(cb->name_entry_size - length - IMM2_SIZE)); |
176 | | |
177 | 15.4k | if (--duplicate_count == 0) break; |
178 | | |
179 | 22.7k | while (TRUE) |
180 | 22.7k | { |
181 | 22.7k | ++ng; |
182 | 22.7k | if (ng->name == name) break; |
183 | 22.7k | } |
184 | | |
185 | 14.1k | slot += cb->name_entry_size; |
186 | 14.1k | } |
187 | | |
188 | 1.29k | return tablecount; |
189 | 1.29k | } |
190 | | |
191 | | |
192 | | /************************************************* |
193 | | * Find details of duplicate group names * |
194 | | *************************************************/ |
195 | | |
196 | | /* This is called from compile_branch() when it needs to know the index and |
197 | | count of duplicates in the names table when processing named backreferences, |
198 | | either directly, or as conditions. |
199 | | |
200 | | Arguments: |
201 | | name points to the name |
202 | | length the length of the name |
203 | | indexptr where to put the index |
204 | | countptr where to put the count of duplicates |
205 | | errorcodeptr where to put an error code |
206 | | cb the compile block |
207 | | |
208 | | Returns: TRUE if OK, FALSE if not, error code set |
209 | | */ |
210 | | |
211 | | BOOL |
212 | | PRIV(compile_find_dupname_details)(PCRE2_SPTR name, uint32_t length, |
213 | | int *indexptr, int *countptr, int *errorcodeptr, compile_block *cb) |
214 | 2.43k | { |
215 | 2.43k | uint32_t i, groupnumber; |
216 | 2.43k | int count; |
217 | 2.43k | PCRE2_UCHAR *slot = cb->name_table; |
218 | | |
219 | | /* Find the first entry in the table */ |
220 | | |
221 | 15.2k | for (i = 0; i < cb->names_found; i++) |
222 | 15.2k | { |
223 | 15.2k | if (PRIV(strncmp)(name, slot + IMM2_SIZE, length) == 0 && |
224 | 2.43k | slot[IMM2_SIZE + length] == 0) break; |
225 | 12.8k | slot += cb->name_entry_size; |
226 | 12.8k | } |
227 | | |
228 | | /* This should not occur, because this function is called only when we know we |
229 | | have duplicate names. Give an internal error. */ |
230 | | |
231 | | /* LCOV_EXCL_START */ |
232 | 2.43k | if (i >= cb->names_found) |
233 | 0 | { |
234 | 0 | PCRE2_DEBUG_UNREACHABLE(); |
235 | 0 | *errorcodeptr = ERR53; |
236 | 0 | cb->erroroffset = name - cb->start_pattern; |
237 | 0 | return FALSE; |
238 | 0 | } |
239 | | /* LCOV_EXCL_STOP */ |
240 | | |
241 | | /* Record the index and then see how many duplicates there are, updating the |
242 | | backref map and maximum back reference as we do. */ |
243 | | |
244 | 2.43k | *indexptr = i; |
245 | 2.43k | count = 0; |
246 | | |
247 | 2.43k | for (;;) |
248 | 95.3k | { |
249 | 95.3k | count++; |
250 | 95.3k | groupnumber = GET2(slot, 0); |
251 | 95.3k | cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1; |
252 | 95.3k | if (groupnumber > cb->top_backref) cb->top_backref = groupnumber; |
253 | 95.3k | if (++i >= cb->names_found) break; |
254 | 93.7k | slot += cb->name_entry_size; |
255 | 93.7k | if (PRIV(strncmp)(name, slot + IMM2_SIZE, length) != 0 || |
256 | 93.4k | (slot + IMM2_SIZE)[length] != 0) break; |
257 | 93.7k | } |
258 | | |
259 | 2.43k | *countptr = count; |
260 | 2.43k | return TRUE; |
261 | 2.43k | } |
262 | | |
263 | | |
264 | | /* Process the capture list of scan substring and recurse |
265 | | operations. Since at least one argument must be present, |
266 | | a 0 return value represents error. */ |
267 | | |
268 | | static size_t |
269 | | PRIV(compile_process_capture_list)(uint32_t *pptr, PCRE2_SIZE offset, |
270 | | int *errorcodeptr, compile_block *cb) |
271 | 3.04k | { |
272 | 3.04k | size_t i, size = 0; |
273 | 3.04k | named_group *ng; |
274 | 3.04k | PCRE2_SPTR name; |
275 | 3.04k | uint32_t length; |
276 | 3.04k | named_group *end = cb->named_groups + cb->names_found; |
277 | | |
278 | 23.2k | while (TRUE) |
279 | 23.2k | { |
280 | 23.2k | ++pptr; |
281 | | |
282 | 23.2k | switch (META_CODE(*pptr)) |
283 | 23.2k | { |
284 | 1.00k | case META_OFFSET: |
285 | 1.00k | GETPLUSOFFSET(offset, pptr); |
286 | 1.00k | continue; |
287 | | |
288 | 1.77k | case META_CAPTURE_NAME: |
289 | 1.77k | offset += META_DATA(*pptr); |
290 | 1.77k | length = *(++pptr); |
291 | 1.77k | name = cb->start_pattern + offset; |
292 | | |
293 | 1.77k | ng = PRIV(compile_find_named_group)(name, length, cb); |
294 | | |
295 | 1.77k | if (ng == NULL) |
296 | 23 | { |
297 | 23 | *errorcodeptr = ERR15; |
298 | 23 | cb->erroroffset = offset; |
299 | 23 | return 0; |
300 | 23 | } |
301 | | |
302 | 1.75k | if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) == 0) |
303 | 339 | { |
304 | 339 | pptr[-1] = META_CAPTURE_NUMBER; |
305 | 339 | pptr[0] = ng->number; |
306 | 339 | size++; |
307 | 339 | continue; |
308 | 339 | } |
309 | | |
310 | | /* Remains only for duplicated names. */ |
311 | 1.41k | pptr[-1] = META_CAPTURE_NAME; |
312 | 1.41k | pptr[0] = (uint32_t)(ng - cb->named_groups); |
313 | 1.41k | size++; |
314 | 1.41k | name = ng->name; |
315 | | |
316 | 129k | while (++ng < end) |
317 | 127k | if (ng->name == name) size++; |
318 | 1.41k | continue; |
319 | | |
320 | 17.4k | case META_CAPTURE_NUMBER: |
321 | 17.4k | offset += META_DATA(*pptr); |
322 | | |
323 | 17.4k | i = *(++pptr); |
324 | 17.4k | if (i > cb->bracount) |
325 | 33 | { |
326 | 33 | *errorcodeptr = ERR15; |
327 | 33 | cb->erroroffset = offset; |
328 | 33 | return 0; |
329 | 33 | } |
330 | 17.4k | if (i > cb->top_backref) cb->top_backref = (uint16_t)i; |
331 | 17.4k | size++; |
332 | 17.4k | continue; |
333 | | |
334 | 2.99k | default: |
335 | 2.99k | break; |
336 | 23.2k | } |
337 | | |
338 | 2.99k | PCRE2_ASSERT(size > 0); |
339 | 2.99k | return size; |
340 | 23.2k | } |
341 | 3.04k | } |
342 | | |
343 | | |
344 | | /******************************************************* |
345 | | * Parse the arguments of scan substring operations * |
346 | | ********************************************************/ |
347 | | |
348 | | /* This function parses the arguments of scan substring operations. |
349 | | |
350 | | Arguments: |
351 | | pptr_start points to the current parsed pattern pointer |
352 | | offset argument starting offset in the pattern |
353 | | errorcodeptr where to put an error code |
354 | | cb the compile block |
355 | | lengthptr NULL during the real compile phase |
356 | | points to length accumulator during pre-compile phase |
357 | | |
358 | | Returns: TRUE if OK, FALSE if not, error code set |
359 | | */ |
360 | | |
361 | | uint32_t * |
362 | | PRIV(compile_parse_scan_substr_args)(uint32_t *pptr, |
363 | | int *errorcodeptr, compile_block *cb, PCRE2_SIZE *lengthptr) |
364 | 1.00k | { |
365 | 1.00k | uint8_t *captures; |
366 | 1.00k | uint8_t *capture_ptr; |
367 | 1.00k | uint8_t bit; |
368 | 1.00k | PCRE2_SPTR name; |
369 | 1.00k | named_group *ng; |
370 | 1.00k | named_group *end = cb->named_groups + cb->names_found; |
371 | 1.00k | BOOL all_found; |
372 | 1.00k | size_t size; |
373 | | |
374 | 1.00k | PCRE2_ASSERT(*pptr == META_OFFSET); |
375 | 1.00k | if (PRIV(compile_process_capture_list)(pptr - 1, 0, errorcodeptr, cb) == 0) |
376 | 26 | return NULL; |
377 | | |
378 | | /* Align to bytes. Since the highest capture can |
379 | | be equal to bracount, +1 is added before the aligning. */ |
380 | 974 | size = (cb->bracount + 1 + 7) >> 3; |
381 | 974 | captures = (uint8_t*)cb->cx->memctl.malloc(size, cb->cx->memctl.memory_data); |
382 | 974 | if (captures == NULL) |
383 | 0 | { |
384 | 0 | *errorcodeptr = ERR21; |
385 | 0 | READPLUSOFFSET(cb->erroroffset, pptr); |
386 | 0 | return NULL; |
387 | 0 | } |
388 | | |
389 | 974 | memset(captures, 0, size); |
390 | | |
391 | 3.33k | while (TRUE) |
392 | 3.33k | { |
393 | 3.33k | switch (META_CODE(*pptr)) |
394 | 3.33k | { |
395 | 974 | case META_OFFSET: |
396 | 974 | pptr++; |
397 | 974 | SKIPOFFSET(pptr); |
398 | 974 | continue; |
399 | | |
400 | 619 | case META_CAPTURE_NAME: |
401 | 619 | ng = cb->named_groups + pptr[1]; |
402 | 619 | PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0); |
403 | 619 | pptr += 2; |
404 | 619 | name = ng->name; |
405 | | |
406 | 619 | all_found = TRUE; |
407 | 619 | do |
408 | 7.30k | { |
409 | 7.30k | if (ng->name != name) continue; |
410 | | |
411 | 3.50k | capture_ptr = captures + (ng->number >> 3); |
412 | 3.50k | PCRE2_ASSERT(capture_ptr < captures + size); |
413 | 3.50k | bit = (uint8_t)(1 << (ng->number & 0x7)); |
414 | | |
415 | 3.50k | if ((*capture_ptr & bit) == 0) |
416 | 2.59k | { |
417 | 2.59k | *capture_ptr |= bit; |
418 | 2.59k | all_found = FALSE; |
419 | 2.59k | } |
420 | 3.50k | } |
421 | 7.30k | while (++ng < end); |
422 | | |
423 | 619 | if (!all_found) |
424 | 476 | { |
425 | 476 | *lengthptr += 1 + 2 * IMM2_SIZE; |
426 | 476 | continue; |
427 | 476 | } |
428 | | |
429 | 143 | pptr[-2] = META_CAPTURE_NUMBER; |
430 | 143 | pptr[-1] = 0; |
431 | 143 | continue; |
432 | | |
433 | 764 | case META_CAPTURE_NUMBER: |
434 | 764 | pptr += 2; |
435 | | |
436 | 764 | capture_ptr = captures + (pptr[-1] >> 3); |
437 | 764 | PCRE2_ASSERT(capture_ptr < captures + size); |
438 | 764 | bit = (uint8_t)(1 << (pptr[-1] & 0x7)); |
439 | | |
440 | 764 | if ((*capture_ptr & bit) != 0) |
441 | 132 | { |
442 | 132 | pptr[-1] = 0; |
443 | 132 | continue; |
444 | 132 | } |
445 | | |
446 | 632 | *capture_ptr |= bit; |
447 | 632 | *lengthptr += 1 + IMM2_SIZE; |
448 | 632 | continue; |
449 | | |
450 | 974 | default: |
451 | 974 | break; |
452 | 3.33k | } |
453 | | |
454 | 974 | break; |
455 | 3.33k | } |
456 | | |
457 | 974 | cb->cx->memctl.free(captures, cb->cx->memctl.memory_data); |
458 | 974 | return pptr - 1; |
459 | 974 | } |
460 | | |
461 | | |
462 | | /* Implement heapsort heapify algorithm. */ |
463 | | |
464 | | static void do_heapify_u16(uint16_t *captures, size_t size, size_t i) |
465 | 181k | { |
466 | 181k | size_t max; |
467 | 181k | size_t left; |
468 | 181k | size_t right; |
469 | 181k | uint16_t tmp; |
470 | | |
471 | 1.27M | while (TRUE) |
472 | 1.27M | { |
473 | 1.27M | max = i; |
474 | 1.27M | left = (i << 1) + 1; |
475 | 1.27M | right = left + 1; |
476 | | |
477 | 1.27M | if (left < size && captures[left] > captures[max]) max = left; |
478 | 1.27M | if (right < size && captures[right] > captures[max]) max = right; |
479 | 1.27M | if (i == max) return; |
480 | | |
481 | 1.09M | tmp = captures[i]; |
482 | 1.09M | captures[i] = captures[max]; |
483 | 1.09M | captures[max] = tmp; |
484 | 1.09M | i = max; |
485 | 1.09M | } |
486 | 181k | } |
487 | | |
488 | | |
489 | | /************************************************* |
490 | | * Parse the arguments of recurse operations * |
491 | | *************************************************/ |
492 | | |
493 | | /* This function parses the arguments of recurse operations. |
494 | | |
495 | | Arguments: |
496 | | pptr_start the current parsed pattern pointer |
497 | | offset argument starting offset in the pattern |
498 | | errorcodeptr where to put an error code |
499 | | cb the compile block |
500 | | lengthptr NULL during the real compile phase |
501 | | points to length accumulator during pre-compile phase |
502 | | |
503 | | Returns: TRUE if OK, FALSE if not, error code set |
504 | | */ |
505 | | |
506 | | BOOL |
507 | | PRIV(compile_parse_recurse_args)(uint32_t *pptr_start, |
508 | | PCRE2_SIZE offset, int *errorcodeptr, compile_block *cb) |
509 | 2.04k | { |
510 | 2.04k | uint32_t *pptr = pptr_start; |
511 | 2.04k | size_t i, size; |
512 | 2.04k | PCRE2_SPTR name; |
513 | 2.04k | named_group *ng; |
514 | 2.04k | named_group *end = cb->named_groups + cb->names_found; |
515 | 2.04k | recurse_arguments *args; |
516 | 2.04k | uint16_t *captures; |
517 | 2.04k | uint16_t *current; |
518 | 2.04k | uint16_t *captures_end; |
519 | 2.04k | uint16_t tmp; |
520 | | |
521 | | /* Process all arguments, compute the required size. */ |
522 | | |
523 | 2.04k | size = PRIV(compile_process_capture_list)(pptr, offset, errorcodeptr, cb); |
524 | 2.04k | if (size == 0) return FALSE; |
525 | | |
526 | 2.01k | args = cb->cx->memctl.malloc( |
527 | 2.01k | sizeof(recurse_arguments) + size * sizeof(uint16_t), cb->cx->memctl.memory_data); |
528 | | |
529 | 2.01k | if (args == NULL) |
530 | 0 | { |
531 | 0 | *errorcodeptr = ERR21; |
532 | 0 | cb->erroroffset = offset; |
533 | 0 | return FALSE; |
534 | 0 | } |
535 | | |
536 | 2.01k | args->header.next = NULL; |
537 | | #ifdef PCRE2_DEBUG |
538 | | args->header.type = CDATA_RECURSE_ARGS; |
539 | | #endif |
540 | 2.01k | args->size = size; |
541 | | |
542 | | /* Caching the pre-processed capture list. */ |
543 | 2.01k | if (cb->last_data != NULL) |
544 | 1.83k | cb->last_data->next = &args->header; |
545 | 180 | else |
546 | 180 | cb->first_data = &args->header; |
547 | | |
548 | 2.01k | cb->last_data = &args->header; |
549 | | |
550 | | /* Create the capture list size. */ |
551 | | |
552 | 2.01k | captures = (uint16_t*)(args + 1); |
553 | | |
554 | 19.7k | while (TRUE) |
555 | 19.7k | { |
556 | 19.7k | ++pptr; |
557 | | |
558 | 19.7k | switch (META_CODE(*pptr)) |
559 | 19.7k | { |
560 | 0 | case META_OFFSET: |
561 | 0 | SKIPOFFSET(pptr); |
562 | 0 | continue; |
563 | | |
564 | 792 | case META_CAPTURE_NAME: |
565 | 792 | ng = cb->named_groups + *(++pptr); |
566 | 792 | PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0); |
567 | 792 | *captures++ = (uint16_t)(ng->number); |
568 | | |
569 | 792 | name = ng->name; |
570 | | |
571 | 122k | while (++ng < end) |
572 | 121k | if (ng->name == name) *captures++ = (uint16_t)(ng->number); |
573 | 792 | continue; |
574 | | |
575 | 16.9k | case META_CAPTURE_NUMBER: |
576 | 16.9k | *captures++ = *(++pptr); |
577 | 16.9k | continue; |
578 | | |
579 | 2.01k | default: |
580 | 2.01k | break; |
581 | 19.7k | } |
582 | | |
583 | 2.01k | break; |
584 | 19.7k | } |
585 | | |
586 | 2.01k | PCRE2_ASSERT(size == (size_t)(captures - (uint16_t*)(args + 1))); |
587 | 2.01k | args->skip_size = (size_t)(pptr - pptr_start) - 1; |
588 | | |
589 | 2.01k | if (size == 1) return TRUE; |
590 | | |
591 | | /* Sort captures. */ |
592 | | |
593 | 1.28k | captures = (uint16_t*)(args + 1); |
594 | 1.28k | i = (size >> 1) - 1; |
595 | 60.6k | while (TRUE) |
596 | 60.6k | { |
597 | 60.6k | do_heapify_u16(captures, size, i); |
598 | 60.6k | if (i == 0) break; |
599 | 59.3k | i--; |
600 | 59.3k | } |
601 | | |
602 | 121k | for (i = size - 1; i > 0; i--) |
603 | 120k | { |
604 | 120k | tmp = captures[0]; |
605 | 120k | captures[0] = captures[i]; |
606 | 120k | captures[i] = tmp; |
607 | | |
608 | 120k | do_heapify_u16(captures, i, 0); |
609 | 120k | } |
610 | | |
611 | | /* Remove duplicates. */ |
612 | | |
613 | 1.28k | captures_end = captures + size; |
614 | 1.28k | tmp = *captures++; |
615 | 1.28k | current = captures; |
616 | | |
617 | 121k | while (current < captures_end) |
618 | 120k | { |
619 | 120k | if (*current != tmp) |
620 | 105k | { |
621 | 105k | tmp = *current; |
622 | 105k | *captures++ = tmp; |
623 | 105k | } |
624 | | |
625 | 120k | current++; |
626 | 120k | } |
627 | | |
628 | 1.28k | args->size = (size_t)(captures - (uint16_t*)(args + 1)); |
629 | 1.28k | return TRUE; |
630 | 2.01k | } |
631 | | |
632 | | /* End of pcre2_compile_cgroup.c */ |