Bug 833403 - Integrate libwebvtt into Mozilla. r=ted

- Updated for new build system (2/28/2013)
 - declaration-after-statement no longer breaking MSVC build
 - Source files and scripts now contain appropriate license info
 - media/webvtt/update.sh no longer hiding unexpected/significant
   errors.
This commit is contained in:
Caitlin Potter 2013-03-01 19:25:19 -05:00
parent 0c4d15256c
commit 1a3621792c
25 changed files with 5689 additions and 0 deletions

View File

@ -4221,6 +4221,7 @@ MOZ_OMX_PLUGIN=
MOZ_VP8=
MOZ_VP8_ERROR_CONCEALMENT=
MOZ_VP8_ENCODER=
MOZ_WEBVTT=1
VPX_AS=
VPX_ASFLAGS=
VPX_AS_DASH_C_FLAG=
@ -5700,6 +5701,10 @@ if test -n "$MOZ_OPUS"; then
AC_DEFINE(MOZ_OPUS)
fi
if test -n "$MOZ_WEBVTT"; then
AC_DEFINE(MOZ_WEBVTT)
fi
dnl ========================================================
dnl = Check alsa availability on Linux if using sydneyaudio
dnl ========================================================
@ -8827,6 +8832,7 @@ AC_SUBST(MOZ_VORBIS)
AC_SUBST(MOZ_TREMOR)
AC_SUBST(MOZ_OPUS)
AC_SUBST(MOZ_WEBM)
AC_SUBST(MOZ_WEBVTT)
AC_SUBST(MOZ_DASH)
AC_SUBST(MOZ_WMF)
AC_SUBST(MOZ_MEDIA_PLUGINS)

View File

@ -121,6 +121,12 @@ ifdef MOZ_ENABLE_SKIA
SHARED_LIBRARY_LIBS += $(MOZ_SKIA_LIBS)
endif
ifdef MOZ_WEBVTT
SHARED_LIBRARY_LIBS += \
$(DEPTH)/media/webvtt/$(LIB_PREFIX)webvtt.$(LIB_SUFFIX) \
$(NULL)
endif
ifdef MOZ_WEBRTC
ifndef MOZ_WEBRTC_IN_LIBXUL
DEFINES += -DMOZ_WEBRTC_GKMEDIA=1

25
media/webvtt/LICENSE Normal file
View File

@ -0,0 +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.

40
media/webvtt/Makefile.in Normal file
View File

@ -0,0 +1,40 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = webvtt
LIBRARY_NAME = webvtt
EXPORTS_NAMESPACES = webvtt
DEFINES += \
-DWEBVTT_NO_CONFIG_H=1 \
-DWEBVTT_STATIC=1 \
$(NULL)
EXPORTS_webvtt = \
include/webvtt/cue.h \
include/webvtt/error.h \
include/webvtt/parser.h \
include/webvtt/string.h \
include/webvtt/util.h \
$(NULL)
CSRCS = \
alloc.c \
cue.c \
cuetext.c \
error.c \
lexer.c \
parser.c \
string.c \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,7 @@
These files are from the WebVTT library, and are extracted from rev
cd5e95654f1fd6712fcf1941f8936870a484f65e of the git repository at
https://github.com/mozilla/webvtt.
The following CPPFLAGS are used in order to build and link in Mozilla
-DWEBVTT_NO_CONFIG_H=1 -- Prevent inclusion of generated headers
-DWEBVTT_STATIC=1 -- Compile as a static library

114
media/webvtt/alloc.c Normal file
View File

@ -0,0 +1,114 @@
/**
* 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 <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 );
static void default_free( void *unused, void *ptr );
struct {
/**
* Number of allocated objects. Forbid changing the allocator if this is not
* equal to 0
*/
webvtt_uint n_alloc;
webvtt_alloc_fn_ptr alloc;
webvtt_free_fn_ptr free;
void *alloc_data;
} allocator = { 0, default_alloc, default_free, 0 };
static void *WEBVTT_CALLBACK
default_alloc( void *unused, webvtt_uint nb )
{
return malloc( nb );
}
static void WEBVTT_CALLBACK
default_free( void *unused, void *ptr )
{
free( ptr );
}
WEBVTT_EXPORT void
webvtt_set_allocator( webvtt_alloc_fn_ptr alloc, webvtt_free_fn_ptr free, void *userdata )
{
/**
* TODO:
* This really needs a lock. But then, so does all the allocation/free
* functions...
* that could be a problem.
*/
if( allocator.n_alloc == 0 ) {
if( alloc && free ) {
allocator.alloc = alloc;
allocator.free = free;
allocator.alloc_data = userdata;
} else if( !alloc && !free ) {
allocator.alloc = &default_alloc;
allocator.free = &default_free;
allocator.alloc_data = 0;
}
}
}
/**
* public alloc/dealloc functions
*/
WEBVTT_EXPORT void *
webvtt_alloc( webvtt_uint nb )
{
void *ret = allocator.alloc( allocator.alloc_data, nb );
if( ret )
{ ++allocator.n_alloc; }
return ret;
}
WEBVTT_EXPORT void *
webvtt_alloc0( webvtt_uint nb )
{
void *ret = allocator.alloc( allocator.alloc_data, nb );
if( ret ) {
++allocator.n_alloc;
memset( ret, 0, nb );
}
return ret;
}
WEBVTT_EXPORT void
webvtt_free( void *data )
{
if( data && allocator.n_alloc ) {
allocator.free( allocator.alloc_data, data );
--allocator.n_alloc;
}
}

307
media/webvtt/cue.c Normal file
View File

