As per a suggestion by Olivier Biot, note that objects pointed to by
[obnox/wireshark/wip.git] / packet-wbxml.c
index ae8c20c9d346afe24b418b26ff3eab1651b964d3..d14ae2e991eaa20be11a8b1d9947f25c5d480fa0 100644 (file)
@@ -2,7 +2,7 @@
  * Routines for wbxml dissection
  * Copyright 2003, Olivier Biot <olivier.biot (ad) siemens.com>
  *
- * $Id: packet-wbxml.c,v 1.7 2003/03/27 19:23:10 guy Exp $
+ * $Id: packet-wbxml.c,v 1.12 2003/10/09 18:54:06 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  *
  * NOTES:
  *
- *  - Although Code Page processing is already foreseen in the tag and
- *    attribute parsing code, there is no mechanism available yet to
- *    properly deal with multiple code pages (see, e.g., the wbxml_map[]
- *    array). As a consequence, the same token rendering will occur,
- *    irrespective of the code pages in use.
- *    As there currently is no registered WBXML type with support of more
- *    than one tag or attribute code page, this is a safe assumption.
+ *  - Code page switches only apply to the following token. In the WBXML/1.x
+ *    ABNF notation, it can be proven that the switch_page can only precede
+ *    the following tokens:
+ *      o  stag      : TAG | LITERAL | LITERAL_A | LITERAL_C | LITERAL_AC
+ *      o  attr      : ATTRSTART | ATTRVALUE
+ *      o  extension : EXT_I | EXT_T | EXT
+ *    Code page switches are displayed in a separate column. The only allowed
+ *    code page switches are from code page 0 to another codepage (by means of
+ *    a SWITCH_PAGE token), and from this other code page back to code page 0
+ *    (this happens automatically).
  *
  *  - In order to render the XML content, recursion is inevitable at some
  *    point (when a tag with content occurs in the content of a tag with
  *    is defined for the parsed WBXML content, then the XML rendering is
  *    displayed with appropriate indentation (maximum nesting level = 255,
  *    after which the nesting and level will safely roll-over to 0).
+ *
+ *  - The WAP Forum defines the order of precedence for finding out the
+ *    WBXML content type (same rules for charset) as follows:
+ *      1. Look in the Content-Type WSP header
+ *      2. Look in the WBXML header
+ *    Currently there is no means of using content type parameters:
+ *      o  Type=<some_type>
+ *      o  Charset=<charset_of_the_content>
+ *    So it is possible some WBXML content types are incorrectly parsed.
+ *    This would only be the case when the content type declaration in the
+ *    WSP Content-Type header would be different (or would have parameters
+ *    which are relevant to the WBXML decoding) from the content type
+ *    identifier specified in the WBXML header.
+ *    TODO: investigate this and provide correct decoding at all times.
  */
 
+typedef struct _value_valuestring {
+  guint32 value;
+  const value_string *valstrptr;
+} value_valuestring;
+
+/* Tries to match val against each element in the value_value_string array vvs.
+ * Returns the associated value_string ptr on a match, or NULL on failure. */
+static const value_string *
+val_to_valstr(guint32 val, const value_valuestring *vvs)
+{
+  gint i = 0;
+
+  while (vvs[i].valstrptr) {
+       if (vvs[i].value == val)
+      return(vvs[i].valstrptr);
+      i++;
+  }
+
+  return(NULL);
+}
+
 
-/************************* Variable declarations *************************/
+/************************** Variable declarations **************************/
 
 
 /* Initialize the protocol and registered fields */
@@ -93,24 +131,11 @@ static gint ett_wbxml_str_tbl = -1;
 static gint ett_wbxml_content = -1;
 
 
+/**************** WBXML related declarations and definitions ****************/
 
-/********** WBXML related declarations and definitions **********/
-
-/* See http://www.wapforum.org/wina/ for an up-to-date list. */
-#define WBXML_WML_10           0x02
-#define WBXML_WTA_10           0x03
-#define WBXML_WML_11           0x04
-#define WBXML_SI_10                    0x05
-#define WBXML_SL_10                    0x06
-#define WBXML_CO_10                    0x07
-#define WBXML_CHANNEL_10       0x08
-#define WBXML_WML_12           0x09
-#define WBXML_WML_13           0x0a
-#define WBXML_PROV_10          0x0b
-#define WBXML_WTAWML_12                0x0c
-#define WBXML_EMN_10           0x0d
-#define WBXML_DRMREL_10                0x0e
 
+/* WBXML public ID mappings. For an up-to-date list, see
+ * http://www.wapforum.org/wina/wbxml-public-docid.htm */
 static const value_string vals_wbxml_public_ids[] = {
        /* 0x00 = literal public identifier */
        { 0x01, "Unknown / missing Public Identifier" },
@@ -128,50 +153,46 @@ static const value_string vals_wbxml_public_ids[] = {
        { 0x0d, "-//WAPFORUM//DTD EMN 1.0//EN (Email Notification 1.0)" },
        { 0x0e, "-//WAPFORUM//DTD DRMREL 1.0//EN (DRMREL 1.0)" },
        
+       /* Registered values - www.syncml.org */
+       { 0x0fd1, "-//SYNCML//DTD SyncML 1.0//EN (SyncML 1.0)" },
+       { 0x0fd3, "-//SYNCML//DTD SyncML 1.1//EN (SyncML 1.1)" },
+
+       /* Registered values - www.wapforum.org/wina/ */
+       { 0x1100, "-//PHONE.COM//DTD ALERT 1.0//EN" },
+       { 0x1101, "-//PHONE.COM//DTD CACHE-OPERATION 1.0//EN" },
+       { 0x1102, "-//PHONE.COM//DTD SIGNAL 1.0//EN" },
+       { 0x1103, "-//PHONE.COM//DTD LIST 1.0//EN" },
+       { 0x1104, "-//PHONE.COM//DTD LISTCMD 1.0//EN" },
+       { 0x1105, "-//PHONE.COM//DTD CHANNEL 1.0//EN" },
+       { 0x1106, "-//PHONE.COM//DTD MMC 1.0//EN" },
+       { 0x1107, "-//PHONE.COM//DTD BEARER-CHOICE 1.0//EN" },
+       { 0x1108, "-//PHONE.COM//DTD WML 1.1//EN (WML+ 1.1)" },
+       { 0x1109, "-//PHONE.COM//DTD CHANNEL 1.1//EN" },
+       { 0x110a, "-//PHONE.COM//DTD LIST 1.1//EN" },
+       { 0x110b, "-//PHONE.COM//DTD LISTCMD 1.1//EN" },
+       { 0x110c, "-//PHONE.COM//DTD MMC 1.1//EN" },
+       { 0x110d, "-//PHONE.COM//DTD WML 1.3//EN (WML+ 1.3)" },
+       { 0x110e, "-//PHONE.COM//DTD MMC 2.0//EN" },
+       
        { 0x00, NULL }
 };
 
-
-
 static const value_string vals_wbxml_versions[] = {
-       { 0x00, "1.0" },
-       { 0x01, "1.1" },
-       { 0x02, "1.2" },
-       { 0x03, "1.3" },
+       { 0x00, "1.0" },        /* WAP-104-WBXML */
+       { 0x01, "1.1" },        /* WAP-135-WBXML */
+       { 0x02, "1.2" },        /* WAP-154-WBXML */
+       { 0x03, "1.3" },        /* WAP-192-WBXML */
        
        { 0x00, NULL }
 };
 
-/* See WAP-104-WBXML */
-static const value_string vals_wbxml10_global_tokens[] = {
-       { 0x00, "SWITCH_PAGE" },
-       { 0x01, "END" },
-       { 0x02, "ENTITY" },
-       { 0x03, "STR_I" },
-       { 0x04, "LITERAL" },
-
-       { 0x40, "EXT_I_0" },
-       { 0x41, "EXT_I_1" },
-       { 0x42, "EXT_I_2" },
-       { 0x43, "PI" },
-       { 0x44, "LITERAL_C" },
-
-       { 0x80, "EXT_T_0" },
-       { 0x81, "EXT_T_1" },
-       { 0x82, "EXT_T_2" },
-       { 0x83, "STR_T" },
-       { 0x84, "LITERAL_A" },
-
-       { 0xC0, "EXT_0" },
-       { 0xC1, "EXT_1" },
-       { 0xC2, "EXT_2" },
-       { 0xC3, "RESERVED_2" },
-       { 0xC4, "LITERAL_AC" },
-
-       { 0x00, NULL }
-};
+/* WBXML 1.0 global tokens: WAP-104-WBXML
+ * Same token mapping as in vals_wbxml1x_global_tokens, but:
+ *   { 0xC3, "RESERVED_2" }
+ */
 
-/* See WAP-135-WBXML, WAP-154-WBXML, WAP-192-WBXML */
+/* WBXML 1.x (x>0) global tokens: WAP-135-WBXML, WAP-154-WBXML, WAP-192-WBXML
+ */
 static const value_string vals_wbxml1x_global_tokens[] = {
        { 0x00, "SWITCH_PAGE" },
        { 0x01, "END" },
@@ -201,12 +222,16 @@ static const value_string vals_wbxml1x_global_tokens[] = {
 };
 
 
-/****************************************************************************/
+/********************** WBXML token mapping definition **********************/
+
 
-/*******************************************
- *      WML 1.0 - Global tokens (EXT)      *
- *******************************************/
-static const value_string vals_wmlc10_global[] = {
+/* WML 1.0
+ * 
+ * Wireless Markup Language
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+static const value_string wbxml_wmlc10_global_cp0[] = {
        { 0x40, "Variable substitution - escaped" },
        { 0x41, "Variable substitution - unescaped" },
        { 0x42, "Variable substitution - no transformation" },
@@ -220,10 +245,8 @@ static const value_string vals_wmlc10_global[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *              WML 1.0 - Tags             *
- *******************************************/
-static const value_string vals_wmlc10_tags[] = {
+/*****         Tag tokens          *****/
+static const value_string wbxml_wmlc10_tags_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        /* 0x05 -- 0xE1 */
        { 0xE2, "A" },
@@ -260,10 +283,8 @@ static const value_string vals_wmlc10_tags[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *       WML 1.0 - Attribute Start         *
- *******************************************/
-static const value_string vals_wmlc10_attrStart[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_wmlc10_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "ACCEPT-CHARSET=" },
        { 0x06, "ALIGN='BOTTOM'" },
@@ -342,10 +363,8 @@ static const value_string vals_wmlc10_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *       WML 1.0 - Attribute Value         *
- *******************************************/
-static const value_string vals_wmlc10_attrValue[] = {
+/*****    Attribute Value tokens   *****/
+static const value_string wbxml_wmlc10_attrValue_cp0[] = {
        /* 0x80 -- 0x84 GLOBAL */
        { 0x85, "'.com/'" },
        { 0x86, "'.edu/'" },
@@ -380,17 +399,41 @@ static const value_string vals_wmlc10_attrValue[] = {
        { 0x00, NULL }
 };
 
-/****************************************************************************/
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_wmlc10_global[] = {
+       { 0, wbxml_wmlc10_global_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc10_tags[] = {
+       { 0, wbxml_wmlc10_tags_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc10_attrStart[] = {
+       { 0, wbxml_wmlc10_attrStart_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc10_attrValue[] = {
+       { 0, wbxml_wmlc10_attrValue_cp0 },
+       { 0, NULL }
+};
+
+
+
 
-/*******************************************
- *      WML 1.1 - Global tokens (EXT)      *
- *******************************************/
-#define vals_wmlc11_global  vals_wmlc10_global
 
-/*******************************************
- *              WML 1.1 - Tags             *
- *******************************************/
-static const value_string vals_wmlc11_tags[] = {
+/* WML 1.1
+ * 
+ * Wireless Markup Language
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+/* Same as in WML 1.0 */
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_wmlc11_tags_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        /* 0x05 -- 0x1B */
        { 0x1C, "a" },
@@ -433,10 +476,8 @@ static const value_string vals_wmlc11_tags[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *       WML 1.1 - Attribute Start         *
- *******************************************/
-static const value_string vals_wmlc11_attrStart[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_wmlc11_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "accept-charset=" },
        { 0x06, "align='bottom'" },
@@ -525,10 +566,8 @@ static const value_string vals_wmlc11_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *       WML 1.1 - Attribute Value         *
- *******************************************/
-static const value_string vals_wmlc11_attrValue[] = {
+/*****    Attribute Value tokens   *****/
+static const value_string wbxml_wmlc11_attrValue_cp0[] = {
        /* 0x80 -- 0x84 GLOBAL */
        { 0x85, "'.com/'" },
        { 0x86, "'.edu/'" },
@@ -563,17 +602,41 @@ static const value_string vals_wmlc11_attrValue[] = {
        { 0x00, NULL }
 };
 
-/****************************************************************************/
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_wmlc11_global[] = {
+       { 0, wbxml_wmlc10_global_cp0 }, /* Same as WML 1.0 */
+       { 0, NULL }
+};
 
-/*******************************************
- *      WML 1.2 - Global tokens (EXT)      *
- *******************************************/
-#define vals_wmlc12_global vals_wmlc11_global
-       
-/*******************************************
- *              WML 1.2 - Tags             *
- *******************************************/
-static const value_string vals_wmlc12_tags[] = {
+static const value_valuestring wbxml_wmlc11_tags[] = {
+       { 0, wbxml_wmlc11_tags_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc11_attrStart[] = {
+       { 0, wbxml_wmlc11_attrStart_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc11_attrValue[] = {
+       { 0, wbxml_wmlc11_attrValue_cp0 },
+       { 0, NULL }
+};
+
+
+
+
+
+/* WML 1.2
+ * 
+ * Wireless Markup Language
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+/* Same as in WML 1.0 */
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_wmlc12_tags_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        /* 0x05 -- 0x1A */
        { 0x1B, "pre" },
@@ -617,10 +680,8 @@ static const value_string vals_wmlc12_tags[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *       WML 1.2 - Attribute Start         *
- *******************************************/
-static const value_string vals_wmlc12_attrStart[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_wmlc12_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "accept-charset=" },
        { 0x06, "align='bottom'" },
@@ -713,30 +774,47 @@ static const value_string vals_wmlc12_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *       WML 1.2 - Attribute Value         *
- *******************************************/
-#define vals_wmlc12_attrValue vals_wmlc11_attrValue
-/* Same as WML 1.1 */
+/*****    Attribute Value tokens   *****/
+/* Same as in WML 1.1 */
+
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_wmlc12_global[] = {
+       { 0, wbxml_wmlc10_global_cp0 }, /* Same as WML 1.0 */
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc12_tags[] = {
+       { 0, wbxml_wmlc12_tags_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc12_attrStart[] = {
+       { 0, wbxml_wmlc12_attrStart_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc12_attrValue[] = {
+       { 0, wbxml_wmlc11_attrValue_cp0 }, /* Same as WML 1.1 */
+       { 0, NULL }
+};
+
 
 
-/****************************************************************************/
 
-/*******************************************
- *      WML 1.3 - Global tokens (EXT)      *
- *******************************************/
-#define vals_wmlc13_global vals_wmlc11_global
 
-/*******************************************
- *              WML 1.3 - Tags             *
- *******************************************/
-#define vals_wmlc13_tags vals_wmlc12_tags
-/* Same as WML 1.1 */
+/* WML 1.3
+ * 
+ * Wireless Markup Language
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+/* Same as in WML 1.0 */
 
-/*******************************************
- *       WML 1.3 - Attribute Start         *
- *******************************************/
-static const value_string vals_wmlc13_attrStart[] = {
+/*****         Tag tokens          *****/
+/* Same as in WML 1.2 */
+
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_wmlc13_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "accept-charset=" },
        { 0x06, "align='bottom'" },
@@ -832,27 +910,43 @@ static const value_string vals_wmlc13_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *       WML 1.3 - Attribute Value         *
- *******************************************/
-#define vals_wmlc13_attrValue vals_wmlc11_attrValue
-/* Same as WML 1.1 */
+/*****    Attribute Value tokens   *****/
+/* Same as in WML 1.1 */
 
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_wmlc13_global[] = {
+       { 0, wbxml_wmlc10_global_cp0 }, /* Same as WML 1.0 */
+       { 0, NULL }
+};
 
-/****************************************************************************/
+static const value_valuestring wbxml_wmlc13_tags[] = {
+       { 0, wbxml_wmlc12_tags_cp0 },
+       { 0, NULL }
+};
 
-/*******************************************
- *      SI 1.0 - Global tokens (EXT)       *
- *******************************************/
-static const value_string vals_sic10_global[] = {
-       { 0x00, NULL }
+static const value_valuestring wbxml_wmlc13_attrStart[] = {
+       { 0, wbxml_wmlc13_attrStart_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_wmlc13_attrValue[] = {
+       { 0, wbxml_wmlc11_attrValue_cp0 }, /* Same as WML 1.1 */
+       { 0, NULL }
 };
 
 
-/*******************************************
- *           SI 1.0 - Tags                 *
- *******************************************/
-static const value_string vals_sic10_tags[] = {
+
+
+
+/* SI 1.0
+ * 
+ * Service Indication
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_sic10_tags_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "si" },
        { 0x06, "indication" },
@@ -862,10 +956,8 @@ static const value_string vals_sic10_tags[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *        SI 1.0 - Attribute Start         *
- *******************************************/
-static const value_string vals_sic10_attrStart[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_sic10_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "action='signal-none'" },
        { 0x06, "action='signal-low'" },
@@ -885,10 +977,8 @@ static const value_string vals_sic10_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *        SI 1.0 - Attribute Value         *
- *******************************************/
-static const value_string vals_sic10_attrValue[] = {
+/*****    Attribute Value tokens   *****/
+static const value_string wbxml_sic10_attrValue_cp0[] = {
        /* 0x80 -- 0x84 GLOBAL */
        { 0x85, "'.com/'" },
        { 0x86, "'.edu/'" },
@@ -898,31 +988,43 @@ static const value_string vals_sic10_attrValue[] = {
        { 0x00, NULL }
 };
 
-/****************************************************************************/
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_sic10_tags[] = {
+       { 0, wbxml_sic10_tags_cp0 },
+       { 0, NULL }
+};
 
+static const value_valuestring wbxml_sic10_attrStart[] = {
+       { 0, wbxml_sic10_attrStart_cp0 },
+       { 0, NULL }
+};
 
-/*******************************************
- *      SL 1.0 - Global tokens (EXT)       *
- *******************************************/
-static const value_string vals_slc10_global[] = {
-       { 0x00, NULL }
+static const value_valuestring wbxml_sic10_attrValue[] = {
+       { 0, wbxml_sic10_attrValue_cp0 },
+       { 0, NULL }
 };
 
 
-/*******************************************
- *           SL 1.0 - Tags                 *
- *******************************************/
-static const value_string vals_slc10_tags[] = {
+
+
+
+/* SL 1.0
+ * 
+ * Service Loading
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_slc10_tags_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "sl" },
 
        { 0x00, NULL }
 };
 
-/*******************************************
- *        SL 1.0 - Attribute Start         *
- *******************************************/
-static const value_string vals_slc10_attrStart[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_slc10_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "action='execute-low'" },
        { 0x06, "action='execute-high'" },
@@ -936,34 +1038,38 @@ static const value_string vals_slc10_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *        SL 1.0 - Attribute Value         *
- *******************************************/
-static const value_string vals_slc10_attrValue[] = {
-       /* 0x80 -- 0x84 GLOBAL */
-       { 0x85, "'.com/'" },
-       { 0x86, "'.edu/'" },
-       { 0x87, "'.net/'" },
-       { 0x88, "'.org/'" },
+/*****    Attribute Value tokens   *****/
+/* Same as in SI 1.0 */
 
-       { 0x00, NULL }
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_slc10_tags[] = {
+       { 0, wbxml_slc10_tags_cp0 },
+       { 0, NULL }
 };
 
-/****************************************************************************/
-
+static const value_valuestring wbxml_slc10_attrStart[] = {
+       { 0, wbxml_slc10_attrStart_cp0 },
+       { 0, NULL }
+};
 
-/*******************************************
- *      CO 1.0 - Global tokens (EXT)       *
- *******************************************/
-static const value_string vals_coc10_global[] = {
-       { 0x00, NULL }
+static const value_valuestring wbxml_slc10_attrValue[] = {
+       { 0, wbxml_sic10_attrValue_cp0 }, /* Same as SI 1.0 */
+       { 0, NULL }
 };
 
 
-/*******************************************
- *           CO 1.0 - Tags                 *
- *******************************************/
-static const value_string vals_coc10_tags[] = {
+
+
+
+/* CO 1.0
+ * 
+ * Cache Operation
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_coc10_tags_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "co" },
        { 0x06, "invalidate-object" },
@@ -972,10 +1078,8 @@ static const value_string vals_coc10_tags[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *        CO 1.0 - Attribute Start         *
- *******************************************/
-static const value_string vals_coc10_attrStart[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_coc10_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "uri=" },
        { 0x06, "uri='http://'" },
@@ -986,35 +1090,38 @@ static const value_string vals_coc10_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *        CO 1.0 - Attribute Value         *
- *******************************************/
-static const value_string vals_coc10_attrValue[] = {
-       /* 0x80 -- 0x84 GLOBAL */
-       { 0x85, "'.com/'" },
-       { 0x86, "'.edu/'" },
-       { 0x87, "'.net/'" },
-       { 0x88, "'.org/'" },
+/*****    Attribute Value tokens   *****/
+/* Same as in SI 1.0 */
 
-       { 0x00, NULL }
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_coc10_tags[] = {
+       { 0, wbxml_coc10_tags_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_coc10_attrStart[] = {
+       { 0, wbxml_coc10_attrStart_cp0 },
+       { 0, NULL }
 };
 
+static const value_valuestring wbxml_coc10_attrValue[] = {
+       { 0, wbxml_sic10_attrValue_cp0 }, /* Same as SI 1.0 */
+       { 0, NULL }
+};
 
-/****************************************************************************/
 
 
-/*******************************************
- *      PROV 1.0 - Global tokens (EXT)       *
- *******************************************/
-static const value_string vals_provc10_global[] = {
-       { 0x00, NULL }
-};
 
 
-/*******************************************
- *           PROV 1.0 - Tags                 *
- *******************************************/
-static const value_string vals_provc10_tags[] = {
+/* PROV 1.0
+ *
+ * Client Provisioning
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_provc10_tags_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "wap-provisioningdoc" },
        { 0x06, "characteristic" },
@@ -1023,10 +1130,8 @@ static const value_string vals_provc10_tags[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *        PROV 1.0 - Attribute Start         *
- *******************************************/
-static const value_string vals_provc10_attrStart[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_provc10_attrStart_cp0[] = {
        /* 0x00 -- 0x04 GLOBAL */
        { 0x05, "name=" },
        { 0x06, "value=" },
@@ -1104,10 +1209,8 @@ static const value_string vals_provc10_attrStart[] = {
        { 0x00, NULL }
 };
 
-/*******************************************
- *        PROV 1.0 - Attribute Value         *
- *******************************************/
-static const value_string vals_provc10_attrValue[] = {
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_provc10_attrValue_cp0[] = {
        /* 0x80 -- 0x84 GLOBAL */
        { 0x85, "'IPV4'" },
        { 0x86, "'IPV6'" },
@@ -1168,167 +1271,573 @@ static const value_string vals_provc10_attrValue[] = {
        { 0x00, NULL }
 };
 
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_provc10_tags[] = {
+       { 0, wbxml_provc10_tags_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_provc10_attrStart[] = {
+       { 0, wbxml_provc10_attrStart_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_provc10_attrValue[] = {
+       { 0, wbxml_provc10_attrValue_cp0 },
+       { 0, NULL }
+};
+
+
+
+
+
+/* EMN 1.0
+ * 
+ * Email Notification
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_emnc10_tags_cp0[] = {
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "emn" },
+
+       { 0x00, NULL }
+};
+
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_emnc10_attrStart_cp0[] = {
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "timestamp=" },
+       { 0x06, "mailbox=" },
+       { 0x07, "mailbox='mailat:'" },
+       { 0x08, "mailbox='pop://'" },
+       { 0x09, "mailbox='imap://'" },
+       { 0x0a, "mailbox='http://'" },
+       { 0x0b, "mailbox='http://www.'" },
+       { 0x0c, "mailbox='https://'" },
+       { 0x0D, "mailbox='https://www.'" },
+
+       { 0x00, NULL }
+};
+
+/*****    Attribute Value tokens   *****/
+/* Same as in SI 1.0 */
+
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_emnc10_tags[] = {
+       { 0, wbxml_emnc10_tags_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_emnc10_attrStart[] = {
+       { 0, wbxml_emnc10_attrStart_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_emnc10_attrValue[] = {
+       { 0, wbxml_sic10_attrValue_cp0 }, /* Same as SI 1.0 */
+       { 0, NULL }
+};
+
+
+
+
+
+/* SyncML 1.0
+ * 
+ * SyncML Representation Protocol
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_syncmlc10_tags_cp0[] = { /* SyncML 1.0 */
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "Add" },
+       { 0x06, "Alert" },
+       { 0x07, "Archive" },
+       { 0x08, "Atomic" },
+       { 0x09, "Chal" },
+       { 0x0A, "Cmd" },
+       { 0x0B, "CmdID" },
+       { 0x0C, "CmdRef" },
+       { 0x0D, "Copy" },
+       { 0x0E, "Cred" },
+       { 0x0F, "Data" },
+       { 0x10, "Delete" },
+       { 0x11, "Exec" },
+       { 0x12, "Final" },
+       { 0x13, "Get" },
+       { 0x14, "Item" },
+       { 0x15, "Lang" },
+       { 0x16, "LocName" },
+       { 0x17, "LocURI" },
+       { 0x18, "Map" },
+       { 0x19, "MapItem" },
+       { 0x1A, "Meta" },
+       { 0x1B, "MsgID" },
+       { 0x1C, "MsgRef" },
+       { 0x1D, "NoResp" },
+       { 0x1E, "NoResults" },
+       { 0x1F, "Put" },
+       { 0x20, "Replace" },
+       { 0x21, "RespURI" },
+       { 0x22, "Results" },
+       { 0x23, "Search" },
+       { 0x24, "Sequence" },
+       { 0x25, "SessionID" },
+       { 0x26, "SftDel" },
+       { 0x27, "Source" },
+       { 0x28, "SourceRef" },
+       { 0x29, "Status" },
+       { 0x2A, "Sync" },
+       { 0x2B, "SyncBody" },
+       { 0x2C, "SyncHdr" },
+       { 0x2D, "SyncML" },
+       { 0x2E, "Target" },
+       { 0x2F, "TargetRef" },
+       /* 0x30 - Reserved */
+       { 0x31, "VerDTD" },
+       { 0x32, "VerProto" },
+
+       { 0x00, NULL }
+};
+
+static const value_string wbxml_syncmlc10_tags_cp1[] = { /* MetInf 1.0 */
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "Anchor" },
+       { 0x06, "EMI" },
+       { 0x07, "Format" },
+       { 0x08, "FreeID" },
+       { 0x09, "FreeMem" },
+       { 0x0A, "Last" },
+       { 0x0B, "Mark" },
+       { 0x0C, "MaxMsgSize" },
+       { 0x0D, "Mem" },
+       { 0x0E, "MetInf" },
+       { 0x0F, "Next" },
+       { 0x10, "NextNonce" },
+       { 0x11, "SharedMem" },
+       { 0x12, "Size" },
+       { 0x13, "Type" },
+       { 0x14, "Version" },
+
+       { 0x00, NULL }
+};
+
+/*****    Attribute Start tokens   *****/
+
+/*****    Attribute Value tokens   *****/
+
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_syncmlc10_tags[] = {
+       { 0, wbxml_syncmlc10_tags_cp0 }, /* -//SYNCML//DTD SyncML 1.0//EN */
+       { 0, wbxml_syncmlc10_tags_cp1 }, /* -//SYNCML//DTD MetInf 1.0//EN */
+       { 0, NULL }
+};
+
+
+
+
+
+/* SyncML 1.1
+ * 
+ * SyncML Representation Protocol
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_syncmlc11_tags_cp0[] = { /* SyncML 1.1 */
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "Add" },
+       { 0x06, "Alert" },
+       { 0x07, "Archive" },
+       { 0x08, "Atomic" },
+       { 0x09, "Chal" },
+       { 0x0a, "Cmd" },
+       { 0x0b, "CmdID" },
+       { 0x0c, "CmdRef" },
+       { 0x0d, "Copy" },
+       { 0x0e, "Cred" },
+       { 0x0f, "Data" },
+       { 0x10, "Delete" },
+       { 0x11, "Exec" },
+       { 0x12, "Final" },
+       { 0x13, "Get" },
+       { 0x14, "Item" },
+       { 0x15, "Lang" },
+       { 0x16, "LocName" },
+       { 0x17, "LocURI" },
+       { 0x18, "Map" },
+       { 0x19, "MapItem" },
+       { 0x1a, "Meta" },
+       { 0x1b, "MsgID" },
+       { 0x1c, "MsgRef" },
+       { 0x1d, "NoResp" },
+       { 0x1e, "NoResults" },
+       { 0x1f, "Put" },
+       { 0x20, "Replace" },
+       { 0x21, "RespURI" },
+       { 0x22, "Results" },
+       { 0x23, "Search" },
+       { 0x24, "Sequence" },
+       { 0x25, "SessionID" },
+       { 0x26, "SftDel" },
+       { 0x27, "Source" },
+       { 0x28, "SourceRef" },
+       { 0x29, "Status" },
+       { 0x2a, "Sync" },
+       { 0x2b, "SyncBody" },
+       { 0x2c, "SyncHdr" },
+       { 0x2d, "SyncML" },
+       { 0x2e, "Target" },
+       { 0x2f, "TargetRef" },
+       /* 0x30 - Reserved */
+       { 0x31, "VerDTD" },
+       { 0x32, "VerProto" },
+       { 0x33, "NumberOfChanges" },
+       { 0x34, "MoreData" },
+
+       { 0x00, NULL }
+};
+
+static const value_string wbxml_syncmlc11_tags_cp1[] = { /* MetInf 1.1 */
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "Anchor" },
+       { 0x06, "EMI" },
+       { 0x07, "Format" },
+       { 0x08, "FreeID" },
+       { 0x09, "FreeMem" },
+       { 0x0A, "Last" },
+       { 0x0B, "Mark" },
+       { 0x0C, "MaxMsgSize" },
+       { 0x0D, "Mem" },
+       { 0x0E, "MetInf" },
+       { 0x0F, "Next" },
+       { 0x10, "NextNonce" },
+       { 0x11, "SharedMem" },
+       { 0x12, "Size" },
+       { 0x13, "Type" },
+       { 0x14, "Version" },
+       { 0x15, "MaxObjSize" },
+
+       { 0x00, NULL }
+};
+
+/*****    Attribute Start tokens   *****/
+
+/*****    Attribute Value tokens   *****/
+
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_syncmlc11_tags[] = {
+       { 0, wbxml_syncmlc11_tags_cp0 }, /* -//SYNCML//DTD SyncML 1.1//EN */
+       { 0, wbxml_syncmlc11_tags_cp1 }, /* -//SYNCML//DTD MetInf 1.1//EN */
+       { 0, NULL }
+};
 
-/****************************************************************************/
 
 
 
-/* The struct object contains references to objects defined above!
- */
 
-typedef struct {
-       const guint8 defined;
-       const value_string *global;
-       const value_string *tags;
-       const value_string *attrStart;
-       const value_string *attrValue;
-} wbxml_mapping_table;
+/* CHANNEL 1.0
+ * 
+ * WTA Channel
+ ***************************************/
+
+/*****   Global extension tokens   *****/
+
+/*****         Tag tokens          *****/
+static const value_string wbxml_channelc10_tags_cp0[] = {
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "channel" },
+       { 0x06, "title" },
+       { 0x07, "abstract" },
+       { 0x08, "resource" },
+
+       { 0x00, NULL }
+};
+
+/*****    Attribute Start tokens   *****/
+static const value_string wbxml_channelc10_attrStart_cp0[] = {
+       /* 0x00 -- 0x04 GLOBAL */
+       { 0x05, "maxspace" },
+       { 0x06, "base" },
+       { 0x07, "href" },
+       { 0x08, "href='http://'" },
+       { 0x09, "href='https://'" },
+       { 0x0A, "lastmod" },
+       { 0x0B, "etag" },
+       { 0x0C, "md5" },
+       { 0x0D, "success" },
+       { 0x0E, "success='http://'" },
+       { 0x0F, "success='https://'" },
+       { 0x10, "failure" },
+       { 0x11, "failure='http://'" },
+       { 0x12, "failure='https://'" },
+       { 0x13, "EventId" },
+
+       { 0x00, NULL }
+};
+
+/*****    Attribute Value tokens   *****/
 
-/* BEWARE: values 0 and 1 are not defined, so we start from 2
+/***** Token code page aggregation *****/
+static const value_valuestring wbxml_channelc10_tags[] = {
+       { 0, wbxml_channelc10_tags_cp0 },
+       { 0, NULL }
+};
+
+static const value_valuestring wbxml_channelc10_attrStart[] = {
+       { 0, wbxml_channelc10_attrStart_cp0 },
+       { 0, NULL }
+};
+
+
+
+
+
+/********************** WBXML token mapping aggregation **********************/
+
+
+/* The following structure links content types to their token mapping and
+ * contains arrays of pointers to value_string arrays (one per code page).
  */
-static const wbxml_mapping_table wbxml_map[] = {
-       { /* 0x00 = literal public identifier */
-               FALSE, NULL, NULL, NULL, NULL
+typedef struct _wbxml_token_map {
+       const guint32 publicid;  /* WBXML DTD number - see WINA */
+       const guint8 defined;    /* Are there mapping tables defined */
+       const value_valuestring *global;     /* Global token map */
+       const value_valuestring *tags;       /* Tag token map */
+       const value_valuestring *attrStart;  /* Attribute Start token map */
+       const value_valuestring *attrValue;  /* Attribute Value token map */
+} wbxml_token_map;
+
+static const wbxml_token_map *wbxml_content_map (guint32 publicid);
+
+/**
+ ** Aggregation of content type and aggregated code pages
+ ** Content type map lookup will stop at the 1st entry with 2nd member = FALSE
+ **/
+static const wbxml_token_map map[] = {
+#ifdef Test_the_WBXML_parser_without_token_mappings
+       { 0, FALSE, NULL, NULL, NULL, NULL },
+#endif
+       { 0x02, TRUE, /* WML 1.0 */
+               wbxml_wmlc10_global,
+               wbxml_wmlc10_tags,
+               wbxml_wmlc10_attrStart,
+               wbxml_wmlc10_attrValue
        },
-       { /* 0x01 = Unknown or missing public identifier */
-               FALSE, NULL, NULL, NULL, NULL
+#ifdef remove_directive_and_set_TRUE_if_mapping_available
+       { 0x03, FALSE, /* WTA 1.0 (deprecated) */
+               NULL, NULL, NULL, NULL
        },
-       { /* 0x02 = WML 1.0 */
-               TRUE, vals_wmlc10_global, vals_wmlc10_tags,
-               vals_wmlc10_attrStart, vals_wmlc10_attrValue
+#endif
+       { 0x04, TRUE, /* WML 1.1 */
+               wbxml_wmlc11_global,
+               wbxml_wmlc11_tags,
+               wbxml_wmlc11_attrStart,
+               wbxml_wmlc11_attrValue
        },
-       { /* 0x03 = WTA 1.0 - Deprecated */
-               FALSE, NULL, NULL, NULL, NULL
+       { 0x05, TRUE, /* SI 1.0 */
+               NULL, /* wbxml_sic10_global - does not exist */
+               wbxml_sic10_tags,
+               wbxml_sic10_attrStart,
+               wbxml_sic10_attrValue
        },
-       { /* 0x04 = WML 1.1 */
-               TRUE, vals_wmlc11_global, vals_wmlc11_tags,
-               vals_wmlc11_attrStart, vals_wmlc11_attrValue
+       { 0x06, TRUE, /* SL 1.0 */
+               NULL, /* wbxml_slc10_global - does not exist */
+               wbxml_slc10_tags,
+               wbxml_slc10_attrStart,
+               wbxml_slc10_attrValue
        },
-       { /* 0x05 = SI 1.0 */
-               TRUE, vals_sic10_global, vals_sic10_tags,
-               vals_sic10_attrStart, vals_sic10_attrValue
+       { 0x07, TRUE, /* CO 1.0 */
+               NULL, /* wbxml_coc10_global - does not exist */
+               wbxml_coc10_tags,
+               wbxml_coc10_attrStart,
+               wbxml_coc10_attrValue
        },
-       { /* 0x06 = SL 1.0 */
-               TRUE, vals_slc10_global, vals_slc10_tags,
-               vals_slc10_attrStart, vals_slc10_attrValue
+       { 0x08, TRUE, /* CHANNEL 1.0 (deprecated) */
+               NULL, /* wbxml_channelc10_global - does not exist */
+               wbxml_channelc10_tags,
+               wbxml_channelc10_attrStart,
+               NULL, /* wbxml_channelc10_attrValue - does not exist */
        },
-       { /* 0x07 = CO 1.0 */
-               TRUE, vals_coc10_global, vals_coc10_tags,
-               vals_coc10_attrStart, vals_coc10_attrValue
+       { 0x09, TRUE, /* WML 1.2 */
+               wbxml_wmlc12_global,
+               wbxml_wmlc12_tags,
+               wbxml_wmlc12_attrStart,
+               wbxml_wmlc12_attrValue
        },
-       { /* 0x08 = CHANNEL 1.0 */
-               FALSE, NULL, NULL, NULL, NULL
+       { 0x0A, TRUE, /* WML 1.3 */
+               wbxml_wmlc13_global,
+               wbxml_wmlc13_tags,
+               wbxml_wmlc13_attrStart,
+               wbxml_wmlc13_attrValue
        },
-       { /* 0x09 = WML 1.2 */
-               TRUE, vals_wmlc12_global, vals_wmlc12_tags,
-               vals_wmlc12_attrStart, vals_wmlc12_attrValue
+       { 0x0B, TRUE, /* PROV 1.0 */
+               NULL, /* wbxml_provc10_global - does not exist */
+               wbxml_provc10_tags,
+               wbxml_provc10_attrStart,
+               wbxml_provc10_attrValue
        },
-       { /* 0x0A = WML 1.3 */
-               TRUE, vals_wmlc13_global, vals_wmlc13_tags,
-               vals_wmlc13_attrStart, vals_wmlc13_attrValue
+#ifdef remove_directive_and_set_TRUE_if_mapping_available
+       { 0x0C, FALSE, /* WTA-WML 1.2 */
+               NULL, NULL, NULL, NULL
        },
-       { /* 0x0B = PROV 1.0 */
-               TRUE, vals_provc10_global, vals_provc10_tags,
-               vals_provc10_attrStart, vals_provc10_attrValue
+#endif
+       { 0x0D, TRUE, /* EMN 1.0 */
+               NULL, /* wbxml_emnc10_global - does not exist */
+               wbxml_emnc10_tags,
+               wbxml_emnc10_attrStart,
+               wbxml_emnc10_attrValue
        },
-       { /* 0x0C = WTA-WML 1.2 */
-               FALSE, NULL, NULL, NULL, NULL
+#ifdef remove_directive_and_set_TRUE_if_mapping_available
+       { 0x0E, FALSE, /* DRMREL 1.0 */
+               NULL, NULL, NULL, NULL
        },
-       { /* 0x0D = EMN 1.0 */
-               FALSE, NULL, NULL, NULL, NULL
+#endif
+       { 0x0FD1, TRUE, /* SyncML 1.0 */
+               NULL, /* wbxml_syncmlc10_global - does not exist */
+               wbxml_syncmlc10_tags,
+               NULL, /* wbxml_syncmlc10_attrStart - does not exist */
+               NULL, /* wbxml_syncmlc10_attrValue - does not exist */
+       },
+       { 0x0FD3, TRUE, /* SyncML 1.1 */
+               NULL, /* wbxml_syncmlc11_global - does not exist */
+               wbxml_syncmlc11_tags,
+               NULL, /* wbxml_syncmlc11_attrStart - does not exist */
+               NULL, /* wbxml_syncmlc11_attrValue - does not exist */
        },
-       { /* 0x0E = DRMREL 1.0 */
-               FALSE, NULL, NULL, NULL, NULL
+       { 0x1108, TRUE, /* Phone.com - WML+ 1.1 */
+               /* Note: I assumed WML+ 1.1 would be not that different from WML 1.1,
+                *       the real mapping should come from Phone.com (OpenWave)! */
+               wbxml_wmlc11_global, /* Not 100% true */
+               wbxml_wmlc11_tags, /* Not 100% true */
+               wbxml_wmlc11_attrStart, /* Not 100% true */
+               wbxml_wmlc11_attrValue /* Not 100% true */
        },
+       { 0x110D, TRUE, /* Phone.com - WML+ 1.3 */
+               /* Note: I assumed WML+ 1.3 would be not that different from WML 1.3,
+                *       the real mapping should come from Phone.com (OpenWave)! */
+               wbxml_wmlc13_global, /* Not 100% true */
+               wbxml_wmlc13_tags, /* Not 100% true */
+               wbxml_wmlc13_attrStart, /* Not 100% true */
+               wbxml_wmlc13_attrValue /* Not 100% true */
+       },
+       
+       { 0, FALSE, NULL, NULL, NULL, NULL }
 };
-/* Update the entry below when the table above is appended */
-#define WBXML_MAP_MAX_ID 0x0E
 
 
+/* WBXML content token mapping depends on the following parameters:
+ *   - Content type (guint32)
+ *   - Token type (global, tags, attrStart, attrValue)
+ *   - Code page for tag and attribute
+ *
+ * This results in the following steps:
+ *   1. Retrieve content type mapping
+ *   2. If exists, retrieve token type mapping
+ *   3. If exists, retrieve required code page
+ *   4. If exists, retrieve token mapping
+ */
 
+/* Return token mapping for a given content mapping entry. */
+static const char *
+map_token (const value_valuestring *token_map, guint8 codepage, guint8 token) {
+       const value_string *vs;
+       const char *s;
+
+       if (token_map) { /* Found map */
+               if ((vs = val_to_valstr (codepage, token_map))) {
+                       /* Found codepage map */
+                       s = match_strval (token, vs);
+                       if (s) /* Found valid token */
+                                       return s;
+                       /* No valid token mapping in specified code page of token map */
+                       return "(Requested token not defined for this content type)";
+               }
+               /* There is no token map entry for the requested code page */
+               return "(Requested token code page not defined for this content type)";
+       }
+       /* The token map does not exist */
+       return "(Requested token map not defined for this content type)";
+}
 
-/************************** Function prototypes **************************/
 
+/* Returns a pointer to the WBXML token map for the given WBXML public
+ * identifier value (see WINA for a table with defined identifiers). */
+static const wbxml_token_map *wbxml_content_map (guint32 publicid) {
+       gint i = 0;
+
+       while (map[i].defined) {
+               if (map[i].publicid == publicid)
+                       return &(map[i]);
+               i++;
+       }
+       return NULL;
+}
+
+
+/************************** Function prototypes **************************/
 
 
 static void
 dissect_wbxml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
 
-
 void
 proto_register_wbxml(void);
 
-
-/* Parse and display the WBXML string table
- */
+/* Parse and display the WBXML string table */
 static void
 show_wbxml_string_table (proto_tree *tree, tvbuff_t *tvb, guint32 str_tbl,
                guint32 str_tbl_len);
 
-
-/* Return a pointer to the string in the string table.
- * Can also be hacked for inline string retrieval.
- */
-static const char*
-strtbl_lookup (tvbuff_t *tvb, guint32 str_tbl, guint32 offset, guint32 *len);
-
-
-/* Parse data while in STAG state
- */
+/* Parse data while in STAG state */
 static void
 parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                guint32 str_tbl, guint8 *level,
-               guint8 *codepage_stag, guint8 *codepage_attr, guint32 *parsed_length);
-
+               guint32 *parsed_length);
 
 /* Parse data while in STAG state;
- * interpret tokens as defined by content type
- */
+ * interpret tokens as defined by content type */
 static void
 parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                guint32 str_tbl, guint8 *level,
-               guint8 *codepage_stag, guint8 *codepage_attr, guint32 *parsed_length,
-               const wbxml_mapping_table *map);
-
+               guint32 *parsed_length,
+               const wbxml_token_map *map);
 
-/* Parse data while in ATTR state
- */
+/* Parse data while in ATTR state */
 static void
 parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                guint32 offset, guint32 str_tbl, guint8 level,
-               guint8 *codepage_attr, guint32 *parsed_length);
-
+               guint32 *parsed_length);
 
 /* Parse data while in ATTR state;
- * interpret tokens as defined by content type
- */
+ * interpret tokens as defined by content type */
 static void
 parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                guint32 offset, guint32 str_tbl, guint8 level,
-               guint8 *codepage_attr, guint32 *parsed_length,
-               const wbxml_mapping_table *map);
-
-
+               guint32 *parsed_length,
+               const wbxml_token_map *map);
 
 
 /****************** WBXML protocol dissection functions ******************/
 
 
-
-
 /* Code to actually dissect the packets */
 static void
 dissect_wbxml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-
-/* Set up structures needed to add the protocol subtree and manage it */
+       /* Set up structures needed to add the protocol subtree and manage it */
        proto_item *ti;
        proto_tree *wbxml_tree; /* Main WBXML tree */
        proto_tree *wbxml_str_tbl_tree; /* String table subtree */
        proto_tree *wbxml_content_tree; /* Content subtree */
        guint8 version;
        guint offset = 0;
-       const char *token;
        guint32 len;
        guint32 charset=0;
        guint32 charset_len;
@@ -1338,8 +1847,7 @@ dissect_wbxml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        guint32 str_tbl;
        guint32 str_tbl_len;
        guint8 level = 0; /* WBXML recursion level */
-       guint8 codepage_stag = 0; /* Initial codepage in state = STAG */
-       guint8 codepage_attr = 0; /* Initial codepage in state = ATTR */
+       const wbxml_token_map *content_map = NULL;
 
        /* WBXML format
         * 
@@ -1412,16 +1920,17 @@ dissect_wbxml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                str_tbl_len = tvb_get_guintvar (tvb, offset, &len);
                str_tbl = offset + len; /* Start of 1st string in string table */
 
-
                /* Now we can add public ID, charset (if available),
                 * and string table */
                if ( ! publicid ) { /* Read Public ID from string table */
-                       token = strtbl_lookup (tvb, str_tbl, publicid_index, NULL);
+                       len = tvb_strsize (tvb, str_tbl+publicid_index);
                        if (check_col(pinfo->cinfo, COL_INFO))
                                col_append_fstr(pinfo->cinfo, COL_INFO, " Public ID \"%s\")",
-                                               token);
-                       proto_tree_add_string (wbxml_tree, hf_wbxml_public_id_literal,
-                                       tvb, 1, publicid_len, token?token:"[NULL STRING]");
+                                               tvb_format_text (tvb,
+                                                   str_tbl+publicid_index,
+                                                   len-1));
+                       proto_tree_add_item (wbxml_tree, hf_wbxml_public_id_literal,
+                                       tvb, 1, publicid_len, FALSE);
                }
                if ( version ) { /* Charset */
                        proto_tree_add_uint (wbxml_tree, hf_wbxml_charset,
@@ -1450,71 +1959,44 @@ dissect_wbxml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                /* The parse_wbxml_X() functions will process the content correctly,
                 * irrespective of the WBXML version used. For the WBXML body, this
                 * means that there is a different processing for the global token
-                * RESERVED_2 (WBXML 1.0) or OPAQUE (WBXML 1.x with x > 0).
-                */
+                * RESERVED_2 (WBXML 1.0) or OPAQUE (WBXML 1.x with x > 0).  */
                if (wbxml_tree) { /* Show only if visible */
                        if (publicid) {
-#ifdef DEBUG
-                               printf ("WBXML - Content Type : \"%s\"\n",
-                                               match_strval (publicid, vals_wbxml_public_ids));
-#endif
-                               /* Look in wbxml_map[] table for defined mapping */
-                               if (publicid < WBXML_MAP_MAX_ID) {
-                                       if (wbxml_map[publicid].defined) {
+                               /* Retrieve the content token mapping if available */
+                               content_map = wbxml_content_map (publicid);
+                               if (content_map) {
+                                       /* Is there a defined token mapping for publicid? */
+                                       if (content_map->defined) {
                                                proto_tree_add_text (wbxml_content_tree, tvb,
                                                                offset, -1,
-                                                               "Level | State "
+                                                               "Level | State | Codepage "
                                                                "| WBXML Token Description         "
                                                                "| Rendering");
                                                parse_wbxml_tag_defined (wbxml_content_tree,
                                                                tvb, offset, str_tbl, &level,
-                                                               &codepage_stag, &codepage_attr, &len,
-                                                               wbxml_map + publicid);
+                                                               &len, content_map);
                                                return;
                                        }
-                                       proto_tree_add_text (wbxml_content_tree, tvb,
-                                                       offset, -1,
-                                                       "Rendering of this content type"
-                                                       " not (yet) supported");
                                }
+                               proto_tree_add_text (wbxml_content_tree, tvb,
+                                               offset, -1,
+                                               "[Rendering of this content type"
+                                               " not (yet) supported]");
                        }
                        /* Default: WBXML only, no interpretation of the content */
                        proto_tree_add_text (wbxml_content_tree, tvb, offset, -1,
-                                       "Level | State | WBXML Token Description         "
+                                       "Level | State | Codepage "
+                                       "| WBXML Token Description         "
                                        "| Rendering");
                        parse_wbxml_tag (wbxml_content_tree, tvb, offset,
-                                       str_tbl, &level,
-                                       &codepage_stag, &codepage_attr, &len);
+                                       str_tbl, &level, &len);
                        return;
-               } else {
-                       proto_tree_add_text (wbxml_content_tree, tvb, offset, -1,
-                                       "WBXML 1.0 decoding not yet supported");
                }
                return;
        }
 }
 
 
-
-
-/* Return a pointer to the string in the string table.
- * Can also be hacked for inline string retrieval.
- */
-static const char*
-strtbl_lookup (tvbuff_t *tvb, guint32 str_tbl, guint32 offset, guint32 *len)
-{
-       if (len) { /* The "hack" call for inline string reading */
-               *len = tvb_strsize (tvb, str_tbl+offset);
-               return tvb_get_ptr (tvb, str_tbl+offset, *len);
-       } else { /* Normal string table reading */
-               return tvb_get_ptr (tvb, str_tbl+offset,
-                               tvb_strsize (tvb, str_tbl+offset));
-       }
-}
-
-
-
-
 /* Parse and display the WBXML string table (in a 3-column table format).
  * This function displays:
  *  - the offset in the string table,
@@ -1528,23 +2010,20 @@ show_wbxml_string_table (proto_tree *tree, tvbuff_t *tvb, guint32 str_tbl,
        guint32 off = str_tbl;
        guint32 len = 0;
        guint32 end = str_tbl + str_tbl_len;
-       const char *str;
 
        proto_tree_add_text (tree, tvb, off, end,
                        "Start  | Length | String");
        while (off < end) {
-               /* Hack the string table lookup function */
-               str = strtbl_lookup (tvb, off, 0, &len);
+               len = tvb_strsize (tvb, off);
                proto_tree_add_text (tree, tvb, off, len,
                                "%6d | %6d | '%s'",
-                               off - str_tbl, len, str);
+                               off - str_tbl, len,
+                               tvb_format_text (tvb, off, len-1));
                off += len;
        }
 }
 
 
-
-
 /* Indentation code is based on a static const array of space characters.
  * At least one single space is returned */
 static const char indent_buffer[514] = " "
@@ -1563,8 +2042,6 @@ static const char * Indent (guint8 level) {
 }
 
 
-
-
 /********************
  * WBXML tag tokens *
  ********************
@@ -1589,19 +2066,19 @@ static const char * Indent (guint8 level) {
  *               CONTENT
  *             </tag>
  *
- * NOTE: an XML PI is parsed as an attribute list (same syntax).
+ * NOTES
+ *   - An XML PI is parsed as an attribute list (same syntax).
+ *   - A code page switch only applies to the single token that follows.
  */
 
 
-
-
 /* This function parses the WBXML and maps known token interpretations
  * to the WBXML tokens. As a result, the original XML document can be
  * recreated. Indentation is generated in order to ease reading.
  *
  * Attribute parsing is done in parse_wbxml_attribute_list_defined().
  *
- * The wbxml_mapping_table entry *map contains the actual token mapping.
+ * The wbxml_token_map entry *map contains the actual token mapping.
  *
  * NOTE: In order to parse the content, some recursion is required.
  *       However, for performance reasons, recursion has been avoided
@@ -1609,28 +2086,34 @@ static const char * Indent (guint8 level) {
  *       This is achieved by means of the parsing_tag_content and tag_save*
  *       variables.
  *
- * NOTE: Code page switches not yet processed in the code!
- *
  * NOTE: See above for known token mappings.
+ *
+ * NOTE: As tags can be opened and closed, a tag representation lookup
+ *       may happen once or twice for a given tag. For efficiency reasons,
+ *       the literal tag value is stored and used throughout the code.
+ *       With the introduction of code page support, this solution is robust
+ *       as the lookup only occurs once, removing the need for storage of
+ *       the used code page.
  */
 static void
 parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                guint32 str_tbl, guint8 *level,
-               guint8 *codepage_stag, guint8 *codepage_attr, guint32 *parsed_length,
-               const wbxml_mapping_table *map)
+               guint32 *parsed_length,
+               const wbxml_token_map *map)
 {
        guint32 tvb_len = tvb_reported_length (tvb);
        guint32 off = offset;
        guint32 len;
+       guint str_len;
        guint32 ent;
        guint32 index;
-       const char* str;
        guint8 peek;
        guint32 tag_len; /* Length of the index (uintvar) from a LITERAL tag */
        guint8 tag_save_known = 0; /* Will contain peek & 0x3F (tag identity) */
        guint8 tag_new_known = 0; /* Will contain peek & 0x3F (tag identity) */
        const char *tag_save_literal; /* Will contain the LITERAL tag identity */
        const char *tag_new_literal; /* Will contain the LITERAL tag identity */
+       guint8 codepage_stag = 0; /* Initial codepage in state = STAG */
        guint8 parsing_tag_content = FALSE; /* Are we parsing content from a
                                                                                   tag with content: <x>Content</x>
                                                                                   
@@ -1652,72 +2135,93 @@ parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                if ((peek & 0x3F) < 4) switch (peek) { /* Global tokens in state = STAG
                                                                                                  but not the LITERAL tokens */
                        case 0x00: /* SWITCH_PAGE */
-                               peek = tvb_get_guint8 (tvb, off+1);
+                               codepage_stag = tvb_get_guint8 (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 2,
-                                               "        Tag   | SWITCH_PAGE (Tag code page)     "
-                                               "| Code page switch (was: %d, is: %d)",
-                                               *codepage_stag, peek);
-                               *codepage_stag = peek;
+                                               "      | Tag   | T 0->%3d "
+                                               "| SWITCH_PAGE (Tag code page)     "
+                                               "|",
+                                               codepage_stag);
                                off += 2;
                                break;
                        case 0x01: /* END: only possible for Tag with Content */
-                               if (tag_save_known) {
+                               if (tag_save_known) { /* Known TAG */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "  %3d | Tag   | END (Known Tag 0x%02X)            "
+                                                       "  %3d | Tag   |          "
+                                                       "| END (Known Tag 0x%02X)            "
                                                        "| %s</%s>",
                                                        *level, tag_save_known, Indent (*level),
-                                                       match_strval (tag_save_known, map->tags));
+                                                       tag_save_literal); /* We already looked it up! */
                                } else { /* Literal TAG */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "  %3d | Tag   | END (Literal Tag)               "
+                                                       "  %3d | Tag   |          "
+                                                       "| END (Literal Tag)               "
                                                        "| %s</%s>",
-                                                       *level, Indent (*level), tag_save_literal);
+                                                       *level, Indent (*level),
+                                                       tag_save_literal);
                                }
                                (*level)--;
                                off++;
                                *parsed_length = off - offset;
+                               /* Reset code page: not needed as return from recursion */
                                return;
                                break;
                        case 0x02: /* ENTITY */
                                ent = tvb_get_guintvar (tvb, off+1, &len);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | ENTITY                          "
+                                               "  %3d | Tag   |          "
+                                               "| ENTITY                          "
                                                "| %s'&#%u;'",
                                                *level, Indent (*level), ent);
                                off += 1+len;
                                break;
                        case 0x03: /* STR_I */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
+                               len = tvb_strsize (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | STR_I (Inline string)           "
+                                               "  %3d | Tag   |          "
+                                               "| STR_I (Inline string)           "
                                                "| %s\'%s\'",
-                                               *level, Indent(*level), str);
+                                               *level, Indent(*level),
+                                               tvb_format_text (tvb, off+1, len-1));
                                off += 1+len;
                                break;
                        case 0x40: /* EXT_I_0 */
                        case 0x41: /* EXT_I_1 */
                        case 0x42: /* EXT_I_2 */
                                /* Extension tokens */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | EXT_I_%1x    (Extension Token)    "
-                                               "| %s(%s: \'%s\')",
-                                               *level, peek & 0x0f, Indent (*level),
-                                               match_strval (peek, map->global), str);
+                               len = tvb_strsize (tvb, off+1);
+                               if (codepage_stag) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   | T %3d->0 "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "| %s(%s: \'%s\')",
+                                                       *level, codepage_stag, peek & 0x0f, Indent (*level),
+                                                       map_token (map->global, codepage_stag, peek),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                                       /* Reset code page */
+                                       codepage_stag = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   |          "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "| %s(%s: \'%s\')",
+                                                       *level, peek & 0x0f, Indent (*level),
+                                                       map_token (map->global, codepage_stag, peek),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                               }
                                off += 1+len;
                                break;
                        case 0x43: /* PI */
                                proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d | Tag   | PI (XML Processing Instruction) "
+                                               "  %3d | Tag   |          "
+                                               "| PI (XML Processing Instruction) "
                                                "| %s<?xml",
                                                *level, Indent (*level));
-                               parse_wbxml_attribute_list (tree, tvb, off, str_tbl,
-                                               *level, codepage_attr, &len);
+                               parse_wbxml_attribute_list_defined (tree, tvb, off, str_tbl,
+                                               *level, &len, map);
                                off += len;
                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                               "  %3d | Tag   | END (PI)                        "
+                                               "  %3d | Tag   |          "
+                                               "| END (PI)                        "
                                                "| %s?>",
                                                *level, Indent (*level));
                                break;
@@ -1726,46 +2230,77 @@ parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                        case 0x82: /* EXT_T_2 */
                                /* Extension tokens */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | EXT_T_%1x    (Extension Token)    "
-                                               "| %s(%s: \'%s\')",
-                                               *level, peek & 0x0f, Indent (*level),
-                                               match_strval (peek, map->global), str);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
+                               if (codepage_stag) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   | T %3d->0 "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "| %s(%s: \'%s\')",
+                                                       *level, codepage_stag, peek & 0x0f, Indent (*level),
+                                                       map_token (map->global, codepage_stag, peek),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                                       /* Reset code page */
+                                       codepage_stag = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   |          "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "| %s(%s: \'%s\')",
+                                                       *level, peek & 0x0f, Indent (*level),
+                                                       map_token (map->global, codepage_stag, peek),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                               }
                                off += 1+len;
                                break;
                        case 0x83: /* STR_T */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | STR_T (Tableref string)         "
+                                               "  %3d | Tag   |          "
+                                               "| STR_T (Tableref string)         "
                                                "| %s\'%s\'",
-                                               *level, Indent (*level), str);
+                                               *level, Indent (*level),
+                                               tvb_format_text (tvb, str_tbl+index, str_len-1));
                                off += 1+len;
                                break;
                        case 0xC0: /* EXT_0 */
                        case 0xC1: /* EXT_1 */
                        case 0xC2: /* EXT_2 */
                                /* Extension tokens */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d | Tag   | EXT_%1x      (Extension Token)    "
-                                               "| %s(%s)",
-                                               *level, peek & 0x0f, Indent (*level),
-                                               match_strval (peek, map->global));
+                               if (codepage_stag) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d | Tag   | T %3d->0 "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "| %s(%s)",
+                                                       *level, codepage_stag, peek & 0x0f, Indent (*level),
+                                                       map_token (map->global, codepage_stag, peek));
+                                       /* Reset code page */
+                                       codepage_stag = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d | Tag   |          "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "| %s(%s)",
+                                                       *level, peek & 0x0f, Indent (*level),
+                                                       map_token (map->global, codepage_stag, peek));
+                               }
                                off++;
                                break;
                        case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
                                if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
                                        index = tvb_get_guintvar (tvb, off+1, &len);
                                        proto_tree_add_text (tree, tvb, off, 1 + len + index,
-                                                       "  %3d | Tag   | OPAQUE (Opaque data)            "
+                                                       "  %3d | Tag   |          "
+                                                       "| OPAQUE (Opaque data)            "
                                                        "| %s(%d bytes of opaque data)",
                                                        *level, Indent (*level), index);
                                        off += 1+len+index;
                                } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "        Tag   | RESERVED_2     (Invalid Token!) "
-                                                       "| WBXML 1.0 parsing stops here.");
+                                                       "  %3d | Tag   |          "
+                                                       "| RESERVED_2     (Invalid Token!) "
+                                                       "| WBXML 1.0 parsing stops here.",
+                                                       *level);
                                        /* Stop processing as it is impossible to parse now */
                                        off = tvb_len;
                                        *parsed_length = off - offset;
@@ -1775,8 +2310,10 @@ parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
 
                                /* No default clause, as all cases have been treated */
                } else { /* LITERAL or Known TAG */
-                       /*
-                        * We must store the initial tag, and also retrieve the new tag.
+                       /* We must store the initial tag, and also retrieve the new tag.
+                        * For efficiency reasons, we store the literal tag representation
+                        * for known tags too, so we can easily close the tag without the
+                        * need of a new lookup and avoiding storage of token codepage.
                         * 
                         * There are 4 possibilities:
                         *
@@ -1790,16 +2327,17 @@ parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                        tag_len = 0;
                        if ((peek & 0x3F) == 4) { /* LITERAL */
                                index = tvb_get_guintvar (tvb, off+1, &tag_len);
-                               tag_new_literal = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
+                               tag_new_literal = tvb_get_ptr (tvb, str_tbl+index, str_len);
                                tag_new_known = 0; /* invalidate known tag_new */
-                       } else {
+                       } else { /* Known tag */
                                tag_new_known = peek & 0x3F;
-                               tag_new_literal = NULL; /* invalidate LITERAL tag_new */
+                               tag_new_literal = map_token (map->tags, codepage_stag,
+                                                                               tag_new_known);
+                               /* Stored looked up tag name string */
                        }
 
-                       /*
-                        * Parsing of TAG starts HERE
-                        */
+                       /* Parsing of TAG starts HERE */
                        if (peek & 0x40) { /* Content present */
                                /* Content follows
                                 * [!] An explicit END token is expected in these cases!
@@ -1814,56 +2352,84 @@ parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                                         * recursion will take care of it */
                                        (*level)++;
                                        parse_wbxml_tag_defined (tree, tvb, off, str_tbl, level,
-                                                       codepage_stag, codepage_attr, &len, map);
+                                                       &len, map);
                                        off += len;
                                } else { /* Now we will have content to parse */
                                        /* Save the start tag so we can properly close it later. */
-                                       if ((peek & 0x3F) == 4) {
+                                       if ((peek & 0x3F) == 4) { /* Literal tag */
                                                tag_save_literal = tag_new_literal;
                                                tag_save_known = 0;
-                                       } else {
+                                       } else { /* Known tag */
                                                tag_save_known = tag_new_known;
-                                               tag_save_literal = NULL;
+                                               tag_save_literal = tag_new_literal;
+                                               /* The last statement avoids needless lookups */
                                        }
                                        /* Process the attribute list if present */
                                        if (peek & 0x80) { /* Content and Attribute list present */
                                                if (tag_new_known) { /* Known tag */
-                                                       proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
-                                                                       "|   Known Tag 0x%02X           (AC) "
-                                                                       "| %s<%s",
-                                                                       *level, tag_new_known, Indent (*level),
-                                                                       match_strval (tag_new_known, map->tags));
+                                                       if (codepage_stag) { /* Not default code page */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   | T %3d->0 "
+                                                                               "|   Known Tag 0x%02X           (AC) "
+                                                                               "| %s<%s",
+                                                                               *level, codepage_stag, tag_new_known,
+                                                                               Indent (*level), tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                               /* Reset code page */
+                                                               codepage_stag = 0;
+                                                       } else { /* Code page 0 */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   |          "
+                                                                               "|   Known Tag 0x%02X           (AC) "
+                                                                               "| %s<%s",
+                                                                               *level, tag_new_known,
+                                                                               Indent (*level), tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                       }
                                                        off++;
                                                } else { /* LITERAL tag */
                                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
+                                                                       "  %3d | Tag   |          "
                                                                        "| LITERAL_AC (Literal tag)   (AC) "
                                                                        "| %s<%s",
                                                                        *level, Indent (*level), tag_new_literal);
                                                        off += 1 + tag_len;
                                                }
                                                parse_wbxml_attribute_list_defined (tree, tvb,
-                                                               off, str_tbl,
-                                                               *level, codepage_attr, &len, map);
+                                                               off, str_tbl, *level, &len, map);
                                                off += len;
                                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| END (attribute list)            "
                                                                "| %s>",
                                                                *level, Indent (*level));
                                        } else { /* Content, no Attribute list */
                                                if (tag_new_known) { /* Known tag */
-                                                       proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
-                                                                       "|   Known Tag 0x%02X           (.C) "
-                                                                       "| %s<%s>",
-                                                                       *level, tag_new_known, Indent (*level),
-                                                                       match_strval (tag_new_known, map->tags));
+                                                       if (codepage_stag) { /* Not default code page */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   | T %3d->0 "
+                                                                               "|   Known Tag 0x%02X           (.C) "
+                                                                               "| %s<%s>",
+                                                                               *level, codepage_stag, tag_new_known,
+                                                                               Indent (*level),
+                                                                               tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                               /* Reset code page */
+                                                               codepage_stag = 0;
+                                                       } else { /* Code page 0 */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   |          "
+                                                                               "|   Known Tag 0x%02X           (.C) "
+                                                                               "| %s<%s>",
+                                                                               *level, tag_new_known,
+                                                                               Indent (*level),
+                                                                               tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                       }
                                                        off++;
                                                } else { /* LITERAL tag */
                                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
+                                                                       "  %3d | Tag   |          "
                                                                        "| LITERAL_C  (Literal Tag)   (.C) "
                                                                        "| %s<%s>",
                                                                        *level, Indent (*level), tag_new_literal);
@@ -1889,51 +2455,75 @@ parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                                (*level)++;
                                if (peek & 0x80) { /* No Content, Attribute list present */
                                        if (tag_new_known) { /* Known tag */
-                                               proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
-                                                               "|   Known Tag 0x%02X           (A.) "
-                                                               "| %s<%s",
-                                                               *level, tag_new_known, Indent (*level),
-                                                               match_strval (tag_new_known, map->tags));
+                                               if (codepage_stag) { /* Not default code page */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   | T %3d->0 "
+                                                                       "|   Known Tag 0x%02X           (A.) "
+                                                                       "| %s<%s",
+                                                                       *level, codepage_stag, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                                       /* Reset code page */
+                                                       codepage_stag = 0;
+                                               } else { /* Code page 0 */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   |          "
+                                                                       "|   Known Tag 0x%02X           (A.) "
+                                                                       "| %s<%s",
+                                                                       *level, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                               }
                                                off++;
                                                parse_wbxml_attribute_list_defined (tree, tvb,
-                                                               off, str_tbl,
-                                                               *level, codepage_attr, &len, map);
+                                                               off, str_tbl, *level, &len, map);
                                                off += len;
                                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| END (Known Tag)                 "
                                                                "| %s/>",
                                                                *level, Indent (*level));
                                        } else { /* LITERAL tag */
                                                proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| LITERAL_A  (Literal Tag)   (A.) "
                                                                "| %s<%s",
                                                                *level, Indent (*level), tag_new_literal);
                                                off += 1 + tag_len;
                                                parse_wbxml_attribute_list_defined (tree, tvb,
-                                                               off, str_tbl,
-                                                               *level, codepage_attr, &len, map);
+                                                               off, str_tbl, *level, &len, map);
                                                off += len;
                                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| END (Literal Tag)               "
                                                                "| %s/>",
                                                                *level, Indent (*level));
                                        }
                                } else { /* No Content, No Attribute list */
                                        if (tag_new_known) { /* Known tag */
-                                               proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
-                                                               "|   Known Tag 0x%02x           (..) "
-                                                               "| %s<%s />",
-                                                               *level, tag_new_known, Indent (*level),
-                                                               match_strval (tag_new_known, map->tags));
+                                               if (codepage_stag) { /* Not default code page */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   | T %3d->0 "
+                                                                       "|   Known Tag 0x%02x           (..) "
+                                                                       "| %s<%s />",
+                                                                       *level, codepage_stag, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                                       /* Reset code page */
+                                                       codepage_stag = 0;
+                                               } else { /* Code page 0 */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   |          "
+                                                                       "|   Known Tag 0x%02x           (..) "
+                                                                       "| %s<%s />",
+                                                                       *level, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                               }
                                                off++;
                                        } else { /* LITERAL tag */
                                                proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| LITERAL    (Literal Tag)   (..) "
                                                                "| %s<%s />",
                                                                *level, Indent (*level), tag_new_literal);
@@ -1941,38 +2531,38 @@ parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                                        }
                                }
                                (*level)--;
+                               /* TODO: Do I have to reset code page here? */
                        }
                } /* if (tag & 0x3F) >= 5 */
        } /* while */
 }
 
 
-
-
 /* This function performs the WBXML decoding as in parse_wbxml_tag_defined()
  * but this time no WBXML mapping is performed.
  *
  * Attribute parsing is done in parse_wbxml_attribute_list().
- *
- * NOTE: Code page switches not yet processed in the code!
  */
 static void
 parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                guint32 str_tbl, guint8 *level,
-               guint8 *codepage_stag, guint8 *codepage_attr, guint32 *parsed_length)
+               guint32 *parsed_length)
 {
        guint32 tvb_len = tvb_reported_length (tvb);
        guint32 off = offset;
        guint32 len;
+       guint str_len;
        guint32 ent;
        guint32 index;
-       const char* str;
        guint8 peek;
        guint32 tag_len; /* Length of the index (uintvar) from a LITERAL tag */
        guint8 tag_save_known = 0; /* Will contain peek & 0x3F (tag identity) */
        guint8 tag_new_known = 0; /* Will contain peek & 0x3F (tag identity) */
        const char *tag_save_literal; /* Will contain the LITERAL tag identity */
        const char *tag_new_literal; /* Will contain the LITERAL tag identity */
+       char tag_save_buf[10]; /* Will contain "tag_0x%02X" */
+       char tag_new_buf[10]; /* Will contain "tag_0x%02X" */
+       guint8 codepage_stag = 0; /* Initial codepage in state = STAG */
        guint8 parsing_tag_content = FALSE; /* Are we parsing content from a
                                                                                   tag with content: <x>Content</x>
                                                                                   
@@ -1994,71 +2584,91 @@ parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                if ((peek & 0x3F) < 4) switch (peek) { /* Global tokens in state = STAG
                                                                                                  but not the LITERAL tokens */
                        case 0x00: /* SWITCH_PAGE */
-                               peek = tvb_get_guint8 (tvb, off+1);
+                               codepage_stag = tvb_get_guint8 (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 2,
-                                               "        Tag   | SWITCH_PAGE (Tag code page)     "
-                                               "| Code page switch (was: %d, is: %d)",
-                                               *codepage_stag, peek);
-                               *codepage_stag = peek;
+                                               "      | Tag   | T 0->%3d "
+                                               "| SWITCH_PAGE (Tag code page)     "
+                                               "|",
+                                               codepage_stag);
                                off += 2;
                                break;
                        case 0x01: /* END: only possible for Tag with Content */
-                               if (tag_save_known) {
+                               if (tag_save_known) { /* Known TAG */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "  %3d | Tag   | END (Known Tag 0x%02X)            "
-                                                       "| %s</Tag_0x%02X>",
+                                                       "  %3d | Tag   |          "
+                                                       "| END (Known Tag 0x%02X)            "
+                                                       "| %s</%s>",
                                                        *level, tag_save_known, Indent (*level),
-                                                       tag_save_known);
+                                                       tag_save_literal); /* We already looked it up! */
                                } else { /* Literal TAG */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "  %3d | Tag   | END (Literal Tag)               "
+                                                       "  %3d | Tag   |          "
+                                                       "| END (Literal Tag)               "
                                                        "| %s</%s>",
-                                                       *level, Indent (*level), tag_save_literal);
+                                                       *level, Indent (*level),
+                                                       tag_save_literal);
                                }
                                (*level)--;
                                off++;
                                *parsed_length = off - offset;
+                               /* Reset code page: not needed as return from recursion */
                                return;
                                break;
                        case 0x02: /* ENTITY */
                                ent = tvb_get_guintvar (tvb, off+1, &len);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | ENTITY                          "
+                                               "  %3d | Tag   |          "
+                                               "| ENTITY                          "
                                                "| %s'&#%u;'",
                                                *level, Indent (*level), ent);
                                off += 1+len;
                                break;
                        case 0x03: /* STR_I */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
+                               len = tvb_strsize (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | STR_I (Inline string)           "
+                                               "  %3d | Tag   |          "
+                                               "| STR_I (Inline string)           "
                                                "| %s\'%s\'",
-                                               *level, Indent(*level), str);
+                                               *level, Indent(*level),
+                                               tvb_format_text (tvb, off+1, len-1));
                                off += 1+len;
                                break;
                        case 0x40: /* EXT_I_0 */
                        case 0x41: /* EXT_I_1 */
                        case 0x42: /* EXT_I_2 */
                                /* Extension tokens */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | EXT_I_%1x    (Extension Token)    "
-                                               "| %s(Inline string extension: \'%s\')",
-                                               *level, peek & 0x0f, Indent (*level), str);
+                               len = tvb_strsize (tvb, off+1);
+                               if (codepage_stag) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   | T %3d->0 "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "| %s(Inline string extension: \'%s\')",
+                                                       *level, codepage_stag, peek & 0x0f, Indent (*level),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                                       /* Reset code page */
+                                       codepage_stag = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   |          "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "| %s(Inline string extension: \'%s\')",
+                                                       *level, peek & 0x0f, Indent (*level),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                               }
                                off += 1+len;
                                break;
                        case 0x43: /* PI */
                                proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d | Tag   | PI (XML Processing Instruction) "
+                                               "  %3d | Tag   |          "
+                                               "| PI (XML Processing Instruction) "
                                                "| %s<?xml",
                                                *level, Indent (*level));
                                parse_wbxml_attribute_list (tree, tvb, off, str_tbl,
-                                               *level, codepage_attr, &len);
+                                               *level, &len);
                                off += len;
                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                               "  %3d | Tag   | END (PI)                        "
+                                               "  %3d | Tag   |          "
+                                               "| END (PI)                        "
                                                "| %s?>",
                                                *level, Indent (*level));
                                break;
@@ -2067,44 +2677,74 @@ parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                        case 0x82: /* EXT_T_2 */
                                /* Extension tokens */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | EXT_T_%1x    (Extension Token)    "
-                                               "| %s(Tableref string extension: \'%s\')",
-                                               *level, peek & 0x0f, Indent (*level), str);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
+                               if (codepage_stag) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   | T %3d->0 "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "| %s(Tableref string extension: \'%s\')",
+                                                       *level, codepage_stag, peek & 0x0f, Indent (*level),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                                       /* Reset code page */
+                                       codepage_stag = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d | Tag   |          "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "| %s(Tableref string extension: \'%s\')",
+                                                       *level, peek & 0x0f, Indent (*level),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                               }
                                off += 1+len;
                                break;
                        case 0x83: /* STR_T */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d | Tag   | STR_T (Tableref string)         "
+                                               "  %3d | Tag   |          "
+                                               "| STR_T (Tableref string)         "
                                                "| %s\'%s\'",
-                                               *level, Indent (*level), str);
+                                               *level, Indent (*level),
+                                               tvb_format_text (tvb, str_tbl+index, str_len-1));
                                off += 1+len;
                                break;
                        case 0xC0: /* EXT_0 */
                        case 0xC1: /* EXT_1 */
                        case 0xC2: /* EXT_2 */
                                /* Extension tokens */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d | Tag   | EXT_%1x      (Extension Token)    "
-                                               "| %s(Single-byte extension)",
-                                               *level, peek & 0x0f, Indent (*level));
+                               if (codepage_stag) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d | Tag   | T %3d->0 "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "| %s(Single-byte extension)",
+                                                       *level, codepage_stag, peek & 0x0f,
+                                                       Indent (*level));
+                                       /* Reset code page */
+                                       codepage_stag = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d | Tag   |          "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "| %s(Single-byte extension)",
+                                                       *level, peek & 0x0f, Indent (*level));
+                               }
                                off++;
                                break;
                        case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
                                if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
                                        index = tvb_get_guintvar (tvb, off+1, &len);
                                        proto_tree_add_text (tree, tvb, off, 1 + len + index,
-                                                       "  %3d | Tag   | OPAQUE (Opaque data)            "
+                                                       "  %3d | Tag   |          "
+                                                       "| OPAQUE (Opaque data)            "
                                                        "| %s(%d bytes of opaque data)",
                                                        *level, Indent (*level), index);
                                        off += 1+len+index;
                                } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "        Tag   | RESERVED_2     (Invalid Token!) "
-                                                       "| WBXML 1.0 parsing stops here.");
+                                                       "  %3d | Tag   |          "
+                                                       "| RESERVED_2     (Invalid Token!) "
+                                                       "| WBXML 1.0 parsing stops here.",
+                                                       *level);
                                        /* Stop processing as it is impossible to parse now */
                                        off = tvb_len;
                                        *parsed_length = off - offset;
