xml/cxmllibrary/src/tinydom/src/tiny_dom.c
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 17:02:56 +0300
branchRCL_3
changeset 32 889504eac4fb
permissions -rw-r--r--
Revision: 201014 Kit: 201035

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/
#include "cxml_internal.h"
#include <xml/cxml/nw_tinydom.h>
#include <xml/cxml/nw_wbxml_parse.h>
#include <xml/cxml/nw_wbxml_reader.h>
#include <xml/cxml/nw_wbxml_event.h>
#include "nw_wbxml_parsei.h"

/*Parser flags */

/* Top four bits are pass state */
#define T_PARSE_PASS_MASK      0xF0000000
#define T_PARSE_PASS_1         0x00000000
#define T_PARSE_PASS_2         0x10000000
#define T_PARSE_PASS_3         0x20000000

/* Next 8 bits are for parser states */
#define T_PARSE_S_MASK         0x07F00000
#define T_PARSE_S_TAG_START    0x00000000
#define T_PARSE_S_ATTR_START   0x00100000
#define T_PARSE_S_ATTR_VALS    0x00200000
#define T_PARSE_S_CONTENT      0x00300000
#define T_PARSE_F_EXT          0x08000000 /* Extension substate flag */

  /* Remaining 20 bits are flags */
#define T_PARSE_FLAG_TEXT      0x00000001
#define T_PARSE_FLAG_ATTR      0x00000002

/*
* Implements the tiny dom parser. This includes the methods to build a
* tiny dom tree, and the underlying support routines to access the
* "virtual elements" of the tree. The only thing that currently gets
* in the way of a clean parser interface are several references to the
* underlying parser state here. The underlying parser needs to be
* fixed so it is never necessary to pass this. Several TODOs in this
* file indicate places where references to parser state should be
* removed.  
*/

static
NW_Uint32
GET_PASS(NW_TinyDom_Parser_t* parser){
  return parser->state & T_PARSE_PASS_MASK;
}

static
void 
SET_PASS(NW_TinyDom_Parser_t* parser, NW_Uint32 pass){
  parser->state &= ~T_PARSE_PASS_MASK;
  parser->state |= pass;
}

static
NW_Uint32
GET_STATE(NW_TinyDom_Parser_t* parser){
  return parser->state & T_PARSE_S_MASK;
}

static
void 
SET_STATE(NW_TinyDom_Parser_t* parser, NW_Uint32 state){
  parser->state &= ~T_PARSE_S_MASK;
  parser->state |= state;
}

/* Callbacks to handle parsing passes: 
*
* Tiny dom uses multiple passes to implement the tree lazily. The
* first two build the tree. Later, lazy deserialization invokes
* further passes over parts of the source.
* 
* Pass 1 counts nodes and allocates space, pass 2 builds the
* tree. However, there is much common behavior for both passes, since
* accurate counting of nodes requires running the parser state
* machine. Common behavior is implemented in common callbacks, while
* pass-specific behavior is mostly implemented in pass-specific
* callbacks.
*
* The tree built by passes 1 & 2 contains a node for every tag. If a tag
* has attributes, the tree contains a node for the first attribute,
* attached as the first child of the node. For text content, the tree
* contains a node for the first text element in each sequence of text
* elements. The goal of the tree design is to make it easy to find
* elements for deserialization while using the minimum amount of
* storage.
* 
* The deserialization API invokes parser methods that know how to
* parse one of the node types stored in the tree (tags, attributes,
* text). The API sets the parser offset using the node offset,
* identifies the node type using the node type flags, and then calls
* the appropriate parser method to parse a section of the source.
* 
* When called for deserialization the parser generates events as usual:
* these are handled by the pass 3 handlers which build the appropriate
* data structures for the API to return.
* 
* This may seem like a rather byzantine mechanism for
* deserialization, but the goal is to use exactly the same parsing
* code for all operations on the source. This makes it easy to change
* or replace parsing code.  Also, all of the parsing logic is kept in
* the parser module: the dom module (this one) has no knowledge of
* parsing. This makes it easy to attach the dom module to different
* parsers (one for wbxml, one for xml).  
*
* A note on buffer usage: tiny trees use segmented expandable buffers
* (ebuffers) so that the tree can be read and written in minimum memory.
* When building a tree from an existing buffer (passes 1 & 2), the whole
* buffer is contained in the ebuffer segment 0. This means that the 
* offsets we store in the tree nodes (which are indexes into the ebuffer)
* are the same as the parser offsets in the buffer. However, for 
* deserialization (pass 3), we may be reading a tree that was constructed
* or modified via the dom api. This may have multiple segments and a given
* node offset may refer to an address in any segment. Therefore, when setting
* the parser offset from a node source offset, we first need to translate
* the node source offset into a segment + offset form, and use this to set
* the parser.   
*/


static 
NW_Status_t 
Pass_1_StartDocument_CB (NW_WBXML_Parser_t *parser, 
                         NW_WBXML_Document_t *doc, 
                         void *context)
{

  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  NW_REQUIRED_PARAM(parser);
  NW_REQUIRED_PARAM(doc);

  SET_STATE(tiny_parser, T_PARSE_S_CONTENT);
  tiny_parser->state &= ~T_PARSE_FLAG_TEXT; /* prepare for text */
  tiny_parser->node_count = 1;
  return NW_STAT_SUCCESS;

}

static 
NW_Status_t 
Pass_2_StartDocument_CB (NW_WBXML_Parser_t *parser, 
                         NW_WBXML_Document_t *doc, 
                         void *context)
{
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  NW_REQUIRED_PARAM(parser);
  NW_REQUIRED_PARAM(doc);

  tiny_parser->dom_tree->root_node = NW_TinyTree_setRoot(&(tiny_parser->dom_tree->tree), 0);

  if (tiny_parser->dom_tree->root_node != NULL){
    tiny_parser->current_node = tiny_parser->dom_tree->root_node;
    NW_TinyTree_Node_setUserFlags(tiny_parser->current_node, T_DOM_NODE_DOC);
    SET_STATE(tiny_parser, T_PARSE_S_CONTENT);
    tiny_parser->state &= ~T_PARSE_FLAG_TEXT; /* prepare for text */
    return NW_STAT_SUCCESS;
  }
  else{
    return NW_STAT_OUT_OF_MEMORY;
  }  
}

/* Private utility function to do NW_Byte reordering of ucs2 strings */
/* TODO:  move this to our string library */

static 
void
NW_String_Ucs2_ntoh(NW_String_t *string){
  NW_Uint32 i;
  NW_Ucs2 character;

  for(i = 0; i < string->length; i+=2){
    character = (NW_Ucs2)((string->storage[i] << 8) | string->storage[i+1]);
    (void) NW_Mem_memcpy (&string->storage[i], &character, sizeof (character));
  }
}

/* 
 * This callback sets the parser pass and takes care of any NW_Byte reordering 
 * that needs to be done on the string table. For some encodings (such as ucs2)
 * this allows applications to reference strings from the original storage.
 */

/* TODO:  TODO: Add a flag to document to check if this has already been done 
  (in case the same buffer is parsed over again from the beginning.)
 */