@ -0,0 +1,307 @@
/**
* 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 <stdlib.h>
#include <string.h>
#include "parser_internal.h"
#include "cue_internal.h"
WEBVTT_EXPORT webvtt_status
webvtt_create_cue( webvtt_cue **pcue )
{
webvtt_cue *cue;
if( !pcue ) {
return WEBVTT_INVALID_PARAM;
}
cue = (webvtt_cue *)webvtt_alloc0( sizeof(*cue) );
if( !cue ) {
return WEBVTT_OUT_OF_MEMORY;
}
/**
* From http://dev.w3.org/html5/webvtt/#parsing (10/25/2012)
*
* Let cue's text track cue snap-to-lines flag be true.
*
* Let cue's text track cue line position be auto.
*
* Let cue's text track cue text position be 50.
*
* Let cue's text track cue size be 100.
*
* Let cue's text track cue alignment be middle alignment.
*/
webvtt_ref( &cue->refs );
webvtt_init_string( &cue->id );
cue->from = 0xFFFFFFFFFFFFFFFF;
cue->until = 0xFFFFFFFFFFFFFFFF;
cue->snap_to_lines = 1;
cue->settings.position = 50;
cue->settings.size = 100;
cue->settings.align = WEBVTT_ALIGN_MIDDLE;
cue->settings.line = WEBVTT_AUTO;
cue->settings.vertical = WEBVTT_HORIZONTAL;
*pcue = cue;
return WEBVTT_SUCCESS;
}
WEBVTT_EXPORT void
webvtt_ref_cue( webvtt_cue *cue )
{
if( cue ) {
webvtt_ref( &cue->refs );
}
}
WEBVTT_EXPORT void
webvtt_release_cue( webvtt_cue **pcue )
{
if( pcue && *pcue ) {
webvtt_cue *cue = *pcue;
*pcue = 0;
if( webvtt_deref( &cue->refs ) == 0 ) {
webvtt_release_string( &cue->id );
webvtt_release_node( &cue->node_head );
webvtt_free( cue );
}
}
}
WEBVTT_EXPORT int
webvtt_validate_cue( webvtt_cue *cue )
{
if( cue ) {
/**
* validate cue-times (Can't do checks against previously parsed cuetimes.
* That's the applications responsibility
*/
if( BAD_TIMESTAMP(cue->from) || BAD_TIMESTAMP(cue->until) ) {
goto error;
}
if( cue->until <= cue->from ) {
goto error;
}
/**
* Don't do any payload validation, because this would involve parsing the
* payload, which is optional.
*/
return 1;
}
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

@ -0,0 +1,68 @@
/**
* 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 __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
*/
enum {
CUE_HAVE_VERTICAL = (1 << 0),
CUE_HAVE_SIZE = (1 << 1),
CUE_HAVE_POSITION = (1 << 2),
CUE_HAVE_LINE = (1 << 3),
CUE_HAVE_ALIGN = (1 << 4),
CUE_HAVE_SETTINGS = (CUE_HAVE_VERTICAL | CUE_HAVE_SIZE
| CUE_HAVE_POSITION | CUE_HAVE_LINE | CUE_HAVE_ALIGN),
CUE_HAVE_CUEPARAMS = 0x40000000,
CUE_HAVE_ID = 0x80000000,
};
#endif

790
media/webvtt/cuetext.c Normal file
View File

@ -0,0 +1,790 @@
/**
* 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 <stdlib.h>
#include <string.h>
#include "parser_internal.h"
#include "cuetext_internal.h"
#include "cue_internal.h"
#include "string_internal.h"
static void webvtt_skipwhite( webvtt_byte **position );
#ifdef min
# undef min
#endif
#define min(a,b) ( (a) < (b) ? (a) : (b) )
/**
* ERROR macro used for webvtt_parse_cuetext
*/
#undef ERROR
#define ERROR(code) \
do \
{ \
if( self->error ) \
if( self->error( self->userdata, line, col, code ) < 0 ) \
return WEBVTT_PARSE_ERROR; \
} while(0)
/**
* Macros for return statuses based on memory operations.
* This is to avoid many if statements checking for multiple memory operation
* return statuses in functions.
*/
#define CHECK_MEMORY_OP(status) \
if( status != WEBVTT_SUCCESS ) \
return status; \
#define CHECK_MEMORY_OP_JUMP(status_var, returned_status) \
if( returned_status != WEBVTT_SUCCESS) \
{ \
status_var = returned_status; \
goto dealloc; \
} \
/**
* This will only work on null-terminated strings, remember that!
*/
static void
webvtt_skipwhite( webvtt_byte **position )
{
webvtt_byte *p = *position;
while( *p && webvtt_iswhite(*p) ) {
++p;
}
*position = p;
}
WEBVTT_INTERN webvtt_status
webvtt_create_cuetext_token( webvtt_cuetext_token **token, webvtt_cuetext_token_type token_type )
{
webvtt_cuetext_token *temp_token = (webvtt_cuetext_token *)webvtt_alloc0( sizeof(*temp_token) );
if( !temp_token ) {
return WEBVTT_OUT_OF_MEMORY;
}
temp_token->token_type = token_type;
*token = temp_token;
return WEBVTT_SUCCESS;
}
WEBVTT_INTERN webvtt_status
webvtt_create_cuetext_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;
if( WEBVTT_FAILED( status = webvtt_create_cuetext_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_INTERN webvtt_status
webvtt_create_cuetext_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name )
{
webvtt_status status;
if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, END_TOKEN ) ) ) {
return status;
}
webvtt_copy_string( &(*token)->tag_name, tag_name );
return WEBVTT_SUCCESS;
}
WEBVTT_INTERN webvtt_status
webvtt_create_cuetext_text_token( webvtt_cuetext_token **token, webvtt_string *text )
{
webvtt_status status;
if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, TEXT_TOKEN ) ) ) {
return status;
}
webvtt_copy_string( &(*token)->text, text);
return WEBVTT_SUCCESS;
}
WEBVTT_INTERN webvtt_status
webvtt_create_cuetext_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 ) ) ) {
return status;
}
(*token)->time_stamp = time_stamp;
return WEBVTT_SUCCESS;
}
WEBVTT_INTERN void
webvtt_delete_cuetext_token( webvtt_cuetext_token **token )
{
webvtt_cuetext_start_token_data data;
webvtt_cuetext_token *t;
if( !token ) {
return;
}
if( !*token ) {
return;
}
t = *token;
/**
* Note that time stamp tokens do not need to free any internal data because
* they do not allocate anything.
*/
switch( t->token_type ) {
case START_TOKEN:
data = t->start_token_data;
webvtt_release_stringlist( &data.css_classes );
webvtt_release_string( &data.annotations );
webvtt_release_string( &t->tag_name );
break;
case END_TOKEN:
webvtt_release_string( &t->tag_name );
break;
case TEXT_TOKEN:
webvtt_release_string( &t->text );
break;
}
webvtt_free( t );
*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;
}
/**
* 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 )
{
if( !tag_name || !kind ) {
return WEBVTT_INVALID_PARAM;
}
if( webvtt_string_length(tag_name) == 1 ) {
switch( webvtt_string_text(tag_name)[0] ) {
case( UTF8_B ):
*kind = WEBVTT_BOLD;
break;
case( UTF8_I ):
*kind = WEBVTT_ITALIC;
break;
case( UTF8_U ):
*kind = WEBVTT_UNDERLINE;
break;
case( UTF8_C ):
*kind = WEBVTT_CLASS;
break;
case( UTF8_V ):
*kind = WEBVTT_VOICE;
break;
}
} else if( memcmp( webvtt_string_text(tag_name), ruby_tag, min(webvtt_string_length(tag_name), RUBY_TAG_LENGTH) ) == 0 ) {
*kind = WEBVTT_RUBY;
} else if( memcmp( webvtt_string_text(tag_name), rt_tag, min(webvtt_string_length(tag_name), RUBY_TEXT_TAG_LENGTH) ) == 0 ) {
*kind = WEBVTT_RUBY_TEXT;
} else {
return WEBVTT_INVALID_TAG_NAME;
}
return WEBVTT_SUCCESS;
}
WEBVTT_INTERN webvtt_status
webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node, webvtt_node *parent )
{
webvtt_node_kind kind;
if( !token || !node || !parent ) {
return WEBVTT_INVALID_PARAM;
}
/**
* We've recieved a node that is not null.
* In order to prevent memory leaks caused by overwriting a node which the
* caller has not released return unsuccessful.
*/
if( *node ) {
return WEBVTT_UNSUCCESSFUL;
}
switch ( token->token_type ) {
case( TEXT_TOKEN ):
return webvtt_create_text_leaf_node( node, parent, &token->text );
break;
case( START_TOKEN ):
CHECK_MEMORY_OP( webvtt_get_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 );
break;
default:
return WEBVTT_INVALID_TOKEN_TYPE;
}
}
WEBVTT_INTERN webvtt_status
webvtt_cuetext_tokenizer_data_state( webvtt_byte **position,
webvtt_cuetext_token_state *token_state, webvtt_string *result )
{
for ( ; *token_state == DATA; (*position)++ ) {
switch( **position ) {
case UTF8_AMPERSAND:
*token_state = ESCAPE;
break;
case UTF8_LESS_THAN:
if( webvtt_string_length(result) == 0 ) {
*token_state = TAG;
} else {
return WEBVTT_SUCCESS;
}
break;
case UTF8_NULL_BYTE:
return WEBVTT_SUCCESS;
break;
default:
CHECK_MEMORY_OP( webvtt_string_putc( result, *position[0] ) );
break;
}
}
return WEBVTT_UNFINISHED;
}
/**
* Definitions for valid escape values.
* The semicolon is implicit in the comparison.
*/
#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,
UTF8_LEFT_TO_RIGHT_2, UTF8_LEFT_TO_RIGHT_3 };
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_string buffer;
webvtt_status status = WEBVTT_SUCCESS;
CHECK_MEMORY_OP_JUMP( status, webvtt_create_string( 1, &buffer ) );
/**
* Append ampersand here because the algorithm is not able to add it to the
* buffer when it reads it in the DATA state tokenizer.
*/
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, UTF8_AMPERSAND ) );
for( ; *token_state == ESCAPE; (*position)++ ) {
/**
* We have encountered a token termination point.
* Append buffer to result and return success.
*/
if( **position == UTF8_NULL_BYTE || **position == UTF8_LESS_THAN ) {
CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
goto dealloc;
}
/**
* This means we have enocuntered a malformed escape character sequence.
* This means that we need to add that malformed text to the result and
* recreate the buffer to prepare for a new escape sequence.
*/
else if( **position == UTF8_AMPERSAND ) {
CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
webvtt_release_string( &buffer );
CHECK_MEMORY_OP_JUMP( status, webvtt_create_string( 1, &buffer ) );
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, *position[0] ) );
}
/**
* We've encountered the semicolon which is the end of an escape sequence.
* Check if buffer contains a valid escape sequence and if it does append
* 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 ) {
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 ) {
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 ) {
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 ) );
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, **position ) );
}
*token_state = DATA;
}
/**
* Character is alphanumeric. This means we are in the body of the escape
* sequence.
*/
else if( webvtt_isalphanum( **position ) ) {
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, **position ) );
}
/**
* If we have not found an alphanumeric character then we have encountered
* a malformed escape sequence. Add buffer to result and continue to parse
* in DATA state.
*/
else {
CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, **position ) );
*token_state = DATA;
}
}
dealloc:
webvtt_release_string( &buffer );
return status;
}
WEBVTT_INTERN webvtt_status
webvtt_cuetext_tokenizer_tag_state( webvtt_byte **position,
webvtt_cuetext_token_state *token_state, webvtt_string *result )
{
for( ; *token_state == TAG; (*position)++ ) {
if( **position == UTF8_TAB || **position == UTF8_LINE_FEED ||
**position == UTF8_CARRIAGE_RETURN || **position == UTF8_FORM_FEED ||
**position == UTF8_SPACE ) {
*token_state = START_TAG_ANNOTATION;
} else if( webvtt_isdigit( **position ) ) {
CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
*token_state = TIME_STAMP_TAG;
} else {
switch( **position ) {
case UTF8_FULL_STOP:
*token_state = START_TAG_CLASS;
break;
case UTF8_SOLIDUS:
*token_state = END_TAG;
break;
case UTF8_GREATER_THAN:
return WEBVTT_SUCCESS;
break;
case UTF8_NULL_BYTE:
return WEBVTT_SUCCESS;
break;
default:
CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
*token_state = START_TAG;
}
}
}
return WEBVTT_UNFINISHED;
}
WEBVTT_INTERN webvtt_status
webvtt_cuetext_tokenizer_start_tag_state( webvtt_byte **position,
webvtt_cuetext_token_state *token_state, webvtt_string *result )
{
for( ; *token_state == START_TAG; (*position)++ ) {
if( **position == UTF8_TAB || **position == UTF8_FORM_FEED ||
**position == UTF8_SPACE || **position == UTF8_LINE_FEED ||
**position == UTF8_CARRIAGE_RETURN ) {
*token_state = START_TAG_ANNOTATION;
} else {
switch( **position ) {
case UTF8_TAB:
*token_state = START_TAG_ANNOTATION;
break;
case UTF8_FULL_STOP:
*token_state = START_TAG_CLASS;
break;
case UTF8_GREATER_THAN:
return WEBVTT_SUCCESS;
break;
default:
CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
break;
}
}
}
return WEBVTT_UNFINISHED;
}
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_string buffer;
webvtt_status status = WEBVTT_SUCCESS;
CHECK_MEMORY_OP( webvtt_create_string( 1, &buffer ) );
for( ; *token_state == START_TAG_CLASS; (*position)++ ) {
if( **position == UTF8_TAB || **position == UTF8_FORM_FEED ||
**position == UTF8_SPACE || **position == UTF8_LINE_FEED ||
**position == UTF8_CARRIAGE_RETURN) {
CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes, &buffer ) );
*token_state = START_TAG_ANNOTATION;
return WEBVTT_SUCCESS;
} else if( **position == UTF8_GREATER_THAN || **position == UTF8_NULL_BYTE ) {
CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes, &buffer ) );
webvtt_release_string( &buffer );
return WEBVTT_SUCCESS;
} else if( **position == UTF8_FULL_STOP ) {
CHECK_MEMORY_OP_JUMP( status, webvtt_stringlist_push( css_classes, &buffer ) );
webvtt_release_string( &buffer );
CHECK_MEMORY_OP( webvtt_create_string( 1, &buffer ) );
} else {
CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( &buffer, **position ) );
}
}
dealloc:
webvtt_release_string( &buffer );
return status;
}
WEBVTT_INTERN webvtt_status
webvtt_cuetext_tokenizer_start_tag_annotation_state( webvtt_byte **position,
webvtt_cuetext_token_state *token_state, webvtt_string *annotation )
{
for( ; *token_state == START_TAG_ANNOTATION; (*position)++ ) {
if( **position == UTF8_NULL_BYTE || **position == UTF8_GREATER_THAN ) {
return WEBVTT_SUCCESS;
}
CHECK_MEMORY_OP( webvtt_string_putc( annotation, **position ) );
}
return WEBVTT_UNFINISHED;
}
WEBVTT_INTERN webvtt_status
webvtt_cuetext_tokenizer_end_tag_state( webvtt_byte **position,
webvtt_cuetext_token_state *token_state, webvtt_string *result )
{
for( ; *token_state == END_TAG; (*position)++ ) {
if( **position == UTF8_GREATER_THAN || **position == UTF8_NULL_BYTE ) {
return WEBVTT_SUCCESS;
}
CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
}
return WEBVTT_UNFINISHED;
}
WEBVTT_INTERN webvtt_status
webvtt_cuetext_tokenizer_time_stamp_tag_state( webvtt_byte **position,
webvtt_cuetext_token_state *token_state, webvtt_string *result )
{
for( ; *token_state == TIME_STAMP_TAG; (*position)++ ) {
if( **position == UTF8_GREATER_THAN || **position == UTF8_NULL_BYTE ) {
return WEBVTT_SUCCESS;
}
CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
}
return WEBVTT_UNFINISHED;
}
/**
* Need to set up differently.
* Get a status in order to return at end and release memeory.
*/
WEBVTT_INTERN webvtt_status
webvtt_cuetext_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token )
{
webvtt_cuetext_token_state token_state = DATA;
webvtt_string result, annotation;
webvtt_stringlist *css_classes;
webvtt_timestamp time_stamp = 0;
webvtt_status status = WEBVTT_UNFINISHED;
if( !position ) {
return WEBVTT_INVALID_PARAM;
}
webvtt_create_string( 10, &result );
webvtt_create_string( 10, &annotation );
webvtt_create_stringlist( &css_classes );
/**
* Loop while the tokenizer is not finished.
* Based on the state of the tokenizer enter a function to handle that
* particular tokenizer state. Those functions will loop until they either
* change the state of the tokenizer or reach a valid token end point.
*/
while( status == WEBVTT_UNFINISHED ) {
switch( token_state ) {
case DATA :
status = webvtt_cuetext_tokenizer_data_state( position, &token_state, &result );
break;
case ESCAPE:
status = webvtt_cuetext_tokenizer_escape_state( position, &token_state, &result );
break;
case TAG:
status = webvtt_cuetext_tokenizer_tag_state( position, &token_state, &result );
break;
case START_TAG:
status = webvtt_cuetext_tokenizer_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 );
break;
case START_TAG_ANNOTATION:
status = webvtt_cuetext_tokenizer_start_tag_annotation_state( position, &token_state, &annotation );
break;
case END_TAG:
status = webvtt_cuetext_tokenizer_end_tag_state( position, &token_state, &result );
break;
case TIME_STAMP_TAG:
status = webvtt_cuetext_tokenizer_time_stamp_tag_state( position, &token_state, &result );
break;
}
if( token_state == START_TAG_ANNOTATION ) {
webvtt_skipwhite( position );
}
}
if( **position == UTF8_GREATER_THAN )
{ (*position)++; }
if( status == WEBVTT_SUCCESS ) {
/**
* The state that the tokenizer left off on will tell us what kind of token
* needs to be made.
*/
if( token_state == DATA || token_state == ESCAPE ) {
status = webvtt_create_cuetext_text_token( token, &result );
} else if(token_state == TAG || token_state == START_TAG || token_state == START_TAG_CLASS ||
token_state == START_TAG_ANNOTATION) {
/**
* If the tag does not accept an annotation then release the current
* annotation and intialize annotation to a safe empty state
*/
if( !tag_accepts_annotation( &result ) ) {
webvtt_release_string( &annotation );
webvtt_init_string( &annotation );
}
status = webvtt_create_cuetext_start_token( token, &result, css_classes, &annotation );
} else if( token_state == END_TAG ) {
status = webvtt_create_cuetext_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 );
} else {
status = WEBVTT_INVALID_TOKEN_STATE;
}
}
webvtt_release_stringlist( &css_classes );
webvtt_release_string( &result );
webvtt_release_string( &annotation );
return status;
}
/**
* 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_cuetext_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_get_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_internal_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_cuetext_token( &token );
return WEBVTT_SUCCESS;
}

View File

@ -0,0 +1,195 @@
/**
* 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 __INTERN_CUETEXT_H__
# define __INTERN_CUETEXT_H__
# include <webvtt/util.h>
# 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 struct webvtt_cuetext_token_t webvtt_cuetext_token;
typedef struct webvtt_cuetext_start_token_data_t webvtt_cuetext_start_token_data;
/**
* Enumerates token types.
*/
enum
webvtt_cuetext_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. */
TEXT_TOKEN /* Identifies a webvtt_cue_text_text_token. */
};
/**
* Enumerates possible states that the cue text tokenizer can be in.
*/
enum
webvtt_cuetext_token_state_t {
DATA, /* Initial state. */
ESCAPE, /* Parsing an escape value. */
TAG, /* Reached a '<' character, about to start parsing a tag. */
START_TAG, /* Parsing the beginning of a tag i.e. the tag name. */
START_TAG_CLASS, /* Parsing a tag class. Reached when the tokenizer in the
START_TAG
state reaches a '.' character. */
START_TAG_ANNOTATION, /* Parsing a tag annotation. Reached when the tokenizer
in the START_TAG_CLASS state reaches a TAB, SPACE, or
FORM FEED character. */
END_TAG, /* Parsing an end tag. Reached when a '<' character is follwed by a
'/' character. */
TIME_STAMP_TAG /* Parsing a time stamp tag. Reached when a '<' character is
follwed by an integer character. */
};
/**
* Represents a start tag in the cue text.
* These take the form of <[TAG_NAME].[CLASSES] [POSSIBLE_ANNOTATION]> in the
* cue text.
*/
struct
webvtt_cuetext_start_token_data_t {
webvtt_stringlist *css_classes;
webvtt_string annotations;
};
/**
* Contains a void pointer to a concrete token as well as a token type enum that
* identifies what kind of token it is.
*/
struct
webvtt_cuetext_token_t {
webvtt_cuetext_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;
};
};
/**
* 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_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_timestamp time_stamp );
/**
* Returns true if the passed tag matches a tag name that accepts an annotation.
*/
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 );
/**
* 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 );
/**
* Creates a node from a valid token.
* Returns WEBVTT_NOT_SUPPORTED if it does not find a valid tag name.
*/
WEBVTT_INTERN webvtt_status webvtt_create_node_from_token( webvtt_cuetext_token *token, webvtt_node **node, webvtt_node *parent );
/**
* Tokenizes the cue text into something that can be easily understood by the
* 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 );
/**
* Routines that take care of certain states in the webvtt cue text tokenizer.
*/
/**
* 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 );
/**
* 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 );
/**
* 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 );
/**
* 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 );
/**
* 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 );
/**
* 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 );
/**
* 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 );
/**
* 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_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payload, int finished );
#endif

75
media/webvtt/error.c Normal file
View File

@ -0,0 +1,75 @@
/**
* 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 <webvtt/error.h>
static const char *errstr[] = {
/* WEBVTT_ALLOCATION_FAILED */ "error allocating object",
/* WEBVTT_MALFORMED_TAG */ "malformed 'WEBVTT' tag",
/* WEBVTT_EXPECTED_EOL */ "expected newline",
/* WEBVTT_EXPECTED_WHITESPACE */ "expected whitespace",
/* WEBVTT_UNEXPECTED_WHITESPACE */ "unexpected whitespace",
/* WEBVTT_LONG_COMMENT */ "very long tag-comment",
/* WEBVTT_ID_TRUNCATED */ "webvtt-cue-id truncated",
/* WEBVTT_MALFORMED_TIMESTAMP */ "malformed webvtt-timestamp",
/* WEBVTT_EXPECTED_TIMESTAMP */ "expected webvtt-timestamp",
/* WEBVTT_MISSING_CUETIME_SEPARATOR */ "missing webvtt-cuetime-separator `-->'",
/* WEBVTT_EXPECTED_CUETIME_SEPARATOR */ "expected webvtt-cuetime-separator `-->'",
/* WEBVTT_MISSING_CUESETTING_DELIMITER */ "missing whitespace before webvtt-cuesetting",
/* WEBVTT_INVALID_CUESETTING_DELIMITER */ "invalid webvtt-cuesetting key:value delimiter. expected `:'",
/* WEBVTT_INVALID_ENDTIME */ "webvtt-cue end-time must have value greater than start-time",
/* WEBVTT_INVALID_CUESETTING */ "unrecognized webvtt-cue-setting",
/* WEBVTT_UNFINISHED_CUETIMES */ "unfinished webvtt cuetimes. expected 'start-timestamp --> end-timestamp'",
/* WEBVTT_MISSING_CUESETTING_KEYWORD */ "missing setting keyword for value",
/* WEBVTT_VERTICAL_ALREADY_SET */ "'vertical' cue-setting already used",
/* WEBVTT_VERTICAL_BAD_VALUE */ "'vertical' setting must have a value of either 'lr' or 'rl'",
/* WEBVTT_LINE_ALREADY_SET */ "'line' cue-setting already used",
/* WEBVTT_LINE_BAD_VALUE */ "'line' cue-setting must have a value that is an integer (signed) line number, or percentage (%) from top of video display",
/* WEBVTT_POSITION_ALREADY_SET */ "'position' cue-setting already used",
/* WEBVTT_POSITION_BAD_VALUE */ "'position' cue-setting must be a percentage (%) value representing the position in the direction orthogonal to the 'line' setting",
/* WEBVTT_SIZE_ALREADY_SET */ "'size' cue-setting already used",
/* WEBVTT_SIZE_BAD_VALUE */ "'size' cue-setting must have percentage (%) value",
/* WEBVTT_ALIGN_ALREADY_SET */ "'align' cue-setting already used",
/* WEBVTT_ALIGN_BAD_VALUE */ "'align' cue-setting must have a value of either 'start', 'middle', or 'end'",
/* WEBVTT_CUE_CONTAINS_SEPARATOR */ "cue-text line contains unescaped timestamp separator '-->'",
/* WEBVTT_CUE_INCOMPLETE */ "cue contains cue-id, but is missing cuetimes or cue text",
};
/**
* TODO:
* Add i18n localized error strings with support for glibc and msvcrt locale
* identifiers
* (This might be too much work!)
*/
WEBVTT_EXPORT const char *
webvtt_strerror( webvtt_error errno )
{
if( errno >= (sizeof(errstr) / sizeof(*errstr)) ) {
return "";
}
return errstr[ errno ];
}