@@ -2114,8 +2754,10 @@ parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
 
                                /* No default clause, as all cases have been treated */
                } else { /* LITERAL or Known TAG */
-                       /*
-                        * We must store the initial tag, and also retrieve the new tag.
+                       /* We must store the initial tag, and also retrieve the new tag.
+                        * For efficiency reasons, we store the literal tag representation
+                        * for known tags too, so we can easily close the tag without the
+                        * need of a new lookup and avoiding storage of token codepage.
                         * 
                         * There are 4 possibilities:
                         *
@@ -2129,16 +2771,18 @@ parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                        tag_len = 0;
                        if ((peek & 0x3F) == 4) { /* LITERAL */
                                index = tvb_get_guintvar (tvb, off+1, &tag_len);
-                               tag_new_literal = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
+                               tag_new_literal = tvb_get_ptr (tvb, str_tbl+index, str_len);
                                tag_new_known = 0; /* invalidate known tag_new */
-                       } else {
+                       } else { /* Known tag */
                                tag_new_known = peek & 0x3F;
-                               tag_new_literal = NULL; /* invalidate LITERAL tag_new */
+                               sprintf (tag_new_buf, "Tag_0x%02X",
+                                               tag_new_known);
+                               tag_new_literal = tag_new_buf;
+                               /* Stored looked up tag name string */
                        }
 
