Bug 849189 - Update webvtt to recent upstream version. r=rillian
authorJacek Caban <jacek@codeweavers.com>
Fri, 08 Mar 2013 03:47:00 -0800
changeset 134669 aa90108b8074f72d0b87fc008edb69a5d604a85e
parent 134668 aa858d84b69e1a40ca8c99177338d8ecd48b3982
child 134670 8e941dae46ba131d75cd57b0b00eec664c7b88ea
push id2452
push userlsblakk@mozilla.com
push dateMon, 13 May 2013 16:59:38 +0000
treeherdermozilla-beta@d4b152d29d8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs849189
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 849189 - Update webvtt to recent upstream version. r=rillian
media/webvtt/LICENSE
media/webvtt/Makefile.in
media/webvtt/README_MOZILLA
media/webvtt/alloc.c
media/webvtt/cue.c
media/webvtt/cue_internal.h
media/webvtt/cuetext.c
media/webvtt/cuetext_internal.h
media/webvtt/error.c
media/webvtt/include/webvtt/cue.h
media/webvtt/include/webvtt/node.h
media/webvtt/include/webvtt/string.h
media/webvtt/include/webvtt/util.h
media/webvtt/node.c
media/webvtt/node_internal.h
media/webvtt/parser.c
media/webvtt/parser_internal.h
media/webvtt/string.c
--- a/media/webvtt/LICENSE
+++ b/media/webvtt/LICENSE
@@ -1,25 +1,25 @@
-Copyright (c) 2013 Mozilla Foundation and Contributors
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- - Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+Copyright (c) 2013 Mozilla Foundation and Contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ - Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
--- a/media/webvtt/Makefile.in
+++ b/media/webvtt/Makefile.in
@@ -17,24 +17,26 @@ 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/node.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 \
+  node.c \
   parser.c \
   string.c \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/media/webvtt/README_MOZILLA
+++ b/media/webvtt/README_MOZILLA
@@ -1,7 +1,7 @@
 These files are from the WebVTT library, and are extracted from rev
-cd5e95654f1fd6712fcf1941f8936870a484f65e of the git repository at
+6b637c9f30911433e6d5a5be5d8512317a0d8a14 of the git repository at
 https://github.com/mozilla/webvtt.
 
 The following CPPFLAGS are used in order to build and link in Mozilla
 -DWEBVTT_NO_CONFIG_H=1 -- Prevent inclusion of generated headers
 -DWEBVTT_STATIC=1      -- Compile as a static library
--- a/media/webvtt/alloc.c
+++ b/media/webvtt/alloc.c
@@ -21,21 +21,17 @@
  * 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 
--- a/media/webvtt/cue.c
+++ b/media/webvtt/cue.c
@@ -20,18 +20,16 @@
  * 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 ) {
@@ -112,196 +110,8 @@ webvtt_validate_cue( webvtt_cue *cue )
      * 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;
-}
--- a/media/webvtt/cue_internal.h
+++ b/media/webvtt/cue_internal.h
@@ -22,47 +22,34 @@
  * 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,
+  CUE_HEADER_MASK = CUE_HAVE_CUEPARAMS|CUE_HAVE_ID,
 };
 
+static webvtt_bool
+cue_is_incomplete( const webvtt_cue *cue ) {
+  return !cue || ( cue->flags & CUE_HEADER_MASK ) == CUE_HAVE_ID;
+}
+
 #endif
--- a/media/webvtt/cuetext.c
+++ b/media/webvtt/cuetext.c
@@ -76,96 +76,96 @@ 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_create_token( webvtt_cuetext_token **token, webvtt_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_create_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name,
     webvtt_stringlist *css_classes, webvtt_string *annotation )
 {
   webvtt_status status;
-  webvtt_cuetext_start_token_data sd;
+  webvtt_start_token_data sd;
   
-  if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, START_TOKEN ) ) ) {
+  if( WEBVTT_FAILED( status = webvtt_create_token( token, START_TOKEN ) ) ) {
     return status;
   }
   
   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_create_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name )
 {
   webvtt_status status;
 
-  if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, END_TOKEN ) ) ) {
+  if( WEBVTT_FAILED( status = webvtt_create_token( token, END_TOKEN ) ) ) {
     return status;
   }
 
   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_create_text_token( webvtt_cuetext_token **token, webvtt_string *text )
 {
   webvtt_status status;
 
-  if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, TEXT_TOKEN ) ) ) {
+  if( WEBVTT_FAILED( status = webvtt_create_token( token, TEXT_TOKEN ) ) ) {
     return status;
   }
 
   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_create_timestamp_token( webvtt_cuetext_token **token, webvtt_timestamp time_stamp )
 {
   webvtt_status status;
 
-  if( WEBVTT_FAILED( status = webvtt_create_cuetext_token( token, TIME_STAMP_TOKEN ) ) ) {
+  if( WEBVTT_FAILED( status = webvtt_create_token( token, TIME_STAMP_TOKEN ) ) ) {
     return status;
   }
 
   (*token)->time_stamp = time_stamp;
 
   return WEBVTT_SUCCESS;
 }
 
 WEBVTT_INTERN void
-webvtt_delete_cuetext_token( webvtt_cuetext_token **token )
+webvtt_delete_token( webvtt_cuetext_token **token )
 {
-  webvtt_cuetext_start_token_data data;
+  webvtt_start_token_data data;
   webvtt_cuetext_token *t;
   
   if( !token ) {
     return;
   }
   if( !*token ) {
     return;
   }  
@@ -188,41 +188,24 @@ webvtt_delete_cuetext_token( webvtt_cuet
     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;
+  return webvtt_string_is_equal( tag_name, "v", 1 );
 }
 
-/**
- * Definitions for tag tokens that are more then one character long.
- */
-#define RUBY_TAG_LENGTH 4
-#define RUBY_TEXT_TAG_LENGTH 2
-
-webvtt_byte ruby_tag[RUBY_TAG_LENGTH] = { UTF8_R, UTF8_U, UTF8_B, UTF8_Y };
-webvtt_byte rt_tag[RUBY_TEXT_TAG_LENGTH] = { UTF8_R, UTF8_T };
-
 WEBVTT_INTERN webvtt_status
-webvtt_get_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind )
+webvtt_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind )
 {
   if( !tag_name || !kind ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   if( webvtt_string_length(tag_name) == 1 ) {
     switch( webvtt_string_text(tag_name)[0] ) {
       case( UTF8_B ):
@@ -236,19 +219,19 @@ webvtt_get_node_kind_from_tag_name( webv
         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 ) {
+  } else if( webvtt_string_is_equal( tag_name, "ruby", 4 ) ) {
     *kind = WEBVTT_RUBY;
-  } else if( memcmp( webvtt_string_text(tag_name), rt_tag, min(webvtt_string_length(tag_name), RUBY_TEXT_TAG_LENGTH) ) == 0 ) {
+  } else if( webvtt_string_is_equal( tag_name, "rt", 2 ) ) {
     *kind = WEBVTT_RUBY_TEXT;
   } else {
     return WEBVTT_INVALID_TAG_NAME;
   }
 
   return WEBVTT_SUCCESS;
 }
 
@@ -267,37 +250,37 @@ webvtt_create_node_from_token( webvtt_cu
    * 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 );
+      return webvtt_create_text_node( node, parent, &token->text );
       break;
     case( START_TOKEN ):
 
-      CHECK_MEMORY_OP( webvtt_get_node_kind_from_tag_name( &token->tag_name, &kind) );
+      CHECK_MEMORY_OP( webvtt_node_kind_from_tag_name( &token->tag_name, &kind) );
 
       return webvtt_create_internal_node( node, parent, kind,
         token->start_token_data.css_classes, &token->start_token_data.annotations );
 
       break;
     case ( TIME_STAMP_TOKEN ):
-      return webvtt_create_time_stamp_leaf_node( node, parent, token->time_stamp );
+      return webvtt_create_timestamp_node( node, parent, token->time_stamp );
       break;
     default:
       return WEBVTT_INVALID_TOKEN_TYPE;
   }
 }
 
 WEBVTT_INTERN webvtt_status
-webvtt_cuetext_tokenizer_data_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *result )
+webvtt_data_state( webvtt_byte **position, webvtt_token_state *token_state, 
+                   webvtt_string *result )
 {
   for ( ; *token_state == DATA; (*position)++ ) {
     switch( **position ) {
       case UTF8_AMPERSAND:
         *token_state = ESCAPE;
         break;
       case UTF8_LESS_THAN:
         if( webvtt_string_length(result) == 0 ) {
@@ -314,46 +297,32 @@ webvtt_cuetext_tokenizer_data_state( web
         break;
     }
   }
 
   return WEBVTT_UNFINISHED;
 }
 
 /**
- * Definitions for valid escape values.
- * The semicolon is implicit in the comparison.
+ * Definitions for escape sequence replacement strings.
  */
-#define AMP_ESCAPE_LENGTH     4
-#define LT_ESCAPE_LENGTH      3
-#define GT_ESCAPE_LENGTH      3
-#define RLM_ESCAPE_LENGTH     4
-#define LRM_ESCAPE_LENGTH     4
-#define NBSP_ESCAPE_LENGTH    5
 #define RLM_REPLACE_LENGTH    3
 #define LRM_REPLACE_LENGTH    3
 #define NBSP_REPLACE_LENGTH   2
  
-webvtt_byte amp_escape[AMP_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_A, UTF8_M, UTF8_P };
-webvtt_byte lt_escape[LT_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_L, UTF8_T };
-webvtt_byte gt_escape[GT_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_G, UTF8_T };
-webvtt_byte rlm_escape[RLM_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_R, UTF8_L, UTF8_M };
-webvtt_byte lrm_escape[LRM_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_L, UTF8_R, UTF8_M };
-webvtt_byte nbsp_escape[NBSP_ESCAPE_LENGTH] = { UTF8_AMPERSAND, UTF8_N, UTF8_B, UTF8_S, UTF8_P };
-
 webvtt_byte rlm_replace[RLM_REPLACE_LENGTH] = { UTF8_RIGHT_TO_LEFT_1, 
     UTF8_RIGHT_TO_LEFT_2, UTF8_RIGHT_TO_LEFT_3 };
 webvtt_byte lrm_replace[LRM_REPLACE_LENGTH] = { UTF8_LEFT_TO_RIGHT_1,
   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_escape_state( webvtt_byte **position, webvtt_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
@@ -382,63 +351,65 @@ webvtt_cuetext_tokenizer_escape_state( w
       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 ) {
+      if( webvtt_string_is_equal( &buffer, "&amp", 4 ) ) {
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '&' ) );
+      } else if( webvtt_string_is_equal( &buffer, "&lt", 3 ) ) {
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '<' ) );
+      } else if( webvtt_string_is_equal( &buffer, "&gt", 3 ) ) {
+        CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, '>' ) );
+      } else if( webvtt_string_is_equal( &buffer, "&rlm", 4 ) ) {
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, rlm_replace, RLM_REPLACE_LENGTH ) );
-      } else if( memcmp( webvtt_string_text(&buffer), lrm_escape, min(webvtt_string_length(&buffer), LRM_ESCAPE_LENGTH) ) == 0 ) {
+      } else if( webvtt_string_is_equal( &buffer, "&lrm", 4 ) ) {
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, lrm_replace, LRM_REPLACE_LENGTH ) );
-      } else if( memcmp( webvtt_string_text(&buffer), nbsp_escape, min(webvtt_string_length(&buffer), NBSP_ESCAPE_LENGTH) ) == 0 ) {
+      } else if( webvtt_string_is_equal( &buffer, "&nbsp", 5 ) ) {
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_append( result, nbsp_replace, NBSP_REPLACE_LENGTH ) );
       } else {
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_append_string( result, &buffer ) );
         CHECK_MEMORY_OP_JUMP( status, webvtt_string_putc( result, **position ) );
       }
 
       *token_state = DATA;