View File

@ -0,0 +1,194 @@
/**
* 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_CUE_H__
# define __WEBVTT_CUE_H__
# include "util.h"
# include <webvtt/string.h>
#if defined(__cplusplus) || defined(c_plusplus)
#define WEBVTT_CPLUSPLUS 1
extern "C" {
#endif
#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,
WEBVTT_VERTICAL_LR = 1,
WEBVTT_VERTICAL_RL = 2
} webvtt_vertical_type;
typedef enum
webvtt_align_type_t {
WEBVTT_ALIGN_START = 0,
WEBVTT_ALIGN_MIDDLE,
WEBVTT_ALIGN_END,
WEBVTT_ALIGN_LEFT,
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;
int line;
webvtt_uint position;
webvtt_uint size;
webvtt_align_type align;
} webvtt_cue_settings;
typedef struct
webvtt_cue_t {
/**
* PRIVATE.
* Do not touch, okay?
*/
struct webvtt_refcount_t refs;
webvtt_uint flags;
/**
* PUBLIC:
*/
webvtt_timestamp from;
webvtt_timestamp until;
webvtt_cue_settings settings;
webvtt_bool snap_to_lines;
webvtt_string id;
/**
* Parsed cue-text (NULL if has not been parsed)
*/
webvtt_node *node_head;
} webvtt_cue;
WEBVTT_EXPORT webvtt_status webvtt_create_cue( webvtt_cue **pcue );
WEBVTT_EXPORT void webvtt_ref_cue( webvtt_cue *cue );
WEBVTT_EXPORT void webvtt_release_cue( webvtt_cue **pcue );
WEBVTT_EXPORT int webvtt_validate_cue( webvtt_cue *cue );
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

View File

@ -0,0 +1,113 @@
/**
* 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_ERROR_H__
# define __WEBVTT_ERROR_H__
# include "util.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
enum
webvtt_error_t
{
/* There was a problem allocating something */
WEBVTT_ALLOCATION_FAILED = 0,
/**
* 'WEBVTT' is not the first 6 characters in the file
* (not counting UTF8 BOM)
*/
WEBVTT_MALFORMED_TAG,
/* An end-of-line sequence was expected, but not found. */
WEBVTT_EXPECTED_EOL,
/* A string of whitespace was expected, but not found. */
WEBVTT_EXPECTED_WHITESPACE,
/**
* A string of whitespace was found, but was not expected
* (Recoverable error)
*/
WEBVTT_UNEXPECTED_WHITESPACE,
/* Long WEBVTT comment, decide whether to abort parsing or not */
WEBVTT_LONG_COMMENT,
/* A cue-id was too long to fit in the buffer. */
WEBVTT_ID_TRUNCATED,
/* A timestamp is malformed */
WEBVTT_MALFORMED_TIMESTAMP,
/* Expected a timestamp, but didn't find one */
WEBVTT_EXPECTED_TIMESTAMP,
/* Missing timestamp separator */
WEBVTT_MISSING_CUETIME_SEPARATOR,
/* Were expecting a separator, but got some garbage that we can't
recover from instead. */
WEBVTT_EXPECTED_CUETIME_SEPARATOR,
/* Missing cuesetting delimiter */
WEBVTT_MISSING_CUESETTING_DELIMITER,
/* Invalid cuesetting delimiter */
WEBVTT_INVALID_CUESETTING_DELIMITER,
/* End-time is less than or equal to start time */
WEBVTT_INVALID_ENDTIME,
/* Invalid cue-setting */
WEBVTT_INVALID_CUESETTING,
/* unfinished cuetimes */
WEBVTT_UNFINISHED_CUETIMES,
/* valid-looking cuesetting with no keyword */
WEBVTT_MISSING_CUESETTING_KEYWORD,
/* 'vertical' setting already exists for this cue. */
WEBVTT_VERTICAL_ALREADY_SET,
/* Bad 'vertical' value */
WEBVTT_VERTICAL_BAD_VALUE,
/* 'line' setting already exists for this cue. */
WEBVTT_LINE_ALREADY_SET,
/* Bad 'line' value */
WEBVTT_LINE_BAD_VALUE,
/* 'position' setting already exists for this cue. */
WEBVTT_POSITION_ALREADY_SET,
/* Bad 'position' value */
WEBVTT_POSITION_BAD_VALUE,
/* 'size' setting already exists for this cue. */
WEBVTT_SIZE_ALREADY_SET,
/* Bad 'size' value */
WEBVTT_SIZE_BAD_VALUE,
/* 'align' setting already exists for this cue. */
WEBVTT_ALIGN_ALREADY_SET,
/* Bad 'align' value */
WEBVTT_ALIGN_BAD_VALUE,
/* A cue-text object contains the string "-->", which needs to be escaped */
WEBVTT_CUE_CONTAINS_SEPARATOR,
/* A webvtt cue contains only a cue-id, and no cuetimes or payload. */
WEBVTT_CUE_INCOMPLETE,
};
typedef enum webvtt_error_t webvtt_error;
WEBVTT_EXPORT const char *webvtt_strerror( webvtt_error );
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

View File

@ -0,0 +1,58 @@
/**
* 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_PARSER_H__
# define __WEBVTT_PARSER_H__
# include "string.h"
# include "cue.h"
# include "error.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
typedef struct webvtt_parser_t *webvtt_parser;
/**
* Allows application to request error reporting
*/
typedef int ( WEBVTT_CALLBACK *webvtt_error_fn )( void *userdata, webvtt_uint line, webvtt_uint col,
webvtt_error error );
typedef void ( WEBVTT_CALLBACK *webvtt_cue_fn )( void *userdata, webvtt_cue *cue );
WEBVTT_EXPORT webvtt_status webvtt_create_parser( webvtt_cue_fn on_read, webvtt_error_fn on_error, void *
userdata, webvtt_parser *ppout );
WEBVTT_EXPORT void webvtt_delete_parser( webvtt_parser parser );
WEBVTT_EXPORT webvtt_status webvtt_parse_chunk( webvtt_parser self, const void *buffer, webvtt_uint len );
WEBVTT_EXPORT webvtt_status webvtt_finish_parsing( webvtt_parser self );
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

View File

