]> granicus.if.org Git - libass/blob - libass/ass_utils.c
rasterizer: drop outlines with points at too large coordinates
[libass] / libass / ass_utils.c
1 /*
2  * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
3  *
4  * This file is part of libass.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include "config.h"
20 #include "ass_compat.h"
21
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <inttypes.h>
27
28 #include "ass_library.h"
29 #include "ass.h"
30 #include "ass_utils.h"
31 #include "ass_string.h"
32
33 #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM
34
35 #include "x86/cpuid.h"
36
37 int has_sse2(void)
38 {
39     uint32_t eax = 1, ebx, ecx, edx;
40     ass_get_cpuid(&eax, &ebx, &ecx, &edx);
41     return (edx >> 26) & 0x1;
42 }
43
44 int has_avx(void)
45 {
46     uint32_t eax = 1, ebx, ecx, edx;
47     ass_get_cpuid(&eax, &ebx, &ecx, &edx);
48     if(!(ecx & (1 << 27))) // not OSXSAVE
49         return 0;
50     uint32_t misc = ecx;
51     ass_get_xgetbv(0, &eax, &edx);
52     if((eax & 0x6) != 0x6)
53         return 0;
54     eax = 0;
55     ass_get_cpuid(&eax, &ebx, &ecx, &edx);
56     return (ecx & 0x6) == 0x6 ? (misc >> 28) & 0x1 : 0; // check high bits are relevant, then AVX support
57 }
58
59 int has_avx2(void)
60 {
61     uint32_t eax = 7, ebx, ecx, edx;
62     ass_get_cpuid(&eax, &ebx, &ecx, &edx);
63     return (ebx >> 5) & has_avx();
64 }
65
66 #endif // ASM
67
68 #ifndef HAVE_STRNDUP
69 char *ass_strndup(const char *s, size_t n)
70 {
71     char *end = memchr(s, 0, n);
72     size_t len = end ? end - s : n;
73     char *new = len < SIZE_MAX ? malloc(len + 1) : NULL;
74     if (new) {
75         memcpy(new, s, len);
76         new[len] = 0;
77     }
78     return new;
79 }
80 #endif
81
82 void *ass_aligned_alloc(size_t alignment, size_t size)
83 {
84     assert(!(alignment & (alignment - 1))); // alignment must be power of 2
85     if (size >= SIZE_MAX - alignment - sizeof(void *))
86         return NULL;
87     char *allocation = malloc(size + sizeof(void *) + alignment - 1);
88     if (!allocation)
89         return NULL;
90     char *ptr = allocation + sizeof(void *);
91     unsigned int misalign = (uintptr_t)ptr & (alignment - 1);
92     if (misalign)
93         ptr += alignment - misalign;
94     *((void **)ptr - 1) = allocation;
95     return ptr;
96 }
97
98 void ass_aligned_free(void *ptr)
99 {
100     if (ptr)
101         free(*((void **)ptr - 1));
102 }
103
104 /**
105  * This works similar to realloc(ptr, nmemb * size), but checks for overflow.
106  *
107  * Unlike some implementations of realloc, this never acts as a call to free().
108  * If the total size is 0, it is bumped up to 1. This means a NULL return always
109  * means allocation failure, and the unportable realloc(0, 0) case is avoided.
110  */
111 void *ass_realloc_array(void *ptr, size_t nmemb, size_t size)
112 {
113     if (nmemb > (SIZE_MAX / size))
114         return NULL;
115     size *= nmemb;
116     if (size < 1)
117         size = 1;
118
119     return realloc(ptr, size);
120 }
121
122 /**
123  * Like ass_realloc_array(), but:
124  * 1. on failure, return the original ptr value, instead of NULL
125  * 2. set errno to indicate failure (errno!=0) or success (errno==0)
126  */
127 void *ass_try_realloc_array(void *ptr, size_t nmemb, size_t size)
128 {
129     void *new_ptr = ass_realloc_array(ptr, nmemb, size);
130     if (new_ptr) {
131         errno = 0;
132         return new_ptr;
133     } else {
134         errno = ENOMEM;
135         return ptr;
136     }
137 }
138
139 void skip_spaces(char **str)
140 {
141     char *p = *str;
142     while ((*p == ' ') || (*p == '\t'))
143         ++p;
144     *str = p;
145 }
146
147 void rskip_spaces(char **str, char *limit)
148 {
149     char *p = *str;
150     while ((p > limit) && ((p[-1] == ' ') || (p[-1] == '\t')))
151         --p;
152     *str = p;
153 }
154
155 int mystrtoi(char **p, int *res)
156 {
157     char *start = *p;
158     double temp_res = ass_strtod(*p, p);
159     *res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
160     return *p != start;
161 }
162
163 int mystrtoll(char **p, long long *res)
164 {
165     char *start = *p;
166     double temp_res = ass_strtod(*p, p);
167     *res = (long long) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
168     return *p != start;
169 }
170
171 int mystrtod(char **p, double *res)
172 {
173     char *start = *p;
174     *res = ass_strtod(*p, p);
175     return *p != start;
176 }
177
178 int mystrtoi32(char **p, int base, int32_t *res)
179 {
180     char *start = *p;
181     long long temp_res = strtoll(*p, p, base);
182     *res = FFMINMAX(temp_res, INT32_MIN, INT32_MAX);
183     return *p != start;
184 }
185
186 static int read_digits(char **str, int base, uint32_t *res)
187 {
188     char *p = *str;
189     char *start = p;
190     uint32_t val = 0;
191
192     while (1) {
193         int digit;
194         if (*p >= '0' && *p < base + '0')
195             digit = *p - '0';
196         else if (*p >= 'a' && *p < base - 10 + 'a')
197             digit = *p - 'a' + 10;
198         else if (*p >= 'A' && *p < base - 10 + 'A')
199             digit = *p - 'A' + 10;
200         else
201             break;
202         val = val * base + digit;
203         ++p;
204     }
205
206     *res = val;
207     *str = p;
208     return p != start;
209 }
210
211 /**
212  * \brief Convert a string to an integer reduced modulo 2**32
213  * Follows the rules for strtoul but reduces the number modulo 2**32
214  * instead of saturating it to 2**32 - 1.
215  */
216 static int mystrtou32_modulo(char **p, int base, uint32_t *res)
217 {
218     // This emulates scanf with %d or %x format as it works on
219     // Windows, because that's what is used by VSFilter. In practice,
220     // scanf works the same way on other platforms too, but
221     // the standard leaves its behavior on overflow undefined.
222
223     // Unlike scanf and like strtoul, produce 0 for invalid inputs.
224
225     char *start = *p;
226     int sign = 1;
227
228     skip_spaces(p);
229
230     if (**p == '+')
231         ++*p;
232     else if (**p == '-')
233         sign = -1, ++*p;
234
235     if (base == 16 && !ass_strncasecmp(*p, "0x", 2))
236         *p += 2;
237
238     if (read_digits(p, base, res)) {
239         *res *= sign;
240         return 1;
241     } else {
242         *p = start;
243         return 0;
244     }
245 }
246
247 int32_t parse_alpha_tag(char *str)
248 {
249     int32_t alpha = 0;
250
251     while (*str == '&' || *str == 'H')
252         ++str;
253
254     mystrtoi32(&str, 16, &alpha);
255     return alpha;
256 }
257
258 uint32_t parse_color_tag(char *str)
259 {
260     int32_t color = 0;
261
262     while (*str == '&' || *str == 'H')
263         ++str;
264
265     mystrtoi32(&str, 16, &color);
266     return ass_bswap32((uint32_t) color);
267 }
268
269 uint32_t parse_color_header(char *str)
270 {
271     uint32_t color = 0;
272     int base;
273
274     if (!ass_strncasecmp(str, "&h", 2) || !ass_strncasecmp(str, "0x", 2)) {
275         str += 2;
276         base = 16;
277     } else
278         base = 10;
279
280     mystrtou32_modulo(&str, base, &color);
281     return ass_bswap32(color);
282 }
283
284 // Return a boolean value for a string
285 char parse_bool(char *str)
286 {
287     skip_spaces(&str);
288     return !ass_strncasecmp(str, "yes", 3) || strtol(str, NULL, 10) > 0;
289 }
290
291 int parse_ycbcr_matrix(char *str)
292 {
293     skip_spaces(&str);
294     if (*str == '\0')
295         return YCBCR_DEFAULT;
296
297     char *end = str + strlen(str);
298     rskip_spaces(&end, str);
299
300     // Trim a local copy of the input that we know is safe to
301     // modify. The buffer is larger than any valid string + NUL,
302     // so we can simply chop off the rest of the input.
303     char buffer[16];
304     size_t n = FFMIN(end - str, sizeof buffer - 1);
305     memcpy(buffer, str, n);
306     buffer[n] = '\0';
307
308     if (!ass_strcasecmp(buffer, "none"))
309         return YCBCR_NONE;
310     if (!ass_strcasecmp(buffer, "tv.601"))
311         return YCBCR_BT601_TV;
312     if (!ass_strcasecmp(buffer, "pc.601"))
313         return YCBCR_BT601_PC;
314     if (!ass_strcasecmp(buffer, "tv.709"))
315         return YCBCR_BT709_TV;
316     if (!ass_strcasecmp(buffer, "pc.709"))
317         return YCBCR_BT709_PC;
318     if (!ass_strcasecmp(buffer, "tv.240m"))
319         return YCBCR_SMPTE240M_TV;
320     if (!ass_strcasecmp(buffer, "pc.240m"))
321         return YCBCR_SMPTE240M_PC;
322     if (!ass_strcasecmp(buffer, "tv.fcc"))
323         return YCBCR_FCC_TV;
324     if (!ass_strcasecmp(buffer, "pc.fcc"))
325         return YCBCR_FCC_PC;
326     return YCBCR_UNKNOWN;
327 }
328
329 void ass_msg(ASS_Library *priv, int lvl, const char *fmt, ...)
330 {
331     va_list va;
332     va_start(va, fmt);
333     priv->msg_callback(lvl, fmt, va, priv->msg_callback_data);
334     va_end(va);
335 }
336
337 unsigned ass_utf8_get_char(char **str)
338 {
339     uint8_t *strp = (uint8_t *) * str;
340     unsigned c = *strp++;
341     unsigned mask = 0x80;
342     int len = -1;
343     while (c & mask) {
344         mask >>= 1;
345         len++;
346     }
347     if (len <= 0 || len > 4)
348         goto no_utf8;
349     c &= mask - 1;
350     while ((*strp & 0xc0) == 0x80) {
351         if (len-- <= 0)
352             goto no_utf8;
353         c = (c << 6) | (*strp++ & 0x3f);
354     }
355     if (len)
356         goto no_utf8;
357     *str = (char *) strp;
358     return c;
359
360   no_utf8:
361     strp = (uint8_t *) * str;
362     c = *strp++;
363     *str = (char *) strp;
364     return c;
365 }
366
367 /**
368  * Original version from http://www.cprogramming.com/tutorial/utf8.c
369  * \brief Converts a single UTF-32 code point to UTF-8
370  * \param dest Buffer to write to. Writes a NULL terminator.
371  * \param ch 32-bit character code to convert
372  * \return number of bytes written
373  * converts a single character and ASSUMES YOU HAVE ENOUGH SPACE
374  */
375 unsigned ass_utf8_put_char(char *dest, uint32_t ch)
376 {
377     char *orig_dest = dest;
378
379     if (ch < 0x80) {
380         *dest++ = (char)ch;
381     } else if (ch < 0x800) {
382         *dest++ = (ch >> 6) | 0xC0;
383         *dest++ = (ch & 0x3F) | 0x80;
384     } else if (ch < 0x10000) {
385         *dest++ = (ch >> 12) | 0xE0;
386         *dest++ = ((ch >> 6) & 0x3F) | 0x80;
387         *dest++ = (ch & 0x3F) | 0x80;
388     } else if (ch < 0x110000) {
389         *dest++ = (ch >> 18) | 0xF0;
390         *dest++ = ((ch >> 12) & 0x3F) | 0x80;
391         *dest++ = ((ch >> 6) & 0x3F) | 0x80;
392         *dest++ = (ch & 0x3F) | 0x80;
393     }
394
395     *dest = '\0';
396     return dest - orig_dest;
397 }
398
399 /**
400  * \brief Parse UTF-16 and return the code point of the sequence starting at src.
401  * \param src pointer to a pointer to the start of the UTF-16 data
402  *            (will be set to the start of the next code point)
403  * \return the code point
404  */
405 static uint32_t ass_read_utf16be(uint8_t **src, size_t bytes)
406 {
407     if (bytes < 2)
408         goto too_short;
409
410     uint32_t cp = ((*src)[0] << 8) | (*src)[1];
411     *src += 2;
412     bytes -= 2;
413
414     if (cp >= 0xD800 && cp <= 0xDBFF) {
415         if (bytes < 2)
416             goto too_short;
417
418         uint32_t cp2 = ((*src)[0] << 8) | (*src)[1];
419
420         if (cp2 < 0xDC00 || cp2 > 0xDFFF)
421             return 0xFFFD;
422
423         *src += 2;
424
425         cp = 0x10000 + ((cp - 0xD800) << 10) + (cp2 - 0xDC00);
426     }
427
428     if (cp >= 0xDC00 && cp <= 0xDFFF)
429         return 0xFFFD;
430
431     return cp;
432
433 too_short:
434     *src += bytes;
435     return 0xFFFD;
436 }
437
438 void ass_utf16be_to_utf8(char *dst, size_t dst_size, uint8_t *src, size_t src_size)
439 {
440     uint8_t *end = src + src_size;
441
442     if (!dst_size)
443         return;
444
445     while (src < end) {
446         uint32_t cp = ass_read_utf16be(&src, end - src);
447         if (dst_size < 5)
448             break;
449         unsigned s = ass_utf8_put_char(dst, cp);
450         dst += s;
451         dst_size -= s;
452     }
453
454     *dst = '\0';
455 }
456
457 /**
458  * \brief find style by name
459  * \param track track
460  * \param name style name
461  * \return index in track->styles
462  * Returns 0 if no styles found => expects at least 1 style.
463  * Parsing code always adds "Default" style in the beginning.
464  */
465 int lookup_style(ASS_Track *track, char *name)
466 {
467     int i;
468     // '*' seem to mean literally nothing;
469     // VSFilter removes them as soon as it can
470     while (*name == '*')
471         ++name;
472     // VSFilter then normalizes the case of "Default"
473     // (only in contexts where this function is called)
474     if (ass_strcasecmp(name, "Default") == 0)
475         name = "Default";
476     for (i = track->n_styles - 1; i >= 0; --i) {
477         if (strcmp(track->styles[i].Name, name) == 0)
478             return i;
479     }
480     i = track->default_style;
481     ass_msg(track->library, MSGL_WARN,
482             "[%p]: Warning: no style named '%s' found, using '%s'",
483             track, name, track->styles[i].Name);
484     return i;
485 }
486
487 /**
488  * \brief find style by name as in \r
489  * \param track track
490  * \param name style name
491  * \param len style name length
492  * \return style in track->styles
493  * Returns NULL if no style has the given name.
494  */
495 ASS_Style *lookup_style_strict(ASS_Track *track, char *name, size_t len)
496 {
497     int i;
498     for (i = track->n_styles - 1; i >= 0; --i) {
499         if (strncmp(track->styles[i].Name, name, len) == 0 &&
500             track->styles[i].Name[len] == '\0')
501             return track->styles + i;
502     }
503     ass_msg(track->library, MSGL_WARN,
504             "[%p]: Warning: no style named '%.*s' found",
505             track, (int) len, name);
506     return NULL;
507 }
508