/src/ffmpeg/libavutil/avstring.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2000, 2001, 2002 Fabrice Bellard |
3 | | * Copyright (c) 2007 Mans Rullgard |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include <limits.h> |
23 | | #include <stdarg.h> |
24 | | #include <stdint.h> |
25 | | #include <stdio.h> |
26 | | #include <string.h> |
27 | | |
28 | | #include "config.h" |
29 | | #include "mem.h" |
30 | | #include "avassert.h" |
31 | | #include "avstring.h" |
32 | | #include "bprint.h" |
33 | | #include "error.h" |
34 | | #include "macros.h" |
35 | | |
36 | | int av_strstart(const char *str, const char *pfx, const char **ptr) |
37 | 4.09k | { |
38 | 4.09k | while (*pfx && *pfx == *str) { |
39 | 0 | pfx++; |
40 | 0 | str++; |
41 | 0 | } |
42 | 4.09k | if (!*pfx && ptr) |
43 | 0 | *ptr = str; |
44 | 4.09k | return !*pfx; |
45 | 4.09k | } |
46 | | |
47 | | int av_stristart(const char *str, const char *pfx, const char **ptr) |
48 | 0 | { |
49 | 0 | while (*pfx && av_toupper((unsigned)*pfx) == av_toupper((unsigned)*str)) { |
50 | 0 | pfx++; |
51 | 0 | str++; |
52 | 0 | } |
53 | 0 | if (!*pfx && ptr) |
54 | 0 | *ptr = str; |
55 | 0 | return !*pfx; |
56 | 0 | } |
57 | | |
58 | | char *av_stristr(const char *s1, const char *s2) |
59 | 0 | { |
60 | 0 | if (!*s2) |
61 | 0 | return (char*)(intptr_t)s1; |
62 | | |
63 | 0 | do |
64 | 0 | if (av_stristart(s1, s2, NULL)) |
65 | 0 | return (char*)(intptr_t)s1; |
66 | 0 | while (*s1++); |
67 | | |
68 | 0 | return NULL; |
69 | 0 | } |
70 | | |
71 | | char *av_strnstr(const char *haystack, const char *needle, size_t hay_length) |
72 | 0 | { |
73 | 0 | size_t needle_len = strlen(needle); |
74 | 0 | if (!needle_len) |
75 | 0 | return (char*)haystack; |
76 | 0 | while (hay_length >= needle_len) { |
77 | 0 | hay_length--; |
78 | 0 | if (!memcmp(haystack, needle, needle_len)) |
79 | 0 | return (char*)haystack; |
80 | 0 | haystack++; |
81 | 0 | } |
82 | 0 | return NULL; |
83 | 0 | } |
84 | | |
85 | | size_t av_strlcpy(char *dst, const char *src, size_t size) |
86 | 1.36k | { |
87 | 1.36k | size_t len = 0; |
88 | 6.82k | while (++len < size && *src) |
89 | 5.45k | *dst++ = *src++; |
90 | 1.36k | if (len <= size) |
91 | 1.36k | *dst = 0; |
92 | 1.36k | return len + strlen(src) - 1; |
93 | 1.36k | } |
94 | | |
95 | | size_t av_strlcat(char *dst, const char *src, size_t size) |
96 | 0 | { |
97 | 0 | size_t len = strlen(dst); |
98 | 0 | if (size <= len + 1) |
99 | 0 | return len + strlen(src); |
100 | 0 | return len + av_strlcpy(dst + len, src, size - len); |
101 | 0 | } |
102 | | |
103 | | size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) |
104 | 0 | { |
105 | 0 | size_t len = strlen(dst); |
106 | 0 | va_list vl; |
107 | |
|
108 | 0 | va_start(vl, fmt); |
109 | 0 | len += vsnprintf(dst + len, size > len ? size - len : 0, fmt, vl); |
110 | 0 | va_end(vl); |
111 | |
|
112 | 0 | return len; |
113 | 0 | } |
114 | | |
115 | | char *av_asprintf(const char *fmt, ...) |
116 | 0 | { |
117 | 0 | char *p = NULL; |
118 | 0 | va_list va; |
119 | 0 | int len; |
120 | |
|
121 | 0 | va_start(va, fmt); |
122 | 0 | len = vsnprintf(NULL, 0, fmt, va); |
123 | 0 | va_end(va); |
124 | 0 | if (len < 0) |
125 | 0 | goto end; |
126 | | |
127 | 0 | p = av_malloc(len + 1); |
128 | 0 | if (!p) |
129 | 0 | goto end; |
130 | | |
131 | 0 | va_start(va, fmt); |
132 | 0 | len = vsnprintf(p, len + 1, fmt, va); |
133 | 0 | va_end(va); |
134 | 0 | if (len < 0) |
135 | 0 | av_freep(&p); |
136 | |
|
137 | 0 | end: |
138 | 0 | return p; |
139 | 0 | } |
140 | | |
141 | 0 | #define WHITESPACES " \n\t\r" |
142 | | |
143 | | char *av_get_token(const char **buf, const char *term) |
144 | 0 | { |
145 | 0 | char *out = av_realloc(NULL, strlen(*buf) + 1); |
146 | 0 | char *ret = out, *end = out; |
147 | 0 | const char *p = *buf; |
148 | 0 | if (!out) |
149 | 0 | return NULL; |
150 | 0 | p += strspn(p, WHITESPACES); |
151 | |
|
152 | 0 | while (*p && !strspn(p, term)) { |
153 | 0 | char c = *p++; |
154 | 0 | if (c == '\\' && *p) { |
155 | 0 | *out++ = *p++; |
156 | 0 | end = out; |
157 | 0 | } else if (c == '\'') { |
158 | 0 | while (*p && *p != '\'') |
159 | 0 | *out++ = *p++; |
160 | 0 | if (*p) { |
161 | 0 | p++; |
162 | 0 | end = out; |
163 | 0 | } |
164 | 0 | } else { |
165 | 0 | *out++ = c; |
166 | 0 | } |
167 | 0 | } |
168 | |
|
169 | 0 | do |
170 | 0 | *out-- = 0; |
171 | 0 | while (out >= end && strspn(out, WHITESPACES)); |
172 | |
|
173 | 0 | *buf = p; |
174 | |
|
175 | 0 | char *small_ret = av_realloc(ret, out - ret + 2); |
176 | 0 | return small_ret ? small_ret : ret; |
177 | 0 | } |
178 | | |
179 | | char *av_strtok(char *s, const char *delim, char **saveptr) |
180 | 0 | { |
181 | 0 | char *tok; |
182 | |
|
183 | 0 | if (!s && !(s = *saveptr)) |
184 | 0 | return NULL; |
185 | | |
186 | | /* skip leading delimiters */ |
187 | 0 | s += strspn(s, delim); |
188 | | |
189 | | /* s now points to the first non delimiter char, or to the end of the string */ |
190 | 0 | if (!*s) { |
191 | 0 | *saveptr = NULL; |
192 | 0 | return NULL; |
193 | 0 | } |
194 | 0 | tok = s++; |
195 | | |
196 | | /* skip non delimiters */ |
197 | 0 | s += strcspn(s, delim); |
198 | 0 | if (*s) { |
199 | 0 | *s = 0; |
200 | 0 | *saveptr = s+1; |
201 | 0 | } else { |
202 | 0 | *saveptr = NULL; |
203 | 0 | } |
204 | |
|
205 | 0 | return tok; |
206 | 0 | } |
207 | | |
208 | | int av_strcasecmp(const char *a, const char *b) |
209 | 0 | { |
210 | 0 | uint8_t c1, c2; |
211 | 0 | do { |
212 | 0 | c1 = av_tolower(*a++); |
213 | 0 | c2 = av_tolower(*b++); |
214 | 0 | } while (c1 && c1 == c2); |
215 | 0 | return c1 - c2; |
216 | 0 | } |
217 | | |
218 | | int av_strncasecmp(const char *a, const char *b, size_t n) |
219 | 0 | { |
220 | 0 | uint8_t c1, c2; |
221 | 0 | if (n <= 0) |
222 | 0 | return 0; |
223 | 0 | do { |
224 | 0 | c1 = av_tolower(*a++); |
225 | 0 | c2 = av_tolower(*b++); |
226 | 0 | } while (--n && c1 && c1 == c2); |
227 | 0 | return c1 - c2; |
228 | 0 | } |
229 | | |
230 | | char *av_strireplace(const char *str, const char *from, const char *to) |
231 | 0 | { |
232 | 0 | char *ret = NULL; |
233 | 0 | const char *pstr2, *pstr = str; |
234 | 0 | size_t tolen = strlen(to), fromlen = strlen(from); |
235 | 0 | AVBPrint pbuf; |
236 | |
|
237 | 0 | av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); |
238 | 0 | while ((pstr2 = av_stristr(pstr, from))) { |
239 | 0 | av_bprint_append_data(&pbuf, pstr, pstr2 - pstr); |
240 | 0 | pstr = pstr2 + fromlen; |
241 | 0 | av_bprint_append_data(&pbuf, to, tolen); |
242 | 0 | } |
243 | 0 | av_bprint_append_data(&pbuf, pstr, strlen(pstr)); |
244 | 0 | if (!av_bprint_is_complete(&pbuf)) { |
245 | 0 | av_bprint_finalize(&pbuf, NULL); |
246 | 0 | } else { |
247 | 0 | av_bprint_finalize(&pbuf, &ret); |
248 | 0 | } |
249 | |
|
250 | 0 | return ret; |
251 | 0 | } |
252 | | |
253 | | const char *av_basename(const char *path) |
254 | 0 | { |
255 | 0 | char *p; |
256 | | #if HAVE_DOS_PATHS |
257 | | char *q, *d; |
258 | | #endif |
259 | |
|
260 | 0 | if (!path || *path == '\0') |
261 | 0 | return "."; |
262 | | |
263 | 0 | p = strrchr(path, '/'); |
264 | | #if HAVE_DOS_PATHS |
265 | | q = strrchr(path, '\\'); |
266 | | d = strchr(path, ':'); |
267 | | p = FFMAX3(p, q, d); |
268 | | #endif |
269 | |
|
270 | 0 | if (!p) |
271 | 0 | return path; |
272 | | |
273 | 0 | return p + 1; |
274 | 0 | } |
275 | | |
276 | | const char *av_dirname(char *path) |
277 | 0 | { |
278 | 0 | char *p = path ? strrchr(path, '/') : NULL; |
279 | |
|
280 | | #if HAVE_DOS_PATHS |
281 | | char *q = path ? strrchr(path, '\\') : NULL; |
282 | | char *d = path ? strchr(path, ':') : NULL; |
283 | | |
284 | | d = d ? d + 1 : d; |
285 | | |
286 | | p = FFMAX3(p, q, d); |
287 | | #endif |
288 | |
|
289 | 0 | if (!p) |
290 | 0 | return "."; |
291 | | |
292 | 0 | *p = '\0'; |
293 | |
|
294 | 0 | return path; |
295 | 0 | } |
296 | | |
297 | | char *av_append_path_component(const char *path, const char *component) |
298 | 0 | { |
299 | 0 | size_t p_len, c_len; |
300 | 0 | char *fullpath; |
301 | |
|
302 | 0 | if (!path) |
303 | 0 | return av_strdup(component); |
304 | 0 | if (!component) |
305 | 0 | return av_strdup(path); |
306 | | |
307 | 0 | p_len = strlen(path); |
308 | 0 | c_len = strlen(component); |
309 | 0 | if (p_len > SIZE_MAX - c_len || p_len + c_len > SIZE_MAX - 2) |
310 | 0 | return NULL; |
311 | 0 | fullpath = av_malloc(p_len + c_len + 2); |
312 | 0 | if (fullpath) { |
313 | 0 | if (p_len) { |
314 | 0 | av_strlcpy(fullpath, path, p_len + 1); |
315 | 0 | if (c_len) { |
316 | 0 | if (fullpath[p_len - 1] != '/' && component[0] != '/') |
317 | 0 | fullpath[p_len++] = '/'; |
318 | 0 | else if (fullpath[p_len - 1] == '/' && component[0] == '/') |
319 | 0 | p_len--; |
320 | 0 | } |
321 | 0 | } |
322 | 0 | av_strlcpy(&fullpath[p_len], component, c_len + 1); |
323 | 0 | fullpath[p_len + c_len] = 0; |
324 | 0 | } |
325 | 0 | return fullpath; |
326 | 0 | } |
327 | | |
328 | | int av_escape(char **dst, const char *src, const char *special_chars, |
329 | | enum AVEscapeMode mode, int flags) |
330 | 0 | { |
331 | 0 | AVBPrint dstbuf; |
332 | 0 | int ret; |
333 | |
|
334 | 0 | av_bprint_init(&dstbuf, 1, INT_MAX); /* (int)dstbuf.len must be >= 0 */ |
335 | 0 | av_bprint_escape(&dstbuf, src, special_chars, mode, flags); |
336 | |
|
337 | 0 | if (!av_bprint_is_complete(&dstbuf)) { |
338 | 0 | av_bprint_finalize(&dstbuf, NULL); |
339 | 0 | return AVERROR(ENOMEM); |
340 | 0 | } |
341 | 0 | if ((ret = av_bprint_finalize(&dstbuf, dst)) < 0) |
342 | 0 | return ret; |
343 | 0 | return dstbuf.len; |
344 | 0 | } |
345 | | |
346 | | int av_match_name(const char *name, const char *names) |
347 | 0 | { |
348 | 0 | const char *p; |
349 | 0 | size_t len, namelen; |
350 | |
|
351 | 0 | if (!name || !names) |
352 | 0 | return 0; |
353 | | |
354 | 0 | namelen = strlen(name); |
355 | 0 | while (*names) { |
356 | 0 | int negate = '-' == *names; |
357 | 0 | p = strchr(names, ','); |
358 | 0 | if (!p) |
359 | 0 | p = names + strlen(names); |
360 | 0 | names += negate; |
361 | 0 | len = FFMAX(p - names, namelen); |
362 | 0 | if (!av_strncasecmp(name, names, len) || !strncmp("ALL", names, FFMAX(3, p - names))) |
363 | 0 | return !negate; |
364 | 0 | names = p + (*p == ','); |
365 | 0 | } |
366 | 0 | return 0; |
367 | 0 | } |
368 | | |
369 | | int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, |
370 | | unsigned int flags) |
371 | 0 | { |
372 | 0 | const uint8_t *p = *bufp; |
373 | 0 | uint32_t top; |
374 | 0 | uint64_t code; |
375 | 0 | int ret = 0, tail_len; |
376 | 0 | uint32_t overlong_encoding_mins[6] = { |
377 | 0 | 0x00000000, 0x00000080, 0x00000800, 0x00010000, 0x00200000, 0x04000000, |
378 | 0 | }; |
379 | |
|
380 | 0 | if (p >= buf_end) |
381 | 0 | return 0; |
382 | | |
383 | 0 | code = *p++; |
384 | | |
385 | | /* first sequence byte starts with 10, or is 1111-1110 or 1111-1111, |
386 | | which is not admitted */ |
387 | 0 | if ((code & 0xc0) == 0x80 || code >= 0xFE) { |
388 | 0 | ret = AVERROR(EILSEQ); |
389 | 0 | goto end; |
390 | 0 | } |
391 | 0 | top = (code & 128) >> 1; |
392 | |
|
393 | 0 | tail_len = 0; |
394 | 0 | while (code & top) { |
395 | 0 | int tmp; |
396 | 0 | tail_len++; |
397 | 0 | if (p >= buf_end) { |
398 | 0 | (*bufp) ++; |
399 | 0 | return AVERROR(EILSEQ); /* incomplete sequence */ |
400 | 0 | } |
401 | | |
402 | | /* we assume the byte to be in the form 10xx-xxxx */ |
403 | 0 | tmp = *p++ - 128; /* strip leading 1 */ |
404 | 0 | if (tmp>>6) { |
405 | 0 | (*bufp) ++; |
406 | 0 | return AVERROR(EILSEQ); |
407 | 0 | } |
408 | 0 | code = (code<<6) + tmp; |
409 | 0 | top <<= 5; |
410 | 0 | } |
411 | 0 | code &= (top << 1) - 1; |
412 | | |
413 | | /* check for overlong encodings */ |
414 | 0 | av_assert0(tail_len <= 5); |
415 | 0 | if (code < overlong_encoding_mins[tail_len]) { |
416 | 0 | ret = AVERROR(EILSEQ); |
417 | 0 | goto end; |
418 | 0 | } |
419 | | |
420 | 0 | if (code >= 1U<<31) { |
421 | 0 | ret = AVERROR(EILSEQ); /* out-of-range value */ |
422 | 0 | goto end; |
423 | 0 | } |
424 | | |
425 | 0 | *codep = code; |
426 | |
|
427 | 0 | if (code > 0x10FFFF && |
428 | 0 | !(flags & AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES)) |
429 | 0 | ret = AVERROR(EILSEQ); |
430 | 0 | if (code < 0x20 && code != 0x9 && code != 0xA && code != 0xD && |
431 | 0 | flags & AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES) |
432 | 0 | ret = AVERROR(EILSEQ); |
433 | 0 | if (code >= 0xD800 && code <= 0xDFFF && |
434 | 0 | !(flags & AV_UTF8_FLAG_ACCEPT_SURROGATES)) |
435 | 0 | ret = AVERROR(EILSEQ); |
436 | 0 | if ((code == 0xFFFE || code == 0xFFFF) && |
437 | 0 | !(flags & AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS)) |
438 | 0 | ret = AVERROR(EILSEQ); |
439 | |
|
440 | 0 | end: |
441 | 0 | *bufp = p; |
442 | 0 | return ret; |
443 | 0 | } |
444 | | |
445 | | int av_match_list(const char *name, const char *list, char separator) |
446 | 0 | { |
447 | 0 | const char *p, *q; |
448 | |
|
449 | 0 | for (p = name; p && *p; ) { |
450 | 0 | for (q = list; q && *q; ) { |
451 | 0 | int k; |
452 | 0 | for (k = 0; p[k] == q[k] || (p[k]*q[k] == 0 && p[k]+q[k] == separator); k++) |
453 | 0 | if (k && (!p[k] || p[k] == separator)) |
454 | 0 | return 1; |
455 | 0 | q = strchr(q, separator); |
456 | 0 | if(q) |
457 | 0 | q++; |
458 | 0 | } |
459 | 0 | p = strchr(p, separator); |
460 | 0 | if (p) |
461 | 0 | p++; |
462 | 0 | } |
463 | | |
464 | 0 | return 0; |
465 | 0 | } |