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
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdint.h>
25 #include <inttypes.h>
26 //#include <strings.h>
27 #include <limits.h>
28
29 #include "ass_library.h"
30 #include "ass.h"
31 #include "ass_utils.h"
32
33 #if (defined(__i386__) || defined(__x86_64__)) && CONFIG_ASM
34
35 #include "x86/cpuid.h"
36
has_sse2(void)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
has_avx(void)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
has_avx2(void)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
ass_strndup(const char * s,size_t n)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
ass_aligned_alloc(size_t alignment,size_t size)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
ass_aligned_free(void * ptr)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 */
ass_realloc_array(void * ptr,size_t nmemb,size_t size)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 */
ass_try_realloc_array(void * ptr,size_t nmemb,size_t size)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
skip_spaces(char ** str)139 void skip_spaces(char **str)
140 {
141 char *p = *str;
142 while ((*p == ' ') || (*p == '\t'))
143 ++p;
144 *str = p;
145 }
146
rskip_spaces(char ** str,char * limit)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
mystrtoi(char ** p,int * res)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
mystrtoll(char ** p,long long * res)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
mystrtod(char ** p,double * res)171 int mystrtod(char **p, double *res)
172 {
173 char *start = *p;
174 *res = ass_strtod(*p, p);
175 return *p != start;
176 }
177
mystrtoi32(char ** p,int base,int32_t * res)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
read_digits(char ** str,int base,uint32_t * res)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 */
mystrtou32_modulo(char ** p,int base,uint32_t * res)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 && !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
parse_alpha_tag(char * str)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
parse_color_tag(char * str)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
parse_color_header(char * str)269 uint32_t parse_color_header(char *str)
270 {
271 uint32_t color = 0;
272 int base;
273
274 if (!strncasecmp(str, "&h", 2) || !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
parse_bool(char * str)285 char parse_bool(char *str)
286 {
287 skip_spaces(&str);
288 return !strncasecmp(str, "yes", 3) || strtol(str, NULL, 10) > 0;
289 }
290
parse_ycbcr_matrix(char * str)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 (!strcasecmp(buffer, "none"))
309 return YCBCR_NONE;
310 if (!strcasecmp(buffer, "tv.601"))
311 return YCBCR_BT601_TV;
312 if (!strcasecmp(buffer, "pc.601"))
313 return YCBCR_BT601_PC;
314 if (!strcasecmp(buffer, "tv.709"))
315 return YCBCR_BT709_TV;
316 if (!strcasecmp(buffer, "pc.709"))
317 return YCBCR_BT709_PC;
318 if (!strcasecmp(buffer, "tv.240m"))
319 return YCBCR_SMPTE240M_TV;
320 if (!strcasecmp(buffer, "pc.240m"))
321 return YCBCR_SMPTE240M_PC;
322 if (!strcasecmp(buffer, "tv.fcc"))
323 return YCBCR_FCC_TV;
324 if (!strcasecmp(buffer, "pc.fcc"))
325 return YCBCR_FCC_PC;
326 return YCBCR_UNKNOWN;
327 }
328
ass_msg(ASS_Library * priv,int lvl,char * fmt,...)329 void ass_msg(ASS_Library *priv, int lvl, 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
ass_utf8_get_char(char ** str)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 */
ass_utf8_put_char(char * dest,uint32_t ch)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 find style by name
401 * \param track track
402 * \param name style name
403 * \return index in track->styles
404 * Returns 0 if no styles found => expects at least 1 style.
405 * Parsing code always adds "Default" style in the beginning.
406 */
lookup_style(ASS_Track * track,char * name)407 int lookup_style(ASS_Track *track, char *name)
408 {
409 int i;
410 // '*' seem to mean literally nothing;
411 // VSFilter removes them as soon as it can
412 while (*name == '*')
413 ++name;
414 // VSFilter then normalizes the case of "Default"
415 // (only in contexts where this function is called)
416 if (strcasecmp(name, "Default") == 0)
417 name = "Default";
418 for (i = track->n_styles - 1; i >= 0; --i) {
419 if (strcmp(track->styles[i].Name, name) == 0)
420 return i;
421 }
422 i = track->default_style;
423 ass_msg(track->library, MSGL_WARN,
424 "[%p]: Warning: no style named '%s' found, using '%s'",
425 track, name, track->styles[i].Name);
426 return i;
427 }
428
429 /**
430 * \brief find style by name as in \r
431 * \param track track
432 * \param name style name
433 * \param len style name length
434 * \return style in track->styles
435 * Returns NULL if no style has the given name.
436 */
lookup_style_strict(ASS_Track * track,char * name,size_t len)437 ASS_Style *lookup_style_strict(ASS_Track *track, char *name, size_t len)
438 {
439 int i;
440 for (i = track->n_styles - 1; i >= 0; --i) {
441 if (strncmp(track->styles[i].Name, name, len) == 0 &&
442 track->styles[i].Name[len] == '\0')
443 return track->styles + i;
444 }
445 ass_msg(track->library, MSGL_WARN,
446 "[%p]: Warning: no style named '%.*s' found",
447 track, (int) len, name);
448 return NULL;
449 }
450
451 #ifdef CONFIG_ENCA
ass_guess_buffer_cp(ASS_Library * library,unsigned char * buffer,int buflen,char * preferred_language,char * fallback)452 void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
453 int buflen, char *preferred_language,
454 char *fallback)
455 {
456 const char **languages;
457 size_t langcnt;
458 EncaAnalyser analyser;
459 EncaEncoding encoding;
460 char *detected_sub_cp = NULL;
461 int i;
462
463 languages = enca_get_languages(&langcnt);
464 ass_msg(library, MSGL_V, "ENCA supported languages");
465 for (i = 0; i < langcnt; i++) {
466 ass_msg(library, MSGL_V, "lang %s", languages[i]);
467 }
468
469 for (i = 0; i < langcnt; i++) {
470 const char *tmp;
471
472 if (strcasecmp(languages[i], preferred_language) != 0)
473 continue;
474 analyser = enca_analyser_alloc(languages[i]);
475 encoding = enca_analyse_const(analyser, buffer, buflen);
476 tmp = enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV);
477 if (tmp && encoding.charset != ENCA_CS_UNKNOWN) {
478 detected_sub_cp = strdup(tmp);
479 ass_msg(library, MSGL_INFO, "ENCA detected charset: %s", tmp);
480 }
481 enca_analyser_free(analyser);
482 }
483
484 free(languages);
485
486 if (!detected_sub_cp) {
487 detected_sub_cp = strdup(fallback);
488 ass_msg(library, MSGL_INFO,
489 "ENCA detection failed: fallback to %s", fallback);
490 }
491
492 return detected_sub_cp;
493 }
494 #endif
495