From 8523227c6bbc6846ada3a1ec46373804254d4643 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Fri, 8 Mar 2013 03:47:00 -0800 Subject: [PATCH] Bug 849189 - Update webvtt to recent upstream version. r=rillian --- media/webvtt/LICENSE | 50 ++-- media/webvtt/Makefile.in | 2 + media/webvtt/README_MOZILLA | 2 +- media/webvtt/alloc.c | 4 - media/webvtt/cue.c | 190 ------------- media/webvtt/cue_internal.h | 25 +- media/webvtt/cuetext.c | 157 +++++------ media/webvtt/cuetext_internal.h | 64 ++--- media/webvtt/error.c | 6 +- media/webvtt/include/webvtt/cue.h | 96 +------ media/webvtt/include/webvtt/node.h | 119 ++++++++ media/webvtt/include/webvtt/string.h | 9 + media/webvtt/include/webvtt/util.h | 11 + media/webvtt/node.c | 218 +++++++++++++++ media/webvtt/node_internal.h | 50 ++++ media/webvtt/parser.c | 388 ++++++++++++++++++++++++--- media/webvtt/parser_internal.h | 122 ++++++++- media/webvtt/string.c | 12 +- 18 files changed, 1016 insertions(+), 509 deletions(-) create mode 100644 media/webvtt/include/webvtt/node.h create mode 100644 media/webvtt/node.c create mode 100644 media/webvtt/node_internal.h diff --git a/media/webvtt/LICENSE b/media/webvtt/LICENSE index e867ec21993d..5ee97fd74787 100644 --- a/media/webvtt/LICENSE +++ b/media/webvtt/LICENSE @@ -1,25 +1,25 @@ -Copyright (c) 2013 Mozilla Foundation and Contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - - Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - +Copyright (c) 2013 Mozilla Foundation and Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + - Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/media/webvtt/Makefile.in b/media/webvtt/Makefile.in index ff694b3a6108..28554e5eec31 100644 --- a/media/webvtt/Makefile.in +++ b/media/webvtt/Makefile.in @@ -22,6 +22,7 @@ DEFINES += \ EXPORTS_webvtt = \ include/webvtt/cue.h \ include/webvtt/error.h \ + include/webvtt/node.h \ include/webvtt/parser.h \ include/webvtt/string.h \ include/webvtt/util.h \ @@ -33,6 +34,7 @@ CSRCS = \ cuetext.c \ error.c \ lexer.c \ + node.c \ parser.c \ string.c \ $(NULL) diff --git a/media/webvtt/README_MOZILLA b/media/webvtt/README_MOZILLA index b8b8c9ca6705..492341477ab3 100644 --- a/media/webvtt/README_MOZILLA +++ b/media/webvtt/README_MOZILLA @@ -1,5 +1,5 @@ These files are from the WebVTT library, and are extracted from rev -cd5e95654f1fd6712fcf1941f8936870a484f65e of the git repository at +6b637c9f30911433e6d5a5be5d8512317a0d8a14 of the git repository at https://github.com/mozilla/webvtt. The following CPPFLAGS are used in order to build and link in Mozilla diff --git a/media/webvtt/alloc.c b/media/webvtt/alloc.c index 4e802412f74a..41e1879d24da 100644 --- a/media/webvtt/alloc.c +++ b/media/webvtt/alloc.c @@ -26,11 +26,7 @@ */ #include -#if ( defined(__APPLE__) && defined(__MACH__) ) #include -#else -#include -#endif #include static void *default_alloc( void *unused, webvtt_uint nb ); diff --git a/media/webvtt/cue.c b/media/webvtt/cue.c index 977917e8da27..ec37883858c2 100644 --- a/media/webvtt/cue.c +++ b/media/webvtt/cue.c @@ -25,8 +25,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include #include "parser_internal.h" #include "cue_internal.h" @@ -117,191 +115,3 @@ webvtt_validate_cue( webvtt_cue *cue ) error: return 0; } - -static webvtt_node empty_node = { - { 1 }, /* init ref count */ - 0, /* parent */ - WEBVTT_EMPTY_NODE /* node kind */ -}; - -WEBVTT_EXPORT void -webvtt_ref_node( webvtt_node *node ) -{ - if( node ) { - webvtt_ref( &node->refs ); - } -} - -WEBVTT_EXPORT void -webvtt_init_node( webvtt_node **node ) -{ - if( *node != &empty_node ) { - if( node && *node ) { - webvtt_release_node( node ); - } - *node = &empty_node; - webvtt_ref_node( *node ); - } -} - -WEBVTT_INTERN webvtt_status -webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent ) -{ - webvtt_node *temp_node; - - if( !node ) { - return WEBVTT_INVALID_PARAM; - } - - if( !( temp_node = (webvtt_node *)webvtt_alloc0(sizeof(*temp_node)) ) ) - { - return WEBVTT_OUT_OF_MEMORY; - } - - webvtt_ref_node( temp_node ); - temp_node->kind = kind; - temp_node->parent = parent; - *node = temp_node; - - return WEBVTT_SUCCESS; -} - -WEBVTT_INTERN webvtt_status -webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, - webvtt_stringlist *css_classes, webvtt_string *annotation ) -{ - webvtt_status status; - webvtt_internal_node_data *node_data; - - if( WEBVTT_FAILED( status = webvtt_create_node( node, kind, parent ) ) ) { - return status; - } - - if ( !( node_data = (webvtt_internal_node_data *)webvtt_alloc0( sizeof(*node_data) ) ) ) - { - return WEBVTT_OUT_OF_MEMORY; - } - - webvtt_copy_stringlist( &node_data->css_classes, css_classes ); - webvtt_copy_string( &node_data->annotation, annotation ); - node_data->children = NULL; - node_data->length = 0; - node_data->alloc = 0; - - (*node)->data.internal_data = node_data; - - return WEBVTT_SUCCESS; -} - -WEBVTT_INTERN webvtt_status -webvtt_create_head_node( webvtt_node **node ) -{ - webvtt_status status; - webvtt_string temp_annotation; - - webvtt_init_string( &temp_annotation ); - if( WEBVTT_FAILED( status = webvtt_create_internal_node( node, NULL, WEBVTT_HEAD_NODE, NULL, &temp_annotation ) ) ) { - return status; - } - - return WEBVTT_SUCCESS; -} - -WEBVTT_INTERN webvtt_status -webvtt_create_time_stamp_leaf_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp ) -{ - webvtt_status status; - - if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TIME_STAMP, parent ) ) ) { - return status; - } - - (*node)->data.timestamp = time_stamp; - - return WEBVTT_SUCCESS; -} - -WEBVTT_INTERN webvtt_status -webvtt_create_text_leaf_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text ) -{ - webvtt_status status; - - if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TEXT, parent ) ) ) { - return status; - } - - webvtt_copy_string( &(*node)->data.text, text ); - - return WEBVTT_SUCCESS; - -} - -WEBVTT_EXPORT void -webvtt_release_node( webvtt_node **node ) -{ - webvtt_uint i; - webvtt_node *n; - - if( !node || !*node ) { - return; - } - n = *node; - - if( webvtt_deref( &n->refs ) == 0 ) { - if( n->kind == WEBVTT_TEXT ) { - webvtt_release_string( &n->data.text ); - } else if( WEBVTT_IS_VALID_INTERNAL_NODE( n->kind ) && n->data.internal_data ) { - webvtt_release_stringlist( &n->data.internal_data->css_classes ); - webvtt_release_string( &n->data.internal_data->annotation ); - for( i = 0; i < n->data.internal_data->length; i++ ) { - webvtt_release_node( n->data.internal_data->children + i ); - } - webvtt_free( n->data.internal_data->children ); - webvtt_free( n->data.internal_data ); - } - webvtt_free( n ); - } - *node = 0; -} - -WEBVTT_INTERN webvtt_status -webvtt_attach_internal_node( webvtt_node *parent, webvtt_node *to_attach ) -{ - webvtt_node **next = 0; - webvtt_internal_node_data *nd = 0; - - if( !parent || !to_attach || !parent->data.internal_data ) { - return WEBVTT_INVALID_PARAM; - } - nd = parent->data.internal_data; - - if( nd->alloc == 0 ) { - next = (webvtt_node **)webvtt_alloc0( sizeof( webvtt_node * ) * 8 ); - - if( !next ) { - return WEBVTT_OUT_OF_MEMORY; - } - - nd->children = next; - nd->alloc = 8; - } - - if( nd->length + 1 >= ( nd->alloc / 3 ) * 2 ) { - - next = (webvtt_node **)webvtt_alloc0( sizeof( *next ) * nd->alloc * 2 ); - - if( !next ) { - return WEBVTT_OUT_OF_MEMORY; - } - - nd->alloc *= 2; - memcpy( next, nd->children, nd->length * sizeof( webvtt_node * ) ); - webvtt_free( nd->children ); - nd->children = next; - } - - nd->children[ nd->length++ ] = to_attach; - webvtt_ref_node( to_attach ); - - return WEBVTT_SUCCESS; -} diff --git a/media/webvtt/cue_internal.h b/media/webvtt/cue_internal.h index 0255cd73eb5f..7f634eba0468 100644 --- a/media/webvtt/cue_internal.h +++ b/media/webvtt/cue_internal.h @@ -27,27 +27,8 @@ #ifndef __INTERN_CUE_H__ # define __INTERN_CUE_H__ -# include # include -/** - * Routines for creating nodes. - */ -WEBVTT_INTERN webvtt_status webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent ); -WEBVTT_INTERN webvtt_status webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, webvtt_stringlist *css_classes, webvtt_string *annotation ); -/** - * We probably shouldn't have a 'head node' type. - * We should just return a list of node trees... - */ -WEBVTT_INTERN webvtt_status webvtt_create_head_node( webvtt_node **node ); -WEBVTT_INTERN webvtt_status webvtt_create_time_stamp_leaf_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp ); -WEBVTT_INTERN webvtt_status webvtt_create_text_leaf_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text ); - -/** - * Attaches a node to the internal node list of another node. - */ -WEBVTT_INTERN webvtt_status webvtt_attach_internal_node( webvtt_node *parent, webvtt_node *to_attach ); - /** * Private cue flags */ @@ -63,6 +44,12 @@ enum { CUE_HAVE_CUEPARAMS = 0x40000000, CUE_HAVE_ID = 0x80000000, + CUE_HEADER_MASK = CUE_HAVE_CUEPARAMS|CUE_HAVE_ID, }; +static webvtt_bool +cue_is_incomplete( const webvtt_cue *cue ) { + return !cue || ( cue->flags & CUE_HEADER_MASK ) == CUE_HAVE_ID; +} + #endif diff --git a/media/webvtt/cuetext.c b/media/webvtt/cuetext.c index 334a5aab0521..705fb66f69b4 100644 --- a/media/webvtt/cuetext.c +++ b/media/webvtt/cuetext.c @@ -81,7 +81,7 @@ webvtt_skipwhite( webvtt_byte **position ) } WEBVTT_INTERN webvtt_status -webvtt_create_cuetext_token( webvtt_cuetext_token **token, webvtt_cuetext_token_type token_type ) +webvtt_create_token( webvtt_cuetext_token **token, webvtt_token_type token_type ) { webvtt_cuetext_token *temp_token = (webvtt_cuetext_token *)webvtt_alloc0( sizeof(*temp_token) ); @@ -96,13 +96,13 @@ webvtt_create_cuetext_token( webvtt_cuetext_token **token, webvtt_cuetext_token_ } WEBVTT_INTERN webvtt_status -webvtt_create_cuetext_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name, +webvtt_create_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name, webvtt_stringlist *css_classes, webvtt_string *annotation ) { webvtt_status status; - webvtt_cuetext_start_token_data sd; + webvtt_start_token_data sd; - if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, START_TOKEN ) ) ) { + if( WEBVTT_FAILED( status = webvtt_create_token( token, START_TOKEN ) ) ) { return status; } @@ -116,11 +116,11 @@ webvtt_create_cuetext_start_token( webvtt_cuetext_token **token, webvtt_string * } WEBVTT_INTERN webvtt_status -webvtt_create_cuetext_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name ) +webvtt_create_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name ) { webvtt_status status; - if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, END_TOKEN ) ) ) { + if( WEBVTT_FAILED( status = webvtt_create_token( token, END_TOKEN ) ) ) { return status; } @@ -130,11 +130,11 @@ webvtt_create_cuetext_end_token( webvtt_cuetext_token **token, webvtt_string *ta } WEBVTT_INTERN webvtt_status -webvtt_create_cuetext_text_token( webvtt_cuetext_token **token, webvtt_string *text ) +webvtt_create_text_token( webvtt_cuetext_token **token, webvtt_string *text ) { webvtt_status status; - if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, TEXT_TOKEN ) ) ) { + if( WEBVTT_FAILED( status = webvtt_create_token( token, TEXT_TOKEN ) ) ) { return status; } @@ -144,11 +144,11 @@ webvtt_create_cuetext_text_token( webvtt_cuetext_token **token, webvtt_string *t } WEBVTT_INTERN webvtt_status -webvtt_create_cuetext_timestamp_token( webvtt_cuetext_token **token, webvtt_timestamp time_stamp ) +webvtt_create_timestamp_token( webvtt_cuetext_token **token, webvtt_timestamp time_stamp ) { webvtt_status status; - if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, TIME_STAMP_TOKEN ) ) ) { + if( WEBVTT_FAILED( status = webvtt_create_token( token, TIME_STAMP_TOKEN ) ) ) { return status; } @@ -158,9 +158,9 @@ webvtt_create_cuetext_timestamp_token( webvtt_cuetext_token **token, webvtt_time } WEBVTT_INTERN void -webvtt_delete_cuetext_token( webvtt_cuetext_token **token ) +webvtt_delete_token( webvtt_cuetext_token **token ) { - webvtt_cuetext_start_token_data data; + webvtt_start_token_data data; webvtt_cuetext_token *t; if( !token ) { @@ -193,31 +193,14 @@ webvtt_delete_cuetext_token( webvtt_cuetext_token **token ) *token = 0; } -/** - * Definitions for tag names that accept annotationsm - */ -#define V_TAG_LENGTH 1 - -webvtt_byte v_tag[V_TAG_LENGTH] = { UTF8_V }; - WEBVTT_INTERN int tag_accepts_annotation( webvtt_string *tag_name ) { - return memcmp( webvtt_string_text( tag_name ), v_tag, - min(webvtt_string_length( tag_name ), V_TAG_LENGTH) ) == 0; + return webvtt_string_is_equal( tag_name, "v", 1 ); } -/** - * Definitions for tag tokens that are more then one character long. - */ -#define RUBY_TAG_LENGTH 4 -#define RUBY_TEXT_TAG_LENGTH 2 - -webvtt_byte ruby_tag[RUBY_TAG_LENGTH] = { UTF8_R, UTF8_U, UTF8_B, UTF8_Y }; -webvtt_byte rt_tag[RUBY_TEXT_TAG_LENGTH] = { UTF8_R, UTF8_T }; - WEBVTT_INTERN webvtt_status -webvtt_get_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind ) +webvtt_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind ) { if( !tag_name || !kind ) { return WEBVTT_INVALID_PARAM; @@ -241,9 +224,9 @@ webvtt_get_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *k *kind = WEBVTT_VOICE; break; } - } else if( memcmp( webvtt_string_text(tag_name), ruby_tag, min(webvtt_string_length(tag_name), RUBY_TAG_LENGTH) ) == 0 ) { + } else if( webvtt_string_is_equal( tag_name, "ruby", 4 ) ) { *kind = WEBVTT_RUBY; - } else if( memcmp( webvtt_string_text(tag_name), rt_tag, min(webvtt_string_length(tag_name), RUBY_TEXT_TAG_LENGTH) ) == 0 ) { + } else if( webvtt_string_is_equal( tag_name, "rt", 2 ) ) { *kind = WEBVTT_RUBY_TEXT; } else { return WEBVTT_INVALID_TAG_NAME; @@ -272,18 +255,18 @@ webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node, switch ( token->token_type ) { case( TEXT_TOKEN ): - return webvtt_create_text_leaf_node( node, parent, &token->text ); + return webvtt_create_text_node( node, parent, &token->text ); break; case( START_TOKEN ): - CHECK_MEMORY_OP( webvtt_get_node_kind_from_tag_name( &token->tag_name, &kind) ); + CHECK_MEMORY_OP( webvtt_node_kind_from_tag_name( &token->tag_name, &kind) ); return webvtt_create_internal_node( node, parent, kind, token->start_token_data.css_classes, &token->start_token_data.annotations ); break; case ( TIME_STAMP_TOKEN ): - return webvtt_create_time_stamp_leaf_node( node, parent, token->time_stamp ); + return webvtt_create_timestamp_node( node, parent, token->time_stamp ); break; default: return WEBVTT_INVALID_TOKEN_TYPE; @@ -291,8 +274,8 @@ webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node, } WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_data_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ) +webvtt_data_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_string *result ) { for ( ; *token_state == DATA; (*position)++ ) { switch( **position ) { @@ -319,26 +302,12 @@ webvtt_cuetext_tokenizer_data_state( webvtt_byte **position, } /** - * Definitions for valid escape values. - * The semicolon is implicit in the comparison. + * Definitions for escape sequence replacement strings. */ -#define AMP_ESCAPE_LENGTH 4 -#define LT_ESCAPE_LENGTH 3 -#define GT_ESCAPE_LENGTH 3 -#define RLM_ESCAPE_LENGTH 4 -#define LRM_ESCAPE_LENGTH 4 -#define NBSP_ESCAPE_LENGTH 5 #define RLM_REPLACE_LENGTH 3 #define LRM_REPLACE_LENGTH 3 #define NBSP_REPLACE_LENGTH 2 -webvtt_byte amp_escape[AMP_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_A, UTF8_M, UTF8_P }; -webvtt_byte lt_escape[LT_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_L, UTF8_T }; -webvtt_byte gt_escape[GT_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_G, UTF8_T }; -webvtt_byte rlm_escape[RLM_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_R, UTF8_L, UTF8_M }; -webvtt_byte lrm_escape[LRM_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_L, UTF8_R, UTF8_M }; -webvtt_byte nbsp_escape[NBSP_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_N, UTF8_B, UTF8_S, UTF8_P }; - webvtt_byte rlm_replace[RLM_REPLACE_LENGTH] = { UTF8_RIGHT_TO_LEFT_1, UTF8_RIGHT_TO_LEFT_2, UTF8_RIGHT_TO_LEFT_3 }; webvtt_byte lrm_replace[LRM_REPLACE_LENGTH] = { UTF8_LEFT_TO_RIGHT_1, @@ -347,8 +316,8 @@ webvtt_byte nbsp_replace[NBSP_REPLACE_LENGTH] = { UTF8_NO_BREAK_SPACE_1, UTF8_NO_BREAK_SPACE_2 }; WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_escape_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ) +webvtt_escape_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_string *result ) { webvtt_string buffer; webvtt_status status = WEBVTT_SUCCESS; @@ -387,17 +356,17 @@ webvtt_cuetext_tokenizer_escape_state( webvtt_byte **position, * the interpretation to result and change the state to DATA. */ else if( **position == UTF8_SEMI_COLON ) { - if( memcmp( webvtt_string_text(&buffer), amp_escape, min(webvtt_string_length(&buffer), AMP_ESCAPE_LENGTH ) ) == 0 ) { - CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, UTF8_AMPERSAND ) ); - } else if( memcmp( webvtt_string_text(&buffer), lt_escape, min(webvtt_string_length(&buffer), LT_ESCAPE_LENGTH ) ) == 0 ) { - CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, UTF8_LESS_THAN ) ); - } else if( memcmp( webvtt_string_text(&buffer), gt_escape, min(webvtt_string_length(&buffer), GT_ESCAPE_LENGTH) ) == 0 ) { - CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, UTF8_GREATER_THAN ) ); - } else if( memcmp( webvtt_string_text(&buffer), rlm_escape, min(webvtt_string_length(&buffer), RLM_ESCAPE_LENGTH) ) == 0 ) { + if( webvtt_string_is_equal( &buffer, "&", 4 ) ) { + CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '&' ) ); + } else if( webvtt_string_is_equal( &buffer, "<", 3 ) ) { + CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '<' ) ); + } else if( webvtt_string_is_equal( &buffer, ">", 3 ) ) { + CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '>' ) ); + } else if( webvtt_string_is_equal( &buffer, "&rlm", 4 ) ) { CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, rlm_replace, RLM_REPLACE_LENGTH ) ); - } else if( memcmp( webvtt_string_text(&buffer), lrm_escape, min(webvtt_string_length(&buffer), LRM_ESCAPE_LENGTH) ) == 0 ) { + } else if( webvtt_string_is_equal( &buffer, "&lrm", 4 ) ) { CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, lrm_replace, LRM_REPLACE_LENGTH ) ); - } else if( memcmp( webvtt_string_text(&buffer), nbsp_escape, min(webvtt_string_length(&buffer), NBSP_ESCAPE_LENGTH) ) == 0 ) { + } else if( webvtt_string_is_equal( &buffer, " ", 5 ) ) { CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, nbsp_replace, NBSP_REPLACE_LENGTH ) ); } else { CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) ); @@ -405,6 +374,7 @@ webvtt_cuetext_tokenizer_escape_state( webvtt_byte **position, } *token_state = DATA; + status = WEBVTT_UNFINISHED; } /** * Character is alphanumeric. This means we are in the body of the escape @@ -421,6 +391,7 @@ webvtt_cuetext_tokenizer_escape_state( webvtt_byte **position, else { CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) ); CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, **position ) ); + status = WEBVTT_UNFINISHED; *token_state = DATA; } } @@ -432,8 +403,8 @@ dealloc: } WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ) +webvtt_tag_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_string *result ) { for( ; *token_state == TAG; (*position)++ ) { if( **position == UTF8_TAB || **position == UTF8_LINE_FEED || @@ -468,8 +439,8 @@ webvtt_cuetext_tokenizer_tag_state( webvtt_byte **position, } WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_start_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ) +webvtt_start_tag_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_string *result ) { for( ; *token_state == START_TAG; (*position)++ ) { if( **position == UTF8_TAB || **position == UTF8_FORM_FEED || @@ -498,8 +469,8 @@ webvtt_cuetext_tokenizer_start_tag_state( webvtt_byte **position, } WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_start_tag_class_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_stringlist *css_classes ) +webvtt_class_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_stringlist *css_classes ) { webvtt_string buffer; webvtt_status status = WEBVTT_SUCCESS; @@ -533,8 +504,8 @@ dealloc: } WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_start_tag_annotation_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *annotation ) +webvtt_annotation_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_string *annotation ) { for( ; *token_state == START_TAG_ANNOTATION; (*position)++ ) { if( **position == UTF8_NULL_BYTE || **position == UTF8_GREATER_THAN ) { @@ -547,8 +518,8 @@ webvtt_cuetext_tokenizer_start_tag_annotation_state( webvtt_byte **position, } WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_end_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ) +webvtt_end_tag_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_string *result ) { for( ; *token_state == END_TAG; (*position)++ ) { if( **position == UTF8_GREATER_THAN || **position == UTF8_NULL_BYTE ) { @@ -561,8 +532,8 @@ webvtt_cuetext_tokenizer_end_tag_state( webvtt_byte **position, } WEBVTT_INTERN webvtt_status -webvtt_cuetext_tokenizer_time_stamp_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ) +webvtt_timestamp_state( webvtt_byte **position, webvtt_token_state *token_state, + webvtt_string *result ) { for( ; *token_state == TIME_STAMP_TAG; (*position)++ ) { if( **position == UTF8_GREATER_THAN || **position == UTF8_NULL_BYTE ) { @@ -581,7 +552,7 @@ webvtt_cuetext_tokenizer_time_stamp_tag_state( webvtt_byte **position, WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token ) { - webvtt_cuetext_token_state token_state = DATA; + webvtt_token_state token_state = DATA; webvtt_string result, annotation; webvtt_stringlist *css_classes; webvtt_timestamp time_stamp = 0; @@ -604,28 +575,28 @@ webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token ) while( status == WEBVTT_UNFINISHED ) { switch( token_state ) { case DATA : - status = webvtt_cuetext_tokenizer_data_state( position, &token_state, &result ); + status = webvtt_data_state( position, &token_state, &result ); break; case ESCAPE: - status = webvtt_cuetext_tokenizer_escape_state( position, &token_state, &result ); + status = webvtt_escape_state( position, &token_state, &result ); break; case TAG: - status = webvtt_cuetext_tokenizer_tag_state( position, &token_state, &result ); + status = webvtt_tag_state( position, &token_state, &result ); break; case START_TAG: - status = webvtt_cuetext_tokenizer_start_tag_state( position, &token_state, &result ); + status = webvtt_start_tag_state( position, &token_state, &result ); break; case START_TAG_CLASS: - status = webvtt_cuetext_tokenizer_start_tag_class_state( position, &token_state, css_classes ); + status = webvtt_class_state( position, &token_state, css_classes ); break; case START_TAG_ANNOTATION: - status = webvtt_cuetext_tokenizer_start_tag_annotation_state( position, &token_state, &annotation ); + status = webvtt_annotation_state( position, &token_state, &annotation ); break; case END_TAG: - status = webvtt_cuetext_tokenizer_end_tag_state( position, &token_state, &result ); + status = webvtt_end_tag_state( position, &token_state, &result ); break; case TIME_STAMP_TAG: - status = webvtt_cuetext_tokenizer_time_stamp_tag_state( position, &token_state, &result ); + status = webvtt_timestamp_state( position, &token_state, &result ); break; } @@ -643,7 +614,7 @@ webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token ) * needs to be made. */ if( token_state == DATA || token_state == ESCAPE ) { - status = webvtt_create_cuetext_text_token( token, &result ); + status = webvtt_create_text_token( token, &result ); } else if(token_state == TAG || token_state == START_TAG || token_state == START_TAG_CLASS || token_state == START_TAG_ANNOTATION) { /** @@ -654,12 +625,12 @@ webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token ) webvtt_release_string( &annotation ); webvtt_init_string( &annotation ); } - status = webvtt_create_cuetext_start_token( token, &result, css_classes, &annotation ); + status = webvtt_create_start_token( token, &result, css_classes, &annotation ); } else if( token_state == END_TAG ) { - status = webvtt_create_cuetext_end_token( token, &result ); + status = webvtt_create_end_token( token, &result ); } else if( token_state == TIME_STAMP_TAG ) { parse_timestamp( webvtt_string_text( &result ), &time_stamp ); - status = webvtt_create_cuetext_timestamp_token( token, time_stamp ); + status = webvtt_create_timestamp_token( token, time_stamp ); } else { status = WEBVTT_INVALID_TOKEN_STATE; } @@ -716,7 +687,7 @@ webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payloa */ while( *position != UTF8_NULL_BYTE ) { - webvtt_delete_cuetext_token( &token ); + webvtt_delete_token( &token ); /* Step 7. */ switch( webvtt_cuetext_tokenizer( &position, &token ) ) { @@ -745,7 +716,7 @@ webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payloa * We have encountered an end token but it is not in a format that is * supported, throw away the token. */ - if( webvtt_get_node_kind_from_tag_name( &token->tag_name, &kind ) == WEBVTT_INVALID_TAG_NAME ) { + if( webvtt_node_kind_from_tag_name( &token->tag_name, &kind ) == WEBVTT_INVALID_TAG_NAME ) { continue; } @@ -769,7 +740,7 @@ webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payloa /* Do something here? */ } else { - webvtt_attach_internal_node( current_node, temp_node ); + webvtt_attach_node( current_node, temp_node ); if( WEBVTT_IS_VALID_INTERNAL_NODE( temp_node->kind ) ) { current_node = temp_node; @@ -784,7 +755,7 @@ webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payloa webvtt_skipwhite( &position ); } - webvtt_delete_cuetext_token( &token ); + webvtt_delete_token( &token ); return WEBVTT_SUCCESS; } diff --git a/media/webvtt/cuetext_internal.h b/media/webvtt/cuetext_internal.h index 5cadb2d825e3..8aa093fb4539 100644 --- a/media/webvtt/cuetext_internal.h +++ b/media/webvtt/cuetext_internal.h @@ -31,17 +31,17 @@ # include # include -typedef enum webvtt_cuetext_token_type_t webvtt_cuetext_token_type; -typedef enum webvtt_cuetext_token_state_t webvtt_cuetext_token_state; +typedef enum webvtt_token_type_t webvtt_token_type; +typedef enum webvtt_token_state_t webvtt_token_state; typedef struct webvtt_cuetext_token_t webvtt_cuetext_token; -typedef struct webvtt_cuetext_start_token_data_t webvtt_cuetext_start_token_data; +typedef struct webvtt_start_token_data_t webvtt_start_token_data; /** * Enumerates token types. */ enum -webvtt_cuetext_token_type_t { +webvtt_token_type_t { START_TOKEN, /* Identifies a webvtt_cue_text_start_tag_token. */ END_TOKEN, /* Identifies a webvtt_cue_text_end_tag_token. */ TIME_STAMP_TOKEN, /* Identifies a webvtt_cue_text_time_stamp_token. */ @@ -52,7 +52,7 @@ webvtt_cuetext_token_type_t { * Enumerates possible states that the cue text tokenizer can be in. */ enum -webvtt_cuetext_token_state_t { +webvtt_token_state_t { DATA, /* Initial state. */ ESCAPE, /* Parsing an escape value. */ TAG, /* Reached a '<' character, about to start parsing a tag. */ @@ -75,7 +75,7 @@ webvtt_cuetext_token_state_t { * cue text. */ struct -webvtt_cuetext_start_token_data_t { +webvtt_start_token_data_t { webvtt_stringlist *css_classes; webvtt_string annotations; }; @@ -86,12 +86,12 @@ webvtt_cuetext_start_token_data_t { */ struct webvtt_cuetext_token_t { - webvtt_cuetext_token_type token_type; + webvtt_token_type token_type; webvtt_string tag_name; // Only used for start token and end token types. union { webvtt_string text; webvtt_timestamp time_stamp; - webvtt_cuetext_start_token_data start_token_data; + webvtt_start_token_data start_token_data; }; }; @@ -99,12 +99,12 @@ webvtt_cuetext_token_t { * Routines for creating cue text tokens. * Sets the passed token to the new token. */ -WEBVTT_INTERN webvtt_status webvtt_create_cuetext_token( webvtt_cuetext_token **token, webvtt_cuetext_token_type token_type ); -WEBVTT_INTERN webvtt_status webvtt_create_cuetext_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name, +WEBVTT_INTERN webvtt_status webvtt_create_token( webvtt_cuetext_token **token, webvtt_token_type token_type ); +WEBVTT_INTERN webvtt_status webvtt_create_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name, webvtt_stringlist *css_classes, webvtt_string *annotation ); -WEBVTT_INTERN webvtt_status webvtt_create_cuetext_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name ); -WEBVTT_INTERN webvtt_status webvtt_create_cuetext_text_token( webvtt_cuetext_token **token, webvtt_string *text ); -WEBVTT_INTERN webvtt_status webvtt_create_cuetext_timestamp_token( webvtt_cuetext_token **token, +WEBVTT_INTERN webvtt_status webvtt_create_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name ); +WEBVTT_INTERN webvtt_status webvtt_create_text_token( webvtt_cuetext_token **token, webvtt_string *text ); +WEBVTT_INTERN webvtt_status webvtt_create_timestamp_token( webvtt_cuetext_token **token, webvtt_timestamp time_stamp ); /** @@ -115,14 +115,14 @@ WEBVTT_INTERN int tag_accepts_annotation( webvtt_string *tag_name ); /** * Routines for deleting cue text tokens. */ -WEBVTT_INTERN void webvtt_delete_cuetext_token( webvtt_cuetext_token **token ); +WEBVTT_INTERN void webvtt_delete_token( webvtt_cuetext_token **token ); /** * Converts the textual representation of a node kind into a particular kind. * I.E. tag_name of 'ruby' would create a ruby kind, etc. * Returns a WEBVTT_NOT_SUPPORTED if it does not find a valid tag name. */ -WEBVTT_INTERN webvtt_status webvtt_get_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind ); +WEBVTT_INTERN webvtt_status webvtt_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind ); /** * Creates a node from a valid token. @@ -135,7 +135,7 @@ WEBVTT_INTERN webvtt_status webvtt_create_node_from_token( webvtt_cuetext_token * cue text parser. * Referenced from - http://dev.w3.org/html5/webvtt/#webvtt-cue-text-tokenizer */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token ); +WEBVTT_INTERN webvtt_status webvtt_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token ); /** * Routines that take care of certain states in the webvtt cue text tokenizer. @@ -144,51 +144,51 @@ WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer( webvtt_byte **position, we /** * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-data-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_data_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ); +WEBVTT_INTERN webvtt_status webvtt_data_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_string *result ); /** * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-escape-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_escape_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ); +WEBVTT_INTERN webvtt_status webvtt_escape_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_string *result ); /** * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-tag-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ); +WEBVTT_INTERN webvtt_status webvtt_tag_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_string *result ); /** * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-start-tag-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_start_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ); +WEBVTT_INTERN webvtt_status webvtt_start_tag_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_string *result ); /** * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-start-tag-class-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_start_tag_class_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_stringlist *css_classes ); +WEBVTT_INTERN webvtt_status webvtt_class_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_stringlist *css_classes ); /** * Referenced from * http://dev.w3.org/html5/webvtt/#webvtt-start-tag-annotation-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_start_tag_annotation_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *annotation ); +WEBVTT_INTERN webvtt_status webvtt_annotation_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_string *annotation ); /** * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-end-tag-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_end_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ); +WEBVTT_INTERN webvtt_status webvtt_end_tag_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_string *result ); /** * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-timestamp-tag-state */ -WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_time_stamp_tag_state( webvtt_byte **position, - webvtt_cuetext_token_state *token_state, webvtt_string *result ); +WEBVTT_INTERN webvtt_status webvtt_timestamp_state( webvtt_byte **position, + webvtt_token_state *token_state, webvtt_string *result ); WEBVTT_INTERN webvtt_status webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payload, int finished ); diff --git a/media/webvtt/error.c b/media/webvtt/error.c index f7d9f2905226..4f138776f5ab 100644 --- a/media/webvtt/error.c +++ b/media/webvtt/error.c @@ -66,10 +66,10 @@ static const char *errstr[] = { * (This might be too much work!) */ WEBVTT_EXPORT const char * -webvtt_strerror( webvtt_error errno ) +webvtt_strerror( webvtt_error err ) { - if( errno >= (sizeof(errstr) / sizeof(*errstr)) ) { + if( err >= (sizeof(errstr) / sizeof(*errstr)) ) { return ""; } - return errstr[ errno ]; + return errstr[ err ]; } diff --git a/media/webvtt/include/webvtt/cue.h b/media/webvtt/include/webvtt/cue.h index f8ef876fafa2..edcfbbd7fdc1 100644 --- a/media/webvtt/include/webvtt/cue.h +++ b/media/webvtt/include/webvtt/cue.h @@ -29,6 +29,7 @@ # define __WEBVTT_CUE_H__ # include "util.h" # include +# include #if defined(__cplusplus) || defined(c_plusplus) #define WEBVTT_CPLUSPLUS 1 @@ -37,68 +38,6 @@ extern "C" { #define WEBVTT_AUTO (0xFFFFFFFF) -typedef enum -webvtt_node_kind_t { - WEBVTT_NODE_LEAF = 0x80000000, - WEBVTT_NODE_INTERNAL = 0x00000000, - - /** - * Internal Node objects - */ - WEBVTT_NODE_INTERNAL_START = 0, - WEBVTT_CLASS = 0 | WEBVTT_NODE_INTERNAL, - WEBVTT_ITALIC = 1 | WEBVTT_NODE_INTERNAL, - WEBVTT_BOLD = 2 | WEBVTT_NODE_INTERNAL, - WEBVTT_UNDERLINE = 3 | WEBVTT_NODE_INTERNAL, - WEBVTT_RUBY = 4 | WEBVTT_NODE_INTERNAL, - WEBVTT_RUBY_TEXT = 5 | WEBVTT_NODE_INTERNAL, - WEBVTT_VOICE = 6 | WEBVTT_NODE_INTERNAL, - - /** - * This type of node has should not be rendered. - * It is the top of the node list and only contains a list of nodes. - */ - WEBVTT_HEAD_NODE = 7, - - WEBVTT_NODE_INTERNAL_END = 7, - - /** - * Leaf Node objects - */ - WEBVTT_NODE_LEAF_START = 256, - WEBVTT_TEXT = 256 | WEBVTT_NODE_LEAF, - WEBVTT_TIME_STAMP = 257 | WEBVTT_NODE_LEAF, - - WEBVTT_NODE_LEAF_END = 257, - - /* An empty initial state for a node */ - WEBVTT_EMPTY_NODE = 258 -} webvtt_node_kind; - -/** - * Macros to assist in validating node kinds, so that C++ compilers don't - * complain (as long as they provide reinterpret_cast, which they should) - */ -#if defined(__cplusplus) || defined(__cplusplus_cli) || defined(__embedded_cplusplus) || defined(c_plusplus) -# define WEBVTT_CAST(Type,Val) (reinterpret_cast(Val)) -#else -# define WEBVTT_CAST(Type,Val) ((Type)(Val)) -#endif - -#define WEBVTT_IS_LEAF(Kind) ( ((Kind) & WEBVTT_NODE_LEAF) != 0 ) -#define WEBVTT_NODE_INDEX(Kind) ( (Kind) & ~WEBVTT_NODE_LEAF ) -#define WEBVTT_IS_VALID_LEAF_NODE(Kind) ( WEBVTT_IS_LEAF(Kind) && (WEBVTT_NODE_INDEX(Kind) >= WEBVTT_NODE_LEAF_START && WEBVTT_NODE_INDEX(Kind) <= WEBVTT_NODE_LEAF_END ) ) -#define WEBVTT_IS_VALID_INTERNAL_NODE(Kind) ( (!WEBVTT_IS_LEAF(Kind)) && (WEBVTT_NODE_INDEX(Kind) >= WEBVTT_NODE_INTERNAL_START && WEBVTT_NODE_INDEX(Kind) <= WEBVTT_NODE_INTERNAL_END) ) -#define WEBVTT_IS_VALID_NODE_KIND(Kind) ( WEBVTT_IS_VALID_INTERNAL_NODE(Kind) || WEBVTT_IS_VALID_LEAF_NODE(Kind) ) - -/** - * Casting helpers - */ -#define WEBVTT_GET_INTERNAL_NODE(Node) ( WEBVTT_IS_VALID_INTERNAL_NODE(WEBVTT_CAST(webvtt_node,Node)->kind) ? WEBVTT_CAST(webvtt_internal_node,Node) : 0 ) -#define WEBVTT_GET_LEAF_NODE(Node) ( WEBVTT_IS_VALID_LEAF_NODE((WEBVTT_CAST(webvtt_node,Node))->kind) ? WEBVTT_CAST(webvtt_leaf_node,Node) : 0 ) - -struct webvtt_internal_node_data_t; - typedef enum webvtt_vertical_type_t { WEBVTT_HORIZONTAL = 0, @@ -116,39 +55,6 @@ webvtt_align_type_t { WEBVTT_ALIGN_RIGHT } webvtt_align_type; -typedef struct -webvtt_node_t { - - struct webvtt_refcount_t refs; - /** - * The specification asks for uni directional linked list, but we have added - * a parent node in order to facilitate an iterative cue text parsing - * solution. - */ - struct webvtt_node_t *parent; - webvtt_node_kind kind; - - union { - webvtt_string text; - webvtt_timestamp timestamp; - struct webvtt_internal_node_data_t *internal_data; - } data; -} webvtt_node; - -typedef struct -webvtt_internal_node_data_t { - webvtt_string annotation; - webvtt_stringlist *css_classes; - - webvtt_uint alloc; - webvtt_uint length; - webvtt_node **children; -} webvtt_internal_node_data; - -WEBVTT_EXPORT void webvtt_init_node( webvtt_node **node ); -WEBVTT_EXPORT void webvtt_ref_node( webvtt_node *node ); -WEBVTT_EXPORT void webvtt_release_node( webvtt_node **node ); - typedef struct webvtt_cue_settings_t { webvtt_vertical_type vertical; diff --git a/media/webvtt/include/webvtt/node.h b/media/webvtt/include/webvtt/node.h new file mode 100644 index 000000000000..250e8f26eee7 --- /dev/null +++ b/media/webvtt/include/webvtt/node.h @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2013 Mozilla Foundation and Contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __WEBVTT_NODE_H__ +# define __WEBVTT_NODE_H__ +# include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef enum +webvtt_node_kind_t { + WEBVTT_NODE_LEAF = 0x80000000, + WEBVTT_NODE_INTERNAL = 0x00000000, + + /** + * Internal Node objects + */ + WEBVTT_NODE_INTERNAL_START = 0, + WEBVTT_CLASS = 0 | WEBVTT_NODE_INTERNAL, + WEBVTT_ITALIC = 1 | WEBVTT_NODE_INTERNAL, + WEBVTT_BOLD = 2 | WEBVTT_NODE_INTERNAL, + WEBVTT_UNDERLINE = 3 | WEBVTT_NODE_INTERNAL, + WEBVTT_RUBY = 4 | WEBVTT_NODE_INTERNAL, + WEBVTT_RUBY_TEXT = 5 | WEBVTT_NODE_INTERNAL, + WEBVTT_VOICE = 6 | WEBVTT_NODE_INTERNAL, + + /** + * This type of node has should not be rendered. + * It is the top of the node list and only contains a list of nodes. + */ + WEBVTT_HEAD_NODE = 7, + + WEBVTT_NODE_INTERNAL_END = 7, + + /** + * Leaf Node objects + */ + WEBVTT_NODE_LEAF_START = 256, + WEBVTT_TEXT = 256 | WEBVTT_NODE_LEAF, + WEBVTT_TIME_STAMP = 257 | WEBVTT_NODE_LEAF, + + WEBVTT_NODE_LEAF_END = 257, + + /* An empty initial state for a node */ + WEBVTT_EMPTY_NODE = 258 +} webvtt_node_kind; + +#define WEBVTT_IS_LEAF(Kind) ( ((Kind) & WEBVTT_NODE_LEAF) != 0 ) +#define WEBVTT_NODE_INDEX(Kind) ( (Kind) & ~WEBVTT_NODE_LEAF ) +#define WEBVTT_IS_VALID_LEAF_NODE(Kind) ( WEBVTT_IS_LEAF(Kind) && (WEBVTT_NODE_INDEX(Kind) >= WEBVTT_NODE_LEAF_START && WEBVTT_NODE_INDEX(Kind) <= WEBVTT_NODE_LEAF_END ) ) +#define WEBVTT_IS_VALID_INTERNAL_NODE(Kind) ( (!WEBVTT_IS_LEAF(Kind)) && (WEBVTT_NODE_INDEX(Kind) >= WEBVTT_NODE_INTERNAL_START && WEBVTT_NODE_INDEX(Kind) <= WEBVTT_NODE_INTERNAL_END) ) +#define WEBVTT_IS_VALID_NODE_KIND(Kind) ( WEBVTT_IS_VALID_INTERNAL_NODE(Kind) || WEBVTT_IS_VALID_LEAF_NODE(Kind) ) + +struct webvtt_internal_node_data_t; + +typedef struct +webvtt_node_t { + + struct webvtt_refcount_t refs; + /** + * The specification asks for uni directional linked list, but we have added + * a parent node in order to facilitate an iterative cue text parsing + * solution. + */ + struct webvtt_node_t *parent; + webvtt_node_kind kind; + + union { + webvtt_string text; + webvtt_timestamp timestamp; + struct webvtt_internal_node_data_t *internal_data; + } data; +} webvtt_node; + +typedef struct +webvtt_internal_node_data_t { + webvtt_string annotation; + webvtt_stringlist *css_classes; + + webvtt_uint alloc; + webvtt_uint length; + webvtt_node **children; +} webvtt_internal_node_data; + +WEBVTT_EXPORT void webvtt_init_node( webvtt_node **node ); +WEBVTT_EXPORT void webvtt_ref_node( webvtt_node *node ); +WEBVTT_EXPORT void webvtt_release_node( webvtt_node **node ); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif diff --git a/media/webvtt/include/webvtt/string.h b/media/webvtt/include/webvtt/string.h index d51a2e69b966..96e1f2f6fb2e 100644 --- a/media/webvtt/include/webvtt/string.h +++ b/media/webvtt/include/webvtt/string.h @@ -151,6 +151,15 @@ WEBVTT_EXPORT int webvtt_string_getline( webvtt_string *str, const webvtt_byte * */ WEBVTT_EXPORT webvtt_status webvtt_string_putc( webvtt_string *str, webvtt_byte to_append ); + +/** + * webvtt_string_is_equal + * + * compare a string's text to a byte array + * + */ +WEBVTT_EXPORT webvtt_bool webvtt_string_is_equal( webvtt_string *str, webvtt_byte *to_compare, webvtt_uint len ); + /** * webvtt_string_append * diff --git a/media/webvtt/include/webvtt/util.h b/media/webvtt/include/webvtt/util.h index fea72e08ed5b..1978fef65d91 100644 --- a/media/webvtt/include/webvtt/util.h +++ b/media/webvtt/include/webvtt/util.h @@ -192,6 +192,17 @@ extern "C" { * Parser should move to the next cuesetting. */ WEBVTT_NEXT_CUESETTING = -12, + + /* + * Match is not found in a search query + */ + WEBVTT_NO_MATCH_FOUND = -13, + + /** + * Thrown when assertions fail and FATAL_ASSERTION + * is not defined. + */ + WEBVTT_FAILED_ASSERTION = -14, }; typedef enum webvtt_status_t webvtt_status; diff --git a/media/webvtt/node.c b/media/webvtt/node.c new file mode 100644 index 000000000000..bae4d263fb92 --- /dev/null +++ b/media/webvtt/node.c @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2013 Mozilla Foundation and Contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include + #include + #include "node_internal.h" + + static webvtt_node empty_node = { + { 1 }, /* init ref count */ + 0, /* parent */ + WEBVTT_EMPTY_NODE /* node kind */ +}; + +WEBVTT_EXPORT void +webvtt_ref_node( webvtt_node *node ) +{ + if( node ) { + webvtt_ref( &node->refs ); + } +} + +WEBVTT_EXPORT void +webvtt_init_node( webvtt_node **node ) +{ + if( *node != &empty_node ) { + if( node && *node ) { + webvtt_release_node( node ); + } + *node = &empty_node; + webvtt_ref_node( *node ); + } +} + +WEBVTT_INTERN webvtt_status +webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent ) +{ + webvtt_node *temp_node; + + if( !node ) { + return WEBVTT_INVALID_PARAM; + } + + if( !( temp_node = (webvtt_node *)webvtt_alloc0(sizeof(*temp_node)) ) ) + { + return WEBVTT_OUT_OF_MEMORY; + } + + webvtt_ref_node( temp_node ); + temp_node->kind = kind; + temp_node->parent = parent; + *node = temp_node; + + return WEBVTT_SUCCESS; +} + +WEBVTT_INTERN webvtt_status +webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, + webvtt_stringlist *css_classes, webvtt_string *annotation ) +{ + webvtt_status status; + webvtt_internal_node_data *node_data; + + if( WEBVTT_FAILED( status = webvtt_create_node( node, kind, parent ) ) ) { + return status; + } + + if ( !( node_data = (webvtt_internal_node_data *)webvtt_alloc0( sizeof(*node_data) ) ) ) + { + return WEBVTT_OUT_OF_MEMORY; + } + + webvtt_copy_stringlist( &node_data->css_classes, css_classes ); + webvtt_copy_string( &node_data->annotation, annotation ); + node_data->children = NULL; + node_data->length = 0; + node_data->alloc = 0; + + (*node)->data.internal_data = node_data; + + return WEBVTT_SUCCESS; +} + +WEBVTT_INTERN webvtt_status +webvtt_create_head_node( webvtt_node **node ) +{ + webvtt_status status; + webvtt_string temp_annotation; + + webvtt_init_string( &temp_annotation ); + if( WEBVTT_FAILED( status = webvtt_create_internal_node( node, NULL, WEBVTT_HEAD_NODE, NULL, &temp_annotation ) ) ) { + return status; + } + + return WEBVTT_SUCCESS; +} + +WEBVTT_INTERN webvtt_status +webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp ) +{ + webvtt_status status; + + if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TIME_STAMP, parent ) ) ) { + return status; + } + + (*node)->data.timestamp = time_stamp; + + return WEBVTT_SUCCESS; +} + +WEBVTT_INTERN webvtt_status +webvtt_create_text_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text ) +{ + webvtt_status status; + + if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TEXT, parent ) ) ) { + return status; + } + + webvtt_copy_string( &(*node)->data.text, text ); + + return WEBVTT_SUCCESS; + +} + +WEBVTT_EXPORT void +webvtt_release_node( webvtt_node **node ) +{ + webvtt_uint i; + webvtt_node *n; + + if( !node || !*node ) { + return; + } + n = *node; + + if( webvtt_deref( &n->refs ) == 0 ) { + if( n->kind == WEBVTT_TEXT ) { + webvtt_release_string( &n->data.text ); + } else if( WEBVTT_IS_VALID_INTERNAL_NODE( n->kind ) && n->data.internal_data ) { + webvtt_release_stringlist( &n->data.internal_data->css_classes ); + webvtt_release_string( &n->data.internal_data->annotation ); + for( i = 0; i < n->data.internal_data->length; i++ ) { + webvtt_release_node( n->data.internal_data->children + i ); + } + webvtt_free( n->data.internal_data->children ); + webvtt_free( n->data.internal_data ); + } + webvtt_free( n ); + } + *node = 0; +} + +WEBVTT_INTERN webvtt_status +webvtt_attach_node( webvtt_node *parent, webvtt_node *to_attach ) +{ + webvtt_node **next = 0; + webvtt_internal_node_data *nd = 0; + + if( !parent || !to_attach || !parent->data.internal_data ) { + return WEBVTT_INVALID_PARAM; + } + nd = parent->data.internal_data; + + if( nd->alloc == 0 ) { + next = (webvtt_node **)webvtt_alloc0( sizeof( webvtt_node * ) * 8 ); + + if( !next ) { + return WEBVTT_OUT_OF_MEMORY; + } + + nd->children = next; + nd->alloc = 8; + } + + if( nd->length + 1 >= ( nd->alloc / 3 ) * 2 ) { + + next = (webvtt_node **)webvtt_alloc0( sizeof( *next ) * nd->alloc * 2 ); + + if( !next ) { + return WEBVTT_OUT_OF_MEMORY; + } + + nd->alloc *= 2; + memcpy( next, nd->children, nd->length * sizeof( webvtt_node * ) ); + webvtt_free( nd->children ); + nd->children = next; + } + + nd->children[ nd->length++ ] = to_attach; + webvtt_ref_node( to_attach ); + + return WEBVTT_SUCCESS; +} diff --git a/media/webvtt/node_internal.h b/media/webvtt/node_internal.h new file mode 100644 index 000000000000..d7652347ffd7 --- /dev/null +++ b/media/webvtt/node_internal.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2013 Mozilla Foundation and Contributors + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __WEBVTT_NODE_INTERNAL_H__ +# define __WEBVTT_NODE_INTERNAL_H__ +# include + +/** + * Routines for creating nodes. + */ +WEBVTT_INTERN webvtt_status webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent ); +WEBVTT_INTERN webvtt_status webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, webvtt_stringlist *css_classes, webvtt_string *annotation ); +/** + * We probably shouldn't have a 'head node' type. + * We should just return a list of node trees... + */ +WEBVTT_INTERN webvtt_status webvtt_create_head_node( webvtt_node **node ); +WEBVTT_INTERN webvtt_status webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp ); +WEBVTT_INTERN webvtt_status webvtt_create_text_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text ); + +/** + * Attaches a node to the internal node list of another node. + */ +WEBVTT_INTERN webvtt_status webvtt_attach_node( webvtt_node *parent, webvtt_node *to_attach ); + +#endif diff --git a/media/webvtt/parser.c b/media/webvtt/parser.c index e83a57ee0705..17282f7b0d28 100644 --- a/media/webvtt/parser.c +++ b/media/webvtt/parser.c @@ -42,9 +42,13 @@ static const webvtt_byte separator[] = { #define BUFFER (self->buffer + self->position) #define MALFORMED_TIME ((webvtt_timestamp_t)-1.0) -static int find_bytes( const webvtt_byte *buffer, webvtt_uint len, const webvtt_byte *sbytes, webvtt_uint slen ); +static webvtt_status find_bytes( const webvtt_byte *buffer, webvtt_uint len, const webvtt_byte *sbytes, webvtt_uint slen ); static webvtt_status webvtt_skipwhite( const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint len ); static webvtt_int64 parse_int( const webvtt_byte **pb, int *pdigits ); +static void skip_spacetab( const webvtt_byte *text, webvtt_uint *pos, + webvtt_uint len, webvtt_uint *column ); +static void skip_until_white( const webvtt_byte *text, webvtt_uint *pos, + webvtt_uint len, webvtt_uint *column ); WEBVTT_EXPORT webvtt_status webvtt_create_parser( webvtt_cue_fn on_read, @@ -229,6 +233,45 @@ find_newline( const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint len ) return -1; } +static void +skip_spacetab( const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len, + webvtt_uint *column ) +{ + webvtt_uint c = 0; + if( !column ) { + column = &c; + } + while( *pos < len ) { + webvtt_byte ch = text[ *pos ]; + if( ch == 0x20 || ch == 0x09 ) { + ++( *pos ); + ++( *column ); + } else { + break; + } + } +} + +static void +skip_until_white( const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len, + webvtt_uint *column ) +{ + webvtt_uint c = 0; + if( !column ) { + column = &c; + } + while( *pos < len ) { + webvtt_byte ch = text[ *pos ]; + if( ch == 0x20 || ch == 0x09 || ch == 0x0A || ch == 0x0D ) { + break; + } else { + int length = webvtt_utf8_length( text + *pos ); + *pos += length; + ++( *column ); + } + } +} + static webvtt_status webvtt_skipwhite( const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint len ) { @@ -259,25 +302,25 @@ find_next_whitespace( const webvtt_byte *buffer, webvtt_uint *ppos, webvtt_uint /** * basic strnstr-ish routine */ -static int +static webvtt_status find_bytes( const webvtt_byte *buffer, webvtt_uint len, const webvtt_byte *sbytes, webvtt_uint slen ) { webvtt_uint slen2; // check params for integrity if( !buffer || len < 1 || !sbytes || slen < 1 ) { - return 0; + return WEBVTT_INVALID_PARAM; } slen2 = slen - 1; while( len-- >= slen && *buffer ){ if( *buffer == *sbytes && memcmp( buffer + 1, sbytes + 1, slen2 ) == 0 ) { - return 1; + return WEBVTT_SUCCESS; } buffer++; } - return 0; + return WEBVTT_NO_MATCH_FOUND; } /** @@ -355,6 +398,243 @@ do \ } while(0) #define POPBACK() do_pop(self) +static webvtt_status +webvtt_parse_cuesetting( webvtt_parser self, const webvtt_byte *text, + webvtt_uint *pos, webvtt_uint len, webvtt_error bv, webvtt_token + keyword, webvtt_token values[], webvtt_uint *value_column ) { + enum webvtt_param_mode + { + P_KEYWORD, + P_COLON, + P_VALUE + }; + int i; + webvtt_bool precws = 0; + webvtt_bool prevws = 0; + static const webvtt_token value_tokens[] = { + INTEGER, RL, LR, START, MIDDLE, END, LEFT, RIGHT, PERCENTAGE, 0 + }; + static const webvtt_token keyword_tokens[] = { + ALIGN, SIZE, LINE, POSITION, VERTICAL, 0 + }; + enum webvtt_param_mode mode = P_KEYWORD; + webvtt_uint keyword_column = 0; + while( *pos < len ) { + webvtt_uint last_line = self->line; + webvtt_uint last_column = self->column; + webvtt_uint last_pos = *pos; + webvtt_token tk = webvtt_lex( self, text, pos, len, 1 ); + webvtt_uint tp = self->token_pos; + self->token_pos = 0; + + switch( mode ) { + case P_KEYWORD: + switch( tk ) { + case ALIGN: + case SIZE: + case POSITION: + case VERTICAL: + case LINE: + if( tk != keyword ) { + *pos -= tp; + self->column -= tp; + return WEBVTT_NEXT_CUESETTING; + } + if( *pos < len ) { + webvtt_uint column = last_column; + webvtt_byte ch = text[ *pos ]; + if( ch != 0x3A ) { + webvtt_error e = WEBVTT_INVALID_CUESETTING; + if( ch == 0x20 || ch == 0x09 ) { + column = self->column; + e = WEBVTT_UNEXPECTED_WHITESPACE; + skip_spacetab( text, pos, len, &self->column ); + if( text[ *pos ] == 0x3A ) { + skip_until_white( text, pos, len, &self->column ); + } + } else { + skip_until_white( text, pos, len, &self->column ); + } + ERROR_AT_COLUMN( e, column ); + } else { + mode = P_COLON; + keyword_column = last_column; + } + } else { + ERROR_AT_COLUMN( WEBVTT_INVALID_CUESETTING, last_column ); + } + break; + case WHITESPACE: + break; + case NEWLINE: + return WEBVTT_SUCCESS; + break; + default: + ERROR_AT( WEBVTT_INVALID_CUESETTING, last_line, + last_column ); + *pos = *pos + tp + 1; + skip_param: + while( *pos < len && text[ *pos ] != 0x20 + && text[ *pos ] != 0x09 ) { + if( text[ *pos ] == 0x0A || text[ *pos ] == 0x0D ) { + return WEBVTT_SUCCESS; + } + ++( *pos ); + ++self->column; + } + break; + } + break; + case P_COLON: + if( tk == WHITESPACE && !precws ) { + ERROR_AT( WEBVTT_UNEXPECTED_WHITESPACE, last_line, + last_column + ); + precws = 1; + } else if( tk == COLON ) { + mode = P_VALUE; + } else if( token_in_list( tk, value_tokens ) ) { + ERROR_AT( WEBVTT_MISSING_CUESETTING_DELIMITER, last_line, + last_column ); + mode = P_VALUE; + goto get_value; + } else if( token_in_list( tk, keyword_tokens ) ) { + ERROR_AT( WEBVTT_INVALID_CUESETTING, last_line, + keyword_column ); + } else { + ERROR_AT( WEBVTT_INVALID_CUESETTING_DELIMITER, last_line, + last_column ); + *pos = last_pos + tp + 1; + } + break; + case P_VALUE: +get_value: + if( tk == WHITESPACE && !prevws ) { + ERROR_AT( WEBVTT_UNEXPECTED_WHITESPACE, last_line, + last_column ); + } else if( ( i = find_token( tk, values ) ) >= 0 ) { + webvtt_token t = values[ i ] & TF_TOKEN_MASK; + int flags = values[ i ] & TF_FLAGS_MASK; + *value_column = last_column; + if( *pos < len ) { + webvtt_byte ch = text[ *pos ]; + if( ch != 0x20 && ch != 0x09 + && ch != 0x0D && ch != 0x0A ) { + goto bad_value; + } + } + switch( t ) { + case INTEGER: + case PERCENTAGE: + if( ( flags & TF_SIGN_MASK ) != TF_SIGN_MASK ) { + const webvtt_byte p = self->token[ 0 ]; + if( ( ( flags & TF_NEGATIVE ) && p != UTF8_HYPHEN_MINUS ) + || ( ( flags & TF_POSITIVE ) && p == UTF8_HYPHEN_MINUS +) ) { + goto bad_value; + } + } + } + return i + 1; + } else { +bad_value: + ERROR_AT( bv, last_line, last_column ); +bad_value_eol: + while( *pos < len && text[ *pos ] != 0x20 + && text[ *pos ] != 0x09 ) { + if( text[ *pos ] == 0x0A || text[ *pos ] == 0x0D ) { + return WEBVTT_SUCCESS; + } + ++( *pos ); + ++self->column; + } + if( *pos >= len ) { + return WEBVTT_SUCCESS; + } + } + break; + } + } + if( mode == P_VALUE && *pos >= len ) { + ERROR( bv ); + goto bad_value_eol; + } + return WEBVTT_NEXT_CUESETTING; +} + +WEBVTT_INTERN webvtt_status +webvtt_parse_align( webvtt_parser self, webvtt_cue *cue, const +webvtt_byte *text, + webvtt_uint *pos, webvtt_uint len ) +{ + webvtt_uint last_line = self->line; + webvtt_uint last_column = self->column; + webvtt_status v; + webvtt_uint vc; + webvtt_token values[] = { START, MIDDLE, END, LEFT, RIGHT, 0 }; + if( ( v = webvtt_parse_cuesetting( self, text, pos, len, + WEBVTT_ALIGN_BAD_VALUE, ALIGN, values, &vc ) ) > 0 ) { + if( cue->flags & CUE_HAVE_ALIGN ) { + ERROR_AT( WEBVTT_ALIGN_ALREADY_SET, last_line, last_column ); + } + cue->flags |= CUE_HAVE_ALIGN; + switch( values[ v - 1 ] ) { + case START: cue->settings.align = WEBVTT_ALIGN_START; break; + case MIDDLE: cue->settings.align = WEBVTT_ALIGN_MIDDLE; break; + case END: cue->settings.align = WEBVTT_ALIGN_END; break; + case LEFT: cue->settings.align = WEBVTT_ALIGN_LEFT; break; + case RIGHT: cue->settings.align = WEBVTT_ALIGN_RIGHT; break; + } + } + return v >= 0 ? WEBVTT_SUCCESS : v; +} + +WEBVTT_INTERN webvtt_status +webvtt_parse_line( webvtt_parser self, webvtt_cue *cue, const +webvtt_byte *text, + webvtt_uint *pos, webvtt_uint len ) +{ + webvtt_uint last_line = self->line; + webvtt_uint last_column = self->column; + webvtt_status v; + webvtt_uint vc; + webvtt_bool first_flag = 0; + webvtt_token values[] = { INTEGER, PERCENTAGE|TF_POSITIVE, 0 }; + if( ( v = webvtt_parse_cuesetting( self, text, pos, len, + WEBVTT_LINE_BAD_VALUE, LINE, values, &vc ) ) > 0 ) { + webvtt_uint digits; + webvtt_int64 value; + const webvtt_byte *t = self->token; + if( cue->flags & CUE_HAVE_LINE ) { + ERROR_AT( WEBVTT_LINE_ALREADY_SET, last_line, last_column ); + } else { + first_flag = 1; + } + cue->flags |= CUE_HAVE_LINE; + value = parse_int( &t, &digits ); + switch( values[ v - 1 ] & TF_TOKEN_MASK ) { + case INTEGER: { + cue->snap_to_lines = 1; + cue->settings.line = ( int )value; + } + break; + + case PERCENTAGE: { + if( value < 0 || value > 100 ) { + if( first_flag ) { + cue->flags &= ~CUE_HAVE_LINE; + } + ERROR_AT_COLUMN( WEBVTT_LINE_BAD_VALUE, vc ); + return WEBVTT_SUCCESS; + } + cue->snap_to_lines = 0; + cue->settings.line = ( int )value; + } break; + } + } + return v >= 0 ? WEBVTT_SUCCESS : v; +} + WEBVTT_INTERN int parse_cueparams( webvtt_parser self, const webvtt_byte *buffer, webvtt_uint len, webvtt_cue *cue ) @@ -365,6 +645,8 @@ parse_cueparams( webvtt_parser self, const webvtt_byte *buffer, webvtt_uint baddelim = 0; webvtt_uint pos = 0; webvtt_token last_token = 0; + webvtt_uint last_line = self->line; + enum cp_state { CP_T1, CP_T2, CP_T3, CP_T4, CP_T5, /* 'start' cuetime, whitespace1, 'separator', whitespace2, 'end' cuetime */ @@ -396,6 +678,8 @@ parse_cueparams( webvtt_parser self, const webvtt_byte *buffer, while( pos < len ) { webvtt_uint last_column = self->column; webvtt_token token = webvtt_lex( self, buffer, &pos, len, 1 ); + webvtt_uint tlen = self->token_pos; + self->token_pos = 0; _recheck: switch( state ) { /* start timestamp */ @@ -409,7 +693,7 @@ _recheck: ( BAD_TIMESTAMP( cue->from ) ? WEBVTT_EXPECTED_TIMESTAMP : WEBVTT_MALFORMED_TIMESTAMP ), last_column ); - if( !webvtt_isdigit( self->token[self->token_pos - 1] ) ) { + if( self->token_pos && !webvtt_isdigit( self->token[self->token_pos - 1] ) ) { while( pos < len && buffer[pos] != 0x09 && buffer[pos] != 0x20 ) { ++pos; } } if( BAD_TIMESTAMP( cue->from ) ) @@ -513,9 +797,6 @@ else if( !have_ws ) \ case WHITESPACE: have_ws = last_column; break; - case COLON: - ERROR_AT_COLUMN( WEBVTT_MISSING_CUESETTING_KEYWORD, last_column ); - break; case VERTICAL: CHKDELIM have_ws = 0; SETST( CP_V1 ); @@ -525,21 +806,35 @@ else if( !have_ws ) \ SETST( CP_P1 ); break; case ALIGN: - CHKDELIM have_ws = 0; - SETST( CP_A1 ); - break; + { + webvtt_status status; + pos -= tlen; /* Required for parse_align() */ + self->column = last_column; /* Reset for parse_align() */ + status = webvtt_parse_align( self, cue, buffer, &pos, len ); + if( status == WEBVTT_PARSE_ERROR ) { + return WEBVTT_PARSE_ERROR; + } + } + break; + case SIZE: CHKDELIM have_ws = 0; SETST( CP_S1 ); break; case LINE: - CHKDELIM have_ws = 0; - SETST( CP_L1 ); - break; + { + webvtt_status status; + pos -= tlen; /* Required for parse_align() */ + self->column = last_column; /* Reset for parse_align() */ + status = webvtt_parse_line( self, cue, buffer, &pos, len ); + if( status == WEBVTT_PARSE_ERROR ) { + return WEBVTT_PARSE_ERROR; + } + } + break; default: if( have_ws ) { ERROR_AT_COLUMN( WEBVTT_INVALID_CUESETTING, last_column ); - while( pos < len && buffer[pos] != 0x09 && buffer[pos] != 0x20 ) { ++pos; } } else if( token == BADTOKEN ) { /* it was a bad delimiter... */ if( !baddelim ) { @@ -547,6 +842,9 @@ else if( !have_ws ) \ } ++pos; } + while( pos < len && buffer[pos] != 0x09 && buffer[pos] != 0x20 ) { + ++pos; + } } break; #define CS1(S) \ @@ -1018,6 +1316,13 @@ _recheck: webvtt_state *st = FRAMEUP( 1 ); webvtt_string text = st->v.text; + /* FIXME: guard inconsistent state */ + if (!cue) { + ERROR( WEBVTT_PARSE_ERROR ); + status = WEBVTT_PARSE_ERROR; + goto _finish; + } + st->type = V_NONE; st->v.cue = NULL; @@ -1027,7 +1332,7 @@ _recheck: * TODO: Add debug assertion */ if( find_bytes( webvtt_string_text( &text ), webvtt_string_length( &text ), separator, - sizeof( separator ) ) ) { + sizeof( separator ) ) == WEBVTT_SUCCESS) { /* It's not a cue id, we found '-->'. It can't be a second cueparams line, because if we had it, we would be in a different state. */ @@ -1051,7 +1356,7 @@ _recheck: } } else { /* It is a cue-id */ - if( cue->flags & CUE_HAVE_ID ) { + if( cue && cue->flags & CUE_HAVE_ID ) { /** * This isn't actually a cue-id, because we already * have one. It seems to be cuetext, which is occurring @@ -1122,24 +1427,17 @@ read_cuetext( webvtt_parser self, const webvtt_byte *b, webvtt_uint goto _finish; } - if( self->line_buffer.d->length > 1 && self->line_buffer.d->text[ self->line_buffer.d->length - 1 ] == UTF8_LINE_FEED ) { + /** + * We've encountered a line without any cuetext on it, i.e. there is no + * newline character and len is 0 or there is and len is 1, therefore, + * the cue text is finished. + */ + if( self->line_buffer.d->length <= 1 ) { /** * finished */ finished = 1; } - webvtt_string_putc( &self->line_buffer, UTF8_LINE_FEED ); - - if( pos < len ) { - if( b[pos] == UTF8_CARRIAGE_RETURN ) { - if( len - pos >= 2 && b[pos + 1] == UTF8_LINE_FEED ) { - ++pos; - } - ++pos; - } else { - ++pos; - } - } } } while( pos < len && !finished ); _finish: @@ -1385,3 +1683,31 @@ _malformed: *result = 0xFFFFFFFFFFFFFFFF; return 0; } + +WEBVTT_INTERN webvtt_bool +token_in_list( webvtt_token token, const webvtt_token list[] ) +{ + int i = 0; + webvtt_token t; + while( ( t = list[ i++ ] ) != 0 ) { + if( token == t ) { + return 1; + } + } + return 0; +} + +WEBVTT_INTERN int +find_token( webvtt_token token, const webvtt_token list[] ) +{ + int i = 0; + webvtt_token t; + while( ( t = list[ i ] ) != 0 ) { + webvtt_token masked = t & TF_TOKEN_MASK; + if( token == masked ) { + return i; + } + ++i; + } + return -1; +} diff --git a/media/webvtt/parser_internal.h b/media/webvtt/parser_internal.h index d6af94dbce23..4675601e8ddd 100644 --- a/media/webvtt/parser_internal.h +++ b/media/webvtt/parser_internal.h @@ -29,6 +29,18 @@ # define __INTERN_PARSER_H__ # include # include "string_internal.h" +# ifndef NDEBUG +# define NDEBUG +# endif + +# if defined(FATAL_ASSERTION) +# undef NDEBUG +# include +# else +# if defined(BREAK_ON_ASSERTION) && !WEBVTT_OS_WIN32 +static void break_on_assert(); +# endif +# endif typedef enum webvtt_token_t { @@ -217,20 +229,102 @@ WEBVTT_INTERN webvtt_token webvtt_lex( webvtt_parser self, const webvtt_byte *bu WEBVTT_INTERN webvtt_status webvtt_lex_word( webvtt_parser self, webvtt_string *pba, const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length, webvtt_bool finish ); WEBVTT_INTERN int parse_timestamp( const webvtt_byte *b, webvtt_timestamp *result ); +/** + * Flags which can apply additional meaning to a token. find_token() will + * test for only the actual token and ignore the additional flags. + */ +typedef +enum webvtt_token_flags_t +{ + /* Number can be positive */ + TF_POSITIVE = 0x80000000, + + /* Number can be negative */ + TF_NEGATIVE = 0x40000000, + /* (token & TF_SIGN_MASK) == combination of TF_POSITIVE and + TF_NEGATIVE, which indicate what values a number token is allowed + to be */ + TF_SIGN_MASK = ( TF_POSITIVE | TF_NEGATIVE ), + + /* (token & TF_FLAGS_MASK) == webvtt_token_flags value + that is being asked for */ + TF_FLAGS_MASK = TF_SIGN_MASK, + + /* (token & TF_TOKEN_MASK) == webvtt_token value */ + TF_TOKEN_MASK = ( 0xFFFFFFFF & ~TF_FLAGS_MASK ), +} webvtt_token_flags; + +/** + * Return non-zero if a token is found in a NULL-terminated array of tokens, or + * zero if not. + * + * Unlike find_token(), token_in_list() does not make use of + * webvtt_token_flags and thus requiers an exact match. + */ +WEBVTT_INTERN webvtt_bool token_in_list( webvtt_token search_for, + const webvtt_token token_list[] ); + +/** + * Return the index of a token in a NULL-terminated array of tokens, + * or -1 if the token is not found. + * + * find_token() will search for an occurrence of `token' in a list + * where webvtt_token_flags are used. For instance, if the list of + * tokens contains { TF_POSITIVE | INTEGER, TF_POSITIVE | PERCENTAGE, + * 0 }, find_token() will return a match for INTEGER or PERCENTAGE if + * either is searched for. + */ +WEBVTT_INTERN int find_token( webvtt_token search_for, + const webvtt_token token_list[] ); + #define BAD_TIMESTAMP(ts) ( ( ts ) == 0xFFFFFFFFFFFFFFFF ) -#define ERROR(Code) \ -do \ -{ \ - if( !self->error || self->error(self->userdata,self->line,self->column,Code) < 0 ) \ - return WEBVTT_PARSE_ERROR; \ -} while(0) - -#define ERROR_AT_COLUMN(Code,Column) \ -do \ -{ \ - if( !self->error || self->error(self->userdata,self->line,(Column),Code) < 0 ) \ - return WEBVTT_PARSE_ERROR; \ -} while(0) - +#ifdef FATAL_ASSERTION +# define SAFE_ASSERT(condition) assert(condition) +# define DIE_IF(condition) assert( !(condition) ) +#else +# ifdef BREAK_ON_ASSERTION +static void +break_on_assert(void) { +#if WEBVTT_OS_WIN32 + /* __declspec(dllimport) should work for cross compiling gcc as well */ + __declspec(dllimport) void __stdcall DebugBreak( void ); + DebugBreak(); +#else + volatile int *ptr = (volatile int *)0; + *ptr = 1; +#endif +} +# define SAFE_ASSERT(condition) \ +if( !(condition) ) { \ + break_on_assert(); \ + return WEBVTT_FAILED_ASSERTION; \ +} +# define DIE_IF(condition) \ +if( (condition) ) { \ + break_on_assert(); \ +} +# else +# define SAFE_ASSERT(condition) \ +if( !(condition) ) { \ + return WEBVTT_FAILED_ASSERTION; \ +} +# define DIE_IF(condition) +# endif +#endif + +#define ERROR_AT(errno, line, column) \ +do \ +{ \ + if( !self->error \ + || self->error( (self->userdata), (line), (column), (errno) ) < 0 ) { \ + return WEBVTT_PARSE_ERROR; \ + } \ +} while(0) + +#define ERROR(error) \ + ERROR_AT( (error), (self->line), (self->column) ) + +#define ERROR_AT_COLUMN(error, column) \ + ERROR_AT( (error), (self->line), (column) ) #endif diff --git a/media/webvtt/string.c b/media/webvtt/string.c index f8ca9b345234..708107b91ec4 100644 --- a/media/webvtt/string.c +++ b/media/webvtt/string.c @@ -180,7 +180,6 @@ WEBVTT_EXPORT void webvtt_copy_string( webvtt_string *left, const webvtt_string *right ) { if( left ) { - webvtt_string_data *d = left->d; if( right && right->d ) { left->d = right->d; } else { @@ -332,7 +331,7 @@ webvtt_string_getline( webvtt_string *src, const webvtt_byte *buffer, /* truncate. */ (*truncate)++; } else { - if( grow( str, len ) == WEBVTT_OUT_OF_MEMORY ) { + if( grow( str, len + 1 ) == WEBVTT_OUT_OF_MEMORY ) { ret = -1; } d = str->d; @@ -371,6 +370,15 @@ webvtt_string_putc( webvtt_string *str, webvtt_byte to_append ) return result; } +WEBVTT_EXPORT webvtt_bool +webvtt_string_is_equal( webvtt_string *str, webvtt_byte *to_compare, webvtt_uint len ) +{ + if( !str || !to_compare || webvtt_string_length( str ) != len ) { + return 0; + } + return memcmp( webvtt_string_text( str ), to_compare, len ) == 0; +} + WEBVTT_EXPORT webvtt_status webvtt_string_append( webvtt_string *str, const webvtt_byte *buffer, int len ) {