xml/cxmllibrary/src/tinydom/src/tiny_dom.c
changeset 24 74f0b3eb154c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xml/cxmllibrary/src/tinydom/src/tiny_dom.c	Wed Jun 23 20:27:15 2010 +0530
@@ -0,0 +1,1673 @@
+/*
+* 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;
+}
+
+
+
+
+
+
+
+
+
+
+