+      status = WEBVTT_UNFINISHED;
     }
     /**
      * 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 ) );
+      status = WEBVTT_UNFINISHED;
       *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 )
+webvtt_tag_state( webvtt_byte **position, webvtt_token_state *token_state, 
+                  webvtt_string *result )
 {
   for( ; *token_state == TAG; (*position)++ ) {
     if( **position == UTF8_TAB || **position == UTF8_LINE_FEED ||
         **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 ) );
@@ -463,18 +434,18 @@ webvtt_cuetext_tokenizer_tag_state( webv
       }
     }
   }
 
   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 )
+webvtt_start_tag_state( webvtt_byte **position, webvtt_token_state *token_state, 
+                        webvtt_string *result )
 {
   for( ; *token_state == START_TAG; (*position)++ ) {
     if( **position == UTF8_TAB || **position == UTF8_FORM_FEED ||
         **position == UTF8_SPACE || **position == UTF8_LINE_FEED ||
         **position == UTF8_CARRIAGE_RETURN ) {
       *token_state = START_TAG_ANNOTATION;
     } else {
       switch( **position ) {
@@ -493,18 +464,18 @@ webvtt_cuetext_tokenizer_start_tag_state
       }
     }
   }
 
   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_class_state( webvtt_byte **position, webvtt_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 ||
@@ -528,46 +499,46 @@ webvtt_cuetext_tokenizer_start_tag_class
 
 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 )
+webvtt_annotation_state( webvtt_byte **position, webvtt_token_state *token_state, 
+                         webvtt_string *annotation )
 {
   for( ; *token_state == START_TAG_ANNOTATION; (*position)++ ) {
     if( **position == UTF8_NULL_BYTE || **position == UTF8_GREATER_THAN ) {
       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 )
+webvtt_end_tag_state( webvtt_byte **position, webvtt_token_state *token_state, 
+                      webvtt_string *result )
 {
   for( ; *token_state == END_TAG; (*position)++ ) {
     if( **position == UTF8_GREATER_THAN || **position == UTF8_NULL_BYTE ) {
       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 )
+webvtt_timestamp_state( webvtt_byte **position, webvtt_token_state *token_state, 
+                        webvtt_string *result )
 {
   for( ; *token_state == TIME_STAMP_TAG; (*position)++ ) {
     if( **position == UTF8_GREATER_THAN || **position == UTF8_NULL_BYTE ) {
       return WEBVTT_SUCCESS;
     }
     CHECK_MEMORY_OP( webvtt_string_putc( result, **position ) );
   }
 
@@ -576,17 +547,17 @@ webvtt_cuetext_tokenizer_time_stamp_tag_
 
 /**
  * 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_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;
   }
@@ -599,38 +570,38 @@ webvtt_cuetext_tokenizer( webvtt_byte **
    * 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 );
+        status = webvtt_data_state( position, &token_state, &result );
         break;
       case ESCAPE:
-        status = webvtt_cuetext_tokenizer_escape_state( position, &token_state, &result );
+        status = webvtt_escape_state( position, &token_state, &result );
         break;
       case TAG:
-        status = webvtt_cuetext_tokenizer_tag_state( position, &token_state, &result );
+        status = webvtt_tag_state( position, &token_state, &result );
         break;
       case START_TAG:
-        status = webvtt_cuetext_tokenizer_start_tag_state( position, &token_state, &result );
+        status = webvtt_start_tag_state( position, &token_state, &result );
         break;
       case START_TAG_CLASS:
-        status = webvtt_cuetext_tokenizer_start_tag_class_state( position, &token_state, css_classes );
+        status = webvtt_class_state( position, &token_state, css_classes );
         break;
       case START_TAG_ANNOTATION:
-        status = webvtt_cuetext_tokenizer_start_tag_annotation_state( position, &token_state, &annotation );
+        status = webvtt_annotation_state( position, &token_state, &annotation );
         break;
       case END_TAG:
-        status = webvtt_cuetext_tokenizer_end_tag_state( position, &token_state, &result );
+        status = webvtt_end_tag_state( position, &token_state, &result );
         break;
       case TIME_STAMP_TAG:
-        status = webvtt_cuetext_tokenizer_time_stamp_tag_state( position, &token_state, &result );
+        status = webvtt_timestamp_state( position, &token_state, &result );
         break;
     }
 
     if( token_state == START_TAG_ANNOTATION ) {
       webvtt_skipwhite( position );
     }
   }
 
@@ -638,33 +609,33 @@ webvtt_cuetext_tokenizer( webvtt_byte **
   { (*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 );
+      status = webvtt_create_text_token( token, &result );
     } else if(token_state == TAG || token_state == START_TAG || token_state == START_TAG_CLASS ||
               token_state == START_TAG_ANNOTATION) {
       /**
       * 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 );
+      status = webvtt_create_start_token( token, &result, css_classes, &annotation );
     } else if( token_state == END_TAG ) {
-      status = webvtt_create_cuetext_end_token( token, &result );
+      status = webvtt_create_end_token( token, &result );
     } else if( token_state == TIME_STAMP_TAG ) {
       parse_timestamp( webvtt_string_text( &result ), &time_stamp );
-      status = webvtt_create_cuetext_timestamp_token( token, time_stamp );
+      status = webvtt_create_timestamp_token( token, time_stamp );
     } else {
       status = WEBVTT_INVALID_TOKEN_STATE;
     }
   }
   
   webvtt_release_stringlist( &css_classes );
   webvtt_release_string( &result );
   webvtt_release_string( &annotation );
@@ -711,17 +682,17 @@ webvtt_parse_cuetext( webvtt_parser self
   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 );
+    webvtt_delete_token( &token );
 
     /* Step 7. */
     switch( webvtt_cuetext_tokenizer( &position, &token ) ) {
       case( WEBVTT_UNFINISHED ):
         /* Error here. */
         break;
         /* Step 8. */
       case( WEBVTT_SUCCESS ):
@@ -740,17 +711,17 @@ webvtt_parse_cuetext( webvtt_parser self
           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 ) {
+          if( webvtt_node_kind_from_tag_name( &token->tag_name, &kind ) == WEBVTT_INVALID_TAG_NAME ) {
             continue;
           }
 
           /**
            * We have encountered an end token and it matches the start token of
            * the node that we are currently on. Move back up the list of nodes
            * and continue parsing.
            */
@@ -764,27 +735,27 @@ webvtt_parse_cuetext( webvtt_parser self
            * 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 );
+            webvtt_attach_node( current_node, temp_node );
             
             if( WEBVTT_IS_VALID_INTERNAL_NODE( temp_node->kind ) ) { 
               current_node = temp_node; 
             }
             
             /* Release the node as attach internal node increases the count. */
             webvtt_release_node( &temp_node );
           }
         }
         break;
     }
     webvtt_skipwhite( &position );
   }
   