@ -0,0 +1,269 @@
/**
* 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_STRING_H__
# define __WEBVTT_STRING_H__
# include "util.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/**
* webvtt_string - A buffer of utf16 characters
*/
typedef struct webvtt_string_t webvtt_string;
typedef struct webvtt_string_data_t webvtt_string_data;
typedef struct webvtt_stringlist_t webvtt_stringlist;
struct webvtt_string_data_t;
struct
webvtt_string_t {
webvtt_string_data *d;
};
/**
* webvtt_init_string
*
* initialize a string to point to the empty string
*/
WEBVTT_EXPORT void webvtt_init_string( webvtt_string *result );
/**
* webvtt_string_is_empty
*
* return whether or not the string is empty
* qualifications for it being empty are it equaling &empty_string or its length equaling 0
*/
WEBVTT_EXPORT webvtt_uint webvtt_string_is_empty( const webvtt_string *str );
/**
* webvtt_create_string
*
* allocate a new string object with an initial capacity of 'alloc'
* (the string data of 'result' is not expected to contain string data,
* regardless of its value. be sure to release existing strings before using
* webvtt_create_string)
*/
WEBVTT_EXPORT webvtt_status webvtt_create_string( webvtt_uint32 alloc, webvtt_string *result );
/**
* webvtt_create_init_string
*
* allocate and initialize a string with the contents of 'init_text' of length
* 'len' if 'len' < 0, assume init_text to be null-terminated.
*/
WEBVTT_EXPORT webvtt_status webvtt_create_string_with_text( webvtt_string *result, const webvtt_byte *init_text, int len );
/**
* webvtt_ref_string
*
* increase the reference count of--or retain--a string
*
* when the reference count drops to zero, the string is deallocated.
*/
WEBVTT_EXPORT void webvtt_ref_string( webvtt_string *str );
/**
* webvtt_release_string
*
* decrease the reference count of--or release--a string
*
* when the reference count drops to zero, the string is deallocated.
*/
WEBVTT_EXPORT void webvtt_release_string( webvtt_string *str );
/**
* webvtt_string_detach
*
* ensure that the reference count of a string is exactly 1
*
* if the reference count is greater than 1, allocate a new copy of the string
* and return it.
*/
WEBVTT_EXPORT webvtt_status webvtt_string_detach( webvtt_string *str );
/**
* webvtt_copy_string
*
* shallow-clone 'right', storing the result in 'left'.
*/
WEBVTT_EXPORT void webvtt_copy_string( webvtt_string *left, const webvtt_string *right );
/**
* webvtt_string_text
*
* return the text contents of a string
*/
WEBVTT_EXPORT const webvtt_byte *webvtt_string_text( const webvtt_string *str );
/**
* webvtt_string_length
*
* return the length of a strings text
*/
WEBVTT_EXPORT const webvtt_uint32 webvtt_string_length( const webvtt_string *str );
/**
* webvtt_string_capacity
*
* return the current capacity of a string
*/
WEBVTT_EXPORT const webvtt_uint32 webvtt_string_capacity( const webvtt_string *str );
/**
* webvtt_string_getline
*
* collect a line of text (terminated by CR/LF/CRLF) from a buffer, without
* including the terminating character(s)
*/
WEBVTT_EXPORT int webvtt_string_getline( webvtt_string *str, const webvtt_byte *buffer,
webvtt_uint *pos, webvtt_uint len, int *truncate, webvtt_bool finish, webvtt_bool retain_new_line );
/**
* webvtt_string_putc
*
* append a single byte to a webvtt string
*/
WEBVTT_EXPORT webvtt_status webvtt_string_putc( webvtt_string *str, webvtt_byte to_append );
/**
* webvtt_string_append
*
* append a stream of bytes to the string.
*
* if 'len' is < 0, then buffer is expected to be null-terminated.
*/
WEBVTT_EXPORT webvtt_status webvtt_string_append( webvtt_string *str, const webvtt_byte *buffer, int len );
/**
* webvtt_string_appendstr
*
* append the contents of a string object 'other' to a string object 'str'
*/
WEBVTT_EXPORT webvtt_status webvtt_string_append_string( webvtt_string *str, const webvtt_string *other );
/**
* basic dynamic array of strings
*/
struct
webvtt_stringlist_t {
struct webvtt_refcount_t refs;
webvtt_uint alloc;
webvtt_uint length;
webvtt_string *items;
};
/**
* webvtt_create_stringlist
*
* allocate a new, empty stringlist
*/
WEBVTT_EXPORT webvtt_status webvtt_create_stringlist( webvtt_stringlist **result );
/**
* webvtt_ref_stringlist
*
* Increase the ref count of the stringlist
*/
WEBVTT_EXPORT void webvtt_ref_stringlist( webvtt_stringlist *list );
/**
* webvtt_copy_stringlist
*
* create a copy shallow of right from left
*/
WEBVTT_EXPORT void webvtt_copy_stringlist( webvtt_stringlist **left, webvtt_stringlist *right );
/**
* webvtt_release_stringlist
*
* Decrease the ref count of the stringlist and delete it if the ref count is 0
*/
WEBVTT_EXPORT void webvtt_release_stringlist( webvtt_stringlist **list );
/**
* webvtt_stringlist_push
*
* add a new string to the end of the stringlist
*/
WEBVTT_EXPORT webvtt_status webvtt_stringlist_push( webvtt_stringlist *list, webvtt_string *str );
/**
* Helper functions
*/
/**
* webvtt_next_utf8
*
* move the 'begin' pointer to the beginning of the next utf8 character
* sequence.
*/
WEBVTT_EXPORT webvtt_bool webvtt_next_utf8( const webvtt_byte **begin,
const webvtt_byte *end );
/**
* webvtt_skip_utf8
*
* move the 'begin' pointer to the beginning of the utf8 character
* 'n_chars' away.
*
* if 'end' is less than 'begin', will seek backwards.
*/
WEBVTT_EXPORT webvtt_bool webvtt_skip_utf8( const webvtt_byte **begin,
const webvtt_byte *end, int n_chars );
/**
* webvtt_utf8_to_utf16
*
* return the utf16 value of a given character
*/
WEBVTT_EXPORT webvtt_uint16 webvtt_utf8_to_utf16( const webvtt_byte *utf8,
const webvtt_byte *end, webvtt_uint16 *high_surrogate );
/**
* webvtt_utf8_chcount
*
* return the number of Unicode characters (as opposed to units)
* in a utf8 string
*/
WEBVTT_EXPORT int webvtt_utf8_chcount( const webvtt_byte *utf8,
const webvtt_byte *end );
/**
* webvtt_utf8_length
*
* if 'utf8' points to a lead byte, return the length of the sequence.
* if 'utf8' is null, return 0.
* if 'utf8' points to a trail byte, return -1
*/
WEBVTT_EXPORT int webvtt_utf8_length( const webvtt_byte *utf8 );
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

View File

@ -0,0 +1,250 @@
/**
* 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_UTIL_H__
# define __WEBVTT_UTIL_H__
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
# if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
# if !WEBVTT_NO_CONFIG_H
# include "webvtt-config-win32.h"
# endif
# define WEBVTT_OS_WIN32 1
# if defined(_WIN64)
# define WEBVTT_OS_WIN64 1
# endif
# elif !WEBVTT_NO_CONFIG_H
# include <webvtt/webvtt-config.h>
# endif
# if defined(_MSC_VER)
# define WEBVTT_CC_MSVC 1
# define WEBVTT_CALLBACK __cdecl
# if WEBVTT_BUILD_LIBRARY
# define WEBVTT_EXPORT __declspec(dllexport)
# elif !WEBVTT_STATIC
# define WEBVTT_EXPORT __declspec(dllimport)
# else
# define WEBVTT_EXPORT
# endif
# if _MSC_VER >= 1600
# define WEBVTT_HAVE_STDINT 1
# endif
# elif defined(__GNUC__)
# define WEBVTT_CC_GCC 1
# define WEBVTT_HAVE_STDINT 1
# if WEBVTT_OS_WIN32
# if WEBVTT_BUILD_LIBRARY
# define WEBVTT_EXPORT __declspec(dllexport)
# elif !WEBVTT_STATIC
# define WEBVTT_EXPORT __declspec(dllimport)
# else
# define WEBVTT_EXPORT
# endif
# else
# if __GNUC__ >= 4
# define WEBVTT_EXPORT __attribute__((visibility("default")))
# define WEBVTT_INTERN __attribute__((visibility("hidden")))
# endif
# endif
# else
# define WEBVTT_CC_UNKNOWN 1
# endif
# ifndef WEBVTT_CALLBACK
# define WEBVTT_CALLBACK
# endif
# ifndef WEBVTT_EXPORT
# define WEBVTT_EXPORT
# endif
# ifndef WEBVTT_INTERN
# define WEBVTT_INTERN
# endif
# if defined(__cplusplus) || defined(c_plusplus)
# define WEBVTT_INLINE inline
# elif WEBVTT_CC_MSVC
# define WEBVTT_INLINE __inline
# elif WEBVTT_CC_GCC
# define WEBVTT_INLINE __inline__
# endif
# if WEBVTT_HAVE_STDINT
# include <stdint.h>
typedef int8_t webvtt_int8;
typedef int16_t webvtt_int16;
typedef int32_t webvtt_int32;
typedef int64_t webvtt_int64;
typedef uint8_t webvtt_uint8;
typedef uint16_t webvtt_uint16;
typedef uint32_t webvtt_uint32;
typedef uint64_t webvtt_uint64;
# elif defined(_MSC_VER)
typedef signed __int8 webvtt_int8;
typedef signed __int16 webvtt_int16;
typedef signed __int32 webvtt_int32;
typedef signed __int64 webvtt_int64;
typedef unsigned __int8 webvtt_uint8;
typedef unsigned __int16 webvtt_uint16;
typedef unsigned __int32 webvtt_uint32;
typedef unsigned __int64 webvtt_uint64;
# elif WEBVTT_CC_UNKNOWN
# warning "Unknown compiler. Compiler specific int-types probably broken!"
typedef signed char webvtt_int8;
typedef signed short webvtt_int16;
typedef signed long webvtt_int32;
typedef signed long long webvtt_int64;
typedef unsigned char webvtt_uint8;
typedef unsigned short webvtt_uint16;
typedef unsigned long webvtt_uint32;
typedef unsigned long long webvtt_uint64;
# endif
typedef signed int webvtt_int;
typedef signed char webvtt_char;
typedef signed short webvtt_short;
typedef signed long webvtt_long;
typedef signed long long webvtt_longlong;
typedef unsigned int webvtt_uint;
typedef unsigned char webvtt_uchar;
typedef unsigned short webvtt_ushort;
typedef unsigned long webvtt_ulong;
typedef unsigned long long webvtt_ulonglong;
typedef webvtt_uint8 webvtt_byte;
typedef webvtt_int webvtt_bool;
typedef webvtt_uint32 webvtt_length;
typedef webvtt_uint64 webvtt_timestamp;
/**
* Memory allocation callbacks, which allow overriding the allocation strategy.
*/
typedef void *(WEBVTT_CALLBACK *webvtt_alloc_fn_ptr)( void *userdata, webvtt_uint nbytes );
typedef void (WEBVTT_CALLBACK *webvtt_free_fn_ptr)( void *userdata, void *pmem );
/**
* Allocation functions. webvtt_set_allocator() should really be the first
* function called. However, it will do nothing (and not report error) if
* objects have already been allocated and not freed. Therefore, it is NOT
* safe to assume that it worked and use the supplied
* function pointers directly.
*
* Currently, set_allocator (and the other allocation functions) do not use
* any locking mechanism, so the library cannot be considered to be
* thread-safe at this time if changing the allocator is used.
*
* I don't believe there is much of a reason to worry about the overhead of
* using function pointers for allocation, as it is negligible compared to the
* act of allocating memory itself, and having a configurable allocation
* strategy could be very useful.
*/
WEBVTT_EXPORT void *webvtt_alloc( webvtt_uint nb );
WEBVTT_EXPORT void *webvtt_alloc0( webvtt_uint nb );
WEBVTT_EXPORT void webvtt_free( void *data );
WEBVTT_EXPORT void webvtt_set_allocator( webvtt_alloc_fn_ptr alloc, webvtt_free_fn_ptr free, void *userdata );
enum
webvtt_status_t {
WEBVTT_SUCCESS = 0,
WEBVTT_UNFINISHED = -1,
WEBVTT_PARSE_ERROR = -2,
WEBVTT_OUT_OF_MEMORY = -3,
WEBVTT_INVALID_PARAM = -4,
WEBVTT_NOT_SUPPORTED = -5,
WEBVTT_UNSUCCESSFUL = -6,
WEBVTT_INVALID_TAG_NAME = -7,
WEBVTT_INVALID_TOKEN_TYPE = -8,
WEBVTT_INVALID_TOKEN_STATE = -9,
WEBVTT_FAIL = -10, /* This is not very specific! */
/**
* A failure that requires the parser to completely skip beyond a cue.
*/
WEBVTT_SKIP_CUE = -11,
/**
* Parser should move to the next cuesetting.
*/
WEBVTT_NEXT_CUESETTING = -12,
};
typedef enum webvtt_status_t webvtt_status;
/**
* Macros to filter out webvtt status returns.
*/
# define WEBVTT_FAILED(status) ( (status) != WEBVTT_SUCCESS )
struct
webvtt_refcount_t {
# if WEBVTT_OS_WIN32
/**
* 'long' on windows in order to coincide with
* the _Interlocked compiler intrinsics on win32
*/
long value;
# else
int value;
# endif
};
# ifdef WEBVTT_REF_INIT
# undef WEBVTT_REF_INIT
# endif
# define WEBVTT_REF_INIT(Value) { (Value) }
/**
* TODO: Replace these with atomic instructions for systems that provide it
*/
# ifndef WEBVTT_ATOMIC_INC
# define WEBVTT_ATOMIC_INC(x) ( ++(x) )
# endif
# ifndef WEBVTT_ATOMIC_DEC
# define WEBVTT_ATOMIC_DEC(x) ( --(x) )
# endif
# if defined(WEBVTT_INLINE)
static WEBVTT_INLINE int webvtt_ref( struct webvtt_refcount_t *ref )
{
return WEBVTT_ATOMIC_INC(ref->value);
}
static WEBVTT_INLINE int webvtt_deref( struct webvtt_refcount_t *ref )
{
return WEBVTT_ATOMIC_DEC(ref->value);
}
# else
# define webvtt_inc_ref(ref) ( WEBVTT_ATOMIC_INC((ref)->value) )
# define webvtt_dec_ref(ref) ( WEBVTT_ATOMIC_DEC((ref)->value) )
# endif
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif

597
media/webvtt/lexer.c Normal file
View File

@ -0,0 +1,597 @@
/**
* 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 "parser_internal.h"
/**
* There are probably enough jumps and stack pops here to fill up quite a few caches but it may still
* be much smaller than a gigantic table-based solution.
*
* TODO: Replace all char literals with hex values, just in case compiling on a machine which uses an
* incompatible character set
*/
#define U_DIGIT case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
#define U_WHITESPACE case 0x0D: case 0x0A: case 0x20: case 0x09:
#define U_SPACE case 0x20:
#define U_TAB case 0x09:
#define U_CR case 0x0D:
#define U_LF case 0x0A:
#define U_DASH case 0x2D:
#define U_PERIOD case 0x2E:
#define U_GT case 0x3E:
#define U_COLON case 0x3A:
#define U_PERCENT case 0x25:
#define U_0 case 0x30:
#define U_1 case 0x31:
#define U_2 case 0x32:
#define U_3 case 0x33:
#define U_4 case 0x34:
#define U_5 case 0x35:
#define U_6 case 0x36:
#define U_7 case 0x37:
#define U_8 case 0x38:
#define U_9 case 0x39:
#define U_a case 0x61:
#define U_b case 0x62:
#define U_c case 0x63:
#define U_d case 0x64:
#define U_e case 0x65:
#define U_f case 0x66:
#define U_g case 0x67:
#define U_h case 0x68:
#define U_i case 0x69:
#define U_j case 0x6A:
#define U_k case 0x6B:
#define U_l case 0x6C:
#define U_m case 0x6D:
#define U_n case 0x6E:
#define U_o case 0x6F:
#define U_p case 0x70:
#define U_q case 0x71:
#define U_r case 0x72:
#define U_s case 0x73:
#define U_t case 0x74:
#define U_u case 0x75:
#define U_v case 0x76:
#define U_w case 0x77:
#define U_x case 0x78:
#define U_y case 0x79:
#define U_z case 0x7A:
#define U_A case 0x41:
#define U_B case 0x42:
#define U_C case 0x43:
#define U_D case 0x44:
#define U_E case 0x45:
#define U_F case 0x46:
#define U_G case 0x47:
#define U_H case 0x48:
#define U_I case 0x49:
#define U_J case 0x4A:
#define U_K case 0x4B:
#define U_L case 0x4C:
#define U_M case 0x4D:
#define U_N case 0x4E:
#define U_O case 0x4F:
#define U_P case 0x50:
#define U_Q case 0x51:
#define U_R case 0x52:
#define U_S case 0x53:
#define U_T case 0x54:
#define U_U case 0x55:
#define U_V case 0x56:
#define U_W case 0x57:
#define U_X case 0x58:
#define U_Y case 0x59:
#define U_Z case 0x5A:
#define U_BOM0 case 0xEF:
#define U_BOM1 case 0xBB:
#define U_BOM2 case 0xBF:
#define DEFAULT default:
/**
* Just for semantic clarity
*/
#define OR
#define AND
#define OVERFLOW(X) \
if( self->token_pos >= (sizeof(self->token) - 1 ) ) \
{ \
RETURN(X) \
}
#define BEGIN_STATE(state) case state: { switch(c) {
#define END_STATE DEFAULT BACKUP return BADTOKEN; } } break;
#define END_STATE_EX } } break;
#define BACKUP (*pos)--; --self->column; self->token[--self->token_pos] = 0; self->tstate = L_START;
#define SET_STATE(X) self->tstate = X; break;
#define RETURN(X) self->tstate = L_START; return X;
#define SET_NEWLINE self->line++; self->column = 1; RETURN(NEWLINE)
#define CONTINUE continue;
#define RESET self->column = 1; self->bytes = self->token_pos = 0; self->tstate = L_START;
#define BREAK break;
#define CHECK_BROKEN_TIMESTAMP \
if(self->token_pos == sizeof(self->token) - 1 ) \
{ \
ERROR(WEBVTT_MALFORMED_TIMESTAMP); \
return BADTOKEN; \
}
WEBVTT_INTERN webvtt_status
webvtt_lex_word( webvtt_parser self, webvtt_string *str, const webvtt_byte *buffer, webvtt_uint *ppos, webvtt_uint length, webvtt_bool finish )
{
webvtt_status status = WEBVTT_SUCCESS;
webvtt_uint pos = *ppos;
int d = 0;
if( !str ) {
return WEBVTT_INVALID_PARAM;
}
webvtt_init_string( str );
# define ASCII_DASH (0x2D)
# define ASCII_GT (0x3E)
while( pos < length ) {
webvtt_uint last_bytes = self->bytes;
webvtt_uint last_line = self->line;
webvtt_uint last_column = self->column;
webvtt_uint last_pos = pos;
webvtt_token token = webvtt_lex(self, buffer, &pos, length, finish );
if( token == BADTOKEN ) {
if( WEBVTT_FAILED( status = webvtt_string_putc( str, buffer[pos] ) ) ) {
webvtt_release_string( str );
goto _finished;
}
++pos;
} else {
pos = last_pos;
self->bytes = last_bytes;
self->line = last_line;
self->column = last_column;
goto _finished;
}
}
_finished:
*ppos = pos;
return status;
}
WEBVTT_INTERN webvtt_token
webvtt_lex( webvtt_parser self, const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length, webvtt_bool finish )
{
while( *pos < length ) {
webvtt_byte c = buffer[(*pos)++];
self->token[ self->token_pos++ ] = c;
self->token[ self->token_pos ] = 0;
self->column++;
self->bytes++;
switch( self->tstate ) {
BEGIN_STATE(L_START)
U_DIGIT { SET_STATE(L_DIGIT0) }
U_W { SET_STATE(L_WEBVTT0) }
U_DASH { SET_STATE(L_DASH0) }
U_BOM0 { SET_STATE(L_BOM0) }
U_LF { SET_NEWLINE }
U_CR { SET_STATE(L_NEWLINE0) }
U_SPACE OR U_TAB { SET_STATE(L_WHITESPACE) }
U_PERIOD { RETURN(FULL_STOP) }
U_COLON { RETURN(COLON) }
U_p { SET_STATE(L_POSITION0) }
U_a { SET_STATE(L_ALIGN0) }
U_l { SET_STATE(L_L0) }
U_v { SET_STATE(L_VERTICAL0) }
U_r { SET_STATE(L_RL0) }
U_s { SET_STATE(L_S0) }
U_m { SET_STATE(L_MIDDLE0) }
U_e { SET_STATE(L_END0) }
U_N { SET_STATE(L_NOTE1) }
END_STATE
BEGIN_STATE(L_BOM0)
U_BOM1 { SET_STATE(L_BOM1) }
END_STATE
BEGIN_STATE(L_BOM1)
U_BOM2 {
if( self->bytes == 3 ) {
RESET
BREAK
}
RETURN(BOM)
}
END_STATE
BEGIN_STATE(L_WEBVTT0)
U_E { SET_STATE(L_WEBVTT1) }
END_STATE
BEGIN_STATE(L_WEBVTT1)
U_B { SET_STATE(L_WEBVTT2) }
END_STATE
BEGIN_STATE(L_WEBVTT2)
U_V { SET_STATE(L_WEBVTT3) }
END_STATE
BEGIN_STATE(L_WEBVTT3)
U_T { SET_STATE(L_WEBVTT4) }
END_STATE
BEGIN_STATE(L_WEBVTT4)
U_T { RETURN(WEBVTT) }
END_STATE
BEGIN_STATE(L_DASH0)
U_DIGIT { SET_STATE(L_DIGIT0) }
U_DASH { SET_STATE(L_SEP1) }
END_STATE
BEGIN_STATE(L_SEP1)
U_GT { RETURN(SEPARATOR) }
END_STATE
BEGIN_STATE(L_DIGIT0)
U_DIGIT {
OVERFLOW(INTEGER)
SET_STATE(L_DIGIT0)
}
U_COLON { SET_STATE(L_TIMESTAMP1) }
U_PERCENT { RETURN(PERCENTAGE) }
DEFAULT { BACKUP AND RETURN(INTEGER) }
END_STATE_EX
BEGIN_STATE(L_NEWLINE0)
U_LF { SET_NEWLINE }
DEFAULT { BACKUP AND SET_NEWLINE }
END_STATE_EX
BEGIN_STATE(L_WHITESPACE)
U_SPACE OR U_TAB { OVERFLOW(WHITESPACE) SET_STATE(L_WHITESPACE) }
DEFAULT { BACKUP RETURN(WHITESPACE) }
END_STATE_EX
BEGIN_STATE(L_POSITION0)
U_o { SET_STATE(L_POSITION1) }
END_STATE
BEGIN_STATE(L_POSITION1)
U_s { SET_STATE(L_POSITION2) }
END_STATE
BEGIN_STATE(L_POSITION2)
U_i { SET_STATE(L_POSITION3) }
END_STATE
BEGIN_STATE(L_POSITION3)
U_t { SET_STATE(L_POSITION4) }
END_STATE
BEGIN_STATE(L_POSITION4)
U_i { SET_STATE(L_POSITION5) }
END_STATE
BEGIN_STATE(L_POSITION5)
U_o { SET_STATE(L_POSITION6) }
END_STATE
BEGIN_STATE(L_POSITION6)
U_n { RETURN(POSITION) }
END_STATE
BEGIN_STATE(L_ALIGN0)
U_l { SET_STATE(L_ALIGN1) }
END_STATE
BEGIN_STATE(L_ALIGN1)
U_i { SET_STATE(L_ALIGN2) }
END_STATE
BEGIN_STATE(L_ALIGN2)
U_g { SET_STATE(L_ALIGN3) }
END_STATE
BEGIN_STATE(L_ALIGN3)
U_n { RETURN(ALIGN) }
END_STATE
BEGIN_STATE(L_L0)
U_r { RETURN(LR) }
U_i { SET_STATE(L_LINE1) }
U_e { SET_STATE(L_LEFT1) }
END_STATE
BEGIN_STATE(L_LINE1)
U_n { SET_STATE(L_LINE2) }
END_STATE
BEGIN_STATE(L_LINE2)
U_e { RETURN(LINE) }
END_STATE
BEGIN_STATE(L_LEFT1)
U_f { SET_STATE(L_LEFT2) }
END_STATE
BEGIN_STATE(L_LEFT2)
U_t { RETURN(LEFT) }
END_STATE
BEGIN_STATE(L_VERTICAL0)
U_e { SET_STATE(L_VERTICAL1) }
END_STATE
BEGIN_STATE(L_VERTICAL1)
U_r { SET_STATE(L_VERTICAL2) }
END_STATE
BEGIN_STATE(L_VERTICAL2)
U_t { SET_STATE(L_VERTICAL3) }
END_STATE
BEGIN_STATE(L_VERTICAL3)
U_i { SET_STATE(L_VERTICAL4) }
END_STATE
BEGIN_STATE(L_VERTICAL4)
U_c { SET_STATE(L_VERTICAL5) }
END_STATE
BEGIN_STATE(L_VERTICAL5)
U_a { SET_STATE(L_VERTICAL6) }
END_STATE
BEGIN_STATE(L_VERTICAL6)
U_l { RETURN(VERTICAL) }
END_STATE
BEGIN_STATE(L_RL0)
U_l { RETURN(RL) }
U_i { SET_STATE(L_RIGHT1) }
END_STATE
BEGIN_STATE(L_RIGHT1)
U_g { SET_STATE(L_RIGHT2) }
END_STATE
BEGIN_STATE(L_RIGHT2)
U_h { SET_STATE(L_RIGHT3) }
END_STATE
BEGIN_STATE(L_RIGHT3)
U_t { RETURN(RIGHT) }
END_STATE
BEGIN_STATE(L_S0)
U_t { SET_STATE(L_START1) }
U_i { SET_STATE(L_SIZE1) }
END_STATE
BEGIN_STATE(L_SIZE1)
U_z { SET_STATE(L_SIZE2) }
END_STATE
BEGIN_STATE(L_SIZE2)
U_e { RETURN(SIZE) }
END_STATE
BEGIN_STATE(L_START1)
U_a { SET_STATE(L_START2) }
END_STATE
BEGIN_STATE(L_START2)
U_r { SET_STATE(L_START3) }
END_STATE
BEGIN_STATE(L_START3)
U_t { RETURN(START) }
END_STATE
BEGIN_STATE(L_MIDDLE0)
U_i { SET_STATE(L_MIDDLE1) }
END_STATE
BEGIN_STATE(L_MIDDLE1)
U_d { SET_STATE(L_MIDDLE2) }
END_STATE
BEGIN_STATE(L_MIDDLE2)
U_d { SET_STATE(L_MIDDLE3) }
END_STATE
BEGIN_STATE(L_MIDDLE3)
U_l { SET_STATE(L_MIDDLE4) }
END_STATE
BEGIN_STATE(L_MIDDLE4)
U_e { RETURN(MIDDLE) }
END_STATE
BEGIN_STATE(L_END0)
U_n { SET_STATE(L_END1) }
END_STATE
BEGIN_STATE(L_END1)
U_d { RETURN(END) }
END_STATE
BEGIN_STATE(L_TIMESTAMP1)
U_DIGIT {
OVERFLOW(BADTOKEN)
SET_STATE(L_TIMESTAMP1)
}
U_COLON {
OVERFLOW(BADTOKEN)
SET_STATE(L_TIMESTAMP2)
}
U_PERIOD {
OVERFLOW(BADTOKEN)
SET_STATE(L_TIMESTAMP3)
}
END_STATE
BEGIN_STATE(L_TIMESTAMP2)
U_DIGIT {
OVERFLOW(BADTOKEN)
SET_STATE(L_TIMESTAMP2)
}
U_PERIOD {
OVERFLOW(BADTOKEN)
SET_STATE(L_TIMESTAMP3)
}
END_STATE
BEGIN_STATE(L_TIMESTAMP3)
U_DIGIT {
OVERFLOW(TIMESTAMP)
BREAK
}
DEFAULT {
BACKUP
RETURN(TIMESTAMP)
BREAK
}
END_STATE_EX
BEGIN_STATE(L_NOTE1)
U_O { SET_STATE(L_NOTE2) }
END_STATE
BEGIN_STATE(L_NOTE2)
U_T { SET_STATE(L_NOTE3) }
END_STATE
BEGIN_STATE(L_NOTE3)
U_E { RETURN(NOTE) }
END_STATE
}
}
/**
* If we got here, we've reached the end of the buffer.
* We therefore can attempt to finish up
*/
if( finish && self->token_pos ) {
switch( self->tstate ) {
case L_DIGIT0:
RETURN(INTEGER)
case L_TIMESTAMP3:
RETURN(TIMESTAMP)
case L_WHITESPACE:
RETURN(WHITESPACE)
default:
RESET
return BADTOKEN;
}
}
return *pos == length || self->token_pos ? UNFINISHED : BADTOKEN;
}
/**
* token states
L_START + 'W' = L_WEBVTT0
L_START + '-' = L_DASH0
L_START + {D} = L_DIGIT0
L_START + CR = L_NEWLINE0
L_START + LF = *NEWLINE
L_START + SP = L_WHITESPACE
L_START + TB = L_WHITESPACE
L_START + FS = *FULL_STOP
L_START + 'p' = L_POSITION0
L_START + 'a' = L_ALIGN0
L_START + 'l' = L_L0
L_START + 'v' = L_VERTICAL0
L_START + 'r' = L_RL0
L_START + 's' = L_S0
L_START + 'm' = L_MIDDLE0
L_START + 'e' = L_END0
L_WEBVTT0 + 'E' = L_WEBVTT1
L_WEBVTT1 + 'B' = L_WEBVTT2
L_WEBVTT2 + 'V' = L_WEBVTT3
L_WEBVTT3 + 'T' = L_WEBVTT4
L_WEBVTT4 + 'T' = *WEBVTT
L_DASH0 + {D} = L_DIGIT0
L_DASH0 + '-' = L_SEP1
L_SEP1 + '>' = *SEPARATOR
L_DIGIT0 + {D} = L_DIGIT0
L_NEWLINE0 + LF = *NEWLINE
L_WHITESPACE + TB = L_WHITESPACE
L_WHITESPACE + SP = L_WHITESPACE
L_POSITION0 + 'o' = L_POSITION1
L_POSITION1 + 's' = L_POSITION2
L_POSITION2 + 'i' = L_POSITION3
L_POSITION3 + 't' = L_POSITION4
L_POSITION4 + 'i' = L_POSITION5
L_POSITION5 + 'o' = L_POSITION6
L_POSITION6 + 'n' = L_POSITION7
L_POSITION7 + ':' = *POSITION
L_ALIGN0 + 'l' = L_ALIGN1
L_ALIGN1 + 'i' = L_ALIGN2
L_ALIGN2 + 'g' = L_ALIGN3
L_ALIGN3 + 'n' = L_ALIGN4
L_ALIGN4 + ':' = *ALIGN
L0 + 'r' = *LR
L0 + 'i' = L_LINE1
L_LINE1 + 'n' = L_LINE2
L_LINE2 + 'e' = L_LINE3
L_LINE3 + ':' = *LINE
L_VERTICAL0 + 'e' = L_VERTICAL1
L_VERTICAL1 + 'r' = L_VERTICAL2
L_VERTICAL2 + 't' = L_VERTICAL3
L_VERTICAL3 + 'i' = L_VERTICAL4
L_VERTICAL4 + 'c' = L_VERTICAL5
L_VERTICAL5 + 'a' = L_VERTICAL6
L_VERTICAL6 + 'l' = L_VERTICAL7
L_VERTICAL7 + ':' = *VERTICAL
L_RL0 + 'l' = *RL
L_S0 + 't' = L_START1
L_S0 + 'i' = L_SIZE1
L_SIZE1 + 'z' = L_SIZE2
L_SIZE2 + 'e' = L_SIZE3
L_SIZE3 + ':' = *SIZE
L_START1 + 'a' = L_START2
L_START2 + 'r' = L_START3
L_START3 + 't' = *START
L_MIDDLE0 + 'i' = L_MIDDLE1
L_MIDDLE1 + 'd' = L_MIDDLE2
L_MIDDLE2 + 'd' = L_MIDDLE3
L_MIDDLE3 + 'l' = L_MIDDLE4
L_MIDDLE4 + 'e' = *MIDDLE
L_END0 + 'n' = L_END1
L_END1 + 'd' = *END
*/