static 
NW_Status_t 
Pass_1_EndDocument_CB (NW_WBXML_Parser_t *parser, 
                       void *context)
{

  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;
  //NW_String_t string;
  //NW_WBXML_Document_t *doc = tiny_parser->dom_tree->doc;

  NW_REQUIRED_PARAM(parser);

  // WLIU: all byte order conversions are moved to pass 2.
  //if(doc->charset == HTTP_iso_10646_ucs_2){
    /* TODO:  redefine string table as an NW_String_t ?? */
    //string.storage = doc->strtbl.data;
    //string.length = doc->strtbl.length;
    //NW_String_Ucs2_ntoh(&string);
  //}
  SET_PASS(tiny_parser, T_PARSE_PASS_2);
  return NW_STAT_SUCCESS;  
}


static 
NW_Status_t 
Pass_2_EndDocument_CB (NW_WBXML_Parser_t *parser, 
                       void *context)
{

  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  NW_REQUIRED_PARAM(parser);

  SET_PASS(tiny_parser, T_PARSE_PASS_3);
  return NW_STAT_SUCCESS;  
}

static 
NW_Status_t 
Pass_1_Tag_Start_CB (NW_WBXML_Parser_t *parser, 
                     void *context)
{

  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  NW_REQUIRED_PARAM(parser);

  tiny_parser->node_count++;
  return NW_STAT_SUCCESS;
}


static 
NW_Status_t 
Pass_2_Tag_Start_CB (NW_WBXML_Parser_t *parser, 
                     void *context)
{
  NW_Status_t status = NW_STAT_SUCCESS;
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  //Atleast there should be root node, before any tag

  if(tiny_parser->current_node != NULL)
  {
   tiny_parser->current_node = 
     NW_TinyTree_createChild(&(tiny_parser->dom_tree->tree), 
                            tiny_parser->current_node, 
                            (NW_TinyTree_Offset_t)parser->offset);

   if (tiny_parser->current_node != NULL)
   {
     NW_TinyTree_Node_setUserFlags(tiny_parser->current_node, T_DOM_NODE_TAG);
     status = NW_STAT_SUCCESS;
   }
   else
   {
    status =  NW_STAT_FAILURE;
   }  
  }//endif(tiny_parser->current_node != NULL)
  else
  {
   status =  NW_STAT_FAILURE;
  }

  return status;
}//end Pass_2_Tag_Start_CB(..)


static 
NW_Status_t 
Tag_Start_CB (NW_WBXML_Parser_t *parser, 
              void *context)

{
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;
  NW_Status_t s = NW_STAT_FAILURE;

  switch(GET_PASS(tiny_parser)){
  case T_PARSE_PASS_1:
    s = Pass_1_Tag_Start_CB(parser, context);
    break;
  case T_PARSE_PASS_2:
    s = Pass_2_Tag_Start_CB(parser, context);
    break;
  default:
    NW_ASSERT(NW_FALSE);
  }
  SET_STATE(tiny_parser, T_PARSE_S_TAG_START);
  tiny_parser->state &= ~T_PARSE_FLAG_TEXT; /* No longer accumulating text */
  tiny_parser->state &= ~T_PARSE_FLAG_ATTR; /* Turn off attribute flag */
  return s;
}

static
NW_Status_t
Pass_2_Pi_CB (NW_WBXML_Parser_t *parser, 
              void *context)
{
  /* This is exactly like pass 2 tag start except for the node user flag. */
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;
  NW_Status_t s = Tag_Start_CB(parser, context);

  if (s == NW_STAT_SUCCESS) {
    NW_TinyTree_Node_setUserFlags(tiny_parser->current_node, T_DOM_NODE_PI);
  }
  return s;
}

static 
NW_Status_t 
Tag_End_CB (NW_WBXML_Parser_t *parser, 
            void *context)
{
  NW_Status_t status = NW_STAT_SUCCESS;
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;
  NW_Int32 lastvalid;
  NW_REQUIRED_PARAM(parser);

  lastvalid = NW_TinyDom_getLastValid(tiny_parser->dom_tree);
  if(GET_PASS(tiny_parser)== T_PARSE_PASS_2)
  {
    /* for the dom tree appending, we won't handle close tag which is beyond last valid mark */
    if (lastvalid == -1 || (NW_Int32)parser->offset <= lastvalid)
	{
      if(tiny_parser->current_node != NULL)
	  {
      tiny_parser->current_node = NW_TinyTree_findParent(tiny_parser->current_node);
	  }
	  else
	  {
	   status = NW_STAT_FAILURE;
	  }
	}
  }

  if(status == NW_STAT_SUCCESS)
  {
   SET_STATE(tiny_parser, T_PARSE_S_CONTENT);
   tiny_parser->state &= ~T_PARSE_FLAG_TEXT; /* No longer accumulating text */
  }
  return status;
}//end Tag_End_CB (..)

/* 
* The first attribute is added as (first) child of the current node.
* This makes it easy to find attributes for later deserialization
*/

static 
NW_Status_t 
Attr_Start_CB (NW_WBXML_Parser_t *parser, 
               void *context)
{
  NW_Status_t status = NW_STAT_SUCCESS;
  
  NW_TinyTree_Node_t* attr_node;
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  switch(GET_STATE(tiny_parser)){
  case T_PARSE_S_TAG_START:
  case T_PARSE_S_ATTR_START:
  case T_PARSE_S_ATTR_VALS:
    if((tiny_parser->state & T_PARSE_FLAG_ATTR) != T_PARSE_FLAG_ATTR){
      tiny_parser->state |= T_PARSE_FLAG_ATTR;
      switch (GET_PASS(tiny_parser)){
      case T_PARSE_PASS_1:
        tiny_parser->node_count++;
        break;
      case T_PARSE_PASS_2:
        attr_node = NW_TinyTree_createChild(&(tiny_parser->dom_tree->tree), 
                                            tiny_parser->current_node, 
                                            (NW_TinyTree_Offset_t)parser->offset);
        if (attr_node != NULL){
          NW_TinyTree_Node_setUserFlags(attr_node, T_DOM_NODE_ATTR);
        }
        else{
          status = NW_STAT_OUT_OF_MEMORY;
        }                    
        break;
      default:
        NW_ASSERT(NW_FALSE);
        status = NW_STAT_FAILURE;
      }
    }
    SET_STATE(tiny_parser, T_PARSE_S_ATTR_START);
    break;
  default:
    status = NW_STAT_FAILURE;
  }
  return status;  
}

static 
NW_Status_t 
Attr_Val_CB (NW_WBXML_Parser_t *parser, 
             void *context)
{

  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  NW_REQUIRED_PARAM(parser);

  switch(GET_STATE(tiny_parser)){
  case T_PARSE_S_ATTR_START:
  case T_PARSE_S_ATTR_VALS:
    SET_STATE(tiny_parser,T_PARSE_S_ATTR_VALS);
    return NW_STAT_SUCCESS;
  default:
    return NW_STAT_FAILURE;
  }
}

