WEBVTT_INTERN webvtt_status webvtt_create_bytearray_nt( const webvtt_byte *text, webvtt_uint32 alloc, webvtt_bytearray *pba ) { webvtt_uint n = 0; webvtt_status status; webvtt_bytearray s; webvtt_byte b; if( !pba ) { return WEBVTT_INVALID_PARAM; } s = (webvtt_bytearray)webvtt_alloc0( sizeof(struct webvtt_bytearray_t) + (alloc*sizeof(webvtt_byte)) ); if( !s ) { return WEBVTT_OUT_OF_MEMORY; } s->alloc = alloc; s->length = 0; s->text = s->array; s->text[0] = 0; while( (alloc--) && (b = text[n++]) ) { if( WEBVTT_FAILED( status = webvtt_bytearray_putc( &s, b ) ) ) { webvtt_delete_bytearray( &s ); return status; } } *pba = s; 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 int webvtt_bytearray_getline( webvtt_bytearray *pba, const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint len, int *truncate, webvtt_bool finish ) { int ret = 0; webvtt_bytearray ba = *pba; const webvtt_byte *s = buffer + *pos; const webvtt_byte *p = s; const webvtt_byte *n = buffer + len; if( !ba ) { if(WEBVTT_FAILED(webvtt_create_bytearray( 0x100, pba ))) { return -1; } ba = *pba; } while( p < n && *p != CR && *p != LF ) { ++p; } if( p < n || finish ) { ret = 1; /* indicate that we found EOL */ } len = (webvtt_uint)( p - s ); *pos += len; if( ba->length + len + 1 >= ba->alloc ) { if( truncate && ba->alloc >= WEBVTT_MAX_LINE ) { /* truncate. */ (*truncate)++; } else { if( grow( pba, len ) == WEBVTT_OUT_OF_MEMORY ) { ret = -1; } ba = *pba; } } /* Copy everything in */ if( len && ret >= 0 && ba->length + len < ba->alloc ) { memcpy( ba->text + ba->length, s, len ); ba->length += len; ba->text[ ba->length ] = 0; } return ret; }
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_timestamp_token( webvtt_cuetext_token **token, webvtt_timestamp time_stamp ) { webvtt_status status; if( WEBVTT_FAILED( status = webvtt_create_token( token, TIME_STAMP_TOKEN ) ) ) { return status; } (*token)->time_stamp = time_stamp; 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_text_token( webvtt_cuetext_token **token, webvtt_string *text ) { webvtt_status status; if( WEBVTT_FAILED( status = webvtt_create_token( token, TEXT_TOKEN ) ) ) { return status; } webvtt_copy_string( &(*token)->text, text); return WEBVTT_SUCCESS; }
WEBVTT_INTERN webvtt_status webvtt_create_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name ) { webvtt_status status; if( WEBVTT_FAILED( status = webvtt_create_token( token, END_TOKEN ) ) ) { return status; } webvtt_copy_string( &(*token)->tag_name, tag_name ); 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_INTERN webvtt_status webvtt_create_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name, webvtt_stringlist *css_classes, webvtt_string *annotation ) { webvtt_status status; webvtt_start_token_data sd; if( WEBVTT_FAILED( status = webvtt_create_token( token, START_TOKEN ) ) ) { return status; } webvtt_copy_string( &(*token)->tag_name, tag_name ); webvtt_copy_stringlist( &sd.css_classes, css_classes ); webvtt_copy_string( &sd.annotations, annotation ); (*token)->start_token_data = sd; return WEBVTT_SUCCESS; }
WEBVTT_EXPORT webvtt_status webvtt_cue_validate_set_settings( webvtt_parser self, webvtt_cue *cue, const webvtt_string *settings ) { int line = 1; int column = 0; int length; const char *eol; int position = 0; webvtt_status s; if( !cue || !settings ) { return WEBVTT_INVALID_PARAM; } length = (int)webvtt_string_length( settings ); if( ( eol = strchr( webvtt_string_text( settings ), '\r' ) ) || ( eol = strchr( webvtt_string_text( settings ), '\n' ) ) ) { length = (int)( eol - webvtt_string_text( settings ) ); } if( self ) { line = self->line; column = self->column; } /** * http://www.w3.org/html/wg/drafts/html/master/single-page.html#split-a-string-on-spaces * 4. Skip whitespace */ column += webvtt_string_skip_whitespace( settings, &position ); while( position < length ) { webvtt_string word; const char *keyword; const char *end; int nwhite, ncol; /* Collect word (sequence of non-space characters terminated by space) */ if( WEBVTT_FAILED( webvtt_string_collect_word( settings, &word, &position ) ) ) { return WEBVTT_OUT_OF_MEMORY; } /* skip trailing whitespace */ nwhite = webvtt_string_skip_whitespace( settings, &position ); /* Get the word text */ keyword = webvtt_string_text( &word ); /* Get pointer to end of the word. (for chcount()) */ end = keyword + webvtt_string_length( &word ); /* Get the column count that needs to be skipped. */ ncol = webvtt_utf8_chcount( keyword, end ); if( WEBVTT_FAILED( s = webvtt_cue_set_setting_from_string( cue, keyword ) ) ) { if( self ) { /* Figure out which error to emit */ webvtt_error error; if( webvtt_error_for_status( s, &error ) ) { /* There is no non-recoverable cue-setting error. Therefore we do not want to abort the loop, regardless of the return value from the error handler. */ WARNING_AT( error, line, column ); } } } /* Move column pointer beyond word and trailing whitespace */ column += ncol + nwhite; webvtt_release_string( &word ); } if( self ) { self->column = column; } return WEBVTT_SUCCESS; }
/** * Currently line and len are not being kept track of. * Don't think pnode_length is needed as nodes track there list count * internally. */ WEBVTT_INTERN webvtt_status webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payload, int finished ) { const webvtt_byte *cue_text; webvtt_status status; webvtt_byte *position; webvtt_node *node_head; webvtt_node *current_node; webvtt_node *temp_node; webvtt_cuetext_token *token; webvtt_node_kind kind; if( !cue ) { return WEBVTT_INVALID_PARAM; } cue_text = webvtt_string_text( payload ); if( !cue_text ) { return WEBVTT_INVALID_PARAM; } if ( WEBVTT_FAILED(status = webvtt_create_head_node( &cue->node_head ) ) ) { return status; } position = (webvtt_byte *)cue_text; node_head = cue->node_head; current_node = node_head; temp_node = NULL; token = NULL; /** * Routine taken from the W3C specification * http://dev.w3.org/html5/webvtt/#webvtt-cue-text-parsing-rules */ while( *position != UTF8_NULL_BYTE ) { webvtt_delete_token( &token ); /* Step 7. */ switch( webvtt_cuetext_tokenizer( &position, &token ) ) { case( WEBVTT_UNFINISHED ): /* Error here. */ break; /* Step 8. */ case( WEBVTT_SUCCESS ): /** * If we've found an end token which has a valid end token tag name and * a tag name that is equal to the current node then set current to the * parent of current. */ if( token->token_type == END_TOKEN ) { /** * We have encountered an end token but we are at the top of the list * and thus have not encountered any start tokens yet, throw away the * token. */ if( current_node->kind == WEBVTT_HEAD_NODE ) { continue; } /** * We have encountered an end token but it is not in a format that is * supported, throw away the token. */ if( webvtt_node_kind_from_tag_name( &token->tag_name, &kind ) == WEBVTT_INVALID_TAG_NAME ) { continue; } /** * We have encountered an end token and it matches the start token of * the node that we are currently on. Move back up the list of nodes * and continue parsing. */ if( current_node->kind == kind ) { current_node = current_node->parent; } } else { /** * Attempt to create a valid node from the token. * If successful then attach the node to the current nodes list and * also set current to the newly created node if it is an internal * node type. */ if( webvtt_create_node_from_token( token, &temp_node, current_node ) != WEBVTT_SUCCESS ) { /* Do something here? */ } else { webvtt_attach_node( current_node, temp_node ); if( WEBVTT_IS_VALID_INTERNAL_NODE( temp_node->kind ) ) { current_node = temp_node; } /* Release the node as attach internal node increases the count. */ webvtt_release_node( &temp_node ); } } break; } webvtt_skipwhite( &position ); } webvtt_delete_token( &token ); return WEBVTT_SUCCESS; }
/** * Currently line and len are not being kept track of. * Don't think pnode_length is needed as nodes track there list count * internally. */ WEBVTT_INTERN webvtt_status webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payload, int finished ) { const webvtt_byte *cue_text; webvtt_status status; webvtt_byte *position; webvtt_node *node_head; webvtt_node *current_node; webvtt_node *temp_node; webvtt_cuetext_token *token; webvtt_node_kind kind; /** * TODO: Use these parameters! 'finished' isn't really important * here, but 'self' certainly is as it lets us report syntax errors. * * However, for the time being we can trick the compiler into not * warning us about unused variables by doing this. */ ( void )self; ( void )finished; if( !cue ) { return WEBVTT_INVALID_PARAM; } cue_text = webvtt_string_text( payload ); if( !cue_text ) { return WEBVTT_INVALID_PARAM; } if ( WEBVTT_FAILED(status = webvtt_create_head_node( &cue->node_head ) ) ) { return status; } position = (webvtt_byte *)cue_text; node_head = cue->node_head; current_node = node_head; temp_node = NULL; token = NULL; /** * Routine taken from the W3C specification * http://dev.w3.org/html5/webvtt/#webvtt-cue-text-parsing-rules */ while( *position != '\0' ) { webvtt_status status = WEBVTT_SUCCESS; webvtt_delete_token( &token ); /* Step 7. */ if( WEBVTT_FAILED( status = webvtt_cuetext_tokenizer( &position, &token ) ) ) { /* Error here. */ } else { /* Succeeded... Process token */ if( token->token_type == END_TOKEN ) { /** * If we've found an end token which has a valid end token tag name and * a tag name that is equal to the current node then set current to the * parent of current. */ if( current_node->kind == WEBVTT_HEAD_NODE ) { /** * We have encountered an end token but we are at the top of the list * and thus have not encountered any start tokens yet, throw away the * token. */ continue; } if( webvtt_node_kind_from_tag_name( &token->tag_name, &kind ) == WEBVTT_INVALID_TAG_NAME ) { /** * We have encountered an end token but it is not in a format that is * supported, throw away the token. */ continue; } if( current_node->kind == kind ) { /** * We have encountered an end token and it matches the start token of * the node that we are currently on. Move back up the list of nodes * and continue parsing. */ current_node = current_node->parent; } } else { /** * Attempt to create a valid node from the token. * If successful then attach the node to the current nodes list and * also set current to the newly created node if it is an internal * node type. */ if( webvtt_create_node_from_token( token, &temp_node, current_node ) != WEBVTT_SUCCESS ) { /* Do something here? */ } else { webvtt_attach_node( current_node, temp_node ); if( WEBVTT_IS_VALID_INTERNAL_NODE( temp_node->kind ) ) { current_node = temp_node; } /* Release the node as attach internal node increases the count. */ webvtt_release_node( &temp_node ); } } } } webvtt_delete_token( &token ); return WEBVTT_SUCCESS; }
virtual void SetUp() { ASSERT_FALSE( WEBVTT_FAILED( webvtt_create_parser( &dummyread, &dummyerr, 0, &self ) ) ) << "Failed to create parser"; }