LCOV - code coverage report
Current view: top level - src/libavcodec - ass_split.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 229 302 75.8 %
Date: 2017-01-28 02:43:52 Functions: 16 20 80.0 %

          Line data    Source code
       1             : /*
       2             :  * SSA/ASS spliting functions
       3             :  * Copyright (c) 2010  Aurelien Jacobs <aurel@gnuage.org>
       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 "avcodec.h"
      23             : #include "ass_split.h"
      24             : 
      25             : typedef enum {
      26             :     ASS_STR,
      27             :     ASS_INT,
      28             :     ASS_FLT,
      29             :     ASS_COLOR,
      30             :     ASS_TIMESTAMP,
      31             :     ASS_ALGN,
      32             : } ASSFieldType;
      33             : 
      34             : typedef struct {
      35             :     const char *name;
      36             :     int type;
      37             :     int offset;
      38             : } ASSFields;
      39             : 
      40             : typedef struct {
      41             :     const char *section;
      42             :     const char *format_header;
      43             :     const char *fields_header;
      44             :     int         size;
      45             :     int         offset;
      46             :     int         offset_count;
      47             :     ASSFields   fields[24];
      48             : } ASSSection;
      49             : 
      50             : static const ASSSection ass_sections[] = {
      51             :     { .section       = "Script Info",
      52             :       .offset        = offsetof(ASS, script_info),
      53             :       .fields = {{"ScriptType", ASS_STR, offsetof(ASSScriptInfo, script_type)},
      54             :                  {"Collisions", ASS_STR, offsetof(ASSScriptInfo, collisions) },
      55             :                  {"PlayResX",   ASS_INT, offsetof(ASSScriptInfo, play_res_x) },
      56             :                  {"PlayResY",   ASS_INT, offsetof(ASSScriptInfo, play_res_y) },
      57             :                  {"Timer",      ASS_FLT, offsetof(ASSScriptInfo, timer)      },
      58             :                  {0},
      59             :         }
      60             :     },
      61             :     { .section       = "V4+ Styles",
      62             :       .format_header = "Format",
      63             :       .fields_header = "Style",
      64             :       .size          = sizeof(ASSStyle),
      65             :       .offset        = offsetof(ASS, styles),
      66             :       .offset_count  = offsetof(ASS, styles_count),
      67             :       .fields = {{"Name",            ASS_STR,   offsetof(ASSStyle, name)           },
      68             :                  {"Fontname",        ASS_STR,   offsetof(ASSStyle, font_name)      },
      69             :                  {"Fontsize",        ASS_INT,   offsetof(ASSStyle, font_size)      },
      70             :                  {"PrimaryColour",   ASS_COLOR, offsetof(ASSStyle, primary_color)  },
      71             :                  {"SecondaryColour", ASS_COLOR, offsetof(ASSStyle, secondary_color)},
      72             :                  {"OutlineColour",   ASS_COLOR, offsetof(ASSStyle, outline_color)  },
      73             :                  {"BackColour",      ASS_COLOR, offsetof(ASSStyle, back_color)     },
      74             :                  {"Bold",            ASS_INT,   offsetof(ASSStyle, bold)           },
      75             :                  {"Italic",          ASS_INT,   offsetof(ASSStyle, italic)         },
      76             :                  {"Underline",       ASS_INT,   offsetof(ASSStyle, underline)      },
      77             :                  {"StrikeOut",       ASS_INT,   offsetof(ASSStyle, strikeout)      },
      78             :                  {"ScaleX",          ASS_FLT,   offsetof(ASSStyle, scalex)         },
      79             :                  {"ScaleY",          ASS_FLT,   offsetof(ASSStyle, scaley)         },
      80             :                  {"Spacing",         ASS_FLT,   offsetof(ASSStyle, spacing)        },
      81             :                  {"Angle",           ASS_FLT,   offsetof(ASSStyle, angle)          },
      82             :                  {"BorderStyle",     ASS_INT,   offsetof(ASSStyle, border_style)   },
      83             :                  {"Outline",         ASS_FLT,   offsetof(ASSStyle, outline)        },
      84             :                  {"Shadow",          ASS_FLT,   offsetof(ASSStyle, shadow)         },
      85             :                  {"Alignment",       ASS_INT,   offsetof(ASSStyle, alignment)      },
      86             :                  {"MarginL",         ASS_INT,   offsetof(ASSStyle, margin_l)       },
      87             :                  {"MarginR",         ASS_INT,   offsetof(ASSStyle, margin_r)       },
      88             :                  {"MarginV",         ASS_INT,   offsetof(ASSStyle, margin_v)       },
      89             :                  {"Encoding",        ASS_INT,   offsetof(ASSStyle, encoding)       },
      90             :                  {0},
      91             :         }
      92             :     },
      93             :     { .section       = "V4 Styles",
      94             :       .format_header = "Format",
      95             :       .fields_header = "Style",
      96             :       .size          = sizeof(ASSStyle),
      97             :       .offset        = offsetof(ASS, styles),
      98             :       .offset_count  = offsetof(ASS, styles_count),
      99             :       .fields = {{"Name",            ASS_STR,   offsetof(ASSStyle, name)           },
     100             :                  {"Fontname",        ASS_STR,   offsetof(ASSStyle, font_name)      },
     101             :                  {"Fontsize",        ASS_INT,   offsetof(ASSStyle, font_size)      },
     102             :                  {"PrimaryColour",   ASS_COLOR, offsetof(ASSStyle, primary_color)  },
     103             :                  {"SecondaryColour", ASS_COLOR, offsetof(ASSStyle, secondary_color)},
     104             :                  {"TertiaryColour",  ASS_COLOR, offsetof(ASSStyle, outline_color)  },
     105             :                  {"BackColour",      ASS_COLOR, offsetof(ASSStyle, back_color)     },
     106             :                  {"Bold",            ASS_INT,   offsetof(ASSStyle, bold)           },
     107             :                  {"Italic",          ASS_INT,   offsetof(ASSStyle, italic)         },
     108             :                  {"BorderStyle",     ASS_INT,   offsetof(ASSStyle, border_style)   },
     109             :                  {"Outline",         ASS_FLT,   offsetof(ASSStyle, outline)        },
     110             :                  {"Shadow",          ASS_FLT,   offsetof(ASSStyle, shadow)         },
     111             :                  {"Alignment",       ASS_ALGN,  offsetof(ASSStyle, alignment)      },
     112             :                  {"MarginL",         ASS_INT,   offsetof(ASSStyle, margin_l)       },
     113             :                  {"MarginR",         ASS_INT,   offsetof(ASSStyle, margin_r)       },
     114             :                  {"MarginV",         ASS_INT,   offsetof(ASSStyle, margin_v)       },
     115             :                  {"AlphaLevel",      ASS_INT,   offsetof(ASSStyle, alpha_level)    },
     116             :                  {"Encoding",        ASS_INT,   offsetof(ASSStyle, encoding)       },
     117             :                  {0},
     118             :         }
     119             :     },
     120             :     { .section       = "Events",
     121             :       .format_header = "Format",
     122             :       .fields_header = "Dialogue",
     123             :       .size          = sizeof(ASSDialog),
     124             :       .offset        = offsetof(ASS, dialogs),
     125             :       .offset_count  = offsetof(ASS, dialogs_count),
     126             :       .fields = {{"Layer",   ASS_INT,        offsetof(ASSDialog, layer)   },
     127             :                  {"Start",   ASS_TIMESTAMP,  offsetof(ASSDialog, start)   },
     128             :                  {"End",     ASS_TIMESTAMP,  offsetof(ASSDialog, end)     },
     129             :                  {"Style",   ASS_STR,        offsetof(ASSDialog, style)   },
     130             :                  {"Name",    ASS_STR,        offsetof(ASSDialog, name)    },
     131             :                  {"MarginL", ASS_INT,        offsetof(ASSDialog, margin_l)},
     132             :                  {"MarginR", ASS_INT,        offsetof(ASSDialog, margin_r)},
     133             :                  {"MarginV", ASS_INT,        offsetof(ASSDialog, margin_v)},
     134             :                  {"Effect",  ASS_STR,        offsetof(ASSDialog, effect)  },
     135             :                  {"Text",    ASS_STR,        offsetof(ASSDialog, text)    },
     136             :                  {0},
     137             :         }
     138             :     },
     139             : };
     140             : 
     141             : 
     142             : typedef int (*ASSConvertFunc)(void *dest, const char *buf, int len);
     143             : 
     144         332 : static int convert_str(void *dest, const char *buf, int len)
     145             : {
     146         332 :     char *str = av_malloc(len + 1);
     147         332 :     if (str) {
     148         332 :         memcpy(str, buf, len);
     149         332 :         str[len] = 0;
     150         332 :         if (*(void **)dest)
     151           0 :             av_free(*(void **)dest);
     152         332 :         *(char **)dest = str;
     153             :     }
     154         332 :     return !str;
     155             : }
     156         452 : static int convert_int(void *dest, const char *buf, int len)
     157             : {
     158         452 :     return sscanf(buf, "%d", (int *)dest) == 1;
     159             : }
     160          20 : static int convert_flt(void *dest, const char *buf, int len)
     161             : {
     162          20 :     return sscanf(buf, "%f", (float *)dest) == 1;
     163             : }
     164          20 : static int convert_color(void *dest, const char *buf, int len)
     165             : {
     166          24 :     return sscanf(buf, "&H%8x", (int *)dest) == 1 ||
     167           4 :            sscanf(buf, "%d",    (int *)dest) == 1;
     168             : }
     169           0 : static int convert_timestamp(void *dest, const char *buf, int len)
     170             : {
     171             :     int c, h, m, s, cs;
     172           0 :     if ((c = sscanf(buf, "%d:%02d:%02d.%02d", &h, &m, &s, &cs)) == 4)
     173           0 :         *(int *)dest = 360000*h + 6000*m + 100*s + cs;
     174           0 :     return c == 4;
     175             : }
     176           0 : static int convert_alignment(void *dest, const char *buf, int len)
     177             : {
     178             :     int a;
     179           0 :     if (sscanf(buf, "%d", &a) == 1) {
     180             :         /* convert V4 Style alignment to V4+ Style */
     181           0 :         *(int *)dest = a + ((a&4) >> 1) - 5*!!(a&8);
     182           0 :         return 1;
     183             :     }
     184           0 :     return 0;
     185             : }
     186             : 
     187             : static const ASSConvertFunc convert_func[] = {
     188             :     [ASS_STR]       = convert_str,
     189             :     [ASS_INT]       = convert_int,
     190             :     [ASS_FLT]       = convert_flt,
     191             :     [ASS_COLOR]     = convert_color,
     192             :     [ASS_TIMESTAMP] = convert_timestamp,
     193             :     [ASS_ALGN]      = convert_alignment,
     194             : };
     195             : 
     196             : 
     197             : struct ASSSplitContext {
     198             :     ASS ass;
     199             :     int current_section;
     200             :     int field_number[FF_ARRAY_ELEMS(ass_sections)];
     201             :     int *field_order[FF_ARRAY_ELEMS(ass_sections)];
     202             : };
     203             : 
     204             : 
     205           4 : static uint8_t *realloc_section_array(ASSSplitContext *ctx)
     206             : {
     207           4 :     const ASSSection *section = &ass_sections[ctx->current_section];
     208           4 :     int *count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
     209           4 :     void **section_ptr = (void **)((uint8_t *)&ctx->ass + section->offset);
     210           4 :     uint8_t *tmp = av_realloc_array(*section_ptr, (*count+1), section->size);
     211           4 :     if (!tmp)
     212           0 :         return NULL;
     213           4 :     *section_ptr = tmp;
     214           4 :     tmp += *count * section->size;
     215           4 :     memset(tmp, 0, section->size);
     216           4 :     (*count)++;
     217           4 :     return tmp;
     218             : }
     219             : 
     220         236 : static inline int is_eol(char buf)
     221             : {
     222         236 :     return buf == '\r' || buf == '\n' || buf == 0;
     223             : }
     224             : 
     225        1180 : static inline const char *skip_space(const char *buf)
     226             : {
     227        2508 :     while (*buf == ' ')
     228         148 :         buf++;
     229        1180 :     return buf;
     230             : }
     231             : 
     232           0 : static int *get_default_field_orders(const ASSSection *section, int *number)
     233             : {
     234             :     int i;
     235           0 :     int *order = av_malloc_array(FF_ARRAY_ELEMS(section->fields), sizeof(*order));
     236             : 
     237           0 :     if (!order)
     238           0 :         return NULL;
     239           0 :     for (i = 0; section->fields[i].name; i++)
     240           0 :         order[i] = i;
     241           0 :     *number = i;
     242           0 :     while (i < FF_ARRAY_ELEMS(section->fields))
     243           0 :         order[i++] = -1;
     244           0 :     return order;
     245             : }
     246             : 
     247          12 : static const char *ass_split_section(ASSSplitContext *ctx, const char *buf)
     248             : {
     249          12 :     const ASSSection *section = &ass_sections[ctx->current_section];
     250          12 :     int *number = &ctx->field_number[ctx->current_section];
     251          12 :     int *order = ctx->field_order[ctx->current_section];
     252             :     int *tmp, i, len;
     253             : 
     254          60 :     while (buf && *buf) {
     255          44 :         if (buf[0] == '[') {
     256           8 :             ctx->current_section = -1;
     257           8 :             break;
     258             :         }
     259          36 :         if (buf[0] == ';' || (buf[0] == '!' && buf[1] == ':'))
     260             :             goto next_line; // skip comments
     261             : 
     262          32 :         len = strcspn(buf, ":\r\n");
     263          56 :         if (buf[len] == ':' &&
     264          36 :             (!section->fields_header || strncmp(buf, section->fields_header, len))) {
     265         100 :             for (i = 0; i < FF_ARRAY_ELEMS(ass_sections); i++) {
     266         140 :                 if (ass_sections[i].fields_header &&
     267          60 :                     !strncmp(buf, ass_sections[i].fields_header, len)) {
     268           0 :                     ctx->current_section = i;
     269           0 :                     section = &ass_sections[ctx->current_section];
     270           0 :                     number = &ctx->field_number[ctx->current_section];
     271           0 :                     order = ctx->field_order[ctx->current_section];
     272           0 :                     break;
     273             :                 }
     274             :             }
     275             :         }
     276          32 :         if (section->format_header && !order) {
     277           8 :             len = strlen(section->format_header);
     278           8 :             if (!strncmp(buf, section->format_header, len) && buf[len] == ':') {
     279           8 :                 buf += len + 1;
     280         148 :                 while (!is_eol(*buf)) {
     281         132 :                     buf = skip_space(buf);
     282         132 :                     len = strcspn(buf, ", \r\n");
     283         132 :                     if (!(tmp = av_realloc_array(order, (*number + 1), sizeof(*order))))
     284           0 :                         return NULL;
     285         132 :                     order = tmp;
     286         132 :                     order[*number] = -1;
     287        1280 :                     for (i=0; section->fields[i].name; i++)
     288        1280 :                         if (!strncmp(buf, section->fields[i].name, len)) {
     289         132 :                             order[*number] = i;
     290         132 :                             break;
     291             :                         }
     292         132 :                     (*number)++;
     293         132 :                     buf = skip_space(buf + len + (buf[len] == ','));
     294             :                 }
     295           8 :                 ctx->field_order[ctx->current_section] = order;
     296           8 :                 goto next_line;
     297             :             }
     298             :         }
     299          24 :         if (section->fields_header) {
     300           8 :             len = strlen(section->fields_header);
     301           8 :             if (!strncmp(buf, section->fields_header, len) && buf[len] == ':') {
     302           4 :                 uint8_t *ptr, *struct_ptr = realloc_section_array(ctx);
     303           4 :                 if (!struct_ptr)  return NULL;
     304             : 
     305             :                 /* No format header line found so far, assume default */
     306           4 :                 if (!order) {
     307           0 :                     order = get_default_field_orders(section, number);
     308           0 :                     if (!order)
     309           0 :                         return NULL;
     310           0 :                     ctx->field_order[ctx->current_section] = order;
     311             :                 }
     312             : 
     313           4 :                 buf += len + 1;
     314          96 :                 for (i=0; !is_eol(*buf) && i < *number; i++) {
     315          92 :                     int last = i == *number - 1;
     316          92 :                     buf = skip_space(buf);
     317          92 :                     len = strcspn(buf, last ? "\r\n" : ",\r\n");
     318          92 :                     if (order[i] >= 0) {
     319          92 :                         ASSFieldType type = section->fields[order[i]].type;
     320          92 :                         ptr = struct_ptr + section->fields[order[i]].offset;
     321          92 :                         convert_func[type](ptr, buf, len);
     322             :                     }
     323          92 :                     buf += len;
     324          92 :                     if (!last && *buf) buf++;
     325          92 :                     buf = skip_space(buf);
     326             :                 }
     327             :             }
     328             :         } else {
     329          16 :             len = strcspn(buf, ":\r\n");
     330          16 :             if (buf[len] == ':') {
     331          32 :                 for (i=0; section->fields[i].name; i++)
     332          32 :                     if (!strncmp(buf, section->fields[i].name, len)) {
     333          12 :                         ASSFieldType type = section->fields[i].type;
     334          12 :                         uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
     335          12 :                         ptr += section->fields[i].offset;
     336          12 :                         buf = skip_space(buf + len + 1);
     337          12 :                         convert_func[type](ptr, buf, strcspn(buf, "\r\n"));
     338          12 :                         break;
     339             :                     }
     340             :             }
     341             :         }
     342             : next_line:
     343          36 :         buf += strcspn(buf, "\n");
     344          36 :         buf += !!*buf;
     345             :     }
     346          12 :     return buf;
     347             : }
     348             : 
     349           4 : static int ass_split(ASSSplitContext *ctx, const char *buf)
     350             : {
     351             :     char c, section[16];
     352             :     int i;
     353             : 
     354           4 :     if (ctx->current_section >= 0)
     355           0 :         buf = ass_split_section(ctx, buf);
     356             : 
     357          20 :     while (buf && *buf) {
     358          12 :         if (sscanf(buf, "[%15[0-9A-Za-z+ ]]%c", section, &c) == 2) {
     359          12 :             buf += strcspn(buf, "\n");
     360          12 :             buf += !!*buf;
     361          60 :             for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++)
     362          48 :                 if (!strcmp(section, ass_sections[i].section)) {
     363          12 :                     ctx->current_section = i;
     364          12 :                     buf = ass_split_section(ctx, buf);
     365             :                 }
     366             :         } else {
     367           0 :             buf += strcspn(buf, "\n");
     368           0 :             buf += !!*buf;
     369             :         }
     370             :     }
     371           4 :     return buf ? 0 : AVERROR_INVALIDDATA;
     372             : }
     373             : 
     374           4 : ASSSplitContext *ff_ass_split(const char *buf)
     375             : {
     376           4 :     ASSSplitContext *ctx = av_mallocz(sizeof(*ctx));
     377           4 :     if (!ctx)
     378           0 :         return NULL;
     379           4 :     ctx->current_section = -1;
     380           4 :     if (ass_split(ctx, buf) < 0) {
     381           0 :         ff_ass_split_free(ctx);
     382           0 :         return NULL;
     383             :     }
     384           4 :     return ctx;
     385             : }
     386             : 
     387          16 : static void free_section(ASSSplitContext *ctx, const ASSSection *section)
     388             : {
     389          16 :     uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
     390          16 :     int i, j, *count, c = 1;
     391             : 
     392          16 :     if (section->format_header) {
     393          12 :         ptr   = *(void **)ptr;
     394          12 :         count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
     395             :     } else
     396           4 :         count = &c;
     397             : 
     398          16 :     if (ptr)
     399          16 :         for (i=0; i<*count; i++, ptr += section->size)
     400         120 :             for (j=0; section->fields[j].name; j++) {
     401         112 :                 const ASSFields *field = &section->fields[j];
     402         112 :                 if (field->type == ASS_STR)
     403          16 :                     av_freep(ptr + field->offset);
     404             :             }
     405          16 :     *count = 0;
     406             : 
     407          16 :     if (section->format_header)
     408          12 :         av_freep((uint8_t *)&ctx->ass + section->offset);
     409          16 : }
     410             : 
     411           0 : ASSDialog *ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf,
     412             :                                int cache, int *number)
     413             : {
     414           0 :     ASSDialog *dialog = NULL;
     415             :     int i, count;
     416           0 :     if (!cache)
     417           0 :         for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++)
     418           0 :             if (!strcmp(ass_sections[i].section, "Events")) {
     419           0 :                 free_section(ctx, &ass_sections[i]);
     420           0 :                 break;
     421             :             }
     422           0 :     count = ctx->ass.dialogs_count;
     423           0 :     if (ass_split(ctx, buf) == 0)
     424           0 :         dialog = ctx->ass.dialogs + count;
     425           0 :     if (number)
     426           0 :         *number = ctx->ass.dialogs_count - count;
     427           0 :     return dialog;
     428             : }
     429             : 
     430          80 : void ff_ass_free_dialog(ASSDialog **dialogp)
     431             : {
     432          80 :     ASSDialog *dialog = *dialogp;
     433          80 :     if (!dialog)
     434           0 :         return;
     435          80 :     av_freep(&dialog->style);
     436          80 :     av_freep(&dialog->name);
     437          80 :     av_freep(&dialog->effect);
     438          80 :     av_freep(&dialog->text);
     439          80 :     av_freep(dialogp);
     440             : }
     441             : 
     442          80 : ASSDialog *ff_ass_split_dialog2(ASSSplitContext *ctx, const char *buf)
     443             : {
     444             :     int i;
     445             :     static const ASSFields fields[] = {
     446             :         {"ReadOrder", ASS_INT, offsetof(ASSDialog, readorder)},
     447             :         {"Layer",     ASS_INT, offsetof(ASSDialog, layer)    },
     448             :         {"Style",     ASS_STR, offsetof(ASSDialog, style)    },
     449             :         {"Name",      ASS_STR, offsetof(ASSDialog, name)     },
     450             :         {"MarginL",   ASS_INT, offsetof(ASSDialog, margin_l) },
     451             :         {"MarginR",   ASS_INT, offsetof(ASSDialog, margin_r) },
     452             :         {"MarginV",   ASS_INT, offsetof(ASSDialog, margin_v) },
     453             :         {"Effect",    ASS_STR, offsetof(ASSDialog, effect)   },
     454             :         {"Text",      ASS_STR, offsetof(ASSDialog, text)     },
     455             :     };
     456             : 
     457          80 :     ASSDialog *dialog = av_mallocz(sizeof(*dialog));
     458          80 :     if (!dialog)
     459           0 :         return NULL;
     460             : 
     461         800 :     for (i = 0; i < FF_ARRAY_ELEMS(fields); i++) {
     462             :         size_t len;
     463         720 :         const int last = i == FF_ARRAY_ELEMS(fields) - 1;
     464         720 :         const ASSFieldType type = fields[i].type;
     465         720 :         uint8_t *ptr = (uint8_t *)dialog + fields[i].offset;
     466         720 :         buf = skip_space(buf);
     467         720 :         len = last ? strlen(buf) : strcspn(buf, ",");
     468         720 :         if (len >= INT_MAX) {
     469           0 :             ff_ass_free_dialog(&dialog);
     470           0 :             return NULL;
     471             :         }
     472         720 :         convert_func[type](ptr, buf, len);
     473         720 :         buf += len;
     474         720 :         if (*buf) buf++;
     475             :     }
     476          80 :     return dialog;
     477             : }
     478             : 
     479           4 : void ff_ass_split_free(ASSSplitContext *ctx)
     480             : {
     481           4 :     if (ctx) {
     482             :         int i;
     483          20 :         for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++) {
     484          16 :             free_section(ctx, &ass_sections[i]);
     485          16 :             av_freep(&(ctx->field_order[i]));
     486             :         }
     487           4 :         av_free(ctx);
     488             :     }
     489           4 : }
     490             : 
     491             : 
     492          80 : int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv,
     493             :                                 const char *buf)
     494             : {
     495          80 :     const char *text = NULL;
     496             :     char new_line[2];
     497          80 :     int text_len = 0;
     498             : 
     499        7148 :     while (buf && *buf) {
     500       13626 :         if (text && callbacks->text &&
     501       13178 :             (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
     502        6540 :              !strncmp(buf, "{\\", 2))) {
     503         146 :             callbacks->text(priv, text, text_len);
     504         146 :             text = NULL;
     505             :         }
     506        6988 :         if (sscanf(buf, "\\%1[nN]", new_line) == 1) {
     507         134 :             if (callbacks->new_line)
     508         134 :                 callbacks->new_line(priv, new_line[0] == 'N');
     509         134 :             buf += 2;
     510        6854 :         } else if (!strncmp(buf, "{\\", 2)) {
     511         148 :             buf++;
     512         444 :             while (*buf == '\\') {
     513         148 :                 char style[2], c[2], sep[2], c_num[2] = "0", tmp[128] = {0};
     514         148 :                 unsigned int color = 0xFFFFFFFF;
     515         148 :                 int len, size = -1, an = -1, alpha = -1;
     516         148 :                 int x1, y1, x2, y2, t1 = -1, t2 = -1;
     517         148 :                 if (sscanf(buf, "\\%1[bisu]%1[01\\}]%n", style, c, &len) > 1) {
     518          52 :                     int close = c[0] == '0' ? 1 : c[0] == '1' ? 0 : -1;
     519          52 :                     len += close != -1;
     520          52 :                     if (callbacks->style)
     521          26 :                         callbacks->style(priv, style[0], close);
     522         178 :                 } else if (sscanf(buf, "\\c%1[\\}]%n", sep, &len) > 0 ||
     523         146 :                            sscanf(buf, "\\c&H%X&%1[\\}]%n", &color, sep, &len) > 1 ||
     524         128 :                            sscanf(buf, "\\%1[1234]c%1[\\}]%n", c_num, sep, &len) > 1 ||
     525          64 :                            sscanf(buf, "\\%1[1234]c&H%X&%1[\\}]%n", c_num, &color, sep, &len) > 2) {
     526          64 :                     if (callbacks->color)
     527           0 :                         callbacks->color(priv, color, c_num[0] - '0');
     528         128 :                 } else if (sscanf(buf, "\\alpha%1[\\}]%n", sep, &len) > 0 ||
     529         128 :                            sscanf(buf, "\\alpha&H%2X&%1[\\}]%n", &alpha, sep, &len) > 1 ||
     530         128 :                            sscanf(buf, "\\%1[1234]a%1[\\}]%n", c_num, sep, &len) > 1 ||
     531          64 :                            sscanf(buf, "\\%1[1234]a&H%2X&%1[\\}]%n", c_num, &alpha, sep, &len) > 2) {
     532           0 :                     if (callbacks->alpha)
     533           0 :                         callbacks->alpha(priv, alpha, c_num[0] - '0');
     534         126 :                 } else if (sscanf(buf, "\\fn%1[\\}]%n", sep, &len) > 0 ||
     535          62 :                            sscanf(buf, "\\fn%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
     536           8 :                     if (callbacks->font_name)
     537           0 :                         callbacks->font_name(priv, tmp[0] ? tmp : NULL);
     538         106 :                 } else if (sscanf(buf, "\\fs%1[\\}]%n", sep, &len) > 0 ||
     539          46 :                            sscanf(buf, "\\fs%u%1[\\}]%n", &size, sep, &len) > 1) {
     540          64 :                     if (callbacks->font_size)
     541           0 :                         callbacks->font_size(priv, size);
     542          56 :                 } else if (sscanf(buf, "\\a%1[\\}]%n", sep, &len) > 0 ||
     543          56 :                            sscanf(buf, "\\a%2u%1[\\}]%n", &an, sep, &len) > 1 ||
     544          56 :                            sscanf(buf, "\\an%1[\\}]%n", sep, &len) > 0 ||
     545          28 :                            sscanf(buf, "\\an%1u%1[\\}]%n", &an, sep, &len) > 1) {
     546          26 :                     if (an != -1 && buf[2] != 'n')
     547           0 :                         an = (an&3) + (an&4 ? 6 : an&8 ? 3 : 0);
     548          52 :                     if (callbacks->alignment)
     549           0 :                         callbacks->alignment(priv, an);
     550           4 :                 } else if (sscanf(buf, "\\r%1[\\}]%n", sep, &len) > 0 ||
     551           2 :                            sscanf(buf, "\\r%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
     552           0 :                     if (callbacks->cancel_overrides)
     553           0 :                         callbacks->cancel_overrides(priv, tmp);
     554           4 :                 } else if (sscanf(buf, "\\move(%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, sep, &len) > 4 ||
     555           2 :                            sscanf(buf, "\\move(%d,%d,%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, &t1, &t2, sep, &len) > 6) {
     556           0 :                     if (callbacks->move)
     557           0 :                         callbacks->move(priv, x1, y1, x2, y2, t1, t2);
     558           2 :                 } else if (sscanf(buf, "\\pos(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
     559           2 :                     if (callbacks->move)
     560           0 :                         callbacks->move(priv, x1, y1, x1, y1, -1, -1);
     561           0 :                 } else if (sscanf(buf, "\\org(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
     562           0 :                     if (callbacks->origin)
     563           0 :                         callbacks->origin(priv, x1, y1);
     564             :                 } else {
     565           0 :                     len = strcspn(buf+1, "\\}") + 2;  /* skip unknown code */
     566             :                 }
     567         148 :                 buf += len - 1;
     568             :             }
     569         148 :             if (*buf++ != '}')
     570           0 :                 return AVERROR_INVALIDDATA;
     571             :         } else {
     572        6706 :             if (!text) {
     573         214 :                 text = buf;
     574         214 :                 text_len = 1;
     575             :             } else
     576        6492 :                 text_len++;
     577        6706 :             buf++;
     578             :         }
     579             :     }
     580          80 :     if (text && callbacks->text)
     581          68 :         callbacks->text(priv, text, text_len);
     582          80 :     if (callbacks->end)
     583          40 :         callbacks->end(priv);
     584          80 :     return 0;
     585             : }
     586             : 
     587          40 : ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style)
     588             : {
     589          40 :     ASS *ass = &ctx->ass;
     590             :     int i;
     591             : 
     592          40 :     if (!style || !*style)
     593           0 :         style = "Default";
     594          40 :     for (i=0; i<ass->styles_count; i++)
     595          40 :         if (ass->styles[i].name && !strcmp(ass->styles[i].name, style))
     596          40 :             return ass->styles + i;
     597           0 :     return NULL;
     598             : }

Generated by: LCOV version 1.12