-  webvtt_delete_cuetext_token( &token );
+  webvtt_delete_token( &token );
   
   return WEBVTT_SUCCESS;
 }
--- a/media/webvtt/cuetext_internal.h
+++ b/media/webvtt/cuetext_internal.h
@@ -26,38 +26,38 @@
  */
 
 #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 enum webvtt_token_type_t webvtt_token_type;
+typedef enum webvtt_token_state_t webvtt_token_state;
 
 typedef struct webvtt_cuetext_token_t webvtt_cuetext_token;
-typedef struct webvtt_cuetext_start_token_data_t webvtt_cuetext_start_token_data;
+typedef struct webvtt_start_token_data_t webvtt_start_token_data;
 
 /**
  * Enumerates token types.
  */
 enum
-webvtt_cuetext_token_type_t {
+webvtt_token_type_t {
   START_TOKEN, /* Identifies a webvtt_cue_text_start_tag_token. */
   END_TOKEN, /* Identifies a webvtt_cue_text_end_tag_token. */
   TIME_STAMP_TOKEN, /* Identifies a webvtt_cue_text_time_stamp_token. */
   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 {
+webvtt_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
@@ -70,126 +70,126 @@ webvtt_cuetext_token_state_t {
 };
 
 /**
  * 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_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_token_type token_type;
   webvtt_string tag_name; // Only used for start token and end token types.
   union {
     webvtt_string text;
     webvtt_timestamp time_stamp;
-    webvtt_cuetext_start_token_data start_token_data;
+    webvtt_start_token_data start_token_data;
   };
 };
 
 /**
  * Routines for creating cue text tokens.
  * Sets the passed token to the new token.
  */
-WEBVTT_INTERN webvtt_status webvtt_create_cuetext_token( webvtt_cuetext_token **token, webvtt_cuetext_token_type token_type );
-WEBVTT_INTERN webvtt_status webvtt_create_cuetext_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name,
+WEBVTT_INTERN webvtt_status webvtt_create_token( webvtt_cuetext_token **token, webvtt_token_type token_type );
+WEBVTT_INTERN webvtt_status webvtt_create_start_token( webvtt_cuetext_token **token, webvtt_string *tag_name,
     webvtt_stringlist *css_classes, webvtt_string *annotation );
-WEBVTT_INTERN webvtt_status webvtt_create_cuetext_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name );
-WEBVTT_INTERN webvtt_status webvtt_create_cuetext_text_token( webvtt_cuetext_token **token, webvtt_string *text );
-WEBVTT_INTERN webvtt_status webvtt_create_cuetext_timestamp_token( webvtt_cuetext_token **token,
+WEBVTT_INTERN webvtt_status webvtt_create_end_token( webvtt_cuetext_token **token, webvtt_string *tag_name );
+WEBVTT_INTERN webvtt_status webvtt_create_text_token( webvtt_cuetext_token **token, webvtt_string *text );
+WEBVTT_INTERN webvtt_status webvtt_create_timestamp_token( webvtt_cuetext_token **token,
     webvtt_timestamp time_stamp );
 
 /**
  * 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 );
+WEBVTT_INTERN void webvtt_delete_token( webvtt_cuetext_token **token );
 
 /**
  * Converts the textual representation of a node kind into a particular kind.
  * I.E. tag_name of 'ruby' would create a ruby kind, etc.
  * Returns a WEBVTT_NOT_SUPPORTED if it does not find a valid tag name.
  */
-WEBVTT_INTERN webvtt_status webvtt_get_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind );
+WEBVTT_INTERN webvtt_status webvtt_node_kind_from_tag_name( webvtt_string *tag_name, webvtt_node_kind *kind );
 
 /**
  * Creates a node from a valid token.
  * 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 );
+WEBVTT_INTERN webvtt_status webvtt_tokenizer( webvtt_byte **position, webvtt_cuetext_token **token );
 
 /**
  * Routines that take care of certain states in the webvtt cue text tokenizer.
  */
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-data-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_data_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status webvtt_data_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-escape-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_escape_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status webvtt_escape_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_tag_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status webvtt_tag_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-start-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_start_tag_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status webvtt_start_tag_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-start-tag-class-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_start_tag_class_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_stringlist *css_classes );
+WEBVTT_INTERN webvtt_status webvtt_class_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_stringlist *css_classes );
 
 /**
  * Referenced from 
  * http://dev.w3.org/html5/webvtt/#webvtt-start-tag-annotation-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_start_tag_annotation_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *annotation );
+WEBVTT_INTERN webvtt_status webvtt_annotation_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_string *annotation );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-end-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_end_tag_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status webvtt_end_tag_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_string *result );
 
 /**
  * Referenced from http://dev.w3.org/html5/webvtt/#webvtt-timestamp-tag-state
  */
-WEBVTT_INTERN webvtt_status webvtt_cuetext_tokenizer_time_stamp_tag_state( webvtt_byte **position,
-  webvtt_cuetext_token_state *token_state, webvtt_string *result );
+WEBVTT_INTERN webvtt_status webvtt_timestamp_state( webvtt_byte **position,
+  webvtt_token_state *token_state, webvtt_string *result );
 
 WEBVTT_INTERN webvtt_status webvtt_parse_cuetext( webvtt_parser self, webvtt_cue *cue, webvtt_string *payload, int finished );
 
 #endif