static 
NW_Status_t 
Content_CB (NW_WBXML_Parser_t *parser, 
            void *context)
{

  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  SET_STATE(tiny_parser, T_PARSE_S_CONTENT);
  /* We need to save the current offset to use if we need a text node. Ugh! */
  tiny_parser->content_offset = (NW_TinyTree_Offset_t)parser->offset; 
  return NW_STAT_SUCCESS;
}

/* Count code page switches */

static
NW_Status_t 
Pass_1_CodePage_CB (NW_WBXML_Parser_t *parser, 
                    void *context)
{
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  NW_REQUIRED_PARAM(parser);

  tiny_parser->cp_count++;
  return NW_STAT_SUCCESS;
}


/* 
* The first text element in a series of text elements is added as
* a child to the current element. This may be followed by several more
* text elements in the source buffer.  
*/

static 
NW_Status_t
Text_CB (NW_WBXML_Parser_t *parser, 
         NW_Uint32 val, 
         void *context)
{
  NW_Status_t status = NW_STAT_SUCCESS;
  
  NW_TinyTree_Node_t* text_node;
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)context;

  NW_REQUIRED_PARAM(parser);
  NW_REQUIRED_PARAM(val);

  /*We're getting content but aren't yet accumulating text */
  if((GET_STATE(tiny_parser)==T_PARSE_S_CONTENT)
     &&((tiny_parser->state & T_PARSE_FLAG_TEXT) != T_PARSE_FLAG_TEXT)){

    switch(GET_PASS(tiny_parser)){
    case T_PARSE_PASS_1:
      tiny_parser->node_count++;
      break;
    case T_PARSE_PASS_2:
      /* Attach text as child to current node. */

      if(tiny_parser->current_node != NULL)
      {
       text_node = NW_TinyTree_createChild(&(tiny_parser->dom_tree->tree), 
                                          tiny_parser->current_node, 
                                          tiny_parser->content_offset);
       if (text_node != NULL){
         NW_TinyTree_Node_setUserFlags(text_node, T_DOM_NODE_TEXT);
       }
       else{
         status = NW_STAT_FAILURE;
       }      
      }
      else
      {
       status = NW_STAT_FAILURE;
      }  
      break;
    default:
      NW_ASSERT(NW_FALSE);
      status = NW_STAT_FAILURE;
    }
    tiny_parser->state |= T_PARSE_FLAG_TEXT;
  }
  return status;
}



static 
NW_Status_t 
Pass_1_InlineString_CB (NW_WBXML_Parser_t *parser, 
                        NW_Uint32 len, 
                        void *context)
{

  return Text_CB(parser, len, context);
  
}

/* 
 * Pass 2 text callback to adjust the NW_Byte ordering of inline strings if needed.
 * For some string encodings (such as ucs2) this allows the application to reference
 * them directly from the original storage //TODO: Add a flag to buffer
 */

static 
NW_Status_t 
Pass_2_InlineString_CB (NW_WBXML_Parser_t *parser, 
                        NW_Uint32 len, 
                        void *context)
{

  NW_String_t string;
  NW_TinyDom_Parser_t *tiny_parser = (NW_TinyDom_Parser_t*)parser->context;

  
  if(tiny_parser->dom_tree->doc->charset == HTTP_iso_10646_ucs_2)
    {
     NW_WBXML_Parser_getStringInline(parser, tiny_parser->dom_tree->doc, 
            &string);
     NW_String_Ucs2_ntoh(&string);
    }
  
  return Text_CB(parser, len, context);
}



static 
NW_Status_t 
Extension_CB (NW_WBXML_Parser_t *parser, 
              void *context){

  return Text_CB(parser, 0, context);

}


static const NW_WBXML_EventHandler_t Pass_1_Handler = {
  Pass_1_StartDocument_CB,
  Pass_1_EndDocument_CB,
  Tag_Start_CB, /* PI treated exactly like tag start in pass 1 */
  0,
  Tag_Start_CB,
  Tag_End_CB,
  Attr_Start_CB,
  Attr_Val_CB,
  Content_CB,
  Pass_1_CodePage_CB,
  Extension_CB,  
  0,
  0,
  Pass_1_InlineString_CB,
  Text_CB,
  Text_CB,
  Text_CB,
  Text_CB,
  0  /*TODO: Add exception callback */
};

static const NW_WBXML_EventHandler_t Pass_2_Handler = {
  Pass_2_StartDocument_CB,
  Pass_2_EndDocument_CB,
  Pass_2_Pi_CB,
  Tag_End_CB, /* PI end treated exactly like tag end in pass 2 */
  Tag_Start_CB,
  Tag_End_CB,
  Attr_Start_CB,
  Attr_Val_CB,
  Content_CB,
  0,
  Extension_CB,  
  0,
  0,
  Pass_2_InlineString_CB,
  Text_CB,
  Text_CB,
  Text_CB,
  Text_CB,
  0
};

void
NW_TinyDom_Tree_construct(NW_TinyDom_Tree_t* dom_tree,
                          NW_WBXML_Parser_t* parser,
                          NW_WBXML_Document_t* doc,
                          NW_WBXML_Writer_t* writer)
{
  NW_ASSERT(dom_tree != NULL);
  dom_tree->doc = doc;
  dom_tree->parser = parser;
  dom_tree->writer = writer;
  dom_tree->root_node = 0;
/*  dom_tree->tree = 0;*/
}

void
NW_TinyDom_Tree_destruct(NW_TinyDom_Tree_t* dom_tree)
{
  if (dom_tree != NULL) {
    NW_TinyTree_destruct(&(dom_tree->tree));
  }
}

EXPORT_C void
NW_TinyDom_Parser_construct(NW_TinyDom_Parser_t* dom_parser,
                            NW_TinyDom_Tree_t *dom_tree)
{
  dom_parser->state = 0;
  dom_parser->node_count = 0;
  dom_parser->cp_count = 0;
  dom_parser->current_node = 0;
  dom_parser->content_offset = 0;
  dom_parser->dom_tree = dom_tree;
}

/* Build the tree by running pass 1 and pass 2. */

/* TODO: ADD OUT OF MEMORY HANDLER!!!  */