26
media/webvtt/moz.build Normal file
View File

@ -0,0 +1,26 @@
# vim: set filetype=python:
# 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.

1387
media/webvtt/parser.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,236 @@
/**
* 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 __INTERN_PARSER_H__
# define __INTERN_PARSER_H__
# include <webvtt/parser.h>
# include "string_internal.h"
typedef enum
webvtt_token_t {
BADTOKEN = -2,
UNFINISHED = -1, /* not-token */
BOM,
WEBVTT, /* 'WEBVTT' */
NOTE, /* 'NOTE' */
INTEGER, /* /-?\d+/ */
NEWLINE, /* /[\r\n]|(\r\n)/ */
WHITESPACE, /* /[\t ]/ */
FULL_STOP, /* '.' */
POSITION, /* 'position:' */
ALIGN, /* 'align:' */
SIZE, /* 'size:' */
LINE, /* 'line:' */
VERTICAL, /* 'vertical:' */
RL, /* 'rl' */
LR, /* 'lr' */
START, /* 'start' */
MIDDLE, /* 'middle' */
END, /* 'end' */
LEFT, /* 'left' */
RIGHT, /* 'right' */
SEPARATOR, /* '-->' */
TIMESTAMP,
PERCENTAGE, /* '\d+%' */
COLON, /* ':' */
} webvtt_token;
typedef enum
webvtt_state_value_type_t {
V_NONE,
V_POINTER,
V_INTEGER,
V_CUE,
V_TEXT,
V_LNODE,
V_INODE,
V_TOKEN,
} webvtt_state_value_type;
typedef enum
webvtt_parse_mode_t {
M_WEBVTT = 0,
M_CUETEXT,
M_SKIP_CUE,
M_READ_LINE,
} webvtt_parse_mode;
typedef enum
webvtt_parse_state_t {
/**
* WEBVTT parse states
*/
T_INITIAL = 0,
T_TAG,
T_TAGCOMMENT,
T_EOL,
T_BODY,
T_CUEREAD, /* Read a line of text for a cue */
T_CUE, /* T_CUEID T_CUEPARAMS T_CUETEXT NEWLINE */
T_CUEID, /* T_LINE !~ SEPARATOR && LINE !~ ^NOTE NEWLINE */
T_CUEPARAMS, /* TIMESTAMP WHITESPACE? SEPARATOR WHITESPACE? T_CUESETTING* NEWLINE */
T_CUETEXT, /* T_LINE !~ SEPARATOR NEWLINE NEWLINE */
T_TIMESTAMP, /* This looked like a timestamp to the lexer, may or may not be valid. */
/**
* NOTE comments
*/
T_COMMENT,
/**
* Cue times
*/
T_FROM,
T_SEP_LEFT,
T_SEP,
T_SEP_RIGHT,
T_UNTIL,
/**
* Cue settings
*/
T_PRECUESETTING,
T_CUESETTING,
T_CUESETTING_DELIMITER,
T_CUESETTING_VALUE,
T_SKIP_SETTING /* We have to skip a cue-setting because of an error. */
/**
* Cue text parse states
*/
} webvtt_parse_state;
/**
* lexer state
*/
typedef enum
webvtt_lexer_state_t {
L_START = 0, L_BOM0, L_BOM1, L_WEBVTT0, L_WEBVTT1, L_WEBVTT2, L_WEBVTT3, L_WEBVTT4, L_WEBVTT5, L_DASH0, L_SEP1,
L_DIGIT0, L_NEWLINE0, L_WHITESPACE, L_POSITION0, L_POSITION1, L_POSITION2, L_POSITION3, L_POSITION4, L_POSITION5,
L_POSITION6, L_ALIGN0, L_ALIGN1, L_ALIGN2, L_ALIGN3, L_L0, L_LINE1, L_LINE2, L_LINE3,
L_VERTICAL0, L_VERTICAL1, L_VERTICAL2, L_VERTICAL3, L_VERTICAL4, L_VERTICAL5, L_VERTICAL6, L_RL0,
L_S0, L_SIZE1, L_SIZE2, L_START1, L_START2, L_START3, L_MIDDLE0, L_MIDDLE1, L_MIDDLE2, L_MIDDLE3,
L_MIDDLE4, L_END0, L_END1, L_TIMESTAMP1, L_TIMESTAMP2, L_TIMESTAMP3, L_RIGHT1, L_RIGHT2,
L_RIGHT3, L_NOTE1, L_NOTE2, L_NOTE3, L_LEFT1, L_LEFT2,
} webvtt_lexer_state;
typedef struct
webvtt_state {
webvtt_parse_state state;
webvtt_token token;
webvtt_state_value_type type;
webvtt_uint back;
webvtt_uint line;
webvtt_uint column;
union {
/**
* cue value
*/
webvtt_cue *cue;
/**
* string value
*/
webvtt_string text;
/**
* The cuetext parser is not currently using the state stack, and
* because of this, 'node' is never actually used.
*
* It is here if the cuetext parser begins to use the/a state stack
* in the future.
*/
webvtt_node *node;
/**
* unsigned integer value
*/
webvtt_uint value;
} v;
} webvtt_state;
struct
webvtt_parser_t {
webvtt_uint state;
webvtt_uint bytes; /* number of bytes read. */
webvtt_uint line;
webvtt_uint column;
webvtt_cue_fn read;
webvtt_error_fn error;
void *userdata;
webvtt_bool finished;
/**
* 'mode' can have several states, it is not boolean.
*/
webvtt_parse_mode mode;
webvtt_state *top; /* Top parse state */
webvtt_state astack[0x100];
webvtt_state *stack; /* dynamically allocated stack, if 'astack' fills up */
webvtt_uint stack_alloc; /* item capacity in 'stack' */
webvtt_bool popped;
/**
* line (cue payload also stored here)
*/
int truncate;
webvtt_uint line_pos;
webvtt_string line_buffer;
/**
* tokenizer
*/
webvtt_lexer_state tstate;
webvtt_uint token_pos;
webvtt_byte token[0x100];
};
WEBVTT_INTERN webvtt_token webvtt_lex( webvtt_parser self, const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint length, webvtt_bool finish );
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 );
#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)
#endif