-                       /*
-                        * Parsing of TAG starts HERE
-                        */
+                       /* Parsing of TAG starts HERE */
                        if (peek & 0x40) { /* Content present */
                                /* Content follows
                                 * [!] An explicit END token is expected in these cases!
@@ -2153,55 +2797,86 @@ parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                                         * recursion will take care of it */
                                        (*level)++;
                                        parse_wbxml_tag (tree, tvb, off, str_tbl, level,
-                                                       codepage_stag, codepage_attr, &len);
+                                                       &len);
                                        off += len;
                                } else { /* Now we will have content to parse */
                                        /* Save the start tag so we can properly close it later. */
-                                       if ((peek & 0x3F) == 4) {
+                                       if ((peek & 0x3F) == 4) { /* Literal tag */
                                                tag_save_literal = tag_new_literal;
                                                tag_save_known = 0;
-                                       } else {
+                                       } else { /* Known tag */
                                                tag_save_known = tag_new_known;
-                                               tag_save_literal = NULL;
+                                               sprintf (tag_save_buf, "Tag_0x%02X",
+                                                               tag_new_known);
+                                               tag_save_literal = tag_save_buf;
+                                               /* The last statement avoids needless lookups */
                                        }
                                        /* Process the attribute list if present */
                                        if (peek & 0x80) { /* Content and Attribute list present */
                                                if (tag_new_known) { /* Known tag */
-                                                       proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
-                                                                       "|   Known Tag 0x%02X           (AC) "
-                                                                       "| %s<Tag_0x%02X",
-                                                                       *level, tag_new_known, Indent (*level),
-                                                                       tag_new_known);
+                                                       if (codepage_stag) { /* Not default code page */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   | T %3d->0 "
+                                                                               "|   Known Tag 0x%02X           (AC) "
+                                                                               "| %s<%s",
+                                                                               *level, codepage_stag, tag_new_known,
+                                                                               Indent (*level), tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                               /* Reset code page */
+                                                               codepage_stag = 0;
+                                                       } else { /* Code page 0 */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   |          "
+                                                                               "|   Known Tag 0x%02X           (AC) "
+                                                                               "| %s<%s",
+                                                                               *level, tag_new_known,
+                                                                               Indent (*level), tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                       }
                                                        off++;
                                                } else { /* LITERAL tag */
                                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
+                                                                       "  %3d | Tag   |          "
                                                                        "| LITERAL_AC (Literal tag)   (AC) "
                                                                        "| %s<%s",
                                                                        *level, Indent (*level), tag_new_literal);
                                                        off += 1 + tag_len;
                                                }
-                                               parse_wbxml_attribute_list (tree, tvb, off, str_tbl,
-                                                               *level, codepage_attr, &len);
+                                               parse_wbxml_attribute_list (tree, tvb,
+                                                               off, str_tbl, *level, &len);
                                                off += len;
                                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| END (attribute list)            "
                                                                "| %s>",
                                                                *level, Indent (*level));
                                        } else { /* Content, no Attribute list */
                                                if (tag_new_known) { /* Known tag */
-                                                       proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
-                                                                       "|   Known Tag 0x%02X           (.C) "
-                                                                       "| %s<Tag_0x%02X>",
-                                                                       *level, tag_new_known, Indent (*level),
-                                                                       tag_new_known);
+                                                       if (codepage_stag) { /* Not default code page */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   | T %3d->0 "
+                                                                               "|   Known Tag 0x%02X           (.C) "
+                                                                               "| %s<%s>",
+                                                                               *level, codepage_stag, tag_new_known,
+                                                                               Indent (*level),
+                                                                               tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                               /* Reset code page */
+                                                               codepage_stag = 0;
+                                                       } else { /* Code page 0 */
+                                                               proto_tree_add_text (tree, tvb, off, 1,
+                                                                               "  %3d | Tag   |          "
+                                                                               "|   Known Tag 0x%02X           (.C) "
+                                                                               "| %s<%s>",
+                                                                               *level, tag_new_known,
+                                                                               Indent (*level),
+                                                                               tag_new_literal);
+                                                               /* Tag string already looked up earlier! */
+                                                       }
                                                        off++;
                                                } else { /* LITERAL tag */
                                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                                       "  %3d | Tag   "
+                                                                       "  %3d | Tag   |          "
                                                                        "| LITERAL_C  (Literal Tag)   (.C) "
                                                                        "| %s<%s>",
                                                                        *level, Indent (*level), tag_new_literal);