NW_Status_t
NW_TinyDom_Parser_buildTree(NW_TinyDom_Parser_t *dom_parser, 
                            char *buffer, 
                            NW_Uint32 buffsize,
                            NW_Bool freeBuff)
{

  NW_Status_t status;
  NW_WBXML_CP_Registry_Entry_t* registry;
  NW_WBXML_Dictionary_t* dictionary = NULL;
  NW_String_t string;

  /* Run pass 1 (count nodes and code page switches) */

  status = NW_WBXML_Parser_registerHandler(dom_parser->dom_tree->parser, 
                                           &Pass_1_Handler, 
                                           (void *) dom_parser);
  if (status != NW_STAT_SUCCESS){
    return status;
  }
  status = NW_WBXML_Parser_parseBuffer (dom_parser->dom_tree->parser, 
                                        dom_parser->dom_tree->doc, 
                                        (NW_Byte *) buffer, buffsize);

  if (status != NW_STAT_SUCCESS){
    return status;
  }

  /* Initialize the writer */

  /* First get the dictionary */
  dictionary = NW_WBXML_Dictionary_getByIndex(dom_parser->dom_tree->parser->dictionary);
  
  if(dictionary == NULL){
    return NW_STAT_FAILURE;
  }
  
  /* Initialize the writer */

  NW_WBXML_Writer_Initialize(dom_parser->dom_tree->writer,
                             0, NULL,
                             NULL,
                             dictionary,
                             dictionary,
                             NW_Encoder_StringTable_getStringTableOffset,
                             NW_Encoder_StringTable_addToStringTable,
                             dom_parser->dom_tree->doc->strtbl_extension,
                             NW_Encoder_StringTable_StringTableIterateInit,
                             NW_Encoder_StringTable_StringTableIterateNext,
                             NW_TRUE  /* sizing only pass */);

  /* Setup the tree and any code page registry */

  status = NW_TinyTree_construct(&(dom_parser->dom_tree->tree),
                        (CXML_Vector_Metric_t)(dom_parser->node_count/4 + 2),
                        buffer,
                        buffsize,
                        (void*)dom_parser,
                        freeBuff);
  if (status != NW_STAT_SUCCESS) {
    return status;
  }

  /* TODO: move all of this down into the wbxml parser itself */
  if(dom_parser->cp_count > 0){
    /* There are code page switches, so add a code page registry */
    registry = (NW_WBXML_CP_Registry_Entry_t*) 
      NW_Mem_Malloc((dom_parser->cp_count + 1) * sizeof (NW_WBXML_CP_Registry_Entry_t));
    if (registry == NULL){
      return NW_STAT_OUT_OF_MEMORY;
    }

    NW_Mem_memset(registry, 0, (dom_parser->cp_count + 1) * sizeof (NW_WBXML_CP_Registry_Entry_t) );


    status = NW_WBXML_Parser_addCPRegistry(dom_parser->dom_tree->parser, 
                                           registry, dom_parser->cp_count);
    if (status != NW_STAT_SUCCESS){
      return status;
    }
  }
  /* Run pass 2 (build tree and any code page registry) */
  NW_WBXML_Parser_reset (dom_parser->dom_tree->parser); 
  NW_WBXML_Parser_registerHandler (dom_parser->dom_tree->parser, 
                                   &Pass_2_Handler, 
                                   (void*) dom_parser);
  if(dom_parser->dom_tree->doc->charset == HTTP_iso_10646_ucs_2){
    string.storage = dom_parser->dom_tree->doc->strtbl.data;
    string.length = dom_parser->dom_tree->doc->strtbl.length;

    if (string.length)
      NW_String_Ucs2_ntoh(&string);
  }
  /* set last valid to undefined for non-appending dom tree parsing */
  NW_TinyDom_setLastValid(dom_parser->dom_tree, -1);
  status = NW_WBXML_Parser_parseBuffer(dom_parser->dom_tree->parser, 
                                       dom_parser->dom_tree->doc, 
                                       (NW_Byte *) buffer, 
                                       buffsize);
  if (status != NW_STAT_SUCCESS){
    return status;
  }

  return NW_STAT_SUCCESS;
}