--- a/media/webvtt/error.c
+++ b/media/webvtt/error.c
@@ -61,15 +61,15 @@ static const char *errstr[] = {
 
 /**
  * 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 )
+webvtt_strerror( webvtt_error err )
 {
-  if( errno >= (sizeof(errstr) / sizeof(*errstr)) ) {
+  if( err >= (sizeof(errstr) / sizeof(*errstr)) ) {
     return "";
   }
-  return errstr[ errno ];
+  return errstr[ err ];
 }
--- a/media/webvtt/include/webvtt/cue.h
+++ b/media/webvtt/include/webvtt/cue.h
@@ -24,87 +24,26 @@
  * (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>
+# include <webvtt/node.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 {
@@ -112,49 +51,16 @@ webvtt_align_type_t {
   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;
 
new file mode 100644
--- /dev/null
+++ b/media/webvtt/include/webvtt/node.h
@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) 2013 Mozilla Foundation and Contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+#ifndef __WEBVTT_NODE_H__
+# define __WEBVTT_NODE_H__
+# include <webvtt/string.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+webvtt_node_kind_t {
+  WEBVTT_NODE_LEAF = 0x80000000,
+  WEBVTT_NODE_INTERNAL = 0x00000000,
+
+  /**
+    * Internal Node objects
+    */
+  WEBVTT_NODE_INTERNAL_START = 0,
+  WEBVTT_CLASS = 0 | WEBVTT_NODE_INTERNAL,
+  WEBVTT_ITALIC = 1 | WEBVTT_NODE_INTERNAL,
+  WEBVTT_BOLD = 2 | WEBVTT_NODE_INTERNAL,
+  WEBVTT_UNDERLINE = 3 | WEBVTT_NODE_INTERNAL,
+  WEBVTT_RUBY = 4 | WEBVTT_NODE_INTERNAL,
+  WEBVTT_RUBY_TEXT = 5 | WEBVTT_NODE_INTERNAL,
+  WEBVTT_VOICE = 6 | WEBVTT_NODE_INTERNAL,
+
+  /**
+    * This type of node has should not be rendered.
+    * It is the top of the node list and only contains a list of nodes.
+    */
+  WEBVTT_HEAD_NODE = 7,
+
+  WEBVTT_NODE_INTERNAL_END = 7,
+
+  /**
+    * Leaf Node objects
+    */
+  WEBVTT_NODE_LEAF_START = 256,
+  WEBVTT_TEXT = 256 | WEBVTT_NODE_LEAF,
+  WEBVTT_TIME_STAMP = 257 | WEBVTT_NODE_LEAF,
+
+  WEBVTT_NODE_LEAF_END = 257,
+
+  /* An empty initial state for a node */
+  WEBVTT_EMPTY_NODE = 258
+} webvtt_node_kind;
+
+#define WEBVTT_IS_LEAF(Kind) ( ((Kind) & WEBVTT_NODE_LEAF) != 0 )
+#define WEBVTT_NODE_INDEX(Kind) ( (Kind) & ~WEBVTT_NODE_LEAF )
+#define WEBVTT_IS_VALID_LEAF_NODE(Kind) ( WEBVTT_IS_LEAF(Kind) && (WEBVTT_NODE_INDEX(Kind) >= WEBVTT_NODE_LEAF_START && WEBVTT_NODE_INDEX(Kind) <= WEBVTT_NODE_LEAF_END ) )
+#define WEBVTT_IS_VALID_INTERNAL_NODE(Kind) ( (!WEBVTT_IS_LEAF(Kind)) && (WEBVTT_NODE_INDEX(Kind) >= WEBVTT_NODE_INTERNAL_START && WEBVTT_NODE_INDEX(Kind) <= WEBVTT_NODE_INTERNAL_END) )
+#define WEBVTT_IS_VALID_NODE_KIND(Kind) ( WEBVTT_IS_VALID_INTERNAL_NODE(Kind) || WEBVTT_IS_VALID_LEAF_NODE(Kind) )
+
+struct webvtt_internal_node_data_t;
+
+typedef struct
+webvtt_node_t {
+
+  struct webvtt_refcount_t refs;
+  /**
+    * The specification asks for uni directional linked list, but we have added 
+    * a parent node in order to facilitate an iterative cue text parsing 
+    * solution.
+    */
+  struct webvtt_node_t *parent;
+  webvtt_node_kind kind;
+
+  union {
+    webvtt_string text;
+    webvtt_timestamp timestamp;
+    struct webvtt_internal_node_data_t *internal_data;
+  } data;
+} webvtt_node;
+
+typedef struct
+webvtt_internal_node_data_t {
+  webvtt_string annotation;
+  webvtt_stringlist *css_classes;
+
+  webvtt_uint alloc;
+  webvtt_uint length;
+  webvtt_node **children;
+} webvtt_internal_node_data;
+
+WEBVTT_EXPORT void webvtt_init_node( webvtt_node **node );
+WEBVTT_EXPORT void webvtt_ref_node( webvtt_node *node );
+WEBVTT_EXPORT void webvtt_release_node( webvtt_node **node );
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
--- a/media/webvtt/include/webvtt/string.h
+++ b/media/webvtt/include/webvtt/string.h
@@ -146,16 +146,25 @@ WEBVTT_EXPORT int webvtt_string_getline(
 
 /**
  * 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_is_equal
+ *
+ * compare a string's text to a byte array
+ *
+ */
+WEBVTT_EXPORT webvtt_bool webvtt_string_is_equal( webvtt_string *str, webvtt_byte *to_compare, webvtt_uint len );
+
 /**
  * webvtt_string_append
  *
  * 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 );
--- a/media/webvtt/include/webvtt/util.h
+++ b/media/webvtt/include/webvtt/util.h
@@ -187,16 +187,27 @@ extern "C" {
      * 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,
+
+    /*
+     * Match is not found in a search query
+     */
+     WEBVTT_NO_MATCH_FOUND = -13,
+
+    /**
+     * Thrown when assertions fail and FATAL_ASSERTION
+     * is not defined.
+     */
+    WEBVTT_FAILED_ASSERTION = -14,
   };
 
   typedef enum webvtt_status_t webvtt_status;
 
   /**
    * Macros to filter out webvtt status returns.
    */
 # define WEBVTT_FAILED(status) ( (status) != WEBVTT_SUCCESS )