695
media/webvtt/string.c Normal file
View File

@ -0,0 +1,695 @@
/**
* 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_internal.h"
#include <stdlib.h>
#include <string.h>
static webvtt_string_data empty_string = {
{ 1 }, /* init refcount */
0, /* length */
0, /* capacity */
empty_string.array, /* text */
{ '\0' } /* array */
};
WEBVTT_EXPORT void
webvtt_init_string( webvtt_string *result )
{
if( result ) {
result->d = &empty_string;
webvtt_ref( &result->d->refs );
}
}
WEBVTT_EXPORT webvtt_uint
webvtt_string_is_empty( const webvtt_string *str ) {
return str->d == &empty_string || webvtt_string_length( str ) == 0 ? 1 : 0;
}
/**
* Allocate new string.
*/
WEBVTT_EXPORT webvtt_status
webvtt_create_string( webvtt_uint32 alloc, webvtt_string *result )
{
webvtt_string_data *d;
if( !result ) {
return WEBVTT_INVALID_PARAM;
}
d = ( webvtt_string_data * )webvtt_alloc( sizeof( webvtt_string_data ) + ( alloc * sizeof( webvtt_byte ) ) );
if( !d ) {
return WEBVTT_OUT_OF_MEMORY;
}
d->refs.value = 1;
d->alloc = alloc;
d->length = 0;
d->text = d->array;
d->text[0] = 0;
result->d = d;
return WEBVTT_SUCCESS;
}
WEBVTT_EXPORT webvtt_status
webvtt_create_string_with_text( webvtt_string *result, const webvtt_byte *init_text, int len )
{
webvtt_uint pos = 0;
if( !result ) {
return WEBVTT_INVALID_PARAM;
}
if( !init_text ) {
webvtt_init_string( result );
return WEBVTT_SUCCESS;
}
if( len < 0 ) {
len = strlen( ( const char * )init_text );
}
if( len == 0 ) {
webvtt_init_string( result );
return WEBVTT_SUCCESS;
}
/**
* initialize the string by referencing empty_string
*/
webvtt_init_string( result );
/**
* append the appropriate data to the empty string
*/
return webvtt_string_append( result, init_text, len );
}
/**
* reference counting
*/
WEBVTT_EXPORT void
webvtt_ref_string( webvtt_string *str )
{
if( str ) {
webvtt_ref( &str->d->refs );
}
}
WEBVTT_EXPORT void
webvtt_release_string( webvtt_string *str )
{
/**
* pulls the string data out of the string container, decreases the string
*/
if( str ) {
webvtt_string_data *d = str->d;
str->d = 0;
if( d && webvtt_deref( &d->refs ) == 0 ) {
webvtt_free( d );
}
}
}
/**
* "Detach" a shared string, so that it's safely mutable
*/
WEBVTT_EXPORT webvtt_status
webvtt_string_detach( /* in, out */ webvtt_string *str )
{
webvtt_string_data *d, *q;
if( !str ) {
return WEBVTT_INVALID_PARAM;
}
q = str->d;
if( q->refs.value == 1 ) {
return WEBVTT_SUCCESS;
}
d = ( webvtt_string_data * )webvtt_alloc( sizeof( webvtt_string_data ) + ( sizeof( webvtt_byte ) * str->d->alloc ) );
d->refs.value = 1;
d->text = d->array;
d->alloc = q->alloc;
d->length = q->length;
memcpy( d->text, q->text, q->length );
str->d = d;
if( webvtt_deref( &q->refs ) == 0 ) {
webvtt_free( q );
}
return WEBVTT_SUCCESS;
}
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 {
left->d = &empty_string;
}
webvtt_ref( &left->d->refs );
}
}
WEBVTT_EXPORT const webvtt_byte *
webvtt_string_text(const webvtt_string *str)
{
if( !str || !str->d )
{
return 0;
}
return str->d->text;
}
WEBVTT_EXPORT const webvtt_uint32
webvtt_string_length(const webvtt_string *str)
{
if( !str || !str->d )
{
return 0;
}
return str->d->length;
}
WEBVTT_EXPORT const webvtt_uint32
webvtt_string_capacity(const webvtt_string *str)
{
if( !str || !str->d )
{
return 0;
}
return str->d->alloc;
}
/**
* Reallocate string.
* Grow to at least 'need' characters. Power of 2 growth.
*/
static webvtt_status
grow( webvtt_string *str, webvtt_uint need )
{
static const webvtt_uint page = 0x1000;
webvtt_uint32 n;
webvtt_string_data *p, *d;
webvtt_uint32 grow;
if( !str )
{
return WEBVTT_INVALID_PARAM;
}
if( ( str->d->length + need ) <= str->d->alloc )
{
return WEBVTT_SUCCESS;
}
p = d = str->d;
grow = sizeof( *d ) + ( sizeof( webvtt_byte ) * ( d->length + need ) );
if( grow < page ) {
n = page;
do {
n = n / 2;
} while( n > grow );
if( n < 1 << 6 ) {
n = 1 << 6;
} else {
n = n * 2;
}
} else {
n = page;
do {
n = n * 2;
} while ( n < grow );
}
p = ( webvtt_string_data * )webvtt_alloc( n );
if( !p ) {
return WEBVTT_OUT_OF_MEMORY;
}
p->refs.value = 1;
p->alloc = ( n - sizeof( *p ) ) / sizeof( webvtt_byte );
p->length = d->length;
p->text = p->array;
memcpy( p->text, d->text, sizeof( webvtt_byte ) * p->length );
p->text[ p->length ] = 0;
str->d = p;
if( webvtt_deref( &d->refs ) == 0 ) {
webvtt_free( d );
}
return WEBVTT_SUCCESS;
}
WEBVTT_EXPORT int
webvtt_string_getline( webvtt_string *src, const webvtt_byte *buffer,
webvtt_uint *pos, webvtt_uint len, int *truncate, webvtt_bool finish, webvtt_bool retain_new_line )
{
int ret = 0;
webvtt_string *str = src;
webvtt_string_data *d = 0;
const webvtt_byte *s = buffer + *pos;
const webvtt_byte *p = s;
const webvtt_byte *n = buffer + len;
/**
*if this is public now, maybe we should return webvtt_status so we can
* differentiate between WEBVTT_OUT_OF_MEMORY and WEBVTT_INVALID_PARAM
*/
if( !str ) {
return -1;
}
/* This had better be a valid string_data, or else NULL. */
d = str->d;
if( !str->d ) {
if(WEBVTT_FAILED(webvtt_create_string( 0x100, str ))) {
return -1;
}
d = str->d;
}
while( p < n && *p != UTF8_CARRIAGE_RETURN && *p != UTF8_LINE_FEED ) {
++p;
}
/* Retain the new line character. */
if( p < n && retain_new_line ) {
p++;
}
if( p < n || finish ) {
ret = 1; /* indicate that we found EOL */
}
len = (webvtt_uint)( p - s );
*pos += len;
if( d->length + len + 1 >= d->alloc ) {
if( truncate && d->alloc >= WEBVTT_MAX_LINE ) {
/* truncate. */
(*truncate)++;
} else {
if( grow( str, len ) == WEBVTT_OUT_OF_MEMORY ) {
ret = -1;
}
d = str->d;
}
}
/* Copy everything in */
if( len && ret >= 0 && d->length + len < d->alloc ) {
memcpy( d->text + d->length, s, len );
d->length += len;
d->text[ d->length ] = 0;
}
return ret;
}
WEBVTT_EXPORT webvtt_status
webvtt_string_putc( webvtt_string *str, webvtt_byte to_append )
{
webvtt_status result;
if( !str ) {
return WEBVTT_INVALID_PARAM;
}
if( WEBVTT_FAILED( result = webvtt_string_detach( str ) ) ) {
return result;
}
if( !WEBVTT_FAILED( result = grow( str, 1 ) ) )
{
str->d->text[ str->d->length++ ] = to_append;
str->d->text[ str->d->length ] = 0;
}
return result;
}
WEBVTT_EXPORT webvtt_status
webvtt_string_append( webvtt_string *str, const webvtt_byte *buffer, int len )
{
webvtt_status result;
if( !str || !buffer ) {
return WEBVTT_INVALID_PARAM;
}
if( !str->d ) {
webvtt_init_string( str );
}
if( len < 0 ) {
len = strlen( ( const char * )buffer );
}
if( len == 0 ) {
return WEBVTT_SUCCESS;
}
if( !WEBVTT_FAILED( result = grow( str, str->d->length + len ) ) ) {
memcpy( str->d->text + str->d->length, buffer, len );
str->d->length += len;
/* null-terminate string */
str->d->text[ str->d->length ] = 0;
}
return result;
}
WEBVTT_EXPORT webvtt_status
webvtt_string_append_string( webvtt_string *str, const webvtt_string *other )
{
if( !str || !other ) {
return WEBVTT_INVALID_PARAM;
}
return webvtt_string_append( str, other->d->text, other->d->length );
}
/**
* String lists
*/
WEBVTT_EXPORT webvtt_status
webvtt_create_stringlist( webvtt_stringlist **result )
{
webvtt_stringlist *list;
if( !result ) {
return WEBVTT_INVALID_PARAM;
}
list = ( webvtt_stringlist * )webvtt_alloc0( sizeof( *list ) );
if( !list ) {
return WEBVTT_OUT_OF_MEMORY;
}
list->alloc = 0;
list->length = 0;
webvtt_ref_stringlist( list );
*result = list;
return WEBVTT_SUCCESS;
}
WEBVTT_EXPORT void
webvtt_ref_stringlist( webvtt_stringlist *list )
{
if( list ) {
webvtt_ref( &list->refs );
}
}
WEBVTT_EXPORT void
webvtt_copy_stringlist( webvtt_stringlist **left, webvtt_stringlist *right )
{
if( !left || !right ) {
return;
}
*left = right;
webvtt_ref_stringlist( *left );
}
WEBVTT_EXPORT void
webvtt_release_stringlist( webvtt_stringlist **list )
{
webvtt_stringlist *l;
webvtt_uint i;
if( !list || !*list ) {
return;
}
l = *list;
if( webvtt_deref( &l->refs ) == 0 ) {
if( l->items ) {
for( i = 0; i < l->length; i++ ) {
webvtt_release_string( &l->items[ i ] );
}
webvtt_free( l->items );
}
webvtt_free( l );
}
*list = 0;
}
WEBVTT_EXPORT webvtt_status
webvtt_stringlist_push( webvtt_stringlist *list, webvtt_string *str )
{
if( !list || !str ) {
return WEBVTT_INVALID_PARAM;
}
if( list->length + 1 >= ( ( list->alloc / 3 ) * 2 ) ) {
webvtt_string *arr, *old;
list->alloc = list->alloc == 0 ? 8 : list->alloc * 2;
arr = ( webvtt_string * )webvtt_alloc0( sizeof( webvtt_string ) * list->alloc );
if( !arr ) {
return WEBVTT_OUT_OF_MEMORY;
}
memcpy( arr, list->items, sizeof( webvtt_string ) * list->length );
old = list->items;
list->items = arr;
webvtt_free( old );
}
list->items[list->length].d = str->d;
webvtt_ref_string( list->items + list->length++ );
return WEBVTT_SUCCESS;
}
WEBVTT_EXPORT webvtt_bool
webvtt_next_utf8( const webvtt_byte **begin, const webvtt_byte *end )
{
int c;
const webvtt_byte *p;
if( !begin || !*begin || !**begin || ( end && ( end <= *begin ) ) ) {
/* Either begin is null, or end is null, or end <= begin */
return 0;
}
p = *begin;
if( !end ) {
end = p + strlen( ( const char * )p );
}
c = webvtt_utf8_length( p );
if( c > 0 ) {
p += c;
} else if( ( *p & 0xC0 ) == 0x80 ) {
const webvtt_byte *pc = p + 1;
while( pc < end && ( ( *pc & 0xC0 ) == 0x80 ) ) {
++pc;
}
if( pc <= end ) {
p = pc;
}
}
if( *begin != p && p <= end ) {
*begin = p;
return 1;
}
return 0;
}
WEBVTT_EXPORT webvtt_bool
webvtt_skip_utf8( const webvtt_byte **begin, const webvtt_byte *end, int n_chars )
{
const webvtt_byte *first;
if( !begin || !*begin ) {
return 0;
}
if( n_chars < 0 ) {
return 0;
}
first = *begin;
if( !end ) {
end = first + strlen( ( const char * )first );
}
if( end > first ) {
/* forwards */
while( n_chars && end > *begin ) {
if( webvtt_next_utf8( begin, end ) ) {
--n_chars;
}
}
}
return n_chars == 0;
}
WEBVTT_EXPORT webvtt_uint16
webvtt_utf8_to_utf16( const webvtt_byte *utf8, const webvtt_byte *end,
webvtt_uint16 *high_surrogate )
{
int need = 0, min = 0;
webvtt_uint32 uc = 0;
/* We're missing our pointers */
if( !utf8 ) {
return 0;
}
if( !end ) {
end = utf8 + strlen( ( const char * )utf8 );
}
if( utf8 >= end ) {
return 0;
}
/* If we are returning a surrogate pair, initialize it to 0 */
if( high_surrogate ) {
*high_surrogate = 0;
}
/* We're not at the start of a character */
if( ( *utf8 & 0xC0 ) == 0x80 ) {
return 0;
}
if( *utf8 < 0x80 ) {
return ( webvtt_uint32 )( *utf8 );
}
while( utf8 < end ) {
webvtt_byte ch = *utf8;
utf8++;
if( need ) {
if( ( ch & 0xC0 ) == 0x80 ) {
uc = ( uc << 6 ) | ( ch & 0x3F );
if (!--need) {
int nc;
if ( !( nc = UTF_IS_NONCHAR( uc ) ) && uc > 0xFFFF && uc < 0x110000) {
/* Surrogate pair */
if( high_surrogate ) {
*high_surrogate = UTF_HIGH_SURROGATE( uc );
}
return UTF_LOW_SURROGATE( uc );
} else if ( ( uc < min ) || ( uc >= 0xD800 && uc <= 0xDFFF ) || nc || uc >= 0x110000) {
/* Non-character, overlong sequence, or utf16 surrogate */
return 0xFFFD;
} else {
/* Non-surrogate */
return uc;
}
}
}
} else {
if ( ( ch & 0xE0 ) == 0xC0 ) {
uc = ch & 0x1f;
need = 1;
min = 0x80;
} else if ( ( ch & 0xF0 ) == 0xE0 ) {
uc = ch & 0x0f;
need = 2;
min = 0x800;
} else if ( ( ch & 0xF8 ) == 0xF0 ) {
uc = ch & 0x07;
need = 3;
min = 0x10000;
} else {
/* TODO This should deal with 5-7 byte sequences */
/* return the replacement character in other cases */
return 0xFFFD;
}
}
}
return 0;
}
WEBVTT_EXPORT int
webvtt_utf8_chcount( const webvtt_byte *utf8, const webvtt_byte *end )
{
int n = 0;
const webvtt_byte *p;
if( !utf8 || !*utf8 || ( end != 0 && end < utf8 ) ) {
return 0;
}
if( !end ) {
end = utf8 + strlen( ( const char * )utf8 );
}
for( p = utf8; p < end; ++n ) {
int c = webvtt_utf8_length( p );
if( c < 1 ) {
break;
}
p += c;
}
return n;
}
WEBVTT_EXPORT int
webvtt_utf8_length( const webvtt_byte *utf8 )
{
webvtt_byte ch;
if( !utf8 ) {
return 0;
}
ch = *utf8;
if( ch < 0x80 ) {
return 1;
} else if( ( ch & 0xE0 ) == 0xC0 ) {
return 2;
} else if( ( ch & 0xF0 ) == 0xE0 ) {
return 3;
} else if( ( ch & 0xF8 ) == 0xF0 ) {
return 4;
} else if( ( ch & 0xFE ) == 0xFC ) {
return 5;
}
return -1;
}