/**********************************************************
*/
NW_Status_t
NW_TinyDom_Parser_incrementalBuildTree(
                                       NW_TinyDom_Parser_t *dom_parser, 
                                       char *buffer, 
                                       NW_Uint32 buffsize,
                                       NW_Bool freeBuff,
                                       NW_Int32 lastValid)
{
  
  NW_Status_t status;
  NW_WBXML_CP_Registry_Entry_t *old_registry, *registry;
  NW_WBXML_Dictionary_t* dictionary = NULL;
  NW_Uint32 old_cp_offset = 0;
  NW_String_t string;

  if (dom_parser->dom_tree->tree.tree == NULL)
  {
    status = NW_TinyTree_construct(&(dom_parser->dom_tree->tree),
      (CXML_Vector_Metric_t)(10),/*todo: remove hardcode number */
      buffer,
      buffsize,
      (void*)dom_parser,
      freeBuff);
    if (status != NW_STAT_SUCCESS) {
      goto finish_ibuildtree;
    }
  }
  /* Initialize the writer */
  if (dom_parser->dom_tree->parser->dictionary == 0)
  {
    dom_parser->dom_tree->parser->p = (NW_Byte *)buffer;
    dom_parser->dom_tree->parser->left = buffsize;
    if ((status = NW_WBXML_Parser_docHeaderParse (dom_parser->dom_tree->parser, dom_parser->dom_tree->doc))
      != NW_STAT_SUCCESS)
      goto finish_ibuildtree;
    
    /* Now get the dictionary from the document */
    
    if (dom_parser->dom_tree->doc->publicid > 0){
      dom_parser->dom_tree->parser->dictionary =
        NW_WBXML_Dictionary_getIndexByPublicId (dom_parser->dom_tree->doc->publicid);
    }
    
    else if (dom_parser->dom_tree->doc->doc_type){
      dom_parser->dom_tree->parser->dictionary =
        NW_WBXML_Dictionary_getIndexByDocType (dom_parser->dom_tree->doc->doc_type, dom_parser->dom_tree->doc->charset);
    }
    
    /* If a dictionary could not be attained try using the default public id */
    if (dom_parser->dom_tree->parser->dictionary == 0){
      dom_parser->dom_tree->doc->publicid = dom_parser->dom_tree->doc->default_public_id;
      dom_parser->dom_tree->parser->dictionary =
        NW_WBXML_Dictionary_getIndexByPublicId (dom_parser->dom_tree->doc->publicid);
    }
    
    /* Make the StartDocument callback */
    /* Run pass 2 (build tree and any code page registry) */
    NW_WBXML_Parser_registerHandler (dom_parser->dom_tree->parser, 
      &Pass_2_Handler, 
      (void*) dom_parser);
    SET_PASS(dom_parser, T_PARSE_PASS_2);
    
    if (dom_parser->dom_tree->parser->handler && dom_parser->dom_tree->parser->handler->StartDocument_CB)
    {
      status = (*(dom_parser->dom_tree->parser->handler->StartDocument_CB)) (dom_parser->dom_tree->parser, 
        dom_parser->dom_tree->doc, dom_parser);
      if (status != NW_STAT_SUCCESS)
        goto finish_ibuildtree;
    }  
    
    /* Initialize the writer */
    NW_WBXML_Writer_Initialize(dom_parser->dom_tree->writer,
      0, NULL,
      NULL,
      dictionary,
      dictionary,
      NW_Encoder_StringTable_getStringTableOffset,
      NW_Encoder_StringTable_addToStringTable,
      dom_parser->dom_tree->doc->strtbl_extension,
      NW_Encoder_StringTable_StringTableIterateInit,
      NW_Encoder_StringTable_StringTableIterateNext,
      NW_TRUE  /* sizing only pass */);
  }
  else
  {
    dom_parser->dom_tree->parser->p = (NW_Byte *)buffer + dom_parser->dom_tree->parser->offset;
    dom_parser->dom_tree->parser->left = buffsize - dom_parser->dom_tree->parser->offset;
    
    // copy the previous Ebuffer to overwrite the previous part of wbxml buffer.
    // since the previous part has native endianess, the conversion of endianess 
    // (big endian to little endian) only occurs to new contents.
    (void)NW_Mem_memcpy( 
      buffer, dom_parser->dom_tree->tree.ebuffer->segmentList->storage,
      dom_parser->dom_tree->parser->offset);

  }
  /* First get the dictionary */
  dictionary = NW_WBXML_Dictionary_getByIndex(dom_parser->dom_tree->parser->dictionary);
  
  if(dictionary == NULL){
    status = NW_STAT_FAILURE;
    goto finish_ibuildtree;
  }
  
  /* Setup the tree and any code page registry */
  
  
  NW_TinyDom_setLastValid(dom_parser->dom_tree, lastValid);
  
  /* TODO: move all of this down into the wbxml parser itself */
  if(dom_parser->cp_count > 0){
    /* There are code page switches, so add a code page registry */
    old_registry = dom_parser->dom_tree->parser->cp_registry.storage;
    registry = (NW_WBXML_CP_Registry_Entry_t*)NW_Mem_Malloc((dom_parser->cp_count + 1) * sizeof (NW_WBXML_CP_Registry_Entry_t));
    if (registry == NULL){
      status = NW_STAT_OUT_OF_MEMORY;
      goto finish_ibuildtree;
    }

    NW_Mem_memset(registry, 0, ( (dom_parser->cp_count + 1) * sizeof (NW_WBXML_CP_Registry_Entry_t) ) );
    if (old_registry)
    {
      old_cp_offset = dom_parser->dom_tree->parser->cp_registry.current - dom_parser->dom_tree->parser->cp_registry.storage;
      NW_Mem_memcpy(registry, old_registry, 
        dom_parser->dom_tree->parser->cp_registry.count*sizeof(NW_WBXML_CP_Registry_Entry_t));
      NW_Mem_Free(old_registry);
    }
    status = NW_WBXML_Parser_addCPRegistry(dom_parser->dom_tree->parser, 
      registry, dom_parser->cp_count);
    if (status != NW_STAT_SUCCESS){
      goto finish_ibuildtree;
    }
    dom_parser->dom_tree->parser->cp_registry.current = registry + old_cp_offset;
    // WLIU_DEBUG: dom_parser->dom_tree->parser->cp_registry.realcount = old_cp_offset;
    /* Make sure flag is not set, so that new cp entry could be added to the registry */
    dom_parser->dom_tree->parser->flags &= ~NW_WBXML_REGISTRY_INIT; 
  }
  
  //NW_WBXML_Parser_reset (dom_parser->dom_tree->parser); 
  
  /* Run pass 2 (build tree and any code page registry) */
  NW_WBXML_Parser_registerHandler (dom_parser->dom_tree->parser, 
    &Pass_2_Handler, 
    (void*) dom_parser);
  SET_PASS(dom_parser, T_PARSE_PASS_2);
  SET_STATE(dom_parser, T_PARSE_S_CONTENT);
  dom_parser->state &= ~T_PARSE_FLAG_TEXT; /* prepare for text */
  
  // convert endianess if necessary
  if(dom_parser->dom_tree->doc->charset == HTTP_iso_10646_ucs_2){
    string.storage = dom_parser->dom_tree->doc->strtbl.data;
    string.length = dom_parser->dom_tree->doc->strtbl.length;
    if (string.length)
      NW_String_Ucs2_ntoh(&string);
  }

  NW_TinyTree_EBuffer_Destruct (dom_parser->dom_tree->tree.ebuffer );
  
  dom_parser->dom_tree->tree.ebuffer = NW_TinyTree_EBuffer_Construct((NW_Byte *)buffer, 
    buffsize, 
    NW_TINY_TREE_BLOCK_SIZE_DEFAULT,
    freeBuff);
  
  status = NW_WBXML_Parser_parseBuffer(dom_parser->dom_tree->parser, 
    dom_parser->dom_tree->doc, 
    (NW_Byte *) buffer, 
    buffsize);
  //WLIU_DEBUG: dom_parser->dom_tree->parser->lastValid = NW_TinyDom_getLastValid(dom_parser->dom_tree);
  if (status != NW_STAT_SUCCESS){
    goto finish_ibuildtree;
  }
  dom_parser->dom_tree->parser->offset = NW_TinyDom_getLastValid(dom_parser->dom_tree);
finish_ibuildtree:
  return status;
}

/*****************************************************************************
*/
/* Get a pointer to the dom parser from the tiny tree */

EXPORT_C NW_TinyDom_Parser_t*
NW_TinyDom_getParser(NW_TinyTree_t *tree)

{
  return (NW_TinyDom_Parser_t*)NW_TinyTree_getContext(tree);
}

/* Get a pointer to the dom tree from a tiny tree */

EXPORT_C NW_TinyDom_Tree_t*
NW_TinyDom_getTree(NW_TinyTree_t *tree)

{

  NW_TinyDom_Parser_t *dom_parser;

  dom_parser = NW_TinyDom_getParser(tree);
  if(dom_parser != NULL){
    return dom_parser->dom_tree;
  }
  return NULL;
}

/* Get the doc header from the tiny tree */

NW_WBXML_Document_t *
NW_TinyDom_getDocHeader(NW_TinyTree_t *tree)

{
  NW_TinyDom_Tree_t *dom_tree = NW_TinyDom_getTree(tree);

  if(dom_tree != NULL){
    return dom_tree->doc;
  }
  return NULL;
}

/* Deserialization API */

NW_Uint16
NW_TinyDom_Node_getType(NW_TinyTree_Node_t* node){
  return (NW_Uint16)(NW_TinyTree_Node_getFlags(node) & TNODE_USR_FLAGS);
}

/* Deserialization callbacks */


/* 
* Tag callbacks 
* TODO: Combine these with the rest of the pass 3 callbacks
*/