@@ -2227,49 +2902,75 @@ parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                                (*level)++;
                                if (peek & 0x80) { /* No Content, Attribute list present */
                                        if (tag_new_known) { /* Known tag */
-                                               proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
-                                                               "|   Known Tag 0x%02X           (A.) "
-                                                               "| %s<Tag 0x%02X",
-                                                               *level, tag_new_known, Indent (*level),
-                                                               tag_new_known);
+                                               if (codepage_stag) { /* Not default code page */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   | T %3d->0 "
+                                                                       "|   Known Tag 0x%02X           (A.) "
+                                                                       "| %s<%s",
+                                                                       *level, codepage_stag, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                                       /* Reset code page */
+                                                       codepage_stag = 0;
+                                               } else { /* Code page 0 */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   |          "
+                                                                       "|   Known Tag 0x%02X           (A.) "
+                                                                       "| %s<%s",
+                                                                       *level, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                               }
                                                off++;
-                                               parse_wbxml_attribute_list (tree, tvb, off, str_tbl,
-                                                               *level, codepage_attr, &len);
+                                               parse_wbxml_attribute_list (tree, tvb,
+                                                               off, str_tbl, *level, &len);
                                                off += len;
                                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| END (Known Tag)                 "
                                                                "| %s/>",
                                                                *level, Indent (*level));
                                        } else { /* LITERAL tag */
                                                proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| LITERAL_A  (Literal Tag)   (A.) "
                                                                "| %s<%s",
                                                                *level, Indent (*level), tag_new_literal);
                                                off += 1 + tag_len;