View File

@ -0,0 +1,143 @@
/**
* 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 __INTERN_STRING_H__
# define __INTERN_STRING_H__
# include <webvtt/string.h>
# define UTF8_AMPERSAND (0x26)
# define UTF8_LESS_THAN (0x3C)
# define UTF8_GREATER_THAN (0x3E)
# define UTF8_HYPHEN_MINUS (0x2D)
# define UTF8_LEFT_TO_RIGHT_1 (0xE2)
# define UTF8_LEFT_TO_RIGHT_2 (0x80)
# define UTF8_LEFT_TO_RIGHT_3 (0x8E)
# define UTF8_RIGHT_TO_LEFT_1 (0xE2)
# define UTF8_RIGHT_TO_LEFT_2 (0x80)
# define UTF8_RIGHT_TO_LEFT_3 (0x8F)
# define UTF8_NO_BREAK_SPACE_1 (0xC2)
# define UTF8_NO_BREAK_SPACE_2 (0xA0)
# define UTF8_NULL_BYTE (0x00)
# define UTF8_COLON (0x3A)
# define UTF8_SEMI_COLON (0x3B)
# define UTF8_TAB (0x09)
# define UTF8_FORM_FEED (0x0C)
# define UTF8_LINE_FEED (0x0A)
# define UTF8_CARRIAGE_RETURN (0x0D)
# define UTF8_FULL_STOP (0x2E)
# define UTF8_SOLIDUS (0x2F)
# define UTF8_SPACE (0x20)
# define UTF8_DIGIT_ZERO (0x30)
# define UTF8_DIGIT_NINE (0x39)
# define UTF8_CAPITAL_A (0x41)
# define UTF8_CAPITAL_Z (0x5A)
# define UTF8_A (0x61)
# define UTF8_B (0x62)
# define UTF8_C (0x63)
# define UTF8_D (0x64)
# define UTF8_E (0x65)
# define UTF8_F (0x66)
# define UTF8_G (0x67)
# define UTF8_H (0x68)
# define UTF8_I (0x69)
# define UTF8_J (0x6A)
# define UTF8_K (0x6B)
# define UTF8_L (0x6C)
# define UTF8_M (0x6D)
# define UTF8_N (0x6E)
# define UTF8_O (0x6F)
# define UTF8_P (0x70)
# define UTF8_Q (0x71)
# define UTF8_R (0x72)
# define UTF8_S (0x73)
# define UTF8_T (0x74)
# define UTF8_U (0x75)
# define UTF8_V (0x76)
# define UTF8_W (0x77)
# define UTF8_X (0x78)
# define UTF8_Y (0x79)
# define UTF8_Z (0x7A)
/**
* Taken from ICU
* http://source.icu-project.org/repos/icu/icu/trunk/source/common/unicode/utf.h
*/
# define UTF_IS_NONCHAR( C ) \
( ( C )>=0xFDD0 && \
( ( webvtt_uint32 )( C ) <= 0xfdef || ( ( C ) & 0xFFFE)==0xFFFE) && \
( webvtt_uint32 )( C ) <= 0x10FFFF )
# define UTF_HIGH_SURROGATE( C ) ( webvtt_uint16 )( ( ( C ) >> 10 ) + 0xD7C0 )
# define UTF_LOW_SURROGATE( C ) ( webvtt_uint16 )( ( ( C ) & 0x3FF ) | 0xDC00 )
# ifndef WEBVTT_MAX_LINE
# define WEBVTT_MAX_LINE 0x10000
# endif
# ifdef WEBVTT_INLINE
# define __WEBVTT_STRING_INLINE WEBVTT_INLINE
# else
# define __WEBVTT_STRING_INLINE
# endif
struct
webvtt_string_data_t {
struct webvtt_refcount_t refs;
webvtt_uint32 alloc;
webvtt_uint32 length;
webvtt_byte *text;
webvtt_byte array[1];
};
static __WEBVTT_STRING_INLINE int
webvtt_isalpha( webvtt_byte ch )
{
return ( ( ( ch >= UTF8_CAPITAL_A ) && ( ch <= UTF8_CAPITAL_Z ) ) || ( ( ch >= UTF8_A ) && ( ch <= UTF8_Z ) ) );
}
static __WEBVTT_STRING_INLINE int
webvtt_isdigit( webvtt_byte ch )
{
return ( ( ch >= UTF8_DIGIT_ZERO ) && ( ch <= UTF8_DIGIT_NINE ) );
}
static __WEBVTT_STRING_INLINE int
webvtt_isalphanum( webvtt_byte ch )
{
return ( webvtt_isalpha( ch ) || webvtt_isdigit( ch ) );
}
static __WEBVTT_STRING_INLINE int
webvtt_iswhite( webvtt_byte ch )
{
return ( ( ch == UTF8_CARRIAGE_RETURN ) || ( ch == UTF8_LINE_FEED ) || ( ch == UTF8_FORM_FEED )
|| ( ch == UTF8_TAB ) || ( ch == UTF8_SPACE ) ) ;
}
# undef __WEBVTT_STRING_INLINE
#endif

79
media/webvtt/update.sh Normal file
View File

@ -0,0 +1,79 @@
#!/bin/sh
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Usage: ./update.sh <webvtt_git_repository> <optional revision/branch/refspec>
#
# Copies the needed files from a directory containing the original
# libwebvtt source, and applies any local patches we're carrying.
function die() {
echo "error: $1"
exit 1
}
if [ $# -lt 1 ]; then
die "Usage: update.sh /path/to/webvtt-repository/ commit/remote/branch (default HEAD)"
fi
git --version 2>&1 >/dev/null #executable not found? ok.
have_git=$?
hg --version 2>&1 >/dev/null #executable not found? ok.
have_hg=$?
if [ ${have_git} -ne 0 ]; then
die "Git does not seem to be installed"
fi
start_dir=$PWD
webvtt_branch=HEAD
if [ $# -gt 1 ]; then
webvtt_branch="$2"
fi
webvtt_dir=$(dirname $0)
webvtt_remote=$1
repo_dir=${webvtt_dir}/libwebvtt
cd ${webvtt_remote}
webvtt_isrepo=$(git rev-parse --is-inside-work-tree)
if [ "x${webvtt_isrepo}" != "xtrue" ]; then
cd ${start_dir}
die "$1 does not seem to be a git repository"
fi
webvtt_revision=$(git rev-parse ${webvtt_branch})
echo "Updating media/webvtt to revision ${webvtt_branch} (${webvtt_revision})"
#Ensure that ${repo_dir} is not present to prevent mkdir from failing
#Error hidden because most of the time it shouldn't be present anyways, so an
#error is generally expected.
rm -rf ${start_dir}/${repo_dir} 2>/dev/null
#Try to create temporary directory for repo archive. If this fails,
#print error and exit.
mkdir ${start_dir}/${repo_dir} || exit 1
git archive --format=tar ${webvtt_revision} | tar -C ${start_dir}/${repo_dir} -xf -
cd ${start_dir}
sed -e "s/^[a-z0-9]\{40,40\}/${webvtt_revision}/" \
${webvtt_dir}/README_MOZILLA > ${webvtt_dir}/README_MOZILLA.sed
mv ${webvtt_dir}/README_MOZILLA.sed ${webvtt_dir}/README_MOZILLA \
|| die "Failed to overwrite README_MOZILLA"
rm -rf ${webvtt_dir}/include ${webvtt_dir}/*.c ${webvtt_dir}/*.h
#Create directories
mkdir ${webvtt_dir}/include ${webvtt_dir}/include/webvtt
#Copy C headers, excluding 'webvtt-config' files (hence [^w])
find ${repo_dir}/include/webvtt -type f -name '[^w]*.h' -exec cp '{}' \
${webvtt_dir}/include/webvtt/ \; #Copy C sources
find ${repo_dir}/src/libwebvtt -type f -name '*.[ch]' -exec cp '{}' \
${webvtt_dir}/ \;
cp ${repo_dir}/LICENSE ${webvtt_dir}/
rm -rf ${repo_dir}
# addremove automatically if mercurial is used
if [ ${have_hg} -eq 0 -a -d ${start_dir}/.hg ]; then
hg addremove ${webvtt_dir}/
fi

View File

@ -141,6 +141,12 @@ tier_platform_dirs += \
$(NULL)
endif
ifdef MOZ_WEBVTT
tier_platform_dirs += \
media/webvtt \
$(NULL)
endif
ifdef MOZ_SYDNEYAUDIO
tier_platform_dirs += \
media/libsydneyaudio \

View File

@ -82,6 +82,9 @@ if CONFIG['MOZ_OPUS']:
if CONFIG['MOZ_WEBM']:
add_tier_dir('platform', 'media/libnestegg')
if CONFIG['MOZ_WEBVTT']:
add_tier_dir('platform', 'media/webvtt')
if CONFIG['MOZ_VP8'] and not CONFIG['MOZ_NATIVE_LIBVPX']:
add_tier_dir('platform', 'media/libvpx')