static 
NW_Status_t 
T_Tag_Start_CB (NW_WBXML_Parser_t *parser, 
                void *context)
{
  NW_TinyDom_Tag_t *tag = (NW_TinyDom_Tag_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = tag->tiny_parser;

  NW_REQUIRED_PARAM(parser);

  SET_STATE(tiny_parser, T_PARSE_S_TAG_START);
  return NW_STAT_SUCCESS;
}

static 
NW_Status_t 
T_FQToken_CB (NW_WBXML_Parser_t *parser, 
              NW_Uint32 token, 
              void *context){

  NW_TinyDom_Tag_t *tag = (NW_TinyDom_Tag_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = tag->tiny_parser;

  NW_REQUIRED_PARAM(parser);

  switch (GET_STATE(tiny_parser)){ 
  case T_PARSE_S_TAG_START:
    tag->fq_token = token;
    break;
  default:
    return NW_STAT_SUCCESS;
  }
  return NW_STAT_SUCCESS;
}

static 
NW_Status_t 
T_TableString_CB (NW_WBXML_Parser_t *parser, 
                  NW_Uint32 index, 
                  void *context)
{
  NW_TinyDom_Tag_t *tag = (NW_TinyDom_Tag_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = tag->tiny_parser;

  NW_REQUIRED_PARAM(parser);

  switch (GET_STATE(tiny_parser)){ 
  case T_PARSE_S_TAG_START:
    tag->name_index = index;
    break;
  default:
    return NW_STAT_SUCCESS;
  }
  return NW_STAT_SUCCESS;
}

static const NW_WBXML_EventHandler_t Tag_Handler = {
  0,
  0,
  0,
  0,
  T_Tag_Start_CB,
  0,
  0,
  0,
  0,
  0,
  0,  
  0,
  T_FQToken_CB,
  0,
  T_TableString_CB,
  0,
  0,
  0,
  0
};


/* 
* Pass 3 callbacks. These are called by the parser when deserializing
* text and attributes. Since text elements are just a subset of
* attribute elements, almost exactly the same callbacks can be used
* for both.
*
* Note that parser state between callbacks is only meaningful if the
* callbacks are part of an atomic sequence. Such sequences always
* start with an Attr_Start, Attr_Val or Content callback, followed by
* one of the data type callbacks. Any attempt to use the parser state
* machine in another way is not reentrant.  
*/

static 
NW_Status_t 
Pass_3_Attr_Start_CB (NW_WBXML_Parser_t *parser, 
                      void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;

  NW_REQUIRED_PARAM(parser);

  SET_STATE(tiny_parser, T_PARSE_S_ATTR_START);
  return NW_STAT_SUCCESS;
}

static 
NW_Status_t 
Pass_3_Attr_Val_CB (NW_WBXML_Parser_t *parser, 
                    void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;

  NW_REQUIRED_PARAM(parser);

  SET_STATE(tiny_parser, T_PARSE_S_ATTR_VALS);
  return NW_STAT_SUCCESS;
}

static 
NW_Status_t 
Pass_3_Content_CB (NW_WBXML_Parser_t *parser, 
                   void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;

  NW_REQUIRED_PARAM(parser);

  SET_STATE(tiny_parser, T_PARSE_S_CONTENT);
  return NW_STAT_SUCCESS;
}


static 
NW_Status_t 
Pass_3_Extension_CB (NW_WBXML_Parser_t *parser, 
                     void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;

  NW_REQUIRED_PARAM(parser);

  /* Set the extension substate flag */
  tiny_parser->state |= T_PARSE_F_EXT;
  return NW_STAT_SUCCESS;
}


static 
NW_Status_t 
Pass_3_FQToken_CB (NW_WBXML_Parser_t *parser, 
                   NW_Uint32 token, 
                   void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;
  NW_TinyDom_AttrVal_t* attr_val = (NW_TinyDom_AttrVal_t*)(handle->value);

  NW_REQUIRED_PARAM(parser);

  switch (GET_STATE(tiny_parser)){ 
  case T_PARSE_S_ATTR_START:
    handle->fq_token = token;
    break;
  case T_PARSE_S_ATTR_VALS:
  case T_PARSE_S_CONTENT:
    if((tiny_parser->state & T_PARSE_F_EXT) == T_PARSE_F_EXT){
      attr_val->type = NW_WBXML_ATTR_COMPONENT_EXT;
      attr_val->component.ext.type
        = (NW_Uint8)((tiny_parser->dom_tree->parser->ext_t_not_table_index) ?
           NW_TINYDOM_EXTENSION_TYPE_EXT_T_INTEGER
           : NW_TINYDOM_EXTENSION_TYPE_NORMAL);
      attr_val->component.ext.token = token;
      attr_val->component.ext.value.string.length = 0;
      attr_val->component.ext.value.string.storage = NULL;
    }
    else{ /*TODO: NW_ASSERT that this is not called with T_PARSE_S_ATTR_CONTENT? */
      attr_val->type = NW_WBXML_ATTR_COMPONENT_TOKEN;
      attr_val->component.value_token = token;
    }
    break;
  default:
    break;
  }
  return NW_STAT_SUCCESS;
}

static 
NW_Status_t 
Pass_3_InlineString_CB (NW_WBXML_Parser_t *parser, 
                        NW_Uint32 len, 
                        void *context)
{
  NW_Status_t status;
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;
  NW_TinyDom_AttrVal_t* attr_val = (NW_TinyDom_AttrVal_t*)(handle->value);

  NW_REQUIRED_PARAM(len);

  switch (GET_STATE(tiny_parser)){ 
  case T_PARSE_S_ATTR_VALS:
  case T_PARSE_S_CONTENT:
    if((tiny_parser->state & T_PARSE_F_EXT) == T_PARSE_F_EXT){
      status = NW_WBXML_Parser_getStringInline(parser, 
                                               tiny_parser->dom_tree->doc, 
                                               &(attr_val->component.ext.value.string));
      if(status != NW_STAT_SUCCESS){
        return status;
      }
      tiny_parser->state &= ~T_PARSE_F_EXT; /* Unset extension sub-state */
    }
    else{ 
      attr_val->type = NW_WBXML_ATTR_COMPONENT_STRING;
      status = NW_WBXML_Parser_getStringInline(parser, 
                                               tiny_parser->dom_tree->doc, 
                                               &(attr_val->component.string)); 
      if(status != NW_STAT_SUCCESS){
        return status;
      }

    }
    break;
  default:
    break;
  }
  return NW_STAT_SUCCESS;
}

static 
NW_Status_t 
Pass_3_TableString_CB (NW_WBXML_Parser_t *parser, 
                       NW_Uint32 index, 
                       void *context)
{
  NW_Status_t status;
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;
  NW_TinyDom_AttrVal_t* attr_val = (NW_TinyDom_AttrVal_t*)(handle->value);

  NW_REQUIRED_PARAM(parser);

  switch (GET_STATE(tiny_parser)){
  case T_PARSE_S_ATTR_START:
    handle->name_index = index;
    break;
  case T_PARSE_S_ATTR_VALS:
  case T_PARSE_S_CONTENT:
    if((tiny_parser->state & T_PARSE_F_EXT) == T_PARSE_F_EXT){
      status = NW_WBXML_Document_getTableString(tiny_parser->dom_tree->doc, 
                                                index, 
                                                &(attr_val->component.ext.value.string));
      if(status != NW_STAT_SUCCESS){
        return status;
      }
      tiny_parser->state &= ~T_PARSE_F_EXT; /* Unset extension sub-state */
    }
    else{ 
      attr_val->type = NW_WBXML_ATTR_COMPONENT_STRING;
      status = NW_WBXML_Document_getTableString(tiny_parser->dom_tree->doc, 
                                                index, 
                                                &(attr_val->component.string));
      if(status != NW_STAT_SUCCESS){
        return status;
      } 
    }
    break;
  default:
    break;
  }
  return NW_STAT_SUCCESS;
}


/* TODO: Fill in. This is to get inline integers */

static 
NW_Status_t 
Pass_3_Binary_CB (NW_WBXML_Parser_t *parser, 
                  NW_Uint32 x,
                  void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;

  NW_REQUIRED_PARAM(parser);

  if ((tiny_parser->state & T_PARSE_F_EXT) == T_PARSE_F_EXT) {
    NW_TinyDom_AttrVal_t* attr_val = (NW_TinyDom_AttrVal_t*)(handle->value);
    attr_val->component.ext.value.x = x;
  }
  tiny_parser->state &= ~T_PARSE_F_EXT; /* Unset extension sub-state */
  return NW_STAT_SUCCESS;
}

static 
NW_Status_t 
Pass_3_Opaque_CB (NW_WBXML_Parser_t *parser, 
                  NW_Uint32 len, 
                  void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;  
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;
  NW_TinyDom_AttrVal_t* attr_val = (NW_TinyDom_AttrVal_t*)(handle->value);

  switch (GET_STATE(tiny_parser)){ 
  case T_PARSE_S_ATTR_VALS:
  case T_PARSE_S_CONTENT:
    attr_val->type = NW_WBXML_ATTR_COMPONENT_OPAQUE;
    NW_WBXML_Parser_getOpaque(parser, len, &(attr_val->component.opaque)); 
    break;
  default:
      break;
  }
  return NW_STAT_SUCCESS;
}

static NW_Status_t 
Pass_3_Entity_CB (NW_WBXML_Parser_t *parser, 
                  NW_Uint32 e, 
                  void *context)
{
  NW_TinyDom_AttributeHandle_t *handle = (NW_TinyDom_AttributeHandle_t*)context;
  NW_TinyDom_Parser_t *tiny_parser = handle->tlit.tiny_parser;
  NW_TinyDom_AttrVal_t* attr_val = (NW_TinyDom_AttrVal_t*)(handle->value);

  NW_REQUIRED_PARAM(parser);

  switch (GET_STATE(tiny_parser)){ 
  case T_PARSE_S_ATTR_VALS:
  case T_PARSE_S_CONTENT:
    attr_val->type = NW_WBXML_ATTR_COMPONENT_ENTITY;
    attr_val->component.entity = e;
    break;
  default:
    break;
  }
  return NW_STAT_SUCCESS;
}


static const NW_WBXML_EventHandler_t Pass_3_Handler = {
  0,
  0,
  0,
  0,
  0,
  0,
  Pass_3_Attr_Start_CB,
  Pass_3_Attr_Val_CB,
  Pass_3_Content_CB,
  0,
  Pass_3_Extension_CB,  
  0,
  Pass_3_FQToken_CB,
  Pass_3_InlineString_CB,
  Pass_3_TableString_CB,
  Pass_3_Binary_CB,
  Pass_3_Opaque_CB,
  Pass_3_Entity_CB,
  0
};


/*
* The tiny list iterator is a generic iterator that 
* can be used to invoke parser iterator methods.
*/

static void
TinyDom_ListIterator_init(NW_TinyDom_ListIterator_t *it, 
                          NW_TinyDom_Parser_t *tiny_parser, 
                          NW_TinyTree_Node_t *list_node, 
                          void *context){
  it->tiny_parser = tiny_parser;
  NW_TinyTree_Node_GetSegmentAndOffset(&(tiny_parser->dom_tree->tree),list_node, (NW_Uint8**)&(it->segment), &(it->segSize), &(it->offset));
  it->state = NW_STAT_WBXML_ITERATE_MORE;
  it->context = context;
}

/*
*
* This is a bit complicated: you pass in an iterator function (from
* the parser) that knows how to iterate the type you are interested
* in (e.g. attribute_iterate), and you pass in a handler that the
* parser iterator's callbacks will invoke.  When called, a handler
* receives the interator context field as the context arg.  The
* handler is used to select elements, gather data, etc.  
*
* This, NW_TinyDom_attribute_handle_init, and NW_TinyDom_tag_get, should
* not be called reentrantly (from a parser callback). This doesn't
* seem like a serious restriction. If this becomes a problem, the
* ParserSaveContext/ParserRestoreContext lines can be uncommented to
* make these reentrant.
*/

static 
NW_TinyTree_Offset_t
TinyDom_ListIterator_iterate(NW_TinyDom_ListIterator_t *it, 
                             const NW_WBXML_EventHandler_t *handler, 
                             NW_Status_t (*type_iterator) (NW_WBXML_Parser_t*))
{
  NW_TinyTree_Offset_t startOffset;
  NW_TinyTree_Offset_t sourceOffset;

  
  if (it->state == NW_STAT_WBXML_ITERATE_MORE){
   

    /* Set the parser buffer and buffer size to the values stored in the iterator */
    NW_WBXML_Parser_resetBuffer(it->tiny_parser->dom_tree->parser, 
                                (NW_Byte*) it->segment, 
                                it->segSize);
    
    /* Register the callbacks */
    NW_WBXML_Parser_registerHandler (it->tiny_parser->dom_tree->parser, 
                                     handler, 
                                     it->context);
    startOffset = it->offset;
    /* Now set the parser offset to the value stored in the iterator */
    NW_WBXML_Parser_setOffset(it->tiny_parser->dom_tree->parser, it->offset);
    /* Run the type iterator */
    it->state = (NW_Uint32)(*(type_iterator))(it->tiny_parser->dom_tree->parser);
    /* Set the new iterator offset (the segment should be unchanged)*/
    it->offset = 
      (NW_TinyTree_Offset_t)NW_WBXML_Parser_getOffset(it->tiny_parser->dom_tree->parser);

    if((it->tiny_parser->dom_tree->parser->status != NW_STAT_SUCCESS) ||
       (it->offset == startOffset)){ /* Hack, hack . . The parser didn't advance. */
        return 0;
    }
 
    /* Convert the iterator offset into a source offset to return */

    NW_TinyTree_GetSourceOffset(&(it->tiny_parser->dom_tree->tree), 
                                (NW_Byte*) it->segment, startOffset, &sourceOffset);
    return sourceOffset;
  }
  return 0;
}

void
NW_TinyDom_AttrListHandle_init(NW_TinyDom_AttrListHandle_t *it, 
                               NW_TinyDom_Parser_t *tiny_parser, 
                               NW_TinyTree_Node_t *list_node)
{
  TinyDom_ListIterator_init(it, tiny_parser, list_node, 0); 
}

/* 
* Iterate through a list of attributes. There are
* no attribute list callbacks since we just want to iterate the
* attribute list, returning the start of each attribute.  
*/

NW_TinyTree_Offset_t
NW_TinyDom_AttrListHandle_iterate(NW_TinyDom_AttrListHandle_t *it){
  /* Call list_iterate with a null handler.*/
  return TinyDom_ListIterator_iterate(it, 0, NW_WBXML_Parser_attributeListIterate);
}

/*
* Internal function to iterate the values of an attribute.
*/

NW_TinyTree_Offset_t
NW_TinyDom_AttributeHandle_valsIterate(NW_TinyDom_ListIterator_t *it)
{
  return TinyDom_ListIterator_iterate(it, &Pass_3_Handler, NW_WBXML_Parser_attributeValsIterate);
}

/*String indexes must be less than the largest offset */
#define ILLEGAL_STRING_INDEX ((NW_TinyTree_Offset_t)~0) 

/*
* Initialize an attribute handle by parsing an attribute's start
* token and values, calling the attribute handlers.   
*/

void 
NW_TinyDom_AttributeHandle_init(NW_TinyDom_AttributeHandle_t *handle, 
                                NW_TinyDom_Parser_t *tiny_parser, 
                                NW_TinyTree_Offset_t offset)
{
  /*lint --e{794} Conceivable use of null pointer */

  NW_TinyTree_Node_t dummy_node;
  void *segment;
  NW_TinyTree_Offset_t segSize;
  NW_TinyTree_Offset_t segOffset;

  handle->fq_token = 0;
  handle->name_index = ILLEGAL_STRING_INDEX;
  handle->value = NULL;
  /* Run parser once to get token, name */
  handle->tlit.tiny_parser = tiny_parser;

  /* Fill in a dummy node with the supplied source offset */
  dummy_node.source_offset = offset;

  /* Use this to initialize the parser */
  NW_TinyTree_Node_GetSegmentAndOffset(&(tiny_parser->dom_tree->tree), 
                                       &dummy_node, (NW_Uint8**)&segment, &segSize, &segOffset);

  NW_WBXML_Parser_resetBuffer(tiny_parser->dom_tree->parser, (NW_Byte*) segment, segSize);
  
  NW_WBXML_Parser_registerHandler (tiny_parser->dom_tree->parser, &Pass_3_Handler, handle);
  NW_WBXML_Parser_setOffset(tiny_parser->dom_tree->parser, segOffset);
  /* Run parser once to get past name */
  NW_WBXML_Parser_attributeNameParse(tiny_parser->dom_tree->parser);

 /* Update the dummy node source offset to reflect the parser advance */
  segOffset = 
      (NW_TinyTree_Offset_t)NW_WBXML_Parser_getOffset(tiny_parser->dom_tree->parser);

  NW_TinyTree_GetSourceOffset(&(tiny_parser->dom_tree->tree), (NW_Byte*) segment, 
                              segOffset, &(dummy_node.source_offset));

  TinyDom_ListIterator_init((NW_TinyDom_ListIterator_t*)&(handle->tlit), 
                            tiny_parser, 
                            &dummy_node, 
                            handle);
}

/* Get tag name and token */

static 
void
NW_TinyDom_getTag(NW_TinyDom_Parser_t* tiny_parser, 
                  NW_TinyTree_Node_t* node, 
                  NW_TinyDom_Tag_t* tag)
{
  NW_WBXML_Parser_t *parser = tiny_parser->dom_tree->parser;
  void *segment;
  NW_TinyTree_Offset_t segSize;
  NW_TinyTree_Offset_t segOffset;

  /*NW_WBXML_Parser_t saved_context; */

  tag->tiny_parser = tiny_parser;
  /*NW_WBXML_ParserSaveContext(parser, &saved_context); */
  
  /* Convert the node source offset to segment and offset form */
  NW_TinyTree_Node_GetSegmentAndOffset(&(tiny_parser->dom_tree->tree), 
                                       node, (NW_Uint8**)&segment, &segSize, &segOffset);

  /* Use these values to init the parser */
  NW_WBXML_Parser_resetBuffer(tiny_parser->dom_tree->parser, (NW_Byte*) segment, segSize);
  NW_WBXML_Parser_setOffset(parser, segOffset);
  NW_WBXML_Parser_registerHandler (parser, &Tag_Handler, tag);
  /* Parse the tag name */
  NW_WBXML_Parser_tagNameParse(parser);
  /*NW_WBXML_ParserRestoreContext(parser, &saved_context); */
}

EXPORT_C NW_Uint32
NW_TinyDom_getTagToken(NW_TinyDom_Parser_t* tiny_parser, 
                       NW_TinyTree_Node_t* node)
{
  NW_TinyDom_Tag_t tag;
  NW_TinyDom_getTag(tiny_parser, node, &tag);
  return tag.fq_token;
}


NW_Status_t
NW_TinyDom_getTagName(NW_TinyDom_Parser_t* tiny_parser, 
                      NW_TinyTree_Node_t* node, 
                      NW_String_t* name)
{
  NW_TinyDom_Tag_t tag;

  tag.name_index = ILLEGAL_STRING_INDEX;
  NW_TinyDom_getTag(tiny_parser, node, &tag);
  
  if(tag.name_index != ILLEGAL_STRING_INDEX){
    /*TODO: replace ??*/
    return NW_WBXML_Document_getTableString(tiny_parser->dom_tree->doc, 
                                            tag.name_index, 
                                            name); 
  }
  return NW_STAT_WBXML_NO_NAME;
}

NW_Uint32
NW_TinyDom_AttributeHandle_getToken(NW_TinyDom_AttributeHandle_t *handle)
{
  return handle->fq_token;
}

/* getName is going to return the entire "start token" which might
   include a value prefix */
NW_Status_t
NW_TinyDom_AttributeHandle_getName(NW_TinyDom_AttributeHandle_t *handle,  
                                   NW_String_t *name)
{
  NW_TinyDom_Parser_t * tiny_parser = handle->tlit.tiny_parser;

  if(handle->name_index != ILLEGAL_STRING_INDEX){
    /*TODO: replace?? */
    return NW_WBXML_Document_getTableString(tiny_parser->dom_tree->doc, 
                                            handle->name_index, 
                                            name);
  }
  return NW_STAT_WBXML_NO_NAME;
}

NW_TinyTree_Offset_t
NW_TinyDom_AttributeHandle_iterateValues(NW_TinyDom_AttributeHandle_t* handle, 
                                         NW_TinyDom_AttrVal_t *value)
{
  handle->value = value; /* Set up handle to receive value.*/
  return NW_TinyDom_AttributeHandle_valsIterate((NW_TinyDom_ListIterator_t*)&(handle->tlit));
}


/* Init a text handle */ 

void 
NW_TinyDom_TextHandle_init(NW_TinyDom_TextHandle_t* handle, 
                           NW_TinyDom_Parser_t* tiny_parser, 
                           NW_TinyTree_Offset_t offset)
{
  NW_TinyTree_Node_t dummy_node;

  dummy_node.source_offset = offset; 
  /* Initialize the iterator with this handle as the context */
  TinyDom_ListIterator_init((NW_TinyDom_ListIterator_t *)&(handle->tlit), 
                            tiny_parser, 
                            &dummy_node, 
                            handle);
  handle->value = NULL;
}

/* Iterate through the text items in a text element, calling the text handlers */

NW_TinyTree_Offset_t
NW_TinyDom_TextHandle_iterate(NW_TinyDom_TextHandle_t *handle, 
                              NW_TinyDom_Text_t *item)
{
  handle->value = item;
  return TinyDom_ListIterator_iterate(&(handle->tlit), 
    &Pass_3_Handler, 
    NW_WBXML_Parser_textIterate);
}

void
NW_TinyDom_setLastValid(NW_TinyDom_Tree_t* dom_tree, NW_Int32 lastValid)
{
  NW_ASSERT(dom_tree->tree.tree != NULL);
  dom_tree->tree.tree->lastValid = lastValid;
}


NW_Int32
NW_TinyDom_getLastValid(NW_TinyDom_Tree_t* dom_tree)
{
  if (dom_tree->tree.tree == NULL)
    return 0;
  return dom_tree->tree.tree->lastValid;
}