Bug 849189 - Update webvtt to recent upstream version. r=rillian

This commit is contained in:
Jacek Caban 2013-03-08 03:47:00 -08:00
parent 11e5cd0452
commit e12da958a4
18 changed files with 1016 additions and 509 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -26,11 +26,7 @@
*/
#include <webvtt/util.h>
#if ( defined(__APPLE__) && defined(__MACH__) )
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#include <string.h>
static void *default_alloc( void *unused, webvtt_uint nb );

View File

@ -25,8 +25,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@ -27,27 +27,8 @@
#ifndef __INTERN_CUE_H__
# define __INTERN_CUE_H__
# include <webvtt/string.h>
# include <webvtt/cue.h>
/**
* 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

View File

@ -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, "&amp", 4 ) ) {
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '&' ) );
} else if( webvtt_string_is_equal( &buffer, "&lt", 3 ) ) {
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '<' ) );
} else if( webvtt_string_is_equal( &buffer, "&gt", 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, "&nbsp", 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;
}

View File

@ -31,17 +31,17 @@
# include <webvtt/string.h>
# include <webvtt/cue.h>
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 );

View File

@ -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 ];
}

View File

@ -29,6 +29,7 @@
# define __WEBVTT_CUE_H__
# include "util.h"
# include <webvtt/string.h>
# include <webvtt/node.h>
#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<Type>(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;

View File

@ -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 <webvtt/string.h>
#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

View File

@ -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
*

View File

@ -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;

218
media/webvtt/node.c Normal file
View File

@ -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 <string.h>
#include <stdlib.h>
#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;
}

View File

@ -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 <webvtt/node.h>
/**
* 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

View File

@ -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;
}

View File

@ -29,6 +29,18 @@
# define __INTERN_PARSER_H__
# include <webvtt/parser.h>
# include "string_internal.h"
# ifndef NDEBUG
# define NDEBUG
# endif
# if defined(FATAL_ASSERTION)
# undef NDEBUG
# include <assert.h>
# 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

View File

@ -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 )
{