-                                               parse_wbxml_attribute_list (tree, tvb, off, str_tbl,
-                                                               *level, codepage_attr, &len);
+                                               parse_wbxml_attribute_list (tree, tvb,
+                                                               off, str_tbl, *level, &len);
                                                off += len;
                                                proto_tree_add_text (tree, tvb, off-1, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| END (Literal Tag)               "
                                                                "| %s/>",
                                                                *level, Indent (*level));
                                        }
                                } else { /* No Content, No Attribute list */
                                        if (tag_new_known) { /* Known tag */
-                                               proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
-                                                               "|   Known Tag 0x%02x           (..) "
-                                                               "| %s<Tag_0x%02X />",
-                                                               *level, tag_new_known, Indent (*level),
-                                                               tag_new_known);
+                                               if (codepage_stag) { /* Not default code page */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   | T %3d->0 "
+                                                                       "|   Known Tag 0x%02x           (..) "
+                                                                       "| %s<%s />",
+                                                                       *level, codepage_stag, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                                       /* Reset code page */
+                                                       codepage_stag = 0;
+                                               } else { /* Code page 0 */
+                                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                                       "  %3d | Tag   |          "
+                                                                       "|   Known Tag 0x%02x           (..) "
+                                                                       "| %s<%s />",
+                                                                       *level, tag_new_known,
+                                                                       Indent (*level), tag_new_literal);
+                                                       /* Tag string already looked up earlier! */
+                                               }
                                                off++;
                                        } else { /* LITERAL tag */
                                                proto_tree_add_text (tree, tvb, off, 1,
-                                                               "  %3d | Tag   "
+                                                               "  %3d | Tag   |          "
                                                                "| LITERAL    (Literal Tag)   (..) "
                                                                "| %s<%s />",
                                                                *level, Indent (*level), tag_new_literal);
@@ -2277,53 +2978,49 @@ parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
                                        }
                                }
                                (*level)--;
+                               /* TODO: Do I have to reset code page here? */
                        }
                } /* if (tag & 0x3F) >= 5 */
        } /* while */
 }
 
 
-
-
 /**************************
  * WBXML Attribute tokens *
  **************************
  * Bit Mask  : Example
  * -------------------
  * 0... .... : attr=             (attribute name)
- *             href="http://"    (attribute name with start of attribute value)
- * 1... .... : "www."            (attribute value, or part of it)
+ *             href='http://'    (attribute name with start of attribute value)
+ * 1... .... : 'www.'            (attribute value, or part of it)
  * 
  */
 
 
-
-
 /* This function parses the WBXML and maps known token interpretations
  * to the WBXML tokens. As a result, the original XML document can be
  * recreated. Indentation is generated in order to ease reading.
  *
  * This function performs attribute list parsing.
  * 
- * The wbxml_mapping_table entry *map contains the actual token mapping.
+ * The wbxml_token_map entry *map contains the actual token mapping.
  *
  * NOTE: See above for known token mappings.
- *
- * NOTE: Code page switches not yet processed in the code!
  */
 static void
 parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                guint32 offset, guint32 str_tbl, guint8 level,
-               guint8 *codepage_attr, guint32 *parsed_length,
-               const wbxml_mapping_table *map)
+               guint32 *parsed_length,
+               const wbxml_token_map *map)
 {
        guint32 tvb_len = tvb_reported_length (tvb);
        guint32 off = offset;
        guint32 len;
+       guint str_len;
        guint32 ent;
        guint32 index;
-       const char* str;
        guint8 peek;
+       guint8 codepage_attr = 0; /* Initial codepage in state = ATTR */
 
 #ifdef DEBUG
        printf ("WBXML - parse_wbxml_attr_defined (level = %d, offset = %d)\n",
@@ -2340,18 +3037,17 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                if ((peek & 0x3F) < 5) switch (peek) { /* Global tokens
                                                                                                  in state = ATTR */
                        case 0x00: /* SWITCH_PAGE */
-                               peek = tvb_get_guint8 (tvb, off+1);
+                               codepage_attr = tvb_get_guint8 (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 2,
-                                               "         Attr | SWITCH_PAGE (Attr code page)    "
-                                               "| Code page switch (was: %d, is: %d)",
-                                               *codepage_attr, peek);
-                               *codepage_attr = peek;
+                                               "      |  Attr | A 0->%3d "
+                                               "| SWITCH_PAGE (Attr code page)    |",
+                                               codepage_attr);
                                off += 2;
                                break;
                        case 0x01: /* END */
                                /* BEWARE
                                 *   The Attribute END token means either ">" or "/>"
-                                *   and as a consequence both must be trated separately.
+                                *   and as a consequence both must be treated separately.
                                 *   This is done in the TAG state parser.
                                 */
                                off++;
@@ -2360,40 +3056,57 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                        case 0x02: /* ENTITY */
                                ent = tvb_get_guintvar (tvb, off+1, &len);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | ENTITY                          "
+                                               "  %3d |  Attr |          "
+                                               "| ENTITY                          "
                                                "|     %s'&#%u;'",
                                                level, Indent (level), ent);
                                off += 1+len;
                                break;
                        case 0x03: /* STR_I */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
+                               len = tvb_strsize (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | STR_I (Inline string)           "
+                                               "  %3d |  Attr |          "
+                                               "| STR_I (Inline string)           "
                                                "|     %s\'%s\'",
-                                               level, Indent (level), str);
+                                               level, Indent (level),
+                                               tvb_format_text (tvb, off+1, len-1));
                                off += 1+len;
                                break;
                        case 0x04: /* LITERAL */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | LITERAL (Literal Attribute)     "
+                                               "  %3d |  Attr |          "
+                                               "| LITERAL (Literal Attribute)     "
                                                "|   %s<%s />",
-                                               level, Indent (level), str);
+                                               level, Indent (level),
+                                               tvb_format_text (tvb, str_tbl+index, str_len-1));
                                off += 1+len;
                                break;
                        case 0x40: /* EXT_I_0 */
                        case 0x41: /* EXT_I_1 */
                        case 0x42: /* EXT_I_2 */
                                /* Extension tokens */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | EXT_I_%1x    (Extension Token)    "
-                                               "|     %s(%s: \'%s\')",
-                                               level, peek & 0x0f, Indent (level),
-                                               match_strval (peek, map->global), str);
+                               len = tvb_strsize (tvb, off+1);
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "|     %s(%s: \'%s\')",
+                                                       level, codepage_attr, peek & 0x0f, Indent (level),
+                                                       map_token (map->global, codepage_attr, peek),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr |          "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "|     %s(%s: \'%s\')",
+                                                       level, peek & 0x0f, Indent (level),
+                                                       map_token (map->global, codepage_attr, peek),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                               }
                                off += 1+len;
                                break;
                        /* 0x43 impossible in ATTR state */
@@ -2403,21 +3116,37 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                        case 0x82: /* EXT_T_2 */
                                /* Extension tokens */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | EXT_T_%1x    (Extension Token)    "
-                                               "|     %s(%s: \'%s\')",
-                                               level, peek & 0x0f, Indent (level),
-                                               match_strval (peek, map->global), str);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "|     %s(%s: \'%s\')",
+                                                       level, codepage_attr, peek & 0x0f, Indent (level),
+                                                       map_token (map->global, codepage_attr, peek),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr |          "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "|     %s(%s: \'%s\')",
+                                                       level, peek & 0x0f, Indent (level),
+                                                       map_token (map->global, codepage_attr, peek),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                               }
                                off += 1+len;
                                break;
-                       case 0x83: /* EXT_T */
+                       case 0x83: /* STR_T */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | STR_T (Tableref string)         "
+                                               "  %3d |  Attr |          "
+                                               "| STR_T (Tableref string)         "
                                                "|     %s\'%s\'",
-                                               level, Indent (level), str);
+                                               level, Indent (level),
+                                               tvb_format_text (tvb, str_tbl+index, str_len-1));
                                off += 1+len;
                                break;
                        /* 0x84 impossible in ATTR state */
@@ -2425,25 +3154,40 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                        case 0xC1: /* EXT_1 */
                        case 0xC2: /* EXT_2 */
                                /* Extension tokens */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr | EXT_%1x      (Extension Token)    "
-                                               "|     %s(%s)",
-                                               level, peek & 0x0f, Indent (level),
-                                               match_strval (peek, map->global));
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "|     %s(%s)",
+                                                       level, codepage_attr, peek & 0x0f, Indent (level),
+                                                       map_token (map->global, codepage_attr, peek));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr |          "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "|     %s(%s)",
+                                                       level, peek & 0x0f, Indent (level),
+                                                       map_token (map->global, codepage_attr, peek));
+                               }
                                off++;
                                break;
                        case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
                                if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
                                        index = tvb_get_guintvar (tvb, off+1, &len);
                                        proto_tree_add_text (tree, tvb, off, 1 + len + index,
-                                                       "  %3d |  Attr | OPAQUE (Opaque data)            "
+                                                       "  %3d |  Attr |          "
+                                                       "| OPAQUE (Opaque data)            "
                                                        "|       %s(%d bytes of opaque data)",
                                                        level, Indent (level), index);
                                        off += 1+len+index;
                                } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "         Attr | RESERVED_2     (Invalid Token!) "
-                                                       "| WBXML 1.0 parsing stops here.");
+                                                       "  %3d |  Attr |          "
+                                                       "| RESERVED_2     (Invalid Token!) "
+                                                       "| WBXML 1.0 parsing stops here.",
+                                                       level);
                                        /* Stop processing as it is impossible to parse now */
                                        off = tvb_len;
                                        *parsed_length = off - offset;
@@ -2453,7 +3197,8 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                        /* 0xC4 impossible in ATTR state */
                        default:
                                proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr | %-10s     (Invalid Token!) "
+                                               "  %3d |  Attr |          "
+                                               "| %-10s     (Invalid Token!) "
                                                "| WBXML parsing stops here.",
                                                level, match_strval (peek, vals_wbxml1x_global_tokens));
                                /* Move to end of buffer */
@@ -2461,18 +3206,42 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
                                break;
                } else { /* Known atribute token */
                        if (peek & 0x80) { /* attrValue */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr |   Known attrValue 0x%02X          "
-                                               "|       %s%s",
-                                               level, peek & 0x7f, Indent (level),
-                                               match_strval (peek, map->attrValue));
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "|   Known attrValue 0x%02X          "
+                                                       "|       %s%s",
+                                                       level, codepage_attr, peek & 0x7f, Indent (level),
+                                                       map_token (map->attrValue, codepage_attr, peek));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr |          "
+                                                       "|   Known attrValue 0x%02X          "
+                                                       "|       %s%s",
+                                                       level, peek & 0x7f, Indent (level),
+                                                       map_token (map->attrValue, codepage_attr, peek));
+                               }
                                off++;
                        } else { /* attrStart */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr |   Known attrStart 0x%02X          "
-                                               "|   %s%s",
-                                               level, peek & 0x7f, Indent (level),
-                                               match_strval (peek, map->attrStart));
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "|   Known attrStart 0x%02X          "
+                                                       "|   %s%s",
+                                                       level, codepage_attr, peek & 0x7f, Indent (level),
+                                                       map_token (map->attrStart, codepage_attr, peek));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr |          "
+                                                       "|   Known attrStart 0x%02X          "
+                                                       "|   %s%s",
+                                                       level, peek & 0x7f, Indent (level),
+                                                       map_token (map->attrStart, codepage_attr, peek));
+                               }
                                off++;
                        }
                }
@@ -2480,8 +3249,6 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
 }
 
 
-
-
 /* This function performs the WBXML attribute decoding as in
  * parse_wbxml_attribute_list_defined() but this time no WBXML mapping
  * is performed.
@@ -2493,18 +3260,19 @@ parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
 static void
 parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                guint32 offset, guint32 str_tbl, guint8 level,
-               guint8 *codepage_attr, guint32 *parsed_length)
+               guint32 *parsed_length)
 {
        guint32 tvb_len = tvb_reported_length (tvb);
        guint32 off = offset;
        guint32 len;
+       guint str_len;
        guint32 ent;
        guint32 index;
-       const char* str;
        guint8 peek;
+       guint8 codepage_attr = 0; /* Initial codepage in state = ATTR */
 
 #ifdef DEBUG
-       printf ("WBXML - parse_wbxml_attr_defined (level = %d, offset = %d)\n",
+       printf ("WBXML - parse_wbxml_attr (level = %d, offset = %d)\n",
                        level, offset);
 #endif
        /* Parse attributes */
@@ -2518,18 +3286,17 @@ parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                if ((peek & 0x3F) < 5) switch (peek) { /* Global tokens
                                                                                                  in state = ATTR */
                        case 0x00: /* SWITCH_PAGE */
-                               peek = tvb_get_guint8 (tvb, off+1);
+                               codepage_attr = tvb_get_guint8 (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 2,
-                                               "         Attr | SWITCH_PAGE (Attr code page)    "
-                                               "| Code page switch (was: %d, is: %d)",
-                                               *codepage_attr, peek);
-                               *codepage_attr = peek;
+                                               "      |  Attr | A 0->%3d "
+                                               "| SWITCH_PAGE (Attr code page)    |",
+                                               codepage_attr);
                                off += 2;
                                break;
                        case 0x01: /* END */
                                /* BEWARE
                                 *   The Attribute END token means either ">" or "/>"
-                                *   and as a consequence both must be trated separately.
+                                *   and as a consequence both must be treated separately.
                                 *   This is done in the TAG state parser.
                                 */
                                off++;
@@ -2538,39 +3305,55 @@ parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                        case 0x02: /* ENTITY */
                                ent = tvb_get_guintvar (tvb, off+1, &len);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | ENTITY                          "
+                                               "  %3d |  Attr |          "
+                                               "| ENTITY                          "
                                                "|     %s'&#%u;'",
                                                level, Indent (level), ent);
                                off += 1+len;
                                break;
                        case 0x03: /* STR_I */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
+                               len = tvb_strsize (tvb, off+1);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | STR_I (Inline string)           "
+                                               "  %3d |  Attr |          "
+                                               "| STR_I (Inline string)           "
                                                "|     %s\'%s\'",
-                                               level, Indent (level), str);
+                                               level, Indent (level),
+                                               tvb_format_text (tvb, off+1, len-1));
                                off += 1+len;
                                break;
                        case 0x04: /* LITERAL */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | LITERAL (Literal Attribute)     "
+                                               "  %3d |  Attr |          "
+                                               "| LITERAL (Literal Attribute)     "
                                                "|   %s<%s />",
-                                               level, Indent (level), str);
+                                               level, Indent (level),
+                                               tvb_format_text (tvb, str_tbl+index, str_len-1));
                                off += 1+len;
                                break;
                        case 0x40: /* EXT_I_0 */
                        case 0x41: /* EXT_I_1 */
                        case 0x42: /* EXT_I_2 */
                                /* Extension tokens */
-                               /* Hack the string table lookup function */
-                               str = strtbl_lookup (tvb, off+1, 0, &len);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | EXT_I_%1x    (Extension Token)    "
-                                               "|     %s(Inline string extension: \'%s\')",
-                                               level, peek & 0x0f, Indent (level), str);
+                               len = tvb_strsize (tvb, off+1);
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "|     %s(Inline string extension: \'%s\')",
+                                                       level, codepage_attr, peek & 0x0f, Indent (level),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr |          "
+                                                       "| EXT_I_%1x    (Extension Token)    "
+                                                       "|     %s(Inline string extension: \'%s\')",
+                                                       level, peek & 0x0f, Indent (level),
+                                                       tvb_format_text (tvb, off+1, len-1));
+                               }
                                off += 1+len;
                                break;
                        /* 0x43 impossible in ATTR state */
@@ -2580,20 +3363,35 @@ parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                        case 0x82: /* EXT_T_2 */
                                /* Extension tokens */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
-                               proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | EXT_T_%1x    (Extension Token)    "
-                                               "|     %s(Tableref string extension: \'%s\')",
-                                               level, peek & 0x0f, Indent (level), str);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "|     %s(Tableref string extension: \'%s\')",
+                                                       level, codepage_attr, peek & 0x0f, Indent (level),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1+len,
+                                                       "  %3d |  Attr |          "
+                                                       "| EXT_T_%1x    (Extension Token)    "
+                                                       "|     %s(Tableref string extension: \'%s\')",
+                                                       level, peek & 0x0f, Indent (level),
+                                                       tvb_format_text (tvb, str_tbl+index, str_len-1));
+                               }
                                off += 1+len;
                                break;
-                       case 0x83: /* EXT_T */
+                       case 0x83: /* STR_T */
                                index = tvb_get_guintvar (tvb, off+1, &len);
-                               str = strtbl_lookup (tvb, str_tbl, index, NULL);
+                               str_len = tvb_strsize (tvb, str_tbl+index);
                                proto_tree_add_text (tree, tvb, off, 1+len,
-                                               "  %3d |  Attr | STR_T (Tableref string)         "
+                                               "  %3d |  Attr |          "
+                                               "| STR_T (Tableref string)         "
                                                "|     %s\'%s\'",
-                                               level, Indent (level), str);
+                                               level, Indent (level),
+                                               tvb_format_text (tvb, str_tbl+index, str_len-1));
                                off += 1+len;
                                break;
                        /* 0x84 impossible in ATTR state */
@@ -2601,24 +3399,38 @@ parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                        case 0xC1: /* EXT_1 */
                        case 0xC2: /* EXT_2 */
                                /* Extension tokens */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr | EXT_%1x      (Extension Token)    "
-                                               "|     %s(Single-byte extension)",
-                                               level, peek & 0x0f, Indent (level));
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "|     %s(Single-byte extension)",
+                                                       level, codepage_attr, peek & 0x0f, Indent (level));
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr |          "
+                                                       "| EXT_%1x      (Extension Token)    "
+                                                       "|     %s(Single-byte extension)",
+                                                       level, peek & 0x0f, Indent (level));
+                               }
                                off++;
                                break;
                        case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
                                if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
                                        index = tvb_get_guintvar (tvb, off+1, &len);
                                        proto_tree_add_text (tree, tvb, off, 1 + len + index,
-                                                       "  %3d |  Attr | OPAQUE (Opaque data)            "
+                                                       "  %3d |  Attr |          "
+                                                       "| OPAQUE (Opaque data)            "
                                                        "|       %s(%d bytes of opaque data)",
                                                        level, Indent (level), index);
                                        off += 1+len+index;
                                } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
                                        proto_tree_add_text (tree, tvb, off, 1,
-                                                       "         Attr | RESERVED_2     (Invalid Token!) "
-                                                       "| WBXML 1.0 parsing stops here.");
+                                                       "  %3d |  Attr |          "
+                                                       "| RESERVED_2     (Invalid Token!) "
+                                                       "| WBXML 1.0 parsing stops here.",
+                                                       level);
                                        /* Stop processing as it is impossible to parse now */
                                        off = tvb_len;
                                        *parsed_length = off - offset;
@@ -2628,7 +3440,8 @@ parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                        /* 0xC4 impossible in ATTR state */
                        default:
                                proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr | %-10s     (Invalid Token!) "
+                                               "  %3d |  Attr |          "
+                                               "| %-10s     (Invalid Token!) "
                                                "| WBXML parsing stops here.",
                                                level, match_strval (peek, vals_wbxml1x_global_tokens));
                                /* Move to end of buffer */
@@ -2636,16 +3449,42 @@ parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
                                break;
                } else { /* Known atribute token */
                        if (peek & 0x80) { /* attrValue */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr |   Known attrValue 0x%02X          "
-                                               "|       %sattrValue_0x%02X",
-                                               level, peek & 0x7f, Indent (level), peek);
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "|   Known attrValue 0x%02X          "
+                                                       "|       %sattrValue_0x%02X",
+                                                       level, codepage_attr, peek & 0x7f, Indent (level),
+                                                       peek);
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr |          "
+                                                       "|   Known attrValue 0x%02X          "
+                                                       "|       %sattrValue_0x%02X",
+                                                       level, peek & 0x7f, Indent (level),
+                                                       peek);
+                               }
                                off++;
                        } else { /* attrStart */
-                               proto_tree_add_text (tree, tvb, off, 1,
-                                               "  %3d |  Attr |   Known attrStart 0x%02X          "
-                                               "|   %sattrStart_0x%02X",
-                                               level, peek & 0x7f, Indent (level), peek);
+                               if (codepage_attr) { /* Not default code page */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr | A %3d->0 "
+                                                       "|   Known attrStart 0x%02X          "
+                                                       "|   %sattrStart_0x%02X",
+                                                       level, codepage_attr, peek & 0x7f, Indent (level),
+                                                       peek);
+                                       /* Reset code page */
+                                       codepage_attr = 0;
+                               } else { /* Code page 0 */
+                                       proto_tree_add_text (tree, tvb, off, 1,
+                                                       "  %3d |  Attr |          "
+                                                       "|   Known attrStart 0x%02X          "
+                                                       "|   %sattrStart_0x%02X",
+                                                       level, peek & 0x7f, Indent (level),
+                                                       peek);
+                               }
                                off++;
                        }
                }
@@ -2653,19 +3492,15 @@ parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
 }
 
 
-
-
 /****************** Register the protocol with Ethereal ******************/
 
+
 /* This format is required because a script is used to build the C function
- * that calls the protocol registration.
- */
+ * that calls the protocol registration. */
 
 void
 proto_register_wbxml(void)
-{                 
-
-/* Setup list of header fields  See Section 1.6.1 for details*/
+{ /* Setup list of header fields. See Section 1.6.1 for details. */
        static hf_register_info hf[] = {
                { &hf_wbxml_version,
                        { "Version",
@@ -2674,25 +3509,20 @@ proto_register_wbxml(void)
                          VALS ( vals_wbxml_versions ), 0x00,
                          "WBXML Version", HFILL }
                },
-
                { &hf_wbxml_public_id_known,
                        { "Public Identifier (known)",
                          "wbxml.public_id.known",
                          FT_UINT32, BASE_HEX,
                          VALS ( vals_wbxml_public_ids ), 0x00,
-                         "WBXML Known Public Identifier (integer)",
-                         HFILL }
+                         "WBXML Known Public Identifier (integer)", HFILL }
                },
-
                { &hf_wbxml_public_id_literal,
                        { "Public Identifier (literal)",
                          "wbxml.public_id.literal",
                          FT_STRING, BASE_NONE,
                          NULL, 0x00,
-                         "WBXML Literal Public Identifier (text string)",
-                         HFILL }
+                         "WBXML Literal Public Identifier (text string)", HFILL }
                },
-
                { &hf_wbxml_charset,
                        { "Character Set",
                          "wbxml.charset",
@@ -2700,30 +3530,28 @@ proto_register_wbxml(void)
                          VALS ( vals_character_sets ), 0x00,
                          "WBXML Character Set", HFILL }
                },
-
        };
 
-/* Setup protocol subtree array */
+       /* Setup protocol subtree array */
        static gint *ett[] = {
                &ett_wbxml,
                &ett_wbxml_str_tbl,
                &ett_wbxml_content,
        };
 
-/* Register the protocol name and description */
+       /* Register the protocol name and description */
        proto_wbxml = proto_register_protocol(
                        "WAP Binary XML",
                        "WBXML",
                        "wbxml"
        );
 
-/* Required function calls to register the header fields and subtrees used */
+       /* Required function calls to register the header fields
+        * and subtrees used */
        proto_register_field_array(proto_wbxml, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
 
        register_dissector("wbxml", dissect_wbxml, proto_wbxml);
-/*     register_init_routine(dissect_wbxml); */
-       /* wbxml_handle = find_dissector("wsp-co"); */
 };
 
 
@@ -2747,61 +3575,101 @@ proto_reg_handoff_wbxml(void)
        /**** Well-known WBXML WSP Content-Type values ****/
        
        /* application/vnd.wap.wmlc */
-       dissector_add("wsp.content_type.type", 0x14, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x14, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.wmlc", wbxml_handle);
        
        /* application/vnd.wap.wta-eventc */
-       dissector_add("wsp.content_type.type", 0x16, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x16, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.wta-eventc", wbxml_handle);
        
        /* application/vnd.wap.wbxml */
-       dissector_add("wsp.content_type.type", 0x29, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x29, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.wbxml", wbxml_handle);
        
        /* application/vnd.wap.sic */
-       dissector_add("wsp.content_type.type", 0x2E, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x2E, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.sic", wbxml_handle);
        
        /* application/vnd.wap.slc */
-       dissector_add("wsp.content_type.type", 0x30, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x30, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.slc", wbxml_handle);
        
        /* application/vnd.wap.coc */
-       dissector_add("wsp.content_type.type", 0x32, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x32, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.coc", wbxml_handle);
        
        /* application/vnd.wap.connectivity-wbxml */
-       dissector_add("wsp.content_type.type", 0x36, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x36, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.connectivity-wbxml", wbxml_handle);
        
        /* application/vnd.wap.locc+wbxml */
-       dissector_add("wsp.content_type.type", 0x40, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x40, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.wap.locc+wbxml", wbxml_handle);
        
        /* application/vnd.syncml.dm+wbxml */
-       dissector_add("wsp.content_type.type", 0x42, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x42, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.syncml.dm+wbxml", wbxml_handle);
        
        /* application/vnd.oma.drm.rights+wbxml */
-       dissector_add("wsp.content_type.type", 0x4B, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x4B, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.oma.drm.rights+wbxml", wbxml_handle);
 
-#ifdef WSP_DISSECTOR_REGISTERS_ContentType_AS_FourByteGuint    
-       
        /**** Registered WBXML WSP Content-Type values ****/
 
        /* application/vnd.uplanet.cacheop-wbxml */
-       dissector_add("wsp.content_type.type", 0x0201, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x0201, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.uplanet.cacheop-wbxml", wbxml_handle);
        
        /* application/vnd.uplanet.alert-wbxml */
-       dissector_add("wsp.content_type.type", 0x0203, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x0203, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.uplanet.alert-wbxml", wbxml_handle);
        
        /* application/vnd.uplanet.list-wbxml */
-       dissector_add("wsp.content_type.type", 0x0204, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x0204, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.uplanet.list-wbxml", wbxml_handle);
        
        /* application/vnd.uplanet.listcmd-wbxml */
-       dissector_add("wsp.content_type.type", 0x0205, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x0205, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.uplanet.listcmd-wbxml", wbxml_handle);
        
        /* application/vnd.uplanet.channel-wbxml */
-       dissector_add("wsp.content_type.type", 0x0206, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x0206, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.uplanet.channel-wbxml", wbxml_handle);
        
        /* application/vnd.uplanet.bearer-choice-wbxml */
-       dissector_add("wsp.content_type.type", 0x0209, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x0209, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.uplanet.bearer-choice-wbxml", wbxml_handle);
        
        /* application/vnd.phonecom.mmc-wbxml */
-       dissector_add("wsp.content_type.type", 0x020A, wbxml_handle);
+       dissector_add("wsp.content_type.integer", 0x020A, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.phonecom.mmc-wbxml", wbxml_handle);
        
        /* application/vnd.nokia.syncset+wbxml */
-       dissector_add("wsp.content_type.type", 0x020B, wbxml_handle);
-#endif
+       dissector_add("wsp.content_type.integer", 0x020B, wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/vnd.nokia.syncset+wbxml", wbxml_handle);
+
+       /***** Content types that only have a textual representation *****/
+       dissector_add_string("wsp.content_type.literal",
+                       "application/x-wap-prov.browser-bookmarks", wbxml_handle);
+       dissector_add_string("wsp.content_type.literal",
+                       "application/x-wap-prov.browser-settings", wbxml_handle);
+       
 }