new file mode 100644
--- /dev/null
+++ b/media/webvtt/node.c
@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2013 Mozilla Foundation and Contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+ #include <string.h>
+ #include <stdlib.h>
+ #include "node_internal.h"
+ 
+ static webvtt_node empty_node = {
+  { 1 }, /* init ref count */
+  0, /* parent */
+  WEBVTT_EMPTY_NODE /* node kind */
+};
+
+WEBVTT_EXPORT void
+webvtt_ref_node( webvtt_node *node )
+{
+  if( node ) {
+    webvtt_ref( &node->refs );
+  }
+}
+
+WEBVTT_EXPORT void 
+webvtt_init_node( webvtt_node **node )
+{
+  if( *node != &empty_node ) {
+    if( node && *node ) { 
+      webvtt_release_node( node );
+    }
+    *node = &empty_node;
+    webvtt_ref_node( *node );
+  }
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent )
+{
+  webvtt_node *temp_node;
+
+  if( !node ) {
+    return WEBVTT_INVALID_PARAM;
+  }
+
+  if( !( temp_node = (webvtt_node *)webvtt_alloc0(sizeof(*temp_node)) ) )
+  {
+    return WEBVTT_OUT_OF_MEMORY;
+  }
+
+  webvtt_ref_node( temp_node );
+  temp_node->kind = kind;
+  temp_node->parent = parent;
+  *node = temp_node;
+
+  return WEBVTT_SUCCESS;
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, 
+  webvtt_stringlist *css_classes, webvtt_string *annotation )
+{
+  webvtt_status status;
+  webvtt_internal_node_data *node_data;
+
+  if( WEBVTT_FAILED( status = webvtt_create_node( node, kind, parent ) ) ) {
+    return status;
+  }
+
+  if ( !( node_data = (webvtt_internal_node_data *)webvtt_alloc0( sizeof(*node_data) ) ) )
+  {
+    return WEBVTT_OUT_OF_MEMORY;
+  }
+
+  webvtt_copy_stringlist( &node_data->css_classes, css_classes );
+  webvtt_copy_string( &node_data->annotation, annotation );
+  node_data->children = NULL;
+  node_data->length = 0;
+  node_data->alloc = 0;
+
+  (*node)->data.internal_data = node_data;
+
+  return WEBVTT_SUCCESS;
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_head_node( webvtt_node **node )
+{
+  webvtt_status status;
+  webvtt_string temp_annotation;
+
+  webvtt_init_string( &temp_annotation );
+  if( WEBVTT_FAILED( status = webvtt_create_internal_node( node, NULL, WEBVTT_HEAD_NODE, NULL, &temp_annotation ) ) ) {
+    return status;
+  }
+
+  return WEBVTT_SUCCESS;
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp )
+{
+  webvtt_status status;
+
+  if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TIME_STAMP, parent ) ) ) {
+    return status;
+  }
+
+  (*node)->data.timestamp = time_stamp;
+
+  return WEBVTT_SUCCESS;
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_create_text_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text )
+{
+  webvtt_status status;
+
+  if( WEBVTT_FAILED( status = webvtt_create_node( node, WEBVTT_TEXT, parent ) ) ) {
+    return status;
+  }
+
+  webvtt_copy_string( &(*node)->data.text, text );
+
+  return WEBVTT_SUCCESS;
+
+}
+
+WEBVTT_EXPORT void 
+webvtt_release_node( webvtt_node **node )
+{
+  webvtt_uint i;
+  webvtt_node *n;
+  
+  if( !node || !*node ) {
+    return;
+  }
+  n = *node;
+
+  if( webvtt_deref( &n->refs )  == 0 ) {
+    if( n->kind == WEBVTT_TEXT ) {
+        webvtt_release_string( &n->data.text );
+    } else if( WEBVTT_IS_VALID_INTERNAL_NODE( n->kind ) && n->data.internal_data ) {
+      webvtt_release_stringlist( &n->data.internal_data->css_classes );
+      webvtt_release_string( &n->data.internal_data->annotation );
+      for( i = 0; i < n->data.internal_data->length; i++ ) {
+        webvtt_release_node( n->data.internal_data->children + i );
+      }
+      webvtt_free( n->data.internal_data->children );
+      webvtt_free( n->data.internal_data );
+    }
+    webvtt_free( n );
+  }
+  *node = 0;
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_attach_node( webvtt_node *parent, webvtt_node *to_attach )
+{
+  webvtt_node **next = 0;
+  webvtt_internal_node_data *nd = 0;
+  
+  if( !parent || !to_attach || !parent->data.internal_data ) {
+    return WEBVTT_INVALID_PARAM;
+  }
+  nd = parent->data.internal_data;
+  
+  if( nd->alloc == 0 ) {
+    next = (webvtt_node **)webvtt_alloc0( sizeof( webvtt_node * ) * 8 );
+    
+    if( !next ) {
+      return WEBVTT_OUT_OF_MEMORY;
+    }
+    
+    nd->children = next;
+    nd->alloc = 8;
+  }
+  
+  if( nd->length + 1 >= ( nd->alloc / 3 ) * 2 ) {
+
+    next = (webvtt_node **)webvtt_alloc0( sizeof( *next ) * nd->alloc * 2 );
+    
+    if( !next ) {
+      return WEBVTT_OUT_OF_MEMORY;
+    }
+
+    nd->alloc *= 2;
+    memcpy( next, nd->children, nd->length * sizeof( webvtt_node * ) );
+    webvtt_free( nd->children );
+    nd->children = next;
+  }
+
+  nd->children[ nd->length++ ] = to_attach;
+  webvtt_ref_node( to_attach );
+
+  return WEBVTT_SUCCESS;
+}
new file mode 100644
--- /dev/null
+++ b/media/webvtt/node_internal.h
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2013 Mozilla Foundation and Contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+#ifndef __WEBVTT_NODE_INTERNAL_H__
+# define __WEBVTT_NODE_INTERNAL_H__
+# include <webvtt/node.h>
+
+/**
+ * Routines for creating nodes.
+ */
+WEBVTT_INTERN webvtt_status webvtt_create_node( webvtt_node **node, webvtt_node_kind kind, webvtt_node *parent );
+WEBVTT_INTERN webvtt_status webvtt_create_internal_node( webvtt_node **node, webvtt_node *parent, webvtt_node_kind kind, webvtt_stringlist *css_classes, webvtt_string *annotation );
+/**
+ * We probably shouldn't have a 'head node' type.
+ * We should just return a list of node trees...
+ */
+WEBVTT_INTERN webvtt_status webvtt_create_head_node( webvtt_node **node );
+WEBVTT_INTERN webvtt_status webvtt_create_timestamp_node( webvtt_node **node, webvtt_node *parent, webvtt_timestamp time_stamp );
+WEBVTT_INTERN webvtt_status webvtt_create_text_node( webvtt_node **node, webvtt_node *parent, webvtt_string *text );
+
+/**
+ * Attaches a node to the internal node list of another node.
+ */
+WEBVTT_INTERN webvtt_status webvtt_attach_node( webvtt_node *parent, webvtt_node *to_attach );
+
+#endif
--- a/media/webvtt/parser.c
+++ b/media/webvtt/parser.c
@@ -37,19 +37,23 @@ static const webvtt_byte separator[] = {
 };
 
 #define MSECS_PER_HOUR (3600000)
 #define MSECS_PER_MINUTE (60000)
 #define MSECS_PER_SECOND (1000)
 #define BUFFER (self->buffer + self->position)
 #define MALFORMED_TIME ((webvtt_timestamp_t)-1.0)
 
-static int find_bytes( const webvtt_byte *buffer, webvtt_uint len, const webvtt_byte *sbytes, webvtt_uint slen );
+static webvtt_status find_bytes( const webvtt_byte *buffer, webvtt_uint len, const webvtt_byte *sbytes, webvtt_uint slen );
 static webvtt_status webvtt_skipwhite( const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint len );
 static webvtt_int64 parse_int( const webvtt_byte **pb, int *pdigits );
+static void skip_spacetab( const webvtt_byte *text, webvtt_uint *pos,
+  webvtt_uint len, webvtt_uint *column );
+static void skip_until_white( const webvtt_byte *text, webvtt_uint *pos,
+  webvtt_uint len, webvtt_uint *column );
 
 WEBVTT_EXPORT webvtt_status
 webvtt_create_parser( webvtt_cue_fn on_read,
                       webvtt_error_fn on_error, void *
                       userdata,
                       webvtt_parser *ppout )
 {
   webvtt_parser p;
@@ -224,16 +228,55 @@ find_newline( const webvtt_byte *buffer,
       return 1;
     } else {
       ( *pos )++;
     }
   }
   return -1;
 }
 
+static void
+skip_spacetab( const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len,
+  webvtt_uint *column )
+{
+  webvtt_uint c = 0;
+  if( !column ) {
+    column = &c;
+  }
+  while( *pos < len ) {
+    webvtt_byte ch = text[ *pos ];
+    if( ch == 0x20 || ch == 0x09 ) {
+      ++( *pos );
+      ++( *column );
+    } else {
+      break;
+    }
+  }
+}
+
+static void
+skip_until_white( const webvtt_byte *text, webvtt_uint *pos, webvtt_uint len,
+  webvtt_uint *column )
+{
+  webvtt_uint c = 0;
+  if( !column ) {
+    column = &c;
+  }
+  while( *pos < len ) {
+    webvtt_byte ch = text[ *pos ];
+    if( ch == 0x20 || ch == 0x09 || ch == 0x0A || ch == 0x0D ) {
+      break;
+    } else {
+      int length = webvtt_utf8_length( text + *pos );
+      *pos += length;
+      ++( *column );
+    }
+  }
+}
+
 static webvtt_status
 webvtt_skipwhite( const webvtt_byte *buffer, webvtt_uint *pos, webvtt_uint len )
 {
   if( !buffer || !pos ) {
     return WEBVTT_INVALID_PARAM;
   }
 
   for( ; *pos < len && webvtt_iswhite( buffer[ *pos ] ); (*pos)++ );
@@ -254,35 +297,35 @@ find_next_whitespace( const webvtt_byte 
     ++pos;
   }
   *ppos = pos;
 }
 
 /**
  * basic strnstr-ish routine
  */
-static int
+static webvtt_status
 find_bytes( const webvtt_byte *buffer, webvtt_uint len,
     const webvtt_byte *sbytes, webvtt_uint slen )
 {
   webvtt_uint slen2;
   // check params for integrity
   if( !buffer || len < 1 || !sbytes || slen < 1 ) {
-    return 0;
+    return WEBVTT_INVALID_PARAM;
   }
 
   slen2 = slen - 1;
   while( len-- >= slen && *buffer ){
     if( *buffer == *sbytes && memcmp( buffer + 1, sbytes + 1, slen2 ) == 0 ) {
-      return 1;
+      return WEBVTT_SUCCESS;
     }
     buffer++;
   }
 
-  return 0;
+  return WEBVTT_NO_MATCH_FOUND;
 }
 
 /**
  * Helpers to figure out what state we're on
  */
 #define SP (self->top)
 #define AT_BOTTOM (self->top == self->stack)
 #define ON_HEAP (self->stack_alloc == sizeof(p->astack) / sizeof(p->astack[0]))
