[vlc-commits] codec: webvtt: add CSS lexer/grammar/parser
Francois Cartegnie
git at videolan.org
Tue Nov 7 12:37:32 CET 2017
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon Oct 9 11:27:15 2017 +0200| [649b3d02f50855953cd19b5bdbfee177ffba38d3] | committer: Francois Cartegnie
codec: webvtt: add CSS lexer/grammar/parser
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=649b3d02f50855953cd19b5bdbfee177ffba38d3
---
configure.ac | 19 +
modules/codec/Makefile.am | 12 +
modules/codec/webvtt/CSSGrammar.y | 773 ++++++++++++++++++++++++++++++++++++++
modules/codec/webvtt/CSSLexer.l | 107 ++++++
modules/codec/webvtt/css_bridge.h | 27 ++
modules/codec/webvtt/css_parser.c | 517 +++++++++++++++++++++++++
modules/codec/webvtt/css_parser.h | 182 +++++++++
7 files changed, 1637 insertions(+)
diff --git a/configure.ac b/configure.ac
index 579ed76dab..6f40d056f5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2956,6 +2956,25 @@ AS_IF([test "${enable_tiger}" != "no"], [
])
])
+dnl
+dnl check if we can build the css selector engine
+dnl
+AC_ARG_ENABLE(css,
+[ --enable-css CSS selector engine (default auto)])
+AS_IF([test "${enable_css}" != "no"], [
+ AC_PROG_LEX
+ with_css="no"
+ AS_IF([test "x$LEX" != "x:"], [
+ AC_PROG_YACC
+ dnl can only accept bison or we need byacc feature test for %destructor
+ AS_IF([test "x$YACC" = "xbison -y"], [
+ AC_DEFINE(HAVE_CSS, 1, [Define if CSS engine is built])]
+ with_css="yes"
+ ,[AC_MSG_WARN("Bison not found. CSS support disabled.")])
+ ])
+])
+AM_CONDITIONAL([ENABLE_CSS], [test "${with_css}" = "yes"])
+
dnl
dnl Video plugins
diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 2f625badfb..ca62716bdd 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -228,6 +228,18 @@ libwebvtt_plugin_la_SOURCES = codec/webvtt/subsvtt.c \
demux/webvtt.c \
demux/mp4/minibox.h
codec_LTLIBRARIES += libwebvtt_plugin.la
+AM_YFLAGS = -d
+if ENABLE_CSS
+SUFFIXES += .l .y
+# dependency: we need grammar build first
+BUILT_SOURCES += codec/webvtt/CSSGrammar.h
+libwebvtt_plugin_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/codec/webvtt/ -I$(builddir)/codec/webvtt/
+libwebvtt_plugin_la_SOURCES += codec/webvtt/CSSGrammar.y \
+ codec/webvtt/CSSLexer.l \
+ codec/webvtt/css_parser.c \
+ codec/webvtt/css_parser.h \
+ codec/webvtt/css_bridge.h
+endif
libsvcdsub_plugin_la_SOURCES = codec/svcdsub.c
codec_LTLIBRARIES += libsvcdsub_plugin.la
diff --git a/modules/codec/webvtt/CSSGrammar.y b/modules/codec/webvtt/CSSGrammar.y
new file mode 100644
index 0000000000..00e0babc3f
--- /dev/null
+++ b/modules/codec/webvtt/CSSGrammar.y
@@ -0,0 +1,773 @@
+/*****************************************************************************
+ * CSSGrammar.y: bison production rules for simplified css parsing
+ *****************************************************************************
+ * Copyright © 2017 VideoLabs, VideoLAN and VLC Authors
+ *
+ * Adapted from webkit's CSSGrammar.y:
+ *
+ * Copyright (C) 2002-2003 Lars Knoll (knoll at kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap at nypop.com)
+ * Copyright (C) 2008 Eric Seidel <eric at webkit.org>
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+%pure-parser
+
+%parse-param { yyscan_t scanner } { vlc_css_parser_t *css_parser }
+%lex-param { yyscan_t scanner } { vlc_css_parser_t *css_parser }
+
+%{
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <vlc_common.h>
+#include "css_parser.h"
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+%}
+
+%union {
+ bool boolean;
+ char character;
+ int integer;
+ char *string;
+ enum vlc_css_relation_e relation;
+
+ vlc_css_term_t term;
+ vlc_css_expr_t *expr;
+ vlc_css_rule_t *rule;
+ vlc_css_declaration_t *declaration;
+ vlc_css_declaration_t *declarationList;
+ vlc_css_selector_t *selector;
+ vlc_css_selector_t *selectorList;
+}
+
+%{
+/* See bison pure calling */
+int yylex(union YYSTYPE *, yyscan_t, vlc_css_parser_t *);
+
+static int yyerror(yyscan_t scanner, vlc_css_parser_t *p, const char *msg)
+{
+ VLC_UNUSED(scanner);VLC_UNUSED(p);VLC_UNUSED(msg);
+ return 1;
+}
+
+%}
+
+%expect 10
+
+%nonassoc LOWEST_PREC
+
+%left UNIMPORTANT_TOK
+
+%token WHITESPACE SGML_CD
+%token TOKEN_EOF 0
+
+%token INCLUDES
+%token DASHMATCH
+%token BEGINSWITH
+%token ENDSWITH
+%token CONTAINS
+
+%token <string> STRING
+%right <string> IDENT
+
+%nonassoc <string> IDSEL
+%nonassoc <string> HASH
+%nonassoc ':'
+%nonassoc '.'
+%nonassoc '['
+%nonassoc <character> '*'
+%nonassoc error
+%left '|'
+
+%token FONT_FACE_SYM
+%token CHARSET_SYM
+
+%token IMPORTANT_SYM
+
+%token CDO
+%token CDC
+%token <term> LENGTH
+%token <term> ANGLE
+%token <term> TIME
+%token <term> FREQ
+%token <term> DIMEN
+%token <term> PERCENTAGE
+%token <term> NUMBER
+
+%destructor { vlc_css_term_Clean($$); } <term>
+
+%token <string> URI
+%token <string> FUNCTION
+%token <string> UNICODERANGE
+
+%type <relation> combinator
+
+%type <rule> charset
+%type <rule> ignored_charset
+%type <rule> ruleset
+%type <rule> font_face
+%type <rule> invalid_rule
+%type <rule> rule
+%type <rule> valid_rule
+%destructor { vlc_css_rules_Delete($$); } <rule>
+
+%type <string> ident_or_string
+%type <string> property
+
+%type <selector> specifier
+%type <selector> specifier_list
+%type <selector> simple_selector
+%type <selector> selector
+%type <selectorList> selector_list
+%type <selector> selector_with_trailing_whitespace
+%type <selector> class
+%type <selector> attrib
+%type <selector> pseudo
+%destructor { vlc_css_selectors_Delete($$); } <selector> <selectorList>
+
+%type <declarationList> declaration_list
+%type <declarationList> decl_list
+%type <declaration> declaration
+%destructor { vlc_css_declarations_Delete($$); } <declaration> <declarationList>
+
+%type <boolean> prio
+
+%type <integer> match
+%type <integer> unary_operator
+%type <integer> maybe_unary_operator
+%type <character> operator
+
+%type <expr> expr
+%type <term> term
+%type <term> unary_term
+%type <term> function
+%destructor { vlc_css_expression_Delete($$); } <expr>
+
+%type <string> element_name
+%type <string> attr_name
+
+%destructor { free($$); } <string>
+
+%%
+
+stylesheet:
+ maybe_space maybe_charset maybe_sgml rule_list
+ ;
+
+maybe_space:
+ /* empty */ %prec UNIMPORTANT_TOK
+ | maybe_space WHITESPACE
+ ;
+
+maybe_sgml:
+ /* empty */
+ | maybe_sgml SGML_CD
+ | maybe_sgml WHITESPACE
+ ;
+
+maybe_charset:
+ /* empty */
+ | charset {
+ vlc_css_rules_Delete($1);
+ }
+ ;
+
+closing_brace:
+ '}'
+ | %prec LOWEST_PREC TOKEN_EOF
+ ;
+
+charset:
+ CHARSET_SYM maybe_space STRING maybe_space ';' {
+ free( $3 );
+ $$ = 0;
+ }
+ | CHARSET_SYM error invalid_block {
+ $$ = 0;
+ }
+ | CHARSET_SYM error ';' {
+ $$ = 0;
+ }
+;
+
+ignored_charset:
+ CHARSET_SYM maybe_space STRING maybe_space ';' {
+ // Ignore any @charset rule not at the beginning of the style sheet.
+ free( $3 );
+ $$ = 0;
+ }
+ | CHARSET_SYM maybe_space ';' {
+ $$ = 0;
+ }
+;
+
+rule_list:
+ /* empty */
+ | rule_list rule maybe_sgml {
+ if( $2 )
+ vlc_css_parser_AddRule( css_parser, $2 );
+ }
+ ;
+
+valid_rule:
+ ruleset
+ | font_face
+ ;
+
+rule:
+ valid_rule {
+ $$ = $1;
+ if($$)
+ $$->b_valid = true;
+ }
+ | ignored_charset
+ | invalid_rule
+ ;
+
+font_face:
+ FONT_FACE_SYM maybe_space
+ '{' maybe_space declaration_list closing_brace {
+ vlc_css_declarations_Delete( $5 );
+ $$ = NULL;
+ }
+ | FONT_FACE_SYM error invalid_block {
+ $$ = NULL;
+ }
+ | FONT_FACE_SYM error ';' {
+ $$ = NULL;
+ }
+;
+
+combinator:
+ '+' maybe_space { $$ = RELATION_DIRECTADJACENT; }
+ | '~' maybe_space { $$ = RELATION_INDIRECTADJACENT; }
+ | '>' maybe_space { $$ = RELATION_CHILD; }
+ ;
+
+maybe_unary_operator:
+ unary_operator { $$ = $1; }
+ | { $$ = 1; }
+ ;
+
+unary_operator:
+ '-' { $$ = -1; }
+ | '+' { $$ = 1; }
+ ;
+
+ruleset:
+ selector_list '{' maybe_space declaration_list closing_brace {
+ $$ = vlc_css_rule_New();
+ if($$)
+ {
+ $$->p_selectors = $1;
+ $$->p_declarations = $4;
+ }
+ }
+ ;
+
+selector_list:
+ selector %prec UNIMPORTANT_TOK {
+ if ($1) {
+ $$ = $1;
+ }
+ }
+ | selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK {
+ if ($1 && $4 )
+ {
+ $$ = $1;
+ vlc_css_selector_Append( $$, $4 );
+ }
+ else
+ {
+ vlc_css_selectors_Delete( $1 );
+ vlc_css_selectors_Delete( $4 );
+ $$ = NULL;
+ }
+ }
+ | selector_list error {
+ vlc_css_selectors_Delete( $1 );
+ $$ = NULL;
+ }
+ ;
+
+selector_with_trailing_whitespace:
+ selector WHITESPACE {
+ $$ = $1;
+ }
+ ;
+
+selector:
+ simple_selector {
+ $$ = $1;
+ }
+ | selector_with_trailing_whitespace
+ {
+ $$ = $1;
+ }
+ | selector_with_trailing_whitespace simple_selector
+ {
+ $$ = $1;
+ if ($$)
+ {
+ vlc_css_selector_AddSpecifier( $$, $2 );
+ $2->combinator = RELATION_DESCENDENT;
+ }
+ else $$ = $2;
+ }
+ | selector combinator simple_selector {
+ $$ = $1;
+ if ($$)
+ {
+ vlc_css_selector_AddSpecifier( $$, $3 );
+ $3->combinator = $2;
+ }
+ else $$ = $3;
+ }
+ | selector error {
+ vlc_css_selectors_Delete( $1 );
+ $$ = NULL;
+ }
+ ;
+
+simple_selector:
+ element_name {
+ $$ = vlc_css_selector_New( SELECTOR_SIMPLE, $1 );
+ free( $1 );
+ }
+ | element_name specifier_list {
+ $$ = vlc_css_selector_New( SELECTOR_SIMPLE, $1 );
+ if( $$ && $2 )
+ {
+ vlc_css_selector_AddSpecifier( $$, $2 );
+ }
+ else
+ {
+ vlc_css_selectors_Delete( $2 );
+ }
+ free( $1 );
+ }
+ | specifier_list {
+ $$ = $1;
+ }
+ ;
+
+element_name:
+ IDENT
+ | '*' { $$ = strdup("*"); }
+ ;
+
+specifier_list:
+ specifier {
+ $$ = $1;
+ }
+ | specifier_list specifier {
+ if( $1 )
+ {
+ $$ = $1;
+ while( $1->specifiers.p_first )
+ $1 = $1->specifiers.p_first;
+ vlc_css_selector_AddSpecifier( $1, $2 );
+ }
+ else $$ = $2;
+ }
+ | specifier_list error {
+ vlc_css_selectors_Delete( $1 );
+ $$ = NULL;
+ }
+;
+
+specifier:
+ IDSEL {
+ $$ = vlc_css_selector_New( SPECIFIER_ID, $1 );
+ free( $1 );
+ }
+ /* Case when #fffaaa like token is lexed as HEX instead of IDSEL */
+ | HASH {
+ if ($1[0] >= '0' && $1[0] <= '9') {
+ $$ = NULL;
+ } else {
+ $$ = vlc_css_selector_New( SPECIFIER_ID, $1 );
+ }
+ free( $1 );
+ }
+ | class
+ | attrib
+ | pseudo
+ ;
+
+class:
+ '.' IDENT {
+ $$ = vlc_css_selector_New( SPECIFIER_CLASS, $2 );
+ free( $2 );
+ }
+ ;
+
+attr_name:
+ IDENT maybe_space {
+ $$ = $1;
+ }
+ ;
+
+attrib:
+ '[' maybe_space attr_name ']' {
+ $$ = vlc_css_selector_New( SPECIFIER_ATTRIB, $3 );
+ free( $3 );
+ }
+ | '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' {
+ $$ = vlc_css_selector_New( SPECIFIER_ATTRIB, $3 );
+ if( $$ )
+ {
+ $$->match = $4;
+ $$->p_matchsel = vlc_css_selector_New( SPECIFIER_ID, $6 );
+ }
+ free( $3 );
+ free( $6 );
+ }
+ ;
+
+match:
+ '=' {
+ $$ = MATCH_EQUALS;
+ }
+ | INCLUDES {
+ $$ = MATCH_INCLUDES;
+ }
+ | DASHMATCH {
+ $$ = MATCH_DASHMATCH;
+ }
+ | BEGINSWITH {
+ $$ = MATCH_BEGINSWITH;
+ }
+ | ENDSWITH {
+ $$ = MATCH_ENDSWITH;
+ }
+ | CONTAINS {
+ $$ = MATCH_CONTAINS;
+ }
+ ;
+
+ident_or_string:
+ IDENT
+ | STRING
+ ;
+
+pseudo:
+ ':' IDENT {
+ $$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
+ free( $2 );
+ }
+ | ':' ':' IDENT {
+ $$ = vlc_css_selector_New( SELECTOR_PSEUDOELEMENT, $3 );
+ free( $3 );
+ }
+ // used by :nth-*
+ | ':' FUNCTION maybe_space maybe_unary_operator NUMBER maybe_space ')' {
+ if(*$2 != 0)
+ $2[strlen($2) - 1] = 0;
+ $$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
+ $5.val *= $4;
+ free( $2 );
+ vlc_css_term_Clean( $5 );
+ }
+ // required for WEBVTT weirdos cue::(::past)
+ | ':' ':' FUNCTION maybe_space selector maybe_space ')' {
+ if(*$3 != 0)
+ $3[strlen($3) - 1] = 0;
+ $$ = vlc_css_selector_New( SELECTOR_PSEUDOELEMENT, $3 );
+ free( $3 );
+ if( $$ && $5 )
+ {
+ vlc_css_selector_AddSpecifier( $$, $5 );
+ $5->combinator = RELATION_SELF;
+ }
+ else
+ vlc_css_selectors_Delete( $5 );
+ }
+ // used by :nth-*(odd/even) and :lang
+ | ':' FUNCTION maybe_space IDENT maybe_space ')' {
+ if(*$2 != 0)
+ $2[strlen($2) - 1] = 0;
+ $$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
+ free( $2 );
+ free( $4 );
+ }
+ ;
+
+declaration_list:
+ declaration {
+ $$ = $1;
+ }
+ | decl_list declaration {
+ $$ = $1;
+ if( $$ )
+ vlc_css_declarations_Append( $$, $2 );
+ }
+ | decl_list {
+ $$ = $1;
+ }
+ | error invalid_block_list error {
+ $$ = NULL;
+ }
+ | error {
+ $$ = NULL;
+ }
+ | decl_list error {
+ $$ = $1;
+ }
+ | decl_list invalid_block_list {
+ $$ = $1;
+ }
+ ;
+
+decl_list:
+ declaration ';' maybe_space {
+ $$ = $1;
+ }
+ | declaration invalid_block_list maybe_space {
+ vlc_css_declarations_Delete( $1 );
+ $$ = NULL;
+ }
+ | declaration invalid_block_list ';' maybe_space {
+ vlc_css_declarations_Delete( $1 );
+ $$ = NULL;
+ }
+ | error ';' maybe_space {
+ $$ = NULL;
+ }
+ | error invalid_block_list error ';' maybe_space {
+ $$ = NULL;
+ }
+ | decl_list declaration ';' maybe_space {
+ if( $1 )
+ {
+ $$ = $1;
+ vlc_css_declarations_Append( $$, $2 );
+ }
+ else $$ = $2;
+ }
+ | decl_list error ';' maybe_space {
+ $$ = $1;
+ }
+ | decl_list error invalid_block_list error ';' maybe_space {
+ $$ = $1;
+ }
+ ;
+
+declaration:
+ property ':' maybe_space expr prio {
+ $$ = vlc_css_declaration_New( $1 );
+ if( $$ )
+ $$->expr = $4;
+ else
+ vlc_css_expression_Delete( $4 );
+ free( $1 );
+ }
+ |
+ property error {
+ free( $1 );
+ $$ = NULL;
+ }
+ |
+ property ':' maybe_space error expr prio {
+ free( $1 );
+ vlc_css_expression_Delete( $5 );
+ /* The default movable type template has letter-spacing: .none; Handle this by looking for
+ error tokens at the start of an expr, recover the expr and then treat as an error, cleaning
+ up and deleting the shifted expr. */
+ $$ = NULL;
+ }
+ |
+ property ':' maybe_space expr prio error {
+ free( $1 );
+ vlc_css_expression_Delete( $4 );
+ /* When we encounter something like p {color: red !important fail;} we should drop the declaration */
+ $$ = NULL;
+ }
+ |
+ IMPORTANT_SYM maybe_space {
+ /* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */
+ $$ = NULL;
+ }
+ |
+ property ':' maybe_space {
+ free( $1 );
+ /* div { font-family: } Just reduce away this property with no value. */
+ $$ = NULL;
+ }
+ |
+ property ':' maybe_space error {
+ free( $1 );
+ /* if we come across rules with invalid values like this case: p { weight: *; }, just discard the rule */
+ $$ = NULL;
+ }
+ |
+ property invalid_block {
+ /* if we come across: div { color{;color:maroon} }, ignore everything within curly brackets */
+ free( $1 );
+ $$ = NULL;
+ }
+ ;
+
+property:
+ IDENT maybe_space {
+ $$ = $1;
+ }
+ ;
+
+prio:
+ IMPORTANT_SYM maybe_space { $$ = true; }
+ | /* empty */ { $$ = false; }
+ ;
+
+expr:
+ term {
+ $$ = vlc_css_expression_New( $1 );
+ if( !$$ )
+ vlc_css_term_Clean( $1 );
+ }
+ | expr operator term {
+ $$ = $1;
+ if( !$1 || !vlc_css_expression_AddTerm($1, $2, $3) )
+ vlc_css_term_Clean( $3 );
+ }
+ | expr invalid_block_list {
+ vlc_css_expression_Delete( $1 );
+ $$ = NULL;
+ }
+ | expr invalid_block_list error {
+ vlc_css_expression_Delete( $1 );
+ $$ = NULL;
+ }
+ | expr error {
+ vlc_css_expression_Delete( $1 );
+ $$ = NULL;
+ }
+ ;
+
+operator:
+ '/' maybe_space {
+ $$ = '/';
+ }
+ | ',' maybe_space {
+ $$ = ',';
+ }
+ | /* empty */ {
+ $$ = 0;
+ }
+ ;
+
+term:
+ unary_term { $$ = $1; }
+ | unary_operator unary_term {
+ $$ = $2;
+ $$.val *= $1;
+ }
+ | STRING maybe_space { $$.type = TYPE_STRING; $$.psz = $1; }
+ | IDENT maybe_space { $$.type = TYPE_IDENTIFIER; $$.psz = $1; }
+ /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
+ | DIMEN maybe_space { $$ = $1; }
+ | unary_operator DIMEN maybe_space { $$ = $2; }
+ | URI maybe_space { $$.type = TYPE_URI; $$.psz = $1; }
+ | UNICODERANGE maybe_space { $$.type = TYPE_UNICODERANGE; $$.psz = $1; }
+ | IDSEL maybe_space { $$.type = TYPE_HEXCOLOR; $$.psz = $1; }
+ | HASH maybe_space { $$.type = TYPE_HEXCOLOR; $$.psz = $1; }
+ | '#' maybe_space { $$.type = TYPE_HEXCOLOR; $$.psz = NULL; } /* Handle error case: "color: #;" */
+ /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
+ | function {
+ $$ = $1;
+ }
+ | '%' maybe_space { /* Handle width: %; */
+ $$.type = TYPE_PERCENT; $$.val = 0;
+ }
+ ;
+
+unary_term:
+ NUMBER maybe_space
+ | PERCENTAGE maybe_space
+ | LENGTH maybe_space
+ | ANGLE maybe_space
+ | TIME maybe_space
+ | FREQ maybe_space
+ ;
+
+function:
+ FUNCTION maybe_space expr ')' maybe_space {
+ $$.type = TYPE_FUNCTION; $$.function = $3;
+ $$.psz = $1;
+ if(*$$.psz != 0)
+ $$.psz[strlen($$.psz) - 1] = 0;
+ } |
+ FUNCTION maybe_space expr TOKEN_EOF {
+ $$.type = TYPE_FUNCTION; $$.function = $3; $$.psz = $1;
+ if(*$$.psz != 0)
+ $$.psz[strlen($$.psz) - 1] = 0;
+ } |
+ FUNCTION maybe_space ')' maybe_space {
+ $$.type = TYPE_FUNCTION; $$.function = NULL; $$.psz = $1;
+ if(*$$.psz != 0)
+ $$.psz[strlen($$.psz) - 1] = 0;
+ } |
+ FUNCTION maybe_space error {
+ $$.type = TYPE_FUNCTION; $$.function = NULL; $$.psz = $1;
+ if(*$$.psz != 0)
+ $$.psz[strlen($$.psz) - 1] = 0;
+ }
+ ;
+
+/* error handling rules */
+
+invalid_rule:
+ error invalid_block {
+ $$ = NULL;
+ }
+
+/*
+ Seems like the two rules below are trying too much and violating
+ http://www.hixie.ch/tests/evil/mixed/csserrorhandling.html
+
+ | error ';' {
+ $$ = 0;
+ }
+ | error '}' {
+ $$ = 0;
+ }
+*/
+ ;
+
+invalid_block:
+ '{' error invalid_block_list error closing_brace
+ | '{' error closing_brace
+ ;
+
+invalid_block_list:
+ invalid_block
+ | invalid_block_list error invalid_block
+;
+
+%%
+
+#ifdef YYDEBUG
+ int yydebug=1;
+#else
+ int yydebug=0;
+#endif
diff --git a/modules/codec/webvtt/CSSLexer.l b/modules/codec/webvtt/CSSLexer.l
new file mode 100644
index 0000000000..400131782a
--- /dev/null
+++ b/modules/codec/webvtt/CSSLexer.l
@@ -0,0 +1,107 @@
+/*****************************************************************************
+ * CSSLexer.l : lexer for simplified CSS, based on W3C spec
+ *****************************************************************************
+ * Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+%option case-insensitive
+%option reentrant
+%option bison-bridge
+%option noyywrap
+%option nounput
+%option noinput
+%option never-interactive
+%option nostdinit
+
+%{
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <vlc_common.h>
+#include "css_parser.h"
+#include "CSSGrammar.h"
+#define VAL(a, b) { yylval->term.val = (a); yylval->term.type = TYPE_ ## b; }
+#define us_strtof strtof
+char *d;
+%}
+
+h [0-9a-f]
+nonascii [\200-\377]
+unicode \\{h}{1,6}[ \t\r\n\f]?
+escape {unicode}|\\[ -~\200-\377]
+nmstart [a-z]|{nonascii}|{escape}
+nmchar [a-z0-9-]|{nonascii}|{escape}
+string1 \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
+string2 \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
+
+ident [-]?{nmstart}{nmchar}*
+name {nmchar}+
+num [0-9]+|[0-9]*"."[0-9]+
+string {string1}|{string2}
+url ([!#$%&*-~]|{nonascii}|{escape})*
+w [ \t\r\n\f]*
+nl \n|\r\n|\r|\f
+range \?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}(\?{0,3}|{h}(\?{0,2}|{h}(\??|{h})))))
+
+%%
+
+[ \t\r\n\f]+ {return WHITESPACE;}
+
+\/\*[^*]*\*+([^/][^*]*\*+)*\/ /* ignore comments */
+
+"<!--" {return CDO;}
+"-->" {return CDC;}
+"~=" {return INCLUDES;}
+"|=" {return DASHMATCH;}
+
+{string} { yylval->string = vlc_css_unquotedunescaped(yytext); return STRING;}
+
+{ident} { yylval->string = vlc_css_unescaped(yytext); return IDENT;}
+
+"@font-face" {return FONT_FACE_SYM;}
+
+"!{w}important" {return IMPORTANT_SYM;}
+
+{num}em { VAL( us_strtof(yytext, &d), EMS ); return LENGTH;}
+{num}ex { VAL( atoi(yytext), EXS ); return LENGTH;}
+{num}px { VAL( atoi(yytext), PIXELS ); return LENGTH;}
+{num}cm { VAL( us_strtof(yytext, &d) * 10, MILLIMETERS ); return LENGTH;}
+{num}mm { VAL( atoi(yytext), MILLIMETERS ); return LENGTH;}
+{num}in { VAL( us_strtof(yytext, &d) * 25.4, MILLIMETERS ); return LENGTH;}
+{num}pt { VAL( us_strtof(yytext, &d), POINTS ); return LENGTH;}
+{num}pc { VAL( us_strtof(yytext, &d), POINTS ); return LENGTH;}
+{num}deg { VAL( us_strtof(yytext, &d), DEGREES ); return ANGLE;}
+{num}rad { VAL( us_strtof(yytext, &d) * 0.0174533, DEGREES ); return ANGLE;}
+{num}grad { VAL( us_strtof(yytext, &d) * 1.1111111, DEGREES ); return ANGLE;}
+{num}ms { VAL( atoi(yytext), MILLISECONDS ); return TIME;}
+{num}s { VAL( atoi(yytext) * 1000, MILLISECONDS ); return TIME;}
+{num}Hz { VAL( atoi(yytext), HERTZ ); return FREQ;}
+{num}kHz { VAL( atoi(yytext) * 1000, HERTZ ); return FREQ;}
+{num}{ident} { VAL( 0, DIMENSION ); return DIMEN;}
+{num}% { VAL( atoi(yytext), PERCENT ); return PERCENTAGE;}
+{num} { VAL( us_strtof(yytext, &d), NONE ); return NUMBER;}
+
+"url("{w}{string}{w}")" { yylval->string = vlc_css_unquotedunescaped(yytext); return URI;}
+"url("{w}{url}{w}")" { yylval->string = vlc_css_unquotedunescaped(yytext); return URI;}
+{ident}"(" { yylval->string = vlc_css_unescaped(yytext); return FUNCTION;}
+"#"{ident} {yylval->string = vlc_css_unescaped(yytext); return IDSEL;}
+"#"{name} {yylval->string = vlc_css_unescaped(yytext); return HASH;}
+
+U\+{range} { yylval->string = strdup(yytext); return UNICODERANGE;}
+U\+{h}{1,6}-{h}{1,6} { yylval->string = strdup(yytext); return UNICODERANGE;}
+
+. {return *yytext;}
+
diff --git a/modules/codec/webvtt/css_bridge.h b/modules/codec/webvtt/css_bridge.h
new file mode 100644
index 0000000000..20064eab9b
--- /dev/null
+++ b/modules/codec/webvtt/css_bridge.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * css_bridge.h : CSS grammar/lexer bridge
+ *****************************************************************************
+ * Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#define yyconst const
+typedef void* yyscan_t;
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+int yylex_init (yyscan_t* scanner);
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes, int, yyscan_t yyscanner );
+int yylex_destroy (yyscan_t yyscanner );
+void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner);
diff --git a/modules/codec/webvtt/css_parser.c b/modules/codec/webvtt/css_parser.c
new file mode 100644
index 0000000000..01a948b268
--- /dev/null
+++ b/modules/codec/webvtt/css_parser.c
@@ -0,0 +1,517 @@
+/*****************************************************************************
+ * css_parser.c : CSS parser
+ *****************************************************************************
+ * Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#include "css_bridge.h"
+#include "css_parser.h"
+#include "CSSGrammar.h"
+
+#include <ctype.h>
+
+static void vlc_css_term_Debug( const vlc_css_term_t a, int depth );
+static void vlc_css_expression_Debug( const vlc_css_expr_t *p_expr, int depth );
+static void vlc_css_declarations_Debug( const vlc_css_declaration_t *p_decl, int depth );
+static void vlc_css_selectors_Debug( const vlc_css_selector_t *p_sel, int depth );
+static void vlc_css_rules_Debug( const vlc_css_rule_t *p_rule, int depth );
+
+#define CHAIN_APPEND_IMPL(n, t) CHAIN_APPEND_DECL(n ,t)\
+{\
+ t ** insert = &p_a->p_next;\
+ while( *insert ) insert = &((*insert)->p_next);\
+ *insert = p_b;\
+}
+
+void vlc_css_term_Clean( vlc_css_term_t a )
+{
+ if( a.type >= TYPE_STRING )
+ free( a.psz );
+
+ if( a.type == TYPE_FUNCTION )
+ {
+ if( a.function )
+ vlc_css_expression_Delete( a.function );
+ }
+}
+
+static void vlc_css_term_Debug( const vlc_css_term_t a, int depth )
+{
+ for(int i=0;i<depth;i++) printf(" ");
+ printf("term: ");
+ if( a.type >= TYPE_STRING )
+ {
+ printf("%x %s\n", a.type, a.psz);
+ if( a.type == TYPE_FUNCTION && a.function )
+ vlc_css_expression_Debug( a.function, depth + 1 );
+ }
+ else printf("%x %f\n", a.type, a.val);
+}
+
+bool vlc_css_expression_AddTerm( vlc_css_expr_t *p_expr,
+ char op, vlc_css_term_t a )
+{
+ if( p_expr->i_count >= p_expr->i_alloc )
+ {
+ size_t i_realloc = (p_expr->i_alloc == 0) ? 1 : p_expr->i_alloc + 4;
+ void *reac = realloc( p_expr->seq, i_realloc * sizeof(p_expr->seq[0]) );
+ if( reac )
+ {
+ p_expr->seq = reac;
+ p_expr->i_alloc = i_realloc;
+ }
+ }
+
+ if( p_expr->i_count >= p_expr->i_alloc )
+ return false;
+
+ p_expr->seq[p_expr->i_count].op = op;
+ p_expr->seq[p_expr->i_count++].term = a;
+ return true;
+}
+
+void vlc_css_expression_Delete( vlc_css_expr_t *p_expr )
+{
+ if( p_expr )
+ {
+ for(size_t i=0; i<p_expr->i_count; i++)
+ vlc_css_term_Clean( p_expr->seq[i].term );
+ free( p_expr->seq );
+ }
+ free( p_expr );
+}
+
+static void vlc_css_expression_Debug( const vlc_css_expr_t *p_expr, int depth )
+{
+ if( p_expr )
+ {
+ for(int i=0;i<depth;i++) printf(" ");
+ printf("expression: \n");
+ for(size_t i=0; i<p_expr->i_count; i++)
+ vlc_css_term_Debug( p_expr->seq[i].term, depth + 1 );
+ }
+}
+
+vlc_css_expr_t * vlc_css_expression_New( vlc_css_term_t term )
+{
+ vlc_css_expr_t *p_expr = calloc(1, sizeof(*p_expr));
+ if(!vlc_css_expression_AddTerm( p_expr, 0, term ))
+ {
+ free(p_expr);
+ p_expr = NULL;
+ }
+ return p_expr;
+}
+
+CHAIN_APPEND_IMPL(vlc_css_declarations_Append, vlc_css_declaration_t)
+
+void vlc_css_declarations_Delete( vlc_css_declaration_t *p_decl )
+{
+ while( p_decl )
+ {
+ vlc_css_declaration_t *p_next = p_decl->p_next;
+ vlc_css_expression_Delete( p_decl->expr );
+ free( p_decl->psz_property );
+ free( p_decl );
+ p_decl = p_next;
+ }
+}
+
+static void vlc_css_declarations_Debug( const vlc_css_declaration_t *p_decl, int depth )
+{
+ while( p_decl )
+ {
+ for(int i=0;i<depth;i++) printf(" ");
+ printf("declaration: %s\n", p_decl->psz_property );
+ vlc_css_expression_Debug( p_decl->expr, depth + 1 );
+ p_decl = p_decl->p_next;
+ }
+}
+
+vlc_css_declaration_t * vlc_css_declaration_New( const char *psz )
+{
+ vlc_css_declaration_t *p_decl = calloc(1, sizeof(*p_decl));
+ p_decl->psz_property = strdup(psz);
+ return p_decl;
+}
+
+CHAIN_APPEND_IMPL(vlc_css_selector_Append, vlc_css_selector_t)
+
+void
+vlc_css_selector_AddSpecifier( vlc_css_selector_t *p_sel, vlc_css_selector_t *p_spec )
+{
+ *p_sel->specifiers.pp_append = p_spec;
+ while(p_spec)
+ {
+ p_sel->specifiers.pp_append = &p_spec->p_next;
+ p_spec = p_spec->p_next;
+ }
+}
+
+void vlc_css_selectors_Delete( vlc_css_selector_t *p_sel )
+{
+ while( p_sel )
+ {
+ vlc_css_selector_t *p_next = p_sel->p_next;
+ free( p_sel->psz_name );
+ vlc_css_selectors_Delete( p_sel->specifiers.p_first );
+ vlc_css_selectors_Delete( p_sel->p_matchsel );
+ free( p_sel );
+ p_sel = p_next;
+ }
+}
+
+static void vlc_css_selectors_Debug( const vlc_css_selector_t *p_sel, int depth )
+{
+ while( p_sel )
+ {
+ for(int i=0;i<depth;i++) printf(" "); printf("selector %c%s:\n", p_sel->combinator, p_sel->psz_name );
+ vlc_css_selectors_Debug( p_sel->p_matchsel, depth + 1 );
+ vlc_css_selectors_Debug( p_sel->specifiers.p_first, depth + 1 );
+ p_sel = p_sel->p_next;
+ }
+}
+
+vlc_css_selector_t * vlc_css_selector_New( int type, const char *psz )
+{
+ vlc_css_selector_t *p_sel = calloc(1, sizeof(*p_sel));
+ p_sel->psz_name = strdup(psz);
+ p_sel->type = type;
+ p_sel->combinator = RELATION_SELF;
+ p_sel->specifiers.pp_append = &p_sel->specifiers.p_first;
+ return p_sel;
+}
+
+void vlc_css_rules_Delete( vlc_css_rule_t *p_rule )
+{
+ while(p_rule)
+ {
+ vlc_css_rule_t *p_next = p_rule->p_next;
+ vlc_css_selectors_Delete( p_rule->p_selectors );
+ vlc_css_declarations_Delete( p_rule->p_declarations );
+ free(p_rule);
+ p_rule = p_next;
+ }
+}
+
+static void vlc_css_rules_Debug( const vlc_css_rule_t *p_rule, int depth )
+{
+ int j = 0;
+ while(p_rule)
+ {
+ for(int i=0;i<depth;i++) printf(" "); printf("rule %d:\n", j++);
+ vlc_css_selectors_Debug( p_rule->p_selectors, depth + 1 );
+ vlc_css_declarations_Debug( p_rule->p_declarations, depth + 1 );
+ p_rule = p_rule->p_next;
+ }
+}
+
+vlc_css_rule_t * vlc_css_rule_New( void )
+{
+ vlc_css_rule_t *p_rule = calloc(1, sizeof(*p_rule));
+ return p_rule;
+}
+
+void vlc_css_parser_AddRule( vlc_css_parser_t *p_parser,
+ vlc_css_rule_t *p_rule )
+{
+ (*p_parser->rules.pp_append) = p_rule;
+ p_parser->rules.pp_append = &p_rule->p_next;
+}
+
+void vlc_css_parser_Debug( const vlc_css_parser_t *p_parser )
+{
+ vlc_css_rules_Debug( p_parser->rules.p_first, 0 );
+}
+
+void vlc_css_parser_Clean( vlc_css_parser_t *p_parser )
+{
+ vlc_css_rules_Delete( p_parser->rules.p_first );
+}
+
+void vlc_css_parser_Init( vlc_css_parser_t *p_parser )
+{
+ memset(p_parser, 0, sizeof(vlc_css_parser_t));
+ p_parser->rules.pp_append = &p_parser->rules.p_first;
+}
+
+bool vlc_css_parser_ParseBytes( vlc_css_parser_t *p_parser, const uint8_t *p_data, size_t i_data )
+{
+ yyscan_t yy;
+ yylex_init(&yy);
+
+ YY_BUFFER_STATE buf = yy_scan_bytes( (const char*) p_data, i_data, yy );
+
+ bool b_ret = !yyparse( yy, p_parser );
+
+ yy_delete_buffer( buf, yy );
+ yylex_destroy( yy );
+
+ return b_ret;
+}
+
+bool vlc_css_parser_ParseString( vlc_css_parser_t *p_parser, const char *psz_css )
+{
+ yyscan_t yy;
+ yylex_init(&yy);
+
+ YY_BUFFER_STATE buf = yy_scan_string( psz_css, yy );
+
+ bool b_ret = !yyparse( yy, p_parser );
+
+ yy_delete_buffer( buf, yy );
+ yylex_destroy( yy );
+
+ return b_ret;
+}
+
+static int CodePointToUTF8( uint32_t ucs4, char *p )
+{
+ /* adapted from codepoint conversion from strings.h */
+ if( ucs4 <= 0x7F )
+ {
+ p[0] = ucs4;
+ return 1;
+ }
+ else if( ucs4 <= 0x7FF )
+ {
+ p[0] = 0xC0 | (ucs4 >> 6);
+ p[1] = 0x80 | (ucs4 & 0x3F);
+ return 2;
+ }
+ else if( ucs4 <= 0xFFFF )
+ {
+ p[0] = 0xE0 | (ucs4 >> 12);
+ p[1] = 0x80 | ((ucs4 >> 6) & 0x3F);
+ p[2] = 0x80 | (ucs4 & 0x3F);
+ return 3;
+ }
+ else if( ucs4 <= 0x1FFFFF )
+ {
+ p[0] = 0xF0 | (ucs4 >> 18);
+ p[1] = 0x80 | ((ucs4 >> 12) & 0x3F);
+ p[2] = 0x80 | ((ucs4 >> 6) & 0x3F);
+ p[3] = 0x80 | (ucs4 & 0x3F);
+ return 4;
+ }
+ else if( ucs4 <= 0x3FFFFFF )
+ {
+ p[0] = 0xF8 | (ucs4 >> 24);
+ p[1] = 0x80 | ((ucs4 >> 18) & 0x3F);
+ p[2] = 0x80 | ((ucs4 >> 12) & 0x3F);
+ p[3] = 0x80 | ((ucs4 >> 6) & 0x3F);
+ p[4] = 0x80 | (ucs4 & 0x3F);
+ return 5;
+ }
+ else
+ {
+ p[0] = 0xFC | (ucs4 >> 30);
+ p[1] = 0x80 | ((ucs4 >> 24) & 0x3F);
+ p[2] = 0x80 | ((ucs4 >> 18) & 0x3F);
+ p[3] = 0x80 | ((ucs4 >> 12) & 0x3F);
+ p[4] = 0x80 | ((ucs4 >> 6) & 0x3F);
+ p[5] = 0x80 | (ucs4 & 0x3F);
+ return 6;
+ }
+}
+
+void vlc_css_unescape( char *psz )
+{
+ if( !psz )
+ return;
+ char *r = psz;
+ char *w = psz;
+
+ while( *r )
+ {
+ if( *r == '\\' )
+ {
+ r++;
+ /* newlines */
+ if( *r == 0 )
+ {
+ break;
+ }
+ else if( strchr( "nfr", *r ) )
+ {
+ switch( r[0] )
+ {
+ case 'n':
+ *w++ = '\n';
+ r++;
+ break;
+ case 'r':
+ *w++ = '\r';
+ if( r[1] && r[1] == 'n' )
+ {
+ *w++ = '\n';
+ r++;
+ }
+ r++;
+ break;
+ case 'f':
+ *w++ = '\f';
+ r++;
+ break;
+ }
+ }
+ else if( isxdigit( *r ) )
+ {
+ const char *p_start = r;
+ int i;
+ for( i=0; i<6 && *r && isxdigit( *r ); i++ )
+ r++;
+ const char backup = *r;
+ *r = 0;
+ unsigned i_value = strtoul( p_start, NULL, 16 );
+ *r = backup;
+ if( i < 6 && *r && *r == ' ' )
+ r++;
+ w += CodePointToUTF8( i_value, w );
+ }
+ }
+ else
+ {
+ *w++ = *r++;
+ }
+ }
+
+ *w = 0;
+}
+
+char * vlc_css_unescaped( const char *psz )
+{
+ char *psz_ret = strdup( psz );
+ vlc_css_unescape( psz_ret );
+ return psz_ret;
+}
+
+char * vlc_css_unquoted( const char *psz )
+{
+ char *psz_ret;
+ if( *psz == '\'' || *psz == '\"' )
+ {
+ size_t i_len = strlen(psz);
+ if( psz[i_len - 1] == psz[0] )
+ psz_ret = strndup( psz + 1, i_len - 2 );
+ else
+ psz_ret = strdup( psz );
+ }
+ else
+ {
+ psz_ret = strdup( psz );
+ }
+ return psz_ret;
+}
+
+
+char * vlc_css_unquotedunescaped( const char *psz )
+{
+ char *psz_ret = vlc_css_unquoted( psz );
+ if( psz_ret )
+ vlc_css_unescape( psz_ret );
+ return psz_ret;
+}
+
+#ifdef CSS_PARSER_DEBUG
+
+
+static void css_properties_Debug( const vlc_css_declaration_t *p_decl )
+{
+ printf("set %s to ", p_decl->psz_property);
+ for( size_t i=0; i<p_decl->expr->i_count; i++ )
+ {
+ printf("term %s ", p_decl->expr->seq[i].term.psz);
+ }
+ printf("\n");
+}
+
+void css_selector_Debug( const vlc_css_selector_t *p_sel )
+{
+ printf("select its ");
+ switch( p_sel->combinator )
+ {
+ case RELATION_DESCENDENT:
+ printf("descendent");
+ break;
+ case RELATION_DIRECTADJACENT:
+ printf("adjacent");
+ break;
+ case RELATION_INDIRECTADJACENT:
+ printf("indirect adjacent");
+ break;
+ case RELATION_CHILD:
+ printf("child");
+ break;
+ case RELATION_SELF:
+ break;
+ }
+
+ printf(" nodes matching filter: ");
+ switch( p_sel->type )
+ {
+ case SELECTOR_SIMPLE:
+ printf("<%s>\n", p_sel->psz_name);
+ break;
+ case SELECTOR_PSEUDOCLASS:
+ printf(":%s\n", p_sel->psz_name);
+ break;
+ case SELECTOR_PSEUDOELEMENT:
+ printf("::%s\n", p_sel->psz_name);
+ break;
+ case SPECIFIER_ID:
+ printf("%s\n", p_sel->psz_name);
+ break;
+ case SPECIFIER_CLASS:
+ printf(".%s\n", p_sel->psz_name);
+ break;
+ case SPECIFIER_ATTRIB:
+ printf("[%s]\n", p_sel->psz_name);
+ break;
+ }
+}
+
+void css_rule_Debug( const vlc_css_rule_t *p_rule )
+{
+ if( p_rule == NULL )
+ return;
+ printf("add for rule nodes:\n");
+ for( const vlc_css_selector_t *p_sel = p_rule->p_selectors;
+ p_sel; p_sel = p_sel->p_next )
+ {
+ css_selector_Debug( p_sel );
+ for( const vlc_css_selector_t *p_spec = p_sel->specifiers.p_first;
+ p_spec; p_spec = p_spec->p_next )
+ css_selector_Debug( p_spec );
+
+ if( p_sel->p_next )
+ printf("add nodes\n");
+ }
+
+ for( const vlc_css_declaration_t *p_decl = p_rule->p_declarations;
+ p_decl; p_decl = p_decl->p_next )
+ {
+ css_properties_Debug( p_decl );
+ }
+}
+
+#endif
diff --git a/modules/codec/webvtt/css_parser.h b/modules/codec/webvtt/css_parser.h
new file mode 100644
index 0000000000..4df5bc1fc4
--- /dev/null
+++ b/modules/codec/webvtt/css_parser.h
@@ -0,0 +1,182 @@
+/*****************************************************************************
+ * css_parser.h : CSS parser interface
+ *****************************************************************************
+ * Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef CSS_PARSER_H
+#define CSS_PARSER_H
+
+//#define YYDEBUG 1
+//#define CSS_PARSER_DEBUG
+
+typedef struct vlc_css_parser_t vlc_css_parser_t;
+typedef struct vlc_css_selector_t vlc_css_selector_t;
+typedef struct vlc_css_declaration_t vlc_css_declaration_t;
+typedef struct vlc_css_rule_t vlc_css_rule_t;
+typedef struct vlc_css_expr_t vlc_css_expr_t;
+
+typedef struct
+{
+ float val;
+ char *psz;
+ vlc_css_expr_t *function;
+ enum
+ {
+ TYPE_NONE = 0,
+ TYPE_EMS,
+ TYPE_EXS,
+ TYPE_PIXELS,
+ TYPE_POINTS,
+ TYPE_MILLIMETERS,
+ TYPE_PERCENT,
+ TYPE_MILLISECONDS,
+ TYPE_HERTZ,
+ TYPE_DEGREES,
+ TYPE_DIMENSION,
+ TYPE_STRING = 0x20,
+ TYPE_FUNCTION,
+ TYPE_IDENTIFIER,
+ TYPE_HEXCOLOR,
+ TYPE_UNICODERANGE,
+ TYPE_URI,
+ } type;
+} vlc_css_term_t;
+
+struct vlc_css_expr_t
+{
+ struct
+ {
+ char op;
+ vlc_css_term_t term;
+ } *seq;
+ size_t i_alloc;
+ size_t i_count;
+};
+
+struct vlc_css_declaration_t
+{
+ char *psz_property;
+ vlc_css_expr_t *expr;
+ vlc_css_declaration_t *p_next;
+};
+
+enum vlc_css_match_e
+{
+ MATCH_EQUALS,
+ MATCH_INCLUDES,
+ MATCH_DASHMATCH,
+ MATCH_BEGINSWITH,
+ MATCH_ENDSWITH,
+ MATCH_CONTAINS,
+};
+
+enum vlc_css_relation_e
+{
+ RELATION_SELF = 0,
+ RELATION_DESCENDENT = ' ',
+ RELATION_DIRECTADJACENT = '+',
+ RELATION_INDIRECTADJACENT = '~',
+ RELATION_CHILD = '>',
+};
+
+struct vlc_css_selector_t
+{
+ char *psz_name;
+ enum
+ {
+ SELECTOR_SIMPLE = 0,
+ SELECTOR_PSEUDOCLASS,
+ SELECTOR_PSEUDOELEMENT,
+/* SELECTOR_PSEUDONTHCHILD,
+ SELECTOR_PSEUDONTHTYPE,
+ SELECTOR_PSEUDONTHLASTCHILD,
+ SELECTOR_PSEUDONTHLASTTYPE,*/
+ SPECIFIER_ID,
+ SPECIFIER_CLASS,
+ SPECIFIER_ATTRIB,
+ } type;
+ struct
+ {
+ vlc_css_selector_t *p_first;
+ vlc_css_selector_t **pp_append;
+ } specifiers;
+
+ enum vlc_css_match_e match;
+ vlc_css_selector_t *p_matchsel;
+
+ enum vlc_css_relation_e combinator;
+ vlc_css_selector_t *p_next;
+};
+
+struct vlc_css_rule_t
+{
+ bool b_valid;
+ vlc_css_selector_t *p_selectors;
+ vlc_css_declaration_t *p_declarations;
+
+ vlc_css_rule_t *p_next;
+};
+
+struct vlc_css_parser_t
+{
+ struct
+ {
+ vlc_css_rule_t *p_first;
+ vlc_css_rule_t **pp_append;
+ } rules;
+};
+
+#define CHAIN_APPEND_DECL(n, t) void n( t *p_a, t *p_b )
+
+void vlc_css_term_Clean( vlc_css_term_t a );
+bool vlc_css_expression_AddTerm( vlc_css_expr_t *p_expr, char op, vlc_css_term_t a );
+void vlc_css_expression_Delete( vlc_css_expr_t *p_expr );
+vlc_css_expr_t * vlc_css_expression_New( vlc_css_term_t term );
+
+CHAIN_APPEND_DECL(vlc_css_declarations_Append, vlc_css_declaration_t);
+void vlc_css_declarations_Delete( vlc_css_declaration_t *p_decl );
+vlc_css_declaration_t * vlc_css_declaration_New( const char *psz );
+
+CHAIN_APPEND_DECL(vlc_css_selector_Append, vlc_css_selector_t);
+void vlc_css_selector_AddSpecifier( vlc_css_selector_t *p_sel, vlc_css_selector_t *p_spec );
+void vlc_css_selectors_Delete( vlc_css_selector_t *p_sel );
+vlc_css_selector_t * vlc_css_selector_New( int type, const char *psz );
+
+void vlc_css_rules_Delete( vlc_css_rule_t *p_rule );
+vlc_css_rule_t * vlc_css_rule_New( void );
+
+void vlc_css_parser_AddRule( vlc_css_parser_t *p_parser, vlc_css_rule_t *p_rule );
+void vlc_css_parser_Debug( const vlc_css_parser_t *p_parser );
+void vlc_css_parser_Clean( vlc_css_parser_t *p_parser );
+void vlc_css_parser_Init( vlc_css_parser_t *p_parser );
+
+bool vlc_css_parser_ParseBytes( vlc_css_parser_t *p_parser, const uint8_t *, size_t );
+bool vlc_css_parser_ParseString( vlc_css_parser_t *p_parser, const char * );
+
+void vlc_css_unescape( char *psz );
+char * vlc_css_unquoted( const char *psz );
+char * vlc_css_unescaped( const char *psz );
+char * vlc_css_unquotedunescaped( const char *psz );
+
+# ifdef CSS_PARSER_DEBUG
+
+void css_selector_Debug( const vlc_css_selector_t *p_sel );
+void css_rule_Debug( const vlc_css_rule_t *p_rule );
+
+# endif
+
+#endif
More information about the vlc-commits
mailing list