@@ -350,26 +393,265 @@ do { \
 #define POP() \
 do \
 { \
   --(self->top); \
   self->popped = 1; \
 } while(0)
 #define POPBACK() do_pop(self)
 
+static webvtt_status
+webvtt_parse_cuesetting( webvtt_parser self, const webvtt_byte *text,
+  webvtt_uint *pos, webvtt_uint len, webvtt_error bv, webvtt_token
+  keyword, webvtt_token values[], webvtt_uint *value_column ) {
+  enum webvtt_param_mode
+  {
+    P_KEYWORD,
+    P_COLON,
+    P_VALUE
+  };
+  int i;
+  webvtt_bool precws = 0;
+  webvtt_bool prevws = 0;
+  static const webvtt_token value_tokens[] = {
+    INTEGER, RL, LR, START, MIDDLE, END, LEFT, RIGHT, PERCENTAGE, 0
+  };
+  static const webvtt_token keyword_tokens[] = {
+    ALIGN, SIZE, LINE, POSITION, VERTICAL, 0
+  };
+  enum webvtt_param_mode mode = P_KEYWORD;
+  webvtt_uint keyword_column = 0;
+  while( *pos < len ) {
+    webvtt_uint last_line = self->line;
+    webvtt_uint last_column = self->column;
+    webvtt_uint last_pos = *pos;
+    webvtt_token tk = webvtt_lex( self, text, pos, len, 1 );
+    webvtt_uint tp = self->token_pos;
+    self->token_pos = 0;
+
+    switch( mode ) {
+      case P_KEYWORD:
+        switch( tk ) {
+          case ALIGN:
+          case SIZE:
+          case POSITION:
+          case VERTICAL:
+          case LINE:
+            if( tk != keyword ) {
+              *pos -= tp;
+              self->column -= tp;
+              return WEBVTT_NEXT_CUESETTING;
+            }
+            if( *pos < len ) {
+              webvtt_uint column = last_column;
+              webvtt_byte ch = text[ *pos ];
+              if( ch != 0x3A ) {
+                webvtt_error e = WEBVTT_INVALID_CUESETTING;
+                if( ch == 0x20 || ch == 0x09 ) {
+                  column = self->column;
+                  e = WEBVTT_UNEXPECTED_WHITESPACE;
+                  skip_spacetab( text, pos, len, &self->column );
+                  if( text[ *pos ] == 0x3A ) {
+                    skip_until_white( text, pos, len, &self->column );
+                  }
+                } else {
+                  skip_until_white( text, pos, len, &self->column );
+                }
+                ERROR_AT_COLUMN( e, column );
+              } else {
+                mode = P_COLON;
+                keyword_column = last_column;
+              }
+            } else {
+              ERROR_AT_COLUMN( WEBVTT_INVALID_CUESETTING, last_column );     
+            }
+            break;
+          case WHITESPACE:
+            break;
+          case NEWLINE:
+            return WEBVTT_SUCCESS;
+            break;
+          default:
+            ERROR_AT( WEBVTT_INVALID_CUESETTING, last_line,
+              last_column );
+            *pos = *pos + tp + 1;
+ skip_param:
+            while( *pos < len && text[ *pos ] != 0x20
+              && text[ *pos ] != 0x09 ) {
+              if( text[ *pos ] == 0x0A || text[ *pos ] == 0x0D ) {
+                return WEBVTT_SUCCESS;
+              }
+              ++( *pos );
+              ++self->column;
+            }
+            break;
+        }
+        break;
+      case P_COLON:
+        if( tk == WHITESPACE && !precws ) {
+          ERROR_AT( WEBVTT_UNEXPECTED_WHITESPACE, last_line,
+            last_column
+          );
+          precws = 1;
+        } else if( tk == COLON ) {
+          mode = P_VALUE;
+        } else if( token_in_list( tk, value_tokens ) ) {
+          ERROR_AT( WEBVTT_MISSING_CUESETTING_DELIMITER, last_line,
+            last_column );
+          mode = P_VALUE;
+          goto get_value;
+        } else if( token_in_list( tk, keyword_tokens ) ) {
+          ERROR_AT( WEBVTT_INVALID_CUESETTING, last_line,
+            keyword_column );
+        } else {
+          ERROR_AT( WEBVTT_INVALID_CUESETTING_DELIMITER, last_line,
+            last_column );
+          *pos = last_pos + tp + 1;
+        }
+        break;
+      case P_VALUE:
+get_value:
+        if( tk == WHITESPACE && !prevws ) {
+          ERROR_AT( WEBVTT_UNEXPECTED_WHITESPACE, last_line,
+            last_column );
+        } else if( ( i = find_token( tk, values ) ) >= 0 ) {
+          webvtt_token t = values[ i ] & TF_TOKEN_MASK;
+          int flags = values[ i ] & TF_FLAGS_MASK;
+          *value_column = last_column;
+          if( *pos < len ) {
+            webvtt_byte ch = text[ *pos ];
+            if( ch != 0x20 && ch != 0x09
+              && ch != 0x0D && ch != 0x0A ) {
+              goto bad_value;
+            }
+          }
+          switch( t ) {
+            case INTEGER:
+            case PERCENTAGE:
+              if( ( flags & TF_SIGN_MASK ) != TF_SIGN_MASK ) {
+                const webvtt_byte p = self->token[ 0 ];
+                if( ( ( flags & TF_NEGATIVE ) && p != UTF8_HYPHEN_MINUS )
+                  || ( ( flags & TF_POSITIVE ) && p == UTF8_HYPHEN_MINUS
+) ) {
+                  goto bad_value;
+                }
+              }
+          }
+          return i + 1;
+        } else {
+bad_value:
+          ERROR_AT( bv, last_line, last_column );
+bad_value_eol:
+          while( *pos < len && text[ *pos ] != 0x20
+            && text[ *pos ] != 0x09 ) {
+            if( text[ *pos ] == 0x0A || text[ *pos ] == 0x0D ) {
+              return WEBVTT_SUCCESS;
+            }
+            ++( *pos );
+            ++self->column;
+          }
+          if( *pos >= len ) {
+            return WEBVTT_SUCCESS;
+          }
+        }
+        break;
+    }
+  }
+  if( mode == P_VALUE && *pos >= len ) {
+    ERROR( bv );
+    goto bad_value_eol;
+  }
+  return WEBVTT_NEXT_CUESETTING;
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_parse_align( webvtt_parser self, webvtt_cue *cue, const
+webvtt_byte *text,
+  webvtt_uint *pos, webvtt_uint len )
+{
+  webvtt_uint last_line = self->line;
+  webvtt_uint last_column = self->column;
+  webvtt_status v;
+  webvtt_uint vc;
+  webvtt_token values[] = { START, MIDDLE, END, LEFT, RIGHT, 0 };
+  if( ( v = webvtt_parse_cuesetting( self, text, pos, len,
+    WEBVTT_ALIGN_BAD_VALUE, ALIGN, values, &vc ) ) > 0 ) {
+    if( cue->flags & CUE_HAVE_ALIGN ) {
+      ERROR_AT( WEBVTT_ALIGN_ALREADY_SET, last_line, last_column );
+    }
+    cue->flags |= CUE_HAVE_ALIGN;
+    switch( values[ v - 1 ] ) {
+      case START: cue->settings.align = WEBVTT_ALIGN_START; break;
+      case MIDDLE: cue->settings.align = WEBVTT_ALIGN_MIDDLE; break;
+      case END: cue->settings.align = WEBVTT_ALIGN_END; break;
+      case LEFT: cue->settings.align = WEBVTT_ALIGN_LEFT; break;
+      case RIGHT: cue->settings.align = WEBVTT_ALIGN_RIGHT; break;
+    }
+  }
+  return v >= 0 ? WEBVTT_SUCCESS : v;
+}
+
+WEBVTT_INTERN webvtt_status
+webvtt_parse_line( webvtt_parser self, webvtt_cue *cue, const
+webvtt_byte *text,
+  webvtt_uint *pos, webvtt_uint len )
+{
+  webvtt_uint last_line = self->line;
+  webvtt_uint last_column = self->column;
+  webvtt_status v;
+  webvtt_uint vc;
+  webvtt_bool first_flag = 0;
+  webvtt_token values[] = { INTEGER, PERCENTAGE|TF_POSITIVE, 0 };
+  if( ( v = webvtt_parse_cuesetting( self, text, pos, len,
+    WEBVTT_LINE_BAD_VALUE, LINE, values, &vc ) ) > 0 ) {
+    webvtt_uint digits;
+    webvtt_int64 value;
+    const webvtt_byte *t = self->token;
+    if( cue->flags & CUE_HAVE_LINE ) {
+      ERROR_AT( WEBVTT_LINE_ALREADY_SET, last_line, last_column );
+    } else {
+      first_flag = 1;
+    }
+    cue->flags |= CUE_HAVE_LINE;
+    value = parse_int( &t, &digits );
+    switch( values[ v - 1 ] & TF_TOKEN_MASK ) {
+      case INTEGER: {
+        cue->snap_to_lines = 1;
+        cue->settings.line = ( int )value;
+      }
+      break;
+
+      case PERCENTAGE: {
+        if( value < 0 || value > 100 ) {
+          if( first_flag ) {
+            cue->flags &= ~CUE_HAVE_LINE;
+          }
+          ERROR_AT_COLUMN( WEBVTT_LINE_BAD_VALUE, vc );
+          return WEBVTT_SUCCESS;
+        }
+        cue->snap_to_lines = 0;
+        cue->settings.line = ( int )value;
+      } break;
+    }
+  }
+  return v >= 0 ? WEBVTT_SUCCESS : v;
+}
+
 WEBVTT_INTERN int
 parse_cueparams( webvtt_parser self, const webvtt_byte *buffer,
                  webvtt_uint len, webvtt_cue *cue )
 {
   int digits;
   int have_ws = 0;
   int unexpected_whitespace = 0;
   webvtt_uint baddelim = 0;
   webvtt_uint pos = 0;
   webvtt_token last_token = 0;
+  webvtt_uint last_line = self->line;
+
   enum cp_state {
     CP_T1, CP_T2, CP_T3, CP_T4, CP_T5, /* 'start' cuetime, whitespace1,
                    'separator', whitespace2, 'end' cuetime */
     CP_CS0, /* pre-cuesetting */
 
     CP_SD, /* cuesettings delimiter here */
 
     CP_V1, /* 'vertical' cuesetting */
@@ -391,30 +673,32 @@ parse_cueparams( webvtt_parser self, con
   enum cp_state state = CP_T1;
 
 #define SETST(X) do { baddelim = 0; last_state = state; state = (X); } while( 0 )
 
   self->token_pos = 0;
   while( pos < len ) {
     webvtt_uint last_column = self->column;
     webvtt_token token = webvtt_lex( self, buffer, &pos, len, 1 );
+    webvtt_uint tlen = self->token_pos;
+    self->token_pos = 0;
 _recheck:
     switch( state ) {
         /* start timestamp */
       case CP_T1:
         if( token == WHITESPACE && !unexpected_whitespace ) {
           ERROR_AT_COLUMN( WEBVTT_UNEXPECTED_WHITESPACE, self->column );
           unexpected_whitespace = 1;
         } else if( token == TIMESTAMP )
           if( !parse_timestamp( self->token, &cue->from ) ) {
             ERROR_AT_COLUMN(
               ( BAD_TIMESTAMP( cue->from )
                 ? WEBVTT_EXPECTED_TIMESTAMP
                 : WEBVTT_MALFORMED_TIMESTAMP ), last_column  );
-            if( !webvtt_isdigit( self->token[self->token_pos - 1] ) ) {
+            if( self->token_pos && !webvtt_isdigit( self->token[self->token_pos - 1] ) ) {
               while( pos < len && buffer[pos] != 0x09 && buffer[pos] != 0x20 ) { ++pos; }
             }
             if( BAD_TIMESTAMP( cue->from ) )
             { return -1; }
             SETST( CP_T2 );
           } else {
             SETST( CP_T2 );
           }
@@ -508,50 +792,64 @@ else if( !have_ws ) \
          * Otherwise, if we don't have whitespace and have a bad token, it's an
          * invalid delimiter
          */
       case CP_CS0:
         switch( token ) {
           case WHITESPACE:
             have_ws = last_column;
             break;
-          case COLON:
-            ERROR_AT_COLUMN( WEBVTT_MISSING_CUESETTING_KEYWORD, last_column );
-            break;
           case VERTICAL:
             CHKDELIM have_ws = 0;
             SETST( CP_V1 );
             break;
           case POSITION:
             CHKDELIM have_ws = 0;
             SETST( CP_P1 );
             break;
           case ALIGN:
-            CHKDELIM have_ws = 0;
-            SETST( CP_A1 );
-            break;
+          {
+            webvtt_status status;
+            pos -= tlen; /* Required for parse_align() */
+            self->column = last_column; /* Reset for parse_align() */
+            status = webvtt_parse_align( self, cue, buffer, &pos, len );
+            if( status == WEBVTT_PARSE_ERROR ) {
+              return WEBVTT_PARSE_ERROR;
+            }
+          }
+          break;
+
           case SIZE:
             CHKDELIM have_ws = 0;
             SETST( CP_S1 );
             break;
           case LINE:
-            CHKDELIM have_ws = 0;
-            SETST( CP_L1 );
-            break;
+          {
+            webvtt_status status;
+            pos -= tlen; /* Required for parse_align() */
+            self->column = last_column; /* Reset for parse_align() */
+            status = webvtt_parse_line( self, cue, buffer, &pos, len );
+            if( status == WEBVTT_PARSE_ERROR ) {
+              return WEBVTT_PARSE_ERROR;
+            }
+          }
+          break;
           default:
             if( have_ws ) {
               ERROR_AT_COLUMN( WEBVTT_INVALID_CUESETTING, last_column );
-              while( pos < len && buffer[pos] != 0x09 && buffer[pos] != 0x20 ) { ++pos; }
             } else if( token == BADTOKEN ) {
               /* it was a bad delimiter... */
               if( !baddelim ) {
                 baddelim = last_column;
               }
               ++pos;
             }
+            while( pos < len && buffer[pos] != 0x09 && buffer[pos] != 0x20 ) {
+              ++pos;
+            }
         }
         break;
 #define CS1(S) \
   if( token == COLON ) \
   { if(have_ws) { ERROR_AT_COLUMN(WEBVTT_UNEXPECTED_WHITESPACE,have_ws); } SETST((S)); have_ws = 0; } \
   else if( token == WHITESPACE && !have_ws ) \
   { \
     have_ws = last_column; \
@@ -1013,26 +1311,33 @@ parse_webvtt( webvtt_parser self, const 
           /**
            * We're expecting either cue-id (contains '-->') or cue
            * params
            */
           webvtt_cue *cue = SP->v.cue;
           webvtt_state *st = FRAMEUP( 1 );
           webvtt_string text = st->v.text;
 
+          /* FIXME: guard inconsistent state */
+          if (!cue) {
+            ERROR( WEBVTT_PARSE_ERROR );
+            status = WEBVTT_PARSE_ERROR;
+            goto _finish;
+          }
+
           st->type = V_NONE;
           st->v.cue = NULL;
 
           /**
            * The type should be V_TEXT. If it's not, somethings wrong.
            *
            * TODO: Add debug assertion
            */
           if( find_bytes( webvtt_string_text( &text ), webvtt_string_length( &text ), separator,
-                          sizeof( separator ) ) ) {
+                          sizeof( separator ) ) == WEBVTT_SUCCESS) {
             /* It's not a cue id, we found '-->'. It can't be a second
                cueparams line, because if we had it, we would be in
                a different state. */
             int v;
             /* backup the column */
             self->column = 1;
             if( ( v = parse_cueparams( self, webvtt_string_text( &text ),
                                        webvtt_string_length( &text ), cue ) ) < 0 ) {
@@ -1046,17 +1351,17 @@ parse_webvtt( webvtt_parser self, const 
             } else {
               webvtt_release_string( &text );
               cue->flags |= CUE_HAVE_CUEPARAMS;
               *mode = M_CUETEXT;
               goto _finish;
             }
           } else {
             /* It is a cue-id */
-            if( cue->flags & CUE_HAVE_ID ) {
+            if( cue && cue->flags & CUE_HAVE_ID ) {
               /**
                * This isn't actually a cue-id, because we already
                * have one. It seems to be cuetext, which is occurring
                * before cue-params
                */
               webvtt_release_string( &text );
               ERROR( WEBVTT_CUE_INCOMPLETE );
               *mode = M_SKIP_CUE;
@@ -1117,34 +1422,27 @@ read_cuetext( webvtt_parser self, const 
   do {
     int v;
     if( ( v = webvtt_string_getline( &self->line_buffer, b, &pos, len, &self->truncate, finish, 1 ) ) ) {
       if( v < 0 ) {
         status = WEBVTT_OUT_OF_MEMORY;
         goto _finish;
       }
 
-      if( self->line_buffer.d->length > 1 && self->line_buffer.d->text[ self->line_buffer.d->length - 1 ] == UTF8_LINE_FEED ) {
+      /**
+       * We've encountered a line without any cuetext on it, i.e. there is no
+       * newline character and len is 0 or there is and len is 1, therefore,
+       * the cue text is finished.
+       */
+      if( self->line_buffer.d->length <= 1 ) {
         /**
          * finished
          */
         finished = 1;
       }
-      webvtt_string_putc( &self->line_buffer, UTF8_LINE_FEED );
-
-      if( pos < len ) {
-        if( b[pos] == UTF8_CARRIAGE_RETURN ) {
-          if( len - pos >= 2 && b[pos + 1] == UTF8_LINE_FEED ) {
-            ++pos;
-          }
-          ++pos;
-        } else {
-          ++pos;
-        }
-      }
     }
   } while( pos < len && !finished );
 _finish:
   *ppos = pos;
   /**
    * If we didn't encounter 2 successive EOLs, and it's not the final buffer in
    * the file, notify the caller.
    */
@@ -1380,8 +1678,36 @@ parse_timestamp( const webvtt_byte *b, w
   if( malformed ) {
     return 0;
   }
   return 1;
 _malformed:
   *result = 0xFFFFFFFFFFFFFFFF;
   return 0;
 }
+
+WEBVTT_INTERN webvtt_bool
+token_in_list( webvtt_token token, const webvtt_token list[] )
+{
+  int i = 0;
+  webvtt_token t;
+  while( ( t = list[ i++ ] ) != 0 ) {
+    if( token == t ) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+WEBVTT_INTERN int
+find_token( webvtt_token token, const webvtt_token list[] )
+{
+  int i = 0;
+  webvtt_token t;
+  while( ( t = list[ i ] ) != 0 ) {
+    webvtt_token masked = t & TF_TOKEN_MASK;
+    if( token == masked ) {
+      return i;
+    }
+    ++i;
+  }
+  return -1;
+}
--- a/media/webvtt/parser_internal.h
+++ b/media/webvtt/parser_internal.h
@@ -24,16 +24,28 @@
  * (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"
+# ifndef NDEBUG
+#   define NDEBUG
+# endif
+
+# if defined(FATAL_ASSERTION)
+#   undef NDEBUG
+#   include <assert.h>
+# else
+#   if defined(BREAK_ON_ASSERTION) && !WEBVTT_OS_WIN32
+static void break_on_assert();
+#   endif
+# endif
 
 typedef enum
 webvtt_token_t {
   BADTOKEN = -2,
   UNFINISHED = -1, /* not-token */
   BOM,
   WEBVTT, /* 'WEBVTT' */
   NOTE, /* 'NOTE' */
@@ -212,25 +224,107 @@ webvtt_parser_t {
   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 );
 
+/** 
+ * Flags which can apply additional meaning to a token. find_token() will
+ * test for only the actual token and ignore the additional flags.
+ */
+typedef
+enum webvtt_token_flags_t
+{
+  /* Number can be positive */
+  TF_POSITIVE = 0x80000000,
+
+  /* Number can be negative */
+  TF_NEGATIVE = 0x40000000,
+  /* (token & TF_SIGN_MASK) == combination of TF_POSITIVE and
+     TF_NEGATIVE, which indicate what values a number token is allowed
+     to be */
+  TF_SIGN_MASK = ( TF_POSITIVE | TF_NEGATIVE ),
+
+  /* (token & TF_FLAGS_MASK) == webvtt_token_flags value
+     that is being asked for */
+  TF_FLAGS_MASK = TF_SIGN_MASK,
+
+  /* (token & TF_TOKEN_MASK) == webvtt_token value */
+  TF_TOKEN_MASK = ( 0xFFFFFFFF & ~TF_FLAGS_MASK ),
+} webvtt_token_flags;
+
+/**
+ * Return non-zero if a token is found in a NULL-terminated array of tokens, or
+ * zero if not.
+ *
+ * Unlike find_token(), token_in_list() does not make use of
+ * webvtt_token_flags and thus requiers an exact match.
+ */
+WEBVTT_INTERN webvtt_bool token_in_list( webvtt_token search_for,
+  const webvtt_token token_list[] );
+
+/**
+ * Return the index of a token in a NULL-terminated array of tokens,
+ * or -1 if the token is not found.
+ *
+ * find_token() will search for an occurrence of `token' in a list
+ * where webvtt_token_flags are used. For instance, if the list of
+ * tokens contains { TF_POSITIVE | INTEGER, TF_POSITIVE | PERCENTAGE,
+ * 0 }, find_token() will return a match for INTEGER or PERCENTAGE if
+ * either is searched for.
+ */
+WEBVTT_INTERN int find_token( webvtt_token search_for,
+  const webvtt_token token_list[] );
+
 #define BAD_TIMESTAMP(ts) ( ( ts ) == 0xFFFFFFFFFFFFFFFF )
 
-#define ERROR(Code) \
+#ifdef FATAL_ASSERTION
+#  define SAFE_ASSERT(condition) assert(condition)
+#  define DIE_IF(condition) assert( !(condition) )
+#else
+#  ifdef BREAK_ON_ASSERTION
+static void
+break_on_assert(void) {
+#if WEBVTT_OS_WIN32
+  /* __declspec(dllimport) should work for cross compiling gcc as well */
+  __declspec(dllimport) void __stdcall DebugBreak( void );
+  DebugBreak();
+#else
+  volatile int *ptr = (volatile int *)0;
+  *ptr = 1;
+#endif
+}
+#    define SAFE_ASSERT(condition) \
+if( !(condition) ) { \
+  break_on_assert(); \
+  return WEBVTT_FAILED_ASSERTION; \
+}
+#    define DIE_IF(condition) \
+if( (condition) ) { \
+  break_on_assert(); \
+}
+#  else
+#    define SAFE_ASSERT(condition) \
+if( !(condition) ) { \
+  return WEBVTT_FAILED_ASSERTION; \
+}
+#    define DIE_IF(condition)
+#  endif
+#endif
+
+#define ERROR_AT(errno, line, column) \
 do \
 { \
-  if( !self->error || self->error(self->userdata,self->line,self->column,Code) < 0 ) \
+  if( !self->error \
+    || self->error( (self->userdata), (line), (column), (errno) ) < 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)
+#define ERROR(error) \
+  ERROR_AT( (error), (self->line), (self->column) )
 
+#define ERROR_AT_COLUMN(error, column) \
+  ERROR_AT( (error), (self->line), (column) )
 #endif
--- a/media/webvtt/string.c
+++ b/media/webvtt/string.c
@@ -175,17 +175,16 @@ webvtt_string_detach( /* in, out */ webv
 
   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 );
   }
 }
@@ -327,17 +326,17 @@ webvtt_string_getline( webvtt_string *sr
   }
   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 ) {
+      if( grow( str, len + 1 ) == WEBVTT_OUT_OF_MEMORY ) {
         ret = -1;
       }
       d = str->d;
     }
   }
 
   /* Copy everything in */
   if( len && ret >= 0 && d->length + len < d->alloc ) {
@@ -366,16 +365,25 @@ webvtt_string_putc( webvtt_string *str, 
   {
     str->d->text[ str->d->length++ ] = to_append;
     str->d->text[ str->d->length ] = 0;
   }
 
   return result;
 }
 
+WEBVTT_EXPORT webvtt_bool
+webvtt_string_is_equal( webvtt_string *str, webvtt_byte *to_compare, webvtt_uint len )
+{
+  if( !str || !to_compare || webvtt_string_length( str ) != len ) {
+    return 0;
+  }
+  return memcmp( webvtt_string_text( str ), to_compare, len ) == 0;
+}
+
 WEBVTT_EXPORT webvtt_status
 webvtt_string_append( webvtt_string *str, const webvtt_byte *buffer, int len )
 {
   webvtt_status result;
 
   if( !str || !buffer ) {
     return WEBVTT_INVALID_PARAM;
   }