From Michael Lum: support an AT_SS7PC address type for SS7 point codes,
[metze/wireshark/wip.git] / packet-wbxml.c
1 /* packet-wbxml.c
2  * Routines for wbxml dissection
3  * Copyright 2003, Olivier Biot <olivier.biot (ad) siemens.com>
4  *
5  * $Id: packet-wbxml.c,v 1.18 2003/12/08 20:37:15 obiot Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * WAP Binary XML decoding functionality provided by Olivier Biot.
12  * 
13  * The WAP specifications are found at the WAP Forum:
14  * http://www.wapforum.org/what/Technical.htm
15  * 
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * 
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29  */
30
31 /* Edit this file with 4-space tabulation */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <glib.h>
42
43 #ifdef NEED_SNPRINTF_H
44 # include "snprintf.h"
45 #endif
46
47 #include <epan/packet.h>
48
49 /* We need the function tvb_get_guintvar() */
50 #include "packet-wap.h"
51
52 /* General-purpose debug logger.
53  * Requires double parentheses because of variable arguments of printf().
54  *
55  * Enable debug logging for WBXML by defining AM_FLAGS
56  * so that it contains "-DDEBUG_wbxml"
57  */
58 #ifdef DEBUG_wbxml
59 #define DebugLog(x) \
60         printf("%s:%u: ", __FILE__, __LINE__); \
61         printf x; \
62         fflush(stdout)
63 #else
64 #define DebugLog(x) ;
65 #endif
66
67 /* The code in this source file dissects the WAP Binary XML content,
68  * and if possible renders it. WBXML mappings are defined in the
69  * "wbxml_map[]" array.
70  *
71  * NOTES:
72  *
73  *  - Code page switches only apply to the following token. In the WBXML/1.x
74  *    ABNF notation, it can be proven that the switch_page can only precede
75  *    the following tokens:
76  *      o  stag      : TAG | LITERAL | LITERAL_A | LITERAL_C | LITERAL_AC
77  *      o  attr      : ATTRSTART | ATTRVALUE
78  *      o  extension : EXT_I | EXT_T | EXT
79  *    Code page switches are displayed in a separate column. The only allowed
80  *    code page switches are from code page 0 to another codepage (by means of
81  *    a SWITCH_PAGE token), and from this other code page back to code page 0
82  *    (this happens automatically).
83  *
84  *  - In order to render the XML content, recursion is inevitable at some
85  *    point (when a tag with content occurs in the content of a tag with
86  *    content). The code will however not recurse if this is not strictly
87  *    required (e.g., tag without content in the content of a tag with
88  *    content).
89  *
90  *  - I found it useful to display the XML nesting level as a first "column",
91  *    followed by the abbreviated WBXML token interpretation. When a mapping
92  *    is defined for the parsed WBXML content, then the XML rendering is
93  *    displayed with appropriate indentation (maximum nesting level = 255,
94  *    after which the nesting and level will safely roll-over to 0).
95  *
96  *  - The WAP Forum defines the order of precedence for finding out the
97  *    WBXML content type (same rules for charset) as follows:
98  *      1. Look in the Content-Type WSP header
99  *      2. Look in the WBXML header
100  *    Currently there is no means of using content type parameters:
101  *      o  Type=<some_type>
102  *      o  Charset=<charset_of_the_content>
103  *    So it is possible some WBXML content types are incorrectly parsed.
104  *    This would only be the case when the content type declaration in the
105  *    WSP Content-Type header would be different (or would have parameters
106  *    which are relevant to the WBXML decoding) from the content type
107  *    identifier specified in the WBXML header.
108  *    TODO: investigate this and provide correct decoding at all times.
109  */
110
111 typedef struct _value_valuestring {
112   guint32 value;
113   const value_string *valstrptr;
114 } value_valuestring;
115
116 /* Tries to match val against each element in the value_value_string array vvs.
117  * Returns the associated value_string ptr on a match, or NULL on failure. */
118 static const value_string *
119 val_to_valstr(guint32 val, const value_valuestring *vvs)
120 {
121   gint i = 0;
122
123   while (vvs[i].valstrptr) {
124         if (vvs[i].value == val)
125       return(vvs[i].valstrptr);
126       i++;
127   }
128
129   return(NULL);
130 }
131
132
133 /************************** Variable declarations **************************/
134
135
136 /* Initialize the protocol and registered fields */
137 static int proto_wbxml = -1;
138 static int hf_wbxml_version = -1;
139 static int hf_wbxml_public_id_known = -1;
140 static int hf_wbxml_public_id_literal = -1;
141 static int hf_wbxml_charset = -1;
142
143 /* Initialize the subtree pointers */
144 static gint ett_wbxml = -1;
145 static gint ett_wbxml_str_tbl = -1;
146 static gint ett_wbxml_content = -1;
147
148
149 /**************** WBXML related declarations and definitions ****************/
150
151
152 /* WBXML public ID mappings. For an up-to-date list, see
153  * http://www.wapforum.org/wina/wbxml-public-docid.htm */
154 static const value_string vals_wbxml_public_ids[] = {
155         /* 0x00 = literal public identifier */
156         { 0x01, "Unknown / missing Public Identifier" },
157         { 0x02, "-//WAPFORUM//DTD WML 1.0//EN (WML 1.0)" },
158         { 0x03, "-//WAPFORUM//DTD WTA 1.0//EN (WTA Event 1.0) - Deprecated" },
159         { 0x04, "-//WAPFORUM//DTD WML 1.1//EN (WML 1.1)" },
160         { 0x05, "-//WAPFORUM//DTD SI 1.0//EN (Service Indication 1.0)" },
161         { 0x06, "-//WAPFORUM//DTD SL 1.0//EN (Service Loading 1.0)" },
162         { 0x07, "-//WAPFORUM//DTD CO 1.0//EN (Cache Operation 1.0)" },
163         { 0x08, "-//WAPFORUM//DTD CHANNEL 1.0//EN (Channel 1.1)" },
164         { 0x09, "-//WAPFORUM//DTD WML 1.2//EN (WML 1.2)" },
165         { 0x0a, "-//WAPFORUM//DTD WML 1.3//EN (WML 1.3)" },
166         { 0x0b, "-//WAPFORUM//DTD PROV 1.0//EN (Provisioning 1.0)" },
167         { 0x0c, "-//WAPFORUM//DTD WTA-WML 1.2//EN (WTA-WML 1.2)" },
168         { 0x0d, "-//WAPFORUM//DTD EMN 1.0//EN (Email Notification 1.0)" },
169         { 0x0e, "-//WAPFORUM//DTD DRMREL 1.0//EN (DRMREL 1.0)" },
170         { 0x0f, "-//WIRELESSVILLAGE//DTD CSP 1.0//EN"
171                 " (Wireless Village Client-Server Protocol DTD v1.0)" },
172         { 0x10, "-//WIRELESSVILLAGE//DTD CSP 1.1//EN"
173                 " (Wireless Village Client-Server Protocol DTD v1.1)" },
174
175         /* Registered values - www.syncml.org */
176         { 0x0fd1, "-//SYNCML//DTD SyncML 1.0//EN (SyncML 1.0)" },
177         { 0x0fd3, "-//SYNCML//DTD SyncML 1.1//EN (SyncML 1.1)" },
178
179         /* Registered values - www.wapforum.org/wina/ */
180         { 0x1100, "-//PHONE.COM//DTD ALERT 1.0//EN" },
181         { 0x1101, "-//PHONE.COM//DTD CACHE-OPERATION 1.0//EN" },
182         { 0x1102, "-//PHONE.COM//DTD SIGNAL 1.0//EN" },
183         { 0x1103, "-//PHONE.COM//DTD LIST 1.0//EN" },
184         { 0x1104, "-//PHONE.COM//DTD LISTCMD 1.0//EN" },
185         { 0x1105, "-//PHONE.COM//DTD CHANNEL 1.0//EN" },
186         { 0x1106, "-//PHONE.COM//DTD MMC 1.0//EN" },
187         { 0x1107, "-//PHONE.COM//DTD BEARER-CHOICE 1.0//EN" },
188         { 0x1108, "-//PHONE.COM//DTD WML 1.1//EN (WML+ 1.1)" },
189         { 0x1109, "-//PHONE.COM//DTD CHANNEL 1.1//EN" },
190         { 0x110a, "-//PHONE.COM//DTD LIST 1.1//EN" },
191         { 0x110b, "-//PHONE.COM//DTD LISTCMD 1.1//EN" },
192         { 0x110c, "-//PHONE.COM//DTD MMC 1.1//EN" },
193         { 0x110d, "-//PHONE.COM//DTD WML 1.3//EN (WML+ 1.3)" },
194         { 0x110e, "-//PHONE.COM//DTD MMC 2.0//EN" },
195         /* 0x110F -- 0x11FF: unassigned */
196         { 0x1200, "-//3GPP2.COM//DTD IOTA 1.0//EN" },
197         
198         { 0x00, NULL }
199 };
200
201 static const value_string vals_wbxml_versions[] = {
202         { 0x00, "1.0" },        /* WAP-104-WBXML */
203         { 0x01, "1.1" },        /* WAP-135-WBXML */
204         { 0x02, "1.2" },        /* WAP-154-WBXML */
205         { 0x03, "1.3" },        /* WAP-192-WBXML */
206         
207         { 0x00, NULL }
208 };
209
210 /* WBXML 1.0 global tokens: WAP-104-WBXML
211  * Same token mapping as in vals_wbxml1x_global_tokens, but:
212  *   { 0xC3, "RESERVED_2" }
213  */
214
215 /* WBXML 1.x (x>0) global tokens: WAP-135-WBXML, WAP-154-WBXML, WAP-192-WBXML
216  */
217 static const value_string vals_wbxml1x_global_tokens[] = {
218         { 0x00, "SWITCH_PAGE" },
219         { 0x01, "END" },
220         { 0x02, "ENTITY" },
221         { 0x03, "STR_I" },
222         { 0x04, "LITERAL" },
223
224         { 0x40, "EXT_I_0" },
225         { 0x41, "EXT_I_1" },
226         { 0x42, "EXT_I_2" },
227         { 0x43, "PI" },
228         { 0x44, "LITERAL_C" },
229
230         { 0x80, "EXT_T_0" },
231         { 0x81, "EXT_T_1" },
232         { 0x82, "EXT_T_2" },
233         { 0x83, "STR_T" },
234         { 0x84, "LITERAL_A" },
235
236         { 0xC0, "EXT_0" },
237         { 0xC1, "EXT_1" },
238         { 0xC2, "EXT_2" },
239         { 0xC3, "OPAQUE" },
240         { 0xC4, "LITERAL_AC" },
241
242         { 0x00, NULL }
243 };
244
245
246 /********************** WBXML token mapping definition **********************/
247
248
249 /* WML 1.0
250  * 
251  * Wireless Markup Language
252  ***************************************/
253
254 /*****   Global extension tokens   *****/
255 static const value_string wbxml_wmlc10_global_cp0[] = {
256         { 0x40, "Variable substitution - escaped" },
257         { 0x41, "Variable substitution - unescaped" },
258         { 0x42, "Variable substitution - no transformation" },
259         { 0x80, "Variable substitution - escaped" },
260         { 0x81, "Variable substitution - unescaped" },
261         { 0x82, "Variable substitution - no transformation" },
262         { 0xC0, "Reserved" },
263         { 0xC1, "Reserved" },
264         { 0xC2, "Reserved" },
265
266         { 0x00, NULL }
267 };
268
269 /*****         Tag tokens          *****/
270 static const value_string wbxml_wmlc10_tags_cp0[] = {
271         /* 0x00 -- 0x04 GLOBAL */
272         /* 0x05 -- 0xE1 */
273         { 0xE2, "A" },
274         { 0xE3, "ACCESS" },
275         { 0xE4, "B" },
276         { 0xE5, "BIG" },
277         { 0xE6, "BR" },
278         { 0xE7, "CARD" },
279         { 0xE8, "DO" },
280         { 0xE9, "EM" },
281         { 0xEA, "FIELDSET" },
282         { 0xEB, "GO" },
283         { 0xEC, "HEAD" },
284         { 0xED, "I" },
285         { 0xEE, "IMG" },
286         { 0xEF, "INPUT" },
287         { 0xF0, "META" },
288         { 0xF1, "NOOP" },
289         { 0xF2, "PREV" },
290         { 0xF3, "ONEVENT" },
291         { 0xF4, "OPTGROUP" },
292         { 0xF5, "OPTION" },
293         { 0xF6, "REFRESH" },
294         { 0xF7, "SELECT" },
295         { 0xF8, "SMALL" },
296         { 0xF9, "STRONG" },
297         { 0xFA, "TAB" },
298         { 0xFB, "TEMPLATE" },
299         { 0xFC, "TIMER" },
300         { 0xFD, "U" },
301         { 0xFE, "VAR" },
302         { 0xFF, "WML" },
303
304         { 0x00, NULL }
305 };
306
307 /*****    Attribute Start tokens   *****/
308 static const value_string wbxml_wmlc10_attrStart_cp0[] = {
309         /* 0x00 -- 0x04 GLOBAL */
310         { 0x05, "ACCEPT-CHARSET=" },
311         { 0x06, "ALIGN='BOTTOM'" },
312         { 0x07, "ALIGN='CENTER'" },
313         { 0x08, "ALIGN='LEFT'" },
314         { 0x09, "ALIGN='MIDDLE'" },
315         { 0x0A, "ALIGN='RIGHT'" },
316         { 0x0B, "ALIGN='TOP'" },
317         { 0x0C, "ALT=" },
318         { 0x0D, "CONTENT=" },
319         { 0x0E, "DEFAULT=" },
320         { 0x0F, "DOMAIN=" },
321         { 0x10, "EMPTYOK='FALSE'" },
322         { 0x11, "EMPTYOK='TRUE'" },
323         { 0x12, "FORMAT=" },
324         { 0x13, "HEIGHT=" },
325         { 0x14, "HSPACE=" },
326         { 0x15, "IDEFAULT=" },
327         { 0x16, "IKEY=" },
328         { 0x17, "KEY=" },
329         { 0x18, "LABEL=" },
330         { 0x19, "LOCALSRC=" },
331         { 0x1A, "MAXLENGTH=" },
332         { 0x1B, "METHOD='GET'" },
333         { 0x1C, "METHOD='POST'" },
334         { 0x1D, "MODE='NOWRAP'" },
335         { 0x1E, "MODE='WRAP'" },
336         { 0x1F, "MULTIPLE='FALSE'" },
337         { 0x20, "MULTIPLE='TRUE'" },
338         { 0x21, "NAME=" },
339         { 0x22, "NEWCONTEXT='FALSE'" },
340         { 0x23, "NEWCONTEXT='TRUE'" },
341         { 0x24, "ONCLICK=" },
342         { 0x25, "ONENTERBACKWARD=" },
343         { 0x26, "ONENTERFORWARD=" },
344         { 0x27, "ONTIMER=" },
345         { 0x28, "OPTIONAL='FALSE'" },
346         { 0x29, "OPTIONAL='TRUE'" },
347         { 0x2A, "PATH=" },
348         { 0x2B, "POSTDATA=" },
349         { 0x2C, "PUBLIC='FALSE'" },
350         { 0x2D, "PUBLIC='TRUE'" },
351         { 0x2E, "SCHEME=" },
352         { 0x2F, "SENDREFERER='FALSE'" },
353         { 0x30, "SENDREFERER='TRUE'" },
354         { 0x31, "SIZE=" },
355         { 0x32, "SRC=" },
356         { 0x33, "STYLE='LIST'" },
357         { 0x34, "STYLE='SET'" },
358         { 0x35, "TABINDEX=" },
359         { 0x36, "TITLE=" },
360         { 0x37, "TYPE=" },
361         { 0x38, "TYPE='ACCEPT'" },
362         { 0x39, "TYPE='DELETE'" },
363         { 0x3A, "TYPE='HELP'" },
364         { 0x3B, "TYPE='PASSWORD'" },
365         { 0x3C, "TYPE='ONCLICK'" },
366         { 0x3D, "TYPE='ONENTERBACKWARD'" },
367         { 0x3E, "TYPE='ONENTERFORWARD'" },
368         { 0x3F, "TYPE='ONTIMER'" },
369         /* 0x40 -- 0x44 GLOBAL */
370         { 0x45, "TYPE='OPTIONS'" },
371         { 0x46, "TYPE='PREV'" },
372         { 0x47, "TYPE='RESET'" },
373         { 0x48, "TYPE='TEXT'" },
374         { 0x49, "TYPE='vnd.'" },
375         { 0x4A, "URL=" },
376         { 0x4B, "URL='http://'" },
377         { 0x4C, "URL='https://'" },
378         { 0x4D, "USER-AGENT=" },
379         { 0x4E, "VALUE=" },
380         { 0x4F, "VSPACE=" },
381         { 0x50, "WIDTH=" },
382         { 0x51, "xml:lang=" },
383
384         { 0x00, NULL }
385 };
386
387 /*****    Attribute Value tokens   *****/
388 static const value_string wbxml_wmlc10_attrValue_cp0[] = {
389         /* 0x80 -- 0x84 GLOBAL */
390         { 0x85, "'.com/'" },
391         { 0x86, "'.edu/'" },
392         { 0x87, "'.net/'" },
393         { 0x88, "'.org/'" },
394         { 0x89, "'ACCEPT'" },
395         { 0x8A, "'BOTTOM'" },
396         { 0x8B, "'CLEAR'" },
397         { 0x8C, "'DELETE'" },
398         { 0x8D, "'HELP'" },
399         { 0x8E, "'http://'" },
400         { 0x8F, "'http://www.'" },
401         { 0x90, "'https://'" },
402         { 0x91, "'https://www.'" },
403         { 0x92, "'LIST'" },
404         { 0x93, "'MIDDLE'" },
405         { 0x94, "'NOWRAP'" },
406         { 0x95, "'ONCLICK'" },
407         { 0x96, "'ONENTERBACKWARD'" },
408         { 0x97, "'ONENTERFORWARD'" },
409         { 0x98, "'ONTIMER'" },
410         { 0x99, "'OPTIONS'" },
411         { 0x9A, "'PASSWORD'" },
412         { 0x9B, "'RESET'" },
413         { 0x9C, "'SET'" },
414         { 0x9D, "'TEXT'" },
415         { 0x9E, "'TOP'" },
416         { 0x9F, "'UNKNOWN'" },
417         { 0xA0, "'WRAP'" },
418         { 0xA1, "'www.'" },
419
420         { 0x00, NULL }
421 };
422
423 /***** Token code page aggregation *****/
424 static const value_valuestring wbxml_wmlc10_global[] = {
425         { 0, wbxml_wmlc10_global_cp0 },
426         { 0, NULL }
427 };
428
429 static const value_valuestring wbxml_wmlc10_tags[] = {
430         { 0, wbxml_wmlc10_tags_cp0 },
431         { 0, NULL }
432 };
433
434 static const value_valuestring wbxml_wmlc10_attrStart[] = {
435         { 0, wbxml_wmlc10_attrStart_cp0 },
436         { 0, NULL }
437 };
438
439 static const value_valuestring wbxml_wmlc10_attrValue[] = {
440         { 0, wbxml_wmlc10_attrValue_cp0 },
441         { 0, NULL }
442 };
443
444
445
446
447
448 /* WML 1.1
449  * 
450  * Wireless Markup Language
451  ***************************************/
452
453 /*****   Global extension tokens   *****/
454 /* Same as in WML 1.0 */
455
456 /*****         Tag tokens          *****/
457 static const value_string wbxml_wmlc11_tags_cp0[] = {
458         /* 0x00 -- 0x04 GLOBAL */
459         /* 0x05 -- 0x1B */
460         { 0x1C, "a" },
461         { 0x1D, "td" },
462         { 0x1E, "tr" },
463         { 0x1F, "table" },
464         { 0x20, "p" },
465         { 0x21, "postfield" },
466         { 0x22, "anchor" },
467         { 0x23, "access" },
468         { 0x24, "b" },
469         { 0x25, "big" },
470         { 0x26, "br" },
471         { 0x27, "card" },
472         { 0x28, "do" },
473         { 0x29, "em" },
474         { 0x2A, "fieldset" },
475         { 0x2B, "go" },
476         { 0x2C, "head" },
477         { 0x2D, "i" },
478         { 0x2E, "img" },
479         { 0x2F, "input" },
480         { 0x30, "meta" },
481         { 0x31, "noop" },
482         { 0x32, "prev" },
483         { 0x33, "onevent" },
484         { 0x34, "optgroup" },
485         { 0x35, "option" },
486         { 0x36, "refresh" },
487         { 0x37, "select" },
488         { 0x38, "small" },
489         { 0x39, "strong" },
490         /* 0x3A */
491         { 0x3B, "template" },
492         { 0x3C, "timer" },
493         { 0x3D, "u" },
494         { 0x3E, "setvar" },
495         { 0x3F, "wml" },
496
497         { 0x00, NULL }
498 };
499
500 /*****    Attribute Start tokens   *****/
501 static const value_string wbxml_wmlc11_attrStart_cp0[] = {
502         /* 0x00 -- 0x04 GLOBAL */
503         { 0x05, "accept-charset=" },
504         { 0x06, "align='bottom'" },
505         { 0x07, "align='center'" },
506         { 0x08, "align='left'" },
507         { 0x09, "align='middle'" },
508         { 0x0A, "align='right'" },
509         { 0x0B, "align='top'" },
510         { 0x0C, "alt=" },
511         { 0x0D, "content=" },
512         /* 0x0E */
513         { 0x0F, "domain=" },
514         { 0x10, "emptyok='false'" },
515         { 0x11, "emptyok='true'" },
516         { 0x12, "format=" },
517         { 0x13, "height=" },
518         { 0x14, "hspace=" },
519         { 0x15, "ivalue=" },
520         { 0x16, "iname=" },
521         /* 0x17 */
522         { 0x18, "label=" },
523         { 0x19, "localsrc=" },
524         { 0x1A, "maxlength=" },
525         { 0x1B, "method='get'" },
526         { 0x1C, "method='post'" },
527         { 0x1D, "mode='nowrap'" },
528         { 0x1E, "mode='wrap'" },
529         { 0x1F, "multiple='false'" },
530         { 0x20, "multiple='true'" },
531         { 0x21, "name=" },
532         { 0x22, "newcontext='false'" },
533         { 0x23, "newcontext='true'" },
534         { 0x24, "onpick=" },
535         { 0x25, "onenterbackward=" },
536         { 0x26, "onenterforward=" },
537         { 0x27, "ontimer=" },
538         { 0x28, "optional='false'" },
539         { 0x29, "optional='true'" },
540         { 0x2A, "path=" },
541         /* 0x2B -- 0x2D */
542         { 0x2E, "scheme=" },
543         { 0x2F, "sendreferer='false'" },
544         { 0x30, "sendreferer='true'" },
545         { 0x31, "size=" },
546         { 0x32, "src=" },
547         { 0x33, "ordered='false'" },
548         { 0x34, "ordered='true'" },
549         { 0x35, "tabindex=" },
550         { 0x36, "title=" },
551         { 0x37, "type=" },
552         { 0x38, "type='accept'" },
553         { 0x39, "type='delete'" },
554         { 0x3A, "type='help'" },
555         { 0x3B, "type='password'" },
556         { 0x3C, "type='onpick'" },
557         { 0x3D, "type='onenterbackward'" },
558         { 0x3E, "type='onenterforward'" },
559         { 0x3F, "type='ontimer'" },
560         /* 0x40 -- 0x44 GLOBAL */
561         { 0x45, "type='options'" },
562         { 0x46, "type='prev'" },
563         { 0x47, "type='reset'" },
564         { 0x48, "type='text'" },
565         { 0x49, "type='vnd.'" },
566         { 0x4A, "href=" },
567         { 0x4B, "href='http://'" },
568         { 0x4C, "href='https://'" },
569         { 0x4D, "value=" },
570         { 0x4E, "vspace=" },
571         { 0x4F, "width=" },
572         { 0x50, "xml:lang=" },
573         /* 0x51 */
574         { 0x52, "align=" },
575         { 0x53, "columns=" },
576         { 0x54, "class=" },
577         { 0x55, "id=" },
578         { 0x56, "forua='false'" },
579         { 0x57, "forua='true'" },
580         { 0x58, "src='http://'" },
581         { 0x59, "src='https://'" },
582         { 0x5A, "http-equiv=" },
583         { 0x5B, "http-equiv='Content-Type'" },
584         { 0x5C, "content='application/vnd.wap.wmlc;charset='" },
585         { 0x5D, "http-equiv='Expires'" },
586
587         { 0x00, NULL }
588 };
589
590 /*****    Attribute Value tokens   *****/
591 static const value_string wbxml_wmlc11_attrValue_cp0[] = {
592         /* 0x80 -- 0x84 GLOBAL */
593         { 0x85, "'.com/'" },
594         { 0x86, "'.edu/'" },
595         { 0x87, "'.net/'" },
596         { 0x88, "'.org/'" },
597         { 0x89, "'accept'" },
598         { 0x8A, "'bottom'" },
599         { 0x8B, "'clear'" },
600         { 0x8C, "'delete'" },
601         { 0x8D, "'help'" },
602         { 0x8E, "'http://'" },
603         { 0x8F, "'http://www.'" },
604         { 0x90, "'https://'" },
605         { 0x91, "'https://www.'" },
606         /* 0x92 */
607         { 0x93, "'middle'" },
608         { 0x94, "'nowrap'" },
609         { 0x95, "'onpick'" },
610         { 0x96, "'onenterbackward'" },
611         { 0x97, "'onenterforward'" },
612         { 0x98, "'ontimer'" },
613         { 0x99, "'options'" },
614         { 0x9A, "'password'" },
615         { 0x9B, "'reset'" },
616         /* 0x9C */
617         { 0x9D, "'text'" },
618         { 0x9E, "'top'" },
619         { 0x9F, "'unknown'" },
620         { 0xA0, "'wrap'" },
621         { 0xA1, "'www.'" },
622
623         { 0x00, NULL }
624 };
625
626 /***** Token code page aggregation *****/
627 static const value_valuestring wbxml_wmlc11_global[] = {
628         { 0, wbxml_wmlc10_global_cp0 }, /* Same as WML 1.0 */
629         { 0, NULL }
630 };
631
632 static const value_valuestring wbxml_wmlc11_tags[] = {
633         { 0, wbxml_wmlc11_tags_cp0 },
634         { 0, NULL }
635 };
636
637 static const value_valuestring wbxml_wmlc11_attrStart[] = {
638         { 0, wbxml_wmlc11_attrStart_cp0 },
639         { 0, NULL }
640 };
641
642 static const value_valuestring wbxml_wmlc11_attrValue[] = {
643         { 0, wbxml_wmlc11_attrValue_cp0 },
644         { 0, NULL }
645 };
646
647
648
649
650
651 /* WML 1.2
652  * 
653  * Wireless Markup Language
654  ***************************************/
655
656 /*****   Global extension tokens   *****/
657 /* Same as in WML 1.0 */
658
659 /*****         Tag tokens          *****/
660 static const value_string wbxml_wmlc12_tags_cp0[] = {
661         /* 0x00 -- 0x04 GLOBAL */
662         /* 0x05 -- 0x1A */
663         { 0x1B, "pre" },
664         { 0x1C, "a" },
665         { 0x1D, "td" },
666         { 0x1E, "tr" },
667         { 0x1F, "table" },
668         { 0x20, "p" },
669         { 0x21, "postfield" },
670         { 0x22, "anchor" },
671         { 0x23, "access" },
672         { 0x24, "b" },
673         { 0x25, "big" },
674         { 0x26, "br" },
675         { 0x27, "card" },
676         { 0x28, "do" },
677         { 0x29, "em" },
678         { 0x2A, "fieldset" },
679         { 0x2B, "go" },
680         { 0x2C, "head" },
681         { 0x2D, "i" },
682         { 0x2E, "img" },
683         { 0x2F, "input" },
684         { 0x30, "meta" },
685         { 0x31, "noop" },
686         { 0x32, "prev" },
687         { 0x33, "onevent" },
688         { 0x34, "optgroup" },
689         { 0x35, "option" },
690         { 0x36, "refresh" },
691         { 0x37, "select" },
692         { 0x38, "small" },
693         { 0x39, "strong" },
694         /* 0x3A */
695         { 0x3B, "template" },
696         { 0x3C, "timer" },
697         { 0x3D, "u" },
698         { 0x3E, "setvar" },
699         { 0x3F, "wml" },
700
701         { 0x00, NULL }
702 };
703
704 /*****    Attribute Start tokens   *****/
705 static const value_string wbxml_wmlc12_attrStart_cp0[] = {
706         /* 0x00 -- 0x04 GLOBAL */
707         { 0x05, "accept-charset=" },
708         { 0x06, "align='bottom'" },
709         { 0x07, "align='center'" },
710         { 0x08, "align='left'" },
711         { 0x09, "align='middle'" },
712         { 0x0A, "align='right'" },
713         { 0x0B, "align='top'" },
714         { 0x0C, "alt=" },
715         { 0x0D, "content=" },
716         /* 0x0E */
717         { 0x0F, "domain=" },
718         { 0x10, "emptyok='false'" },
719         { 0x11, "emptyok='true'" },
720         { 0x12, "format=" },
721         { 0x13, "height=" },
722         { 0x14, "hspace=" },
723         { 0x15, "ivalue=" },
724         { 0x16, "iname=" },
725         /* 0x17 */
726         { 0x18, "label=" },
727         { 0x19, "localsrc=" },
728         { 0x1A, "maxlength=" },
729         { 0x1B, "method='get'" },
730         { 0x1C, "method='post'" },
731         { 0x1D, "mode='nowrap'" },
732         { 0x1E, "mode='wrap'" },
733         { 0x1F, "multiple='false'" },
734         { 0x20, "multiple='true'" },
735         { 0x21, "name=" },
736         { 0x22, "newcontext='false'" },
737         { 0x23, "newcontext='true'" },
738         { 0x24, "onpick=" },
739         { 0x25, "onenterbackward=" },
740         { 0x26, "onenterforward=" },
741         { 0x27, "ontimer=" },
742         { 0x28, "optional='false'" },
743         { 0x29, "optional='true'" },
744         { 0x2A, "path=" },
745         /* 0x2B -- 0x2D */
746         { 0x2E, "scheme=" },
747         { 0x2F, "sendreferer='false'" },
748         { 0x30, "sendreferer='true'" },
749         { 0x31, "size=" },
750         { 0x32, "src=" },
751         { 0x33, "ordered='false'" },
752         { 0x34, "ordered='true'" },
753         { 0x35, "tabindex=" },
754         { 0x36, "title=" },
755         { 0x37, "type=" },
756         { 0x38, "type='accept'" },
757         { 0x39, "type='delete'" },
758         { 0x3A, "type='help'" },
759         { 0x3B, "type='password'" },
760         { 0x3C, "type='onpick'" },
761         { 0x3D, "type='onenterbackward'" },
762         { 0x3E, "type='onenterforward'" },
763         { 0x3F, "type='ontimer'" },
764         /* 0x40 -- 0x44 GLOBAL */
765         { 0x45, "type='options'" },
766         { 0x46, "type='prev'" },
767         { 0x47, "type='reset'" },
768         { 0x48, "type='text'" },
769         { 0x49, "type='vnd.'" },
770         { 0x4A, "href=" },
771         { 0x4B, "href='http://'" },
772         { 0x4C, "href='https://'" },
773         { 0x4D, "value=" },
774         { 0x4E, "vspace=" },
775         { 0x4F, "width=" },
776         { 0x50, "xml:lang=" },
777         /* 0x51 */
778         { 0x52, "align=" },
779         { 0x53, "columns=" },
780         { 0x54, "class=" },
781         { 0x55, "id=" },
782         { 0x56, "forua='false'" },
783         { 0x57, "forua='true'" },
784         { 0x58, "src='http://'" },
785         { 0x59, "src='https://'" },
786         { 0x5A, "http-equiv=" },
787         { 0x5B, "http-equiv='Content-Type'" },
788         { 0x5C, "content='application/vnd.wap.wmlc;charset='" },
789         { 0x5D, "http-equiv='Expires'" },
790         { 0x5E, "accesskey=" },
791         { 0x5F, "enctype=" },
792         { 0x60, "enctype='application/x-www-form-urlencoded'" },
793         { 0x61, "enctype='multipart/form-data'" },
794
795         { 0x00, NULL }
796 };
797
798 /*****    Attribute Value tokens   *****/
799 /* Same as in WML 1.1 */
800
801 /***** Token code page aggregation *****/
802 static const value_valuestring wbxml_wmlc12_global[] = {
803         { 0, wbxml_wmlc10_global_cp0 }, /* Same as WML 1.0 */
804         { 0, NULL }
805 };
806
807 static const value_valuestring wbxml_wmlc12_tags[] = {
808         { 0, wbxml_wmlc12_tags_cp0 },
809         { 0, NULL }
810 };
811
812 static const value_valuestring wbxml_wmlc12_attrStart[] = {
813         { 0, wbxml_wmlc12_attrStart_cp0 },
814         { 0, NULL }
815 };
816
817 static const value_valuestring wbxml_wmlc12_attrValue[] = {
818         { 0, wbxml_wmlc11_attrValue_cp0 }, /* Same as WML 1.1 */
819         { 0, NULL }
820 };
821
822
823
824
825
826 /* WML 1.3
827  * 
828  * Wireless Markup Language
829  ***************************************/
830
831 /*****   Global extension tokens   *****/
832 /* Same as in WML 1.0 */
833
834 /*****         Tag tokens          *****/
835 /* Same as in WML 1.2 */
836
837 /*****    Attribute Start tokens   *****/
838 static const value_string wbxml_wmlc13_attrStart_cp0[] = {
839         /* 0x00 -- 0x04 GLOBAL */
840         { 0x05, "accept-charset=" },
841         { 0x06, "align='bottom'" },
842         { 0x07, "align='center'" },
843         { 0x08, "align='left'" },
844         { 0x09, "align='middle'" },
845         { 0x0A, "align='right'" },
846         { 0x0B, "align='top'" },
847         { 0x0C, "alt=" },
848         { 0x0D, "content=" },
849         /* 0x0E */
850         { 0x0F, "domain=" },
851         { 0x10, "emptyok='false'" },
852         { 0x11, "emptyok='true'" },
853         { 0x12, "format=" },
854         { 0x13, "height=" },
855         { 0x14, "hspace=" },
856         { 0x15, "ivalue=" },
857         { 0x16, "iname=" },
858         /* 0x17 */
859         { 0x18, "label=" },
860         { 0x19, "localsrc=" },
861         { 0x1A, "maxlength=" },
862         { 0x1B, "method='get'" },
863         { 0x1C, "method='post'" },
864         { 0x1D, "mode='nowrap'" },
865         { 0x1E, "mode='wrap'" },
866         { 0x1F, "multiple='false'" },
867         { 0x20, "multiple='true'" },
868         { 0x21, "name=" },
869         { 0x22, "newcontext='false'" },
870         { 0x23, "newcontext='true'" },
871         { 0x24, "onpick=" },
872         { 0x25, "onenterbackward=" },
873         { 0x26, "onenterforward=" },
874         { 0x27, "ontimer=" },
875         { 0x28, "optional='false'" },
876         { 0x29, "optional='true'" },
877         { 0x2A, "path=" },
878         /* 0x2B -- 0x2D */
879         { 0x2E, "scheme=" },
880         { 0x2F, "sendreferer='false'" },
881         { 0x30, "sendreferer='true'" },
882         { 0x31, "size=" },
883         { 0x32, "src=" },
884         { 0x33, "ordered='false'" },
885         { 0x34, "ordered='true'" },
886         { 0x35, "tabindex=" },
887         { 0x36, "title=" },
888         { 0x37, "type=" },
889         { 0x38, "type='accept'" },
890         { 0x39, "type='delete'" },
891         { 0x3A, "type='help'" },
892         { 0x3B, "type='password'" },
893         { 0x3C, "type='onpick'" },
894         { 0x3D, "type='onenterbackward'" },
895         { 0x3E, "type='onenterforward'" },
896         { 0x3F, "type='ontimer'" },
897         /* 0x40 -- 0x44 GLOBAL */
898         { 0x45, "type='options'" },
899         { 0x46, "type='prev'" },
900         { 0x47, "type='reset'" },
901         { 0x48, "type='text'" },
902         { 0x49, "type='vnd.'" },
903         { 0x4A, "href=" },
904         { 0x4B, "href='http://'" },
905         { 0x4C, "href='https://'" },
906         { 0x4D, "value=" },
907         { 0x4E, "vspace=" },
908         { 0x4F, "width=" },
909         { 0x50, "xml:lang=" },
910         /* 0x51 */
911         { 0x52, "align=" },
912         { 0x53, "columns=" },
913         { 0x54, "class=" },
914         { 0x55, "id=" },
915         { 0x56, "forua='false'" },
916         { 0x57, "forua='true'" },
917         { 0x58, "src='http://'" },
918         { 0x59, "src='https://'" },
919         { 0x5A, "http-equiv=" },
920         { 0x5B, "http-equiv='Content-Type'" },
921         { 0x5C, "content='application/vnd.wap.wmlc;charset='" },
922         { 0x5D, "http-equiv='Expires'" },
923         { 0x5E, "accesskey=" },
924         { 0x5F, "enctype=" },
925         { 0x60, "enctype='application/x-www-form-urlencoded'" },
926         { 0x61, "enctype='multipart/form-data'" },
927         { 0x62, "xml:space='preserve'" },
928         { 0x63, "xml:space='default'" },
929         { 0x64, "cache-control='no-cache'" },
930
931         { 0x00, NULL }
932 };
933
934 /*****    Attribute Value tokens   *****/
935 /* Same as in WML 1.1 */
936
937 /***** Token code page aggregation *****/
938 static const value_valuestring wbxml_wmlc13_global[] = {
939         { 0, wbxml_wmlc10_global_cp0 }, /* Same as WML 1.0 */
940         { 0, NULL }
941 };
942
943 static const value_valuestring wbxml_wmlc13_tags[] = {
944         { 0, wbxml_wmlc12_tags_cp0 },
945         { 0, NULL }
946 };
947
948 static const value_valuestring wbxml_wmlc13_attrStart[] = {
949         { 0, wbxml_wmlc13_attrStart_cp0 },
950         { 0, NULL }
951 };
952
953 static const value_valuestring wbxml_wmlc13_attrValue[] = {
954         { 0, wbxml_wmlc11_attrValue_cp0 }, /* Same as WML 1.1 */
955         { 0, NULL }
956 };
957
958
959
960
961
962 /* SI 1.0
963  * 
964  * Service Indication
965  ***************************************/
966
967 /*****   Global extension tokens   *****/
968
969 /*****         Tag tokens          *****/
970 static const value_string wbxml_sic10_tags_cp0[] = {
971         /* 0x00 -- 0x04 GLOBAL */
972         { 0x05, "si" },
973         { 0x06, "indication" },
974         { 0x07, "info" },
975         { 0x08, "item" },
976
977         { 0x00, NULL }
978 };
979
980 /*****    Attribute Start tokens   *****/
981 static const value_string wbxml_sic10_attrStart_cp0[] = {
982         /* 0x00 -- 0x04 GLOBAL */
983         { 0x05, "action='signal-none'" },
984         { 0x06, "action='signal-low'" },
985         { 0x07, "action='signal-medium'" },
986         { 0x08, "action='signal-high'" },
987         { 0x09, "action='delete'" },
988         { 0x0a, "created=" },
989         { 0x0b, "href=" },
990         { 0x0c, "href='http://'" },
991         { 0x0d, "href='http://www.'" },
992         { 0x0e, "href='https://'" },
993         { 0x0f, "href='https://www.'" },
994         { 0x10, "si-expires=" },
995         { 0x11, "si-id=" },
996         { 0x12, "class=" },
997
998         { 0x00, NULL }
999 };
1000
1001 /*****    Attribute Value tokens   *****/
1002 static const value_string wbxml_sic10_attrValue_cp0[] = {
1003         /* 0x80 -- 0x84 GLOBAL */
1004         { 0x85, "'.com/'" },
1005         { 0x86, "'.edu/'" },
1006         { 0x87, "'.net/'" },
1007         { 0x88, "'.org/'" },
1008
1009         { 0x00, NULL }
1010 };
1011
1012 /***** Token code page aggregation *****/
1013 static const value_valuestring wbxml_sic10_tags[] = {
1014         { 0, wbxml_sic10_tags_cp0 },
1015         { 0, NULL }
1016 };
1017
1018 static const value_valuestring wbxml_sic10_attrStart[] = {
1019         { 0, wbxml_sic10_attrStart_cp0 },
1020         { 0, NULL }
1021 };
1022
1023 static const value_valuestring wbxml_sic10_attrValue[] = {
1024         { 0, wbxml_sic10_attrValue_cp0 },
1025         { 0, NULL }
1026 };
1027
1028
1029
1030
1031
1032 /* SL 1.0
1033  * 
1034  * Service Loading
1035  ***************************************/
1036
1037 /*****   Global extension tokens   *****/
1038
1039 /*****         Tag tokens          *****/
1040 static const value_string wbxml_slc10_tags_cp0[] = {
1041         /* 0x00 -- 0x04 GLOBAL */
1042         { 0x05, "sl" },
1043
1044         { 0x00, NULL }
1045 };
1046
1047 /*****    Attribute Start tokens   *****/
1048 static const value_string wbxml_slc10_attrStart_cp0[] = {
1049         /* 0x00 -- 0x04 GLOBAL */
1050         { 0x05, "action='execute-low'" },
1051         { 0x06, "action='execute-high'" },
1052         { 0x07, "action='cache'" },
1053         { 0x08, "href=" },
1054         { 0x09, "href='http://'" },
1055         { 0x0a, "href='http://www.'" },
1056         { 0x0b, "href='https://'" },
1057         { 0x0c, "href='https://www.'" },
1058
1059         { 0x00, NULL }
1060 };
1061
1062 /*****    Attribute Value tokens   *****/
1063 /* Same as in SI 1.0 */
1064
1065 /***** Token code page aggregation *****/
1066 static const value_valuestring wbxml_slc10_tags[] = {
1067         { 0, wbxml_slc10_tags_cp0 },
1068         { 0, NULL }
1069 };
1070
1071 static const value_valuestring wbxml_slc10_attrStart[] = {
1072         { 0, wbxml_slc10_attrStart_cp0 },
1073         { 0, NULL }
1074 };
1075
1076 static const value_valuestring wbxml_slc10_attrValue[] = {
1077         { 0, wbxml_sic10_attrValue_cp0 }, /* Same as SI 1.0 */
1078         { 0, NULL }
1079 };
1080
1081
1082
1083
1084
1085 /* CO 1.0
1086  * 
1087  * Cache Operation
1088  ***************************************/
1089
1090 /*****   Global extension tokens   *****/
1091
1092 /*****         Tag tokens          *****/
1093 static const value_string wbxml_coc10_tags_cp0[] = {
1094         /* 0x00 -- 0x04 GLOBAL */
1095         { 0x05, "co" },
1096         { 0x06, "invalidate-object" },
1097         { 0x07, "invalidate-service" },
1098
1099         { 0x00, NULL }
1100 };
1101
1102 /*****    Attribute Start tokens   *****/
1103 static const value_string wbxml_coc10_attrStart_cp0[] = {
1104         /* 0x00 -- 0x04 GLOBAL */
1105         { 0x05, "uri=" },
1106         { 0x06, "uri='http://'" },
1107         { 0x07, "uri='http://www.'" },
1108         { 0x08, "uri='https://'" },
1109         { 0x09, "uri='https://www.'" },
1110
1111         { 0x00, NULL }
1112 };
1113
1114 /*****    Attribute Value tokens   *****/
1115 /* Same as in SI 1.0 */
1116
1117 /***** Token code page aggregation *****/
1118 static const value_valuestring wbxml_coc10_tags[] = {
1119         { 0, wbxml_coc10_tags_cp0 },
1120         { 0, NULL }
1121 };
1122
1123 static const value_valuestring wbxml_coc10_attrStart[] = {
1124         { 0, wbxml_coc10_attrStart_cp0 },
1125         { 0, NULL }
1126 };
1127
1128 static const value_valuestring wbxml_coc10_attrValue[] = {
1129         { 0, wbxml_sic10_attrValue_cp0 }, /* Same as SI 1.0 */
1130         { 0, NULL }
1131 };
1132
1133
1134
1135
1136
1137 /* PROV 1.0
1138  *
1139  * Client Provisioning
1140  ***************************************/
1141
1142 /*****   Global extension tokens   *****/
1143
1144 /*****         Tag tokens          *****/
1145 static const value_string wbxml_provc10_tags_cp0[] = {
1146         /* 0x00 -- 0x04 GLOBAL */
1147         { 0x05, "wap-provisioningdoc" },
1148         { 0x06, "characteristic" },
1149         { 0x07, "parm" },
1150
1151         { 0x00, NULL }
1152 };
1153
1154 /*****    Attribute Start tokens   *****/
1155 static const value_string wbxml_provc10_attrStart_cp0[] = {
1156         /* 0x00 -- 0x04 GLOBAL */
1157         { 0x05, "name=" },
1158         { 0x06, "value=" },
1159         { 0x07, "name='NAME'" },
1160         { 0x08, "name='NAP-ADDRESS'" },
1161         { 0x09, "name='NAP-ADDRTYPE'" },
1162         { 0x0A, "name='CALLTYPE'" },
1163         { 0x0B, "name='VALIDUNTIL'" },
1164         { 0x0C, "name='AUTHTYPE'" },
1165         { 0x0D, "name='AUTHNAME'" },
1166         { 0x0E, "name='AUTHSECRET'" },
1167         { 0x0F, "name='LINGER'" },
1168         { 0x10, "name='BEARER'" },
1169         { 0x11, "name='NAPID'" },
1170         { 0x12, "name='COUNTRY'" },
1171         { 0x13, "name='NETWORK'" },
1172         { 0x14, "name='INTERNET'" },
1173         { 0x15, "name='PROXY-ID'" },
1174         { 0x16, "name='PROXY-PROVIDER-ID'" },
1175         { 0x17, "name='DOMAIN'" },
1176         { 0x18, "name='PROVURL'" },
1177         { 0x19, "name='PXAUTH-TYPE'" },
1178         { 0x1A, "name='PXAUTH-ID'" },
1179         { 0x1B, "name='PXAUTH-PW'" },
1180         { 0x1C, "name='STARTPAGE'" },
1181         { 0x1D, "name='BASAUTH-ID'" },
1182         { 0x1E, "name='BASAUTH-PW'" },
1183         { 0x1F, "name='PUSHENABLED'" },
1184         { 0x20, "name='PXADDR'" },
1185         { 0x21, "name='PXADDRTYPE'" },
1186         { 0x22, "name='TO-NAPID'" },
1187         { 0x23, "name='PORTNBR'" },
1188         { 0x24, "name='SERVICE'" },
1189         { 0x25, "name='LINKSPEED'" },
1190         { 0x26, "name='DNLINKSPEED'" },
1191         { 0x27, "name='LOCAL-ADDR'" },
1192         { 0x28, "name='LOCAL-ADDRTYPE'" },
1193         { 0x29, "name='CONTEXT-ALLOW'" },
1194         { 0x2A, "name='TRUST'" },
1195         { 0x2B, "name='MASTER'" },
1196         { 0x2C, "name='SID'" },
1197         { 0x2D, "name='SOC'" },
1198         { 0x2E, "name='WSP-VERSION'" },
1199         { 0x2F, "name='PHYSICAL-PROXY-ID'" },
1200         { 0x30, "name='CLIENT-ID'" },
1201         { 0x31, "name='DELIVERY-ERR-SDU'" },
1202         { 0x32, "name='DELIVERY-ORDER'" },
1203         { 0x33, "name='TRAFFIC-CLASS'" },
1204         { 0x34, "name='MAX-SDU-SIZE'" },
1205         { 0x35, "name='MAX-BITRATE-UPLINK'" },
1206         { 0x36, "name='MAX-BITRATE-DNLINK'" },
1207         { 0x37, "name='RESIDUAL-BER'" },
1208         { 0x38, "name='SDU-ERROR-RATIO'" },
1209         { 0x39, "name='TRAFFIC-HANDL-PRIO'" },
1210         { 0x3A, "name='TRANSFER-DELAY'" },
1211         { 0x3B, "name='GUARANTEED-BITRATE-UPLINK'" },
1212         { 0x3C, "name='GUARANTEED-BITRATE-DNLINK'" },
1213         /* 0x3D -- 0x3F */
1214         /* 0x40 -- 0x44 GLOBAL */
1215         { 0x45, "version=" },
1216         { 0x46, "version='1.0'" },
1217         /* 0x47 -- 0x4F */
1218         { 0x50, "type=" },
1219         { 0x51, "type='PXLOGICAL'" },
1220         { 0x52, "type='PXPHYSICAL'" },
1221         { 0x53, "type='PORT'" },
1222         { 0x54, "type='VALIDITY'" },
1223         { 0x55, "type='NAPDEF'" },
1224         { 0x56, "type='BOOTSTRAP'" },
1225         { 0x57, "type='VENDORCONFIG'" },
1226         { 0x58, "type='CLIENTIDENTITY'" },
1227         { 0x59, "type='PXAUTHINFO'" },
1228         { 0x5A, "type='NAPAUTHINFO'" },
1229
1230         { 0x00, NULL }
1231 };
1232
1233 /*****    Attribute Start tokens   *****/
1234 static const value_string wbxml_provc10_attrValue_cp0[] = {
1235         /* 0x80 -- 0x84 GLOBAL */
1236         { 0x85, "'IPV4'" },
1237         { 0x86, "'IPV6'" },
1238         { 0x87, "'E164'" },
1239         { 0x88, "'ALPHA'" },
1240         { 0x89, "'APN'" },
1241         { 0x8A, "'SCODE'" },
1242         { 0x8B, "'TETRA-ITSI'" },
1243         { 0x8C, "'MAN'" },
1244         /* 0x8D -- 0x8F */
1245         { 0x90, "'ANALOG-MODEM'" },
1246         { 0x91, "'V.120'" },
1247         { 0x92, "'V.110'" },
1248         { 0x93, "'X.31'" },
1249         { 0x94, "'BIT-TRANSPARENT'" },
1250         { 0x95, "'DIRECT-ASYNCHRONOUS-DATA-SERVICE'" },
1251         /* 0x96 -- 0x99 */
1252         { 0x9A, "'PAP'" },
1253         { 0x9B, "'CHAP'" },
1254         { 0x9C, "'HTTP-BASIC'" },
1255         { 0x9D, "'HTTP-DIGEST'" },
1256         { 0x9E, "'WTLS-SS'" },
1257         /* 0x9F -- 0xA1 */
1258         { 0xA2, "'GSM-USSD'" },
1259         { 0xA3, "'GSM-SMS'" },
1260         { 0xA4, "'ANSI-136-GUTS'" },
1261         { 0xA5, "'IS-95-CDMA-SMS'" },
1262         { 0xA6, "'IS-95-CDMA-CSD'" },
1263         { 0xA7, "'IS-95-CDMA-PACKET'" },
1264         { 0xA8, "'ANSI-136-CSD'" },
1265         { 0xA9, "'ANSI-136-GPRS'" },
1266         { 0xAA, "'GSM-CSD'" },
1267         { 0xAB, "'GSM-GPRS'" },
1268         { 0xAC, "'AMPS-CDPD'" },
1269         { 0xAD, "'PDC-CSD'" },
1270         { 0xAE, "'PDC-PACKET'" },
1271         { 0xAF, "'IDEN-SMS'" },
1272         { 0xB0, "'IDEN-CSD'" },
1273         { 0xB1, "'IDEN-PACKET'" },
1274         { 0xB2, "'FLEX/REFLEX'" },
1275         { 0xB3, "'PHS-SMS'" },
1276         { 0xB4, "'PHS-CSD'" },
1277         { 0xB5, "'TETRA-SDS'" },
1278         { 0xB6, "'TETRA-PACKET'" },
1279         { 0xB7, "'ANSI-136-GHOST'" },
1280         { 0xB8, "'MOBITEX-MPAK'" },
1281         /* 0xB9 -- 0xBF */
1282         /* 0xC0 -- 0xC4 GLOBAL */
1283         { 0xC5, "'AUTOBAUDING'" },
1284         /* 0xC6 -- 0xC9 */
1285         { 0xCA, "'CL-WSP'" },
1286         { 0xCB, "'CO-WSP'" },
1287         { 0xCC, "'CL-SEC-WSP'" },
1288         { 0xCD, "'CO-SEC-WSP'" },
1289         { 0xCE, "'CL-SEC-WTA'" },
1290         { 0xCF, "'CO-SEC-WTA'" },
1291
1292         { 0x00, NULL }
1293 };
1294
1295 /***** Token code page aggregation *****/
1296 static const value_valuestring wbxml_provc10_tags[] = {
1297         { 0, wbxml_provc10_tags_cp0 },
1298         { 0, NULL }
1299 };
1300
1301 static const value_valuestring wbxml_provc10_attrStart[] = {
1302         { 0, wbxml_provc10_attrStart_cp0 },
1303         { 0, NULL }
1304 };
1305
1306 static const value_valuestring wbxml_provc10_attrValue[] = {
1307         { 0, wbxml_provc10_attrValue_cp0 },
1308         { 0, NULL }
1309 };
1310
1311
1312
1313
1314
1315 /* EMN 1.0
1316  * 
1317  * Email Notification
1318  ***************************************/
1319
1320 /*****   Global extension tokens   *****/
1321
1322 /*****         Tag tokens          *****/
1323 static const value_string wbxml_emnc10_tags_cp0[] = {
1324         /* 0x00 -- 0x04 GLOBAL */
1325         { 0x05, "emn" },
1326
1327         { 0x00, NULL }
1328 };
1329
1330 /*****    Attribute Start tokens   *****/
1331 static const value_string wbxml_emnc10_attrStart_cp0[] = {
1332         /* 0x00 -- 0x04 GLOBAL */
1333         { 0x05, "timestamp=" },
1334         { 0x06, "mailbox=" },
1335         { 0x07, "mailbox='mailat:'" },
1336         { 0x08, "mailbox='pop://'" },
1337         { 0x09, "mailbox='imap://'" },
1338         { 0x0a, "mailbox='http://'" },
1339         { 0x0b, "mailbox='http://www.'" },
1340         { 0x0c, "mailbox='https://'" },
1341         { 0x0D, "mailbox='https://www.'" },
1342
1343         { 0x00, NULL }
1344 };
1345
1346 /*****    Attribute Value tokens   *****/
1347 /* Same as in SI 1.0 */
1348
1349 /***** Token code page aggregation *****/
1350 static const value_valuestring wbxml_emnc10_tags[] = {
1351         { 0, wbxml_emnc10_tags_cp0 },
1352         { 0, NULL }
1353 };
1354
1355 static const value_valuestring wbxml_emnc10_attrStart[] = {
1356         { 0, wbxml_emnc10_attrStart_cp0 },
1357         { 0, NULL }
1358 };
1359
1360 static const value_valuestring wbxml_emnc10_attrValue[] = {
1361         { 0, wbxml_sic10_attrValue_cp0 }, /* Same as SI 1.0 */
1362         { 0, NULL }
1363 };
1364
1365
1366
1367
1368
1369 /* SyncML 1.0
1370  * 
1371  * SyncML Representation Protocol
1372  ***************************************/
1373
1374 /*****   Global extension tokens   *****/
1375
1376 /*****         Tag tokens          *****/
1377 static const value_string wbxml_syncmlc10_tags_cp0[] = { /* SyncML 1.0 */
1378         /* 0x00 -- 0x04 GLOBAL */
1379         { 0x05, "Add" },
1380         { 0x06, "Alert" },
1381         { 0x07, "Archive" },
1382         { 0x08, "Atomic" },
1383         { 0x09, "Chal" },
1384         { 0x0A, "Cmd" },
1385         { 0x0B, "CmdID" },
1386         { 0x0C, "CmdRef" },
1387         { 0x0D, "Copy" },
1388         { 0x0E, "Cred" },
1389         { 0x0F, "Data" },
1390         { 0x10, "Delete" },
1391         { 0x11, "Exec" },
1392         { 0x12, "Final" },
1393         { 0x13, "Get" },
1394         { 0x14, "Item" },
1395         { 0x15, "Lang" },
1396         { 0x16, "LocName" },
1397         { 0x17, "LocURI" },
1398         { 0x18, "Map" },
1399         { 0x19, "MapItem" },
1400         { 0x1A, "Meta" },
1401         { 0x1B, "MsgID" },
1402         { 0x1C, "MsgRef" },
1403         { 0x1D, "NoResp" },
1404         { 0x1E, "NoResults" },
1405         { 0x1F, "Put" },
1406         { 0x20, "Replace" },
1407         { 0x21, "RespURI" },
1408         { 0x22, "Results" },
1409         { 0x23, "Search" },
1410         { 0x24, "Sequence" },
1411         { 0x25, "SessionID" },
1412         { 0x26, "SftDel" },
1413         { 0x27, "Source" },
1414         { 0x28, "SourceRef" },
1415         { 0x29, "Status" },
1416         { 0x2A, "Sync" },
1417         { 0x2B, "SyncBody" },
1418         { 0x2C, "SyncHdr" },
1419         { 0x2D, "SyncML" },
1420         { 0x2E, "Target" },
1421         { 0x2F, "TargetRef" },
1422         /* 0x30 - Reserved */
1423         { 0x31, "VerDTD" },
1424         { 0x32, "VerProto" },
1425
1426         { 0x00, NULL }
1427 };
1428
1429 static const value_string wbxml_syncmlc10_tags_cp1[] = { /* MetInf 1.0 */
1430         /* 0x00 -- 0x04 GLOBAL */
1431         { 0x05, "Anchor" },
1432         { 0x06, "EMI" },
1433         { 0x07, "Format" },
1434         { 0x08, "FreeID" },
1435         { 0x09, "FreeMem" },
1436         { 0x0A, "Last" },
1437         { 0x0B, "Mark" },
1438         { 0x0C, "MaxMsgSize" },
1439         { 0x0D, "Mem" },
1440         { 0x0E, "MetInf" },
1441         { 0x0F, "Next" },
1442         { 0x10, "NextNonce" },
1443         { 0x11, "SharedMem" },
1444         { 0x12, "Size" },
1445         { 0x13, "Type" },
1446         { 0x14, "Version" },
1447
1448         { 0x00, NULL }
1449 };
1450
1451 /*****    Attribute Start tokens   *****/
1452
1453 /*****    Attribute Value tokens   *****/
1454
1455 /***** Token code page aggregation *****/
1456 static const value_valuestring wbxml_syncmlc10_tags[] = {
1457         { 0, wbxml_syncmlc10_tags_cp0 }, /* -//SYNCML//DTD SyncML 1.0//EN */
1458         { 0, wbxml_syncmlc10_tags_cp1 }, /* -//SYNCML//DTD MetInf 1.0//EN */
1459         { 0, NULL }
1460 };
1461
1462
1463
1464
1465
1466 /* SyncML 1.1
1467  * 
1468  * SyncML Representation Protocol
1469  ***************************************/
1470
1471 /*****   Global extension tokens   *****/
1472
1473 /*****         Tag tokens          *****/
1474 static const value_string wbxml_syncmlc11_tags_cp0[] = { /* SyncML 1.1 */
1475         /* 0x00 -- 0x04 GLOBAL */
1476         { 0x05, "Add" },
1477         { 0x06, "Alert" },
1478         { 0x07, "Archive" },
1479         { 0x08, "Atomic" },
1480         { 0x09, "Chal" },
1481         { 0x0a, "Cmd" },
1482         { 0x0b, "CmdID" },
1483         { 0x0c, "CmdRef" },
1484         { 0x0d, "Copy" },
1485         { 0x0e, "Cred" },
1486         { 0x0f, "Data" },
1487         { 0x10, "Delete" },
1488         { 0x11, "Exec" },
1489         { 0x12, "Final" },
1490         { 0x13, "Get" },
1491         { 0x14, "Item" },
1492         { 0x15, "Lang" },
1493         { 0x16, "LocName" },
1494         { 0x17, "LocURI" },
1495         { 0x18, "Map" },
1496         { 0x19, "MapItem" },
1497         { 0x1a, "Meta" },
1498         { 0x1b, "MsgID" },
1499         { 0x1c, "MsgRef" },
1500         { 0x1d, "NoResp" },
1501         { 0x1e, "NoResults" },
1502         { 0x1f, "Put" },
1503         { 0x20, "Replace" },
1504         { 0x21, "RespURI" },
1505         { 0x22, "Results" },
1506         { 0x23, "Search" },
1507         { 0x24, "Sequence" },
1508         { 0x25, "SessionID" },
1509         { 0x26, "SftDel" },
1510         { 0x27, "Source" },
1511         { 0x28, "SourceRef" },
1512         { 0x29, "Status" },
1513         { 0x2a, "Sync" },
1514         { 0x2b, "SyncBody" },
1515         { 0x2c, "SyncHdr" },
1516         { 0x2d, "SyncML" },
1517         { 0x2e, "Target" },
1518         { 0x2f, "TargetRef" },
1519         /* 0x30 - Reserved */
1520         { 0x31, "VerDTD" },
1521         { 0x32, "VerProto" },
1522         { 0x33, "NumberOfChanges" },
1523         { 0x34, "MoreData" },
1524
1525         { 0x00, NULL }
1526 };
1527
1528 static const value_string wbxml_syncmlc11_tags_cp1[] = { /* MetInf 1.1 */
1529         /* 0x00 -- 0x04 GLOBAL */
1530         { 0x05, "Anchor" },
1531         { 0x06, "EMI" },
1532         { 0x07, "Format" },
1533         { 0x08, "FreeID" },
1534         { 0x09, "FreeMem" },
1535         { 0x0A, "Last" },
1536         { 0x0B, "Mark" },
1537         { 0x0C, "MaxMsgSize" },
1538         { 0x0D, "Mem" },
1539         { 0x0E, "MetInf" },
1540         { 0x0F, "Next" },
1541         { 0x10, "NextNonce" },
1542         { 0x11, "SharedMem" },
1543         { 0x12, "Size" },
1544         { 0x13, "Type" },
1545         { 0x14, "Version" },
1546         { 0x15, "MaxObjSize" },
1547
1548         { 0x00, NULL }
1549 };
1550
1551 /*****    Attribute Start tokens   *****/
1552
1553 /*****    Attribute Value tokens   *****/
1554
1555 /***** Token code page aggregation *****/
1556 static const value_valuestring wbxml_syncmlc11_tags[] = {
1557         { 0, wbxml_syncmlc11_tags_cp0 }, /* -//SYNCML//DTD SyncML 1.1//EN */
1558         { 0, wbxml_syncmlc11_tags_cp1 }, /* -//SYNCML//DTD MetInf 1.1//EN */
1559         { 0, NULL }
1560 };
1561
1562
1563
1564
1565
1566 /* CHANNEL 1.0
1567  * 
1568  * WTA Channel
1569  ***************************************/
1570
1571 /*****   Global extension tokens   *****/
1572
1573 /*****         Tag tokens          *****/
1574 static const value_string wbxml_channelc10_tags_cp0[] = {
1575         /* 0x00 -- 0x04 GLOBAL */
1576         { 0x05, "channel" },
1577         { 0x06, "title" },
1578         { 0x07, "abstract" },
1579         { 0x08, "resource" },
1580
1581         { 0x00, NULL }
1582 };
1583
1584 /*****    Attribute Start tokens   *****/
1585 static const value_string wbxml_channelc10_attrStart_cp0[] = {
1586         /* 0x00 -- 0x04 GLOBAL */
1587         { 0x05, "maxspace" },
1588         { 0x06, "base" },
1589         { 0x07, "href" },
1590         { 0x08, "href='http://'" },
1591         { 0x09, "href='https://'" },
1592         { 0x0A, "lastmod" },
1593         { 0x0B, "etag" },
1594         { 0x0C, "md5" },
1595         { 0x0D, "success" },
1596         { 0x0E, "success='http://'" },
1597         { 0x0F, "success='https://'" },
1598         { 0x10, "failure" },
1599         { 0x11, "failure='http://'" },
1600         { 0x12, "failure='https://'" },
1601         { 0x13, "EventId" },
1602
1603         { 0x00, NULL }
1604 };
1605
1606 /*****    Attribute Value tokens   *****/
1607
1608 /***** Token code page aggregation *****/
1609 static const value_valuestring wbxml_channelc10_tags[] = {
1610         { 0, wbxml_channelc10_tags_cp0 },
1611         { 0, NULL }
1612 };
1613
1614 static const value_valuestring wbxml_channelc10_attrStart[] = {
1615         { 0, wbxml_channelc10_attrStart_cp0 },
1616         { 0, NULL }
1617 };
1618
1619
1620
1621
1622
1623 /* application/x-wap-prov.browser-settings
1624  * application/x-wap-prov.browser-bookmarks
1625  * 
1626  * Nokia OTA Provisioning document format
1627  ***************************************/
1628
1629 /*****   Global extension tokens   *****/
1630
1631 /*****         Tag tokens          *****/
1632 static const value_string wbxml_nokiaprovc70_tags_cp0[] = {
1633         /* 0x00 -- 0x04 GLOBAL */
1634         { 0x05, "CHARACTERISTIC-LIST" },
1635         { 0x06, "CHARACTERISTIC" },
1636         { 0x07, "PARM" },
1637
1638         { 0x00, NULL }
1639 };
1640
1641 /*****    Attribute Start tokens   *****/
1642 static const value_string wbxml_nokiaprovc70_attrStart_cp0[] = {
1643         /* 0x00 -- 0x04 GLOBAL */
1644         { 0x06, "TYPE='ADDRESS'" },
1645         { 0x07, "TYPE='URL'" },
1646         { 0x08, "TYPE='NAME'" },
1647         { 0x10, "NAME" },
1648         { 0x11, "VALUE" },
1649         { 0x12, "NAME='BEARER'" },
1650         { 0x13, "NAME='PROXY'" },
1651         { 0x14, "NAME='PORT'" },
1652         { 0x15, "NAME='NAME'" },
1653         { 0x16, "NAME='PROXY_TYPE'" },
1654         { 0x17, "NAME='URL'" },
1655         { 0x18, "NAME='PROXY_AUTHNAME'" },
1656         { 0x19, "NAME='PROXY_AUTHSECRET'" },
1657         { 0x1A, "NAME='SMS_SMSC_ADDRESS'" },
1658         { 0x1B, "NAME='USSD_SERVICE_CODE'" },
1659         { 0x1C, "NAME='GPRS_ACCESSPOINTNAME'" },
1660         { 0x1D, "NAME='PPP_LOGINTYPE'" },
1661         { 0x1E, "NAME='PROXY_LOGINTYPE'" },
1662         { 0x21, "NAME='CSD_DIALSTRING'" },
1663         { 0x22, "NAME='PPP_AUTHTYPE'" },
1664         { 0x23, "NAME='PPP_AUTHNAME'" },
1665         { 0x24, "NAME='PPP_AUTHSECRET'" },
1666         { 0x28, "NAME='CSD_CALLTYPE'" },
1667         { 0x29, "NAME='CSD_CALLSPEED'" },
1668         { 0x45, "VALUE='GSM/CSD'" },
1669         { 0x46, "VALUE='GSM/SMS'" },
1670         { 0x47, "VALUE='GSM/USSD'" },
1671         { 0x48, "VALUE='IS-136/CSD'" },
1672         { 0x49, "VALUE='GPRS'" },
1673         { 0x60, "VALUE='9200'" },
1674         { 0x61, "VALUE='9201'" },
1675         { 0x62, "VALUE='9202'" },
1676         { 0x63, "VALUE='9203'" },
1677         { 0x64, "VALUE='AUTOMATIC'" },
1678         { 0x65, "VALUE='MANUAL'" },
1679         { 0x6A, "VALUE='AUTO'" },
1680         { 0x6B, "VALUE='9600'" },
1681         { 0x6C, "VALUE='14400'" },
1682         { 0x6D, "VALUE='19200'" },
1683         { 0x6E, "VALUE='28800'" },
1684         { 0x6F, "VALUE='38400'" },
1685         { 0x70, "VALUE='PAP'" },
1686         { 0x71, "VALUE='CHAP'" },
1687         { 0x72, "VALUE='ANALOGUE'" },
1688         { 0x73, "VALUE='ISDN'" },
1689         { 0x74, "VALUE='43200'" },
1690         { 0x75, "VALUE='57600'" },
1691         { 0x76, "VALUE='MSISDN_NO'" },
1692         { 0x77, "VALUE='IPV4'" },
1693         { 0x78, "VALUE='MS_CHAP'" },
1694         { 0x7C, "TYPE='MMSURL'" },
1695         { 0x7D, "TYPE='ID'" },
1696         { 0x7E, "NAME='ISP_NAME'" },
1697         { 0x7F, "TYPE='BOOKMARK'" },
1698
1699         { 0x00, NULL }
1700 };
1701
1702 /*****    Attribute Value tokens   *****/
1703
1704 /***** Token code page aggregation *****/
1705 static const value_valuestring wbxml_nokiaprovc70_tags[] = {
1706         { 0, wbxml_nokiaprovc70_tags_cp0 },
1707         { 0, NULL }
1708 };
1709
1710 static const value_valuestring wbxml_nokiaprovc70_attrStart[] = {
1711         { 0, wbxml_nokiaprovc70_attrStart_cp0 },
1712         { 0, NULL }
1713 };
1714
1715
1716
1717
1718
1719
1720 /********************** WBXML token mapping aggregation **********************/
1721
1722
1723 /* The following structure links content types to their token mapping and
1724  * contains arrays of pointers to value_string arrays (one per code page).
1725  */
1726 typedef struct _wbxml_token_map {
1727         const guint32 publicid;  /* WBXML DTD number - see WINA (now OMNA) */
1728         const gchar *content_type;      /* Content type if no WBXML DTD number */
1729         const guint8 defined;    /* Are there mapping tables defined */
1730         const value_valuestring *global;     /* Global token map */
1731         const value_valuestring *tags;       /* Tag token map */
1732         const value_valuestring *attrStart;  /* Attribute Start token map */
1733         const value_valuestring *attrValue;  /* Attribute Value token map */
1734 } wbxml_token_map;
1735
1736 static const wbxml_token_map *wbxml_content_map (guint32 publicid,
1737                 const char *content_type);
1738
1739 /**
1740  ** Aggregation of content type and aggregated code pages
1741  ** Content type map lookup will stop at the 1st entry with 3rd member = FALSE
1742  **/
1743 static const wbxml_token_map map[] = {
1744 #ifdef Test_the_WBXML_parser_without_token_mappings
1745         { 0, NULL, FALSE, NULL, NULL, NULL, NULL },
1746 #endif
1747         { 0x02, NULL, TRUE, /* WML 1.0 */
1748                 wbxml_wmlc10_global,
1749                 wbxml_wmlc10_tags,
1750                 wbxml_wmlc10_attrStart,
1751                 wbxml_wmlc10_attrValue
1752         },
1753 #ifdef remove_directive_and_set_TRUE_if_mapping_available
1754         { 0x03, NULL, FALSE, /* WTA 1.0 (deprecated) */
1755                 NULL, NULL, NULL, NULL
1756         },
1757 #endif
1758         { 0x04, NULL, TRUE, /* WML 1.1 */
1759                 wbxml_wmlc11_global,
1760                 wbxml_wmlc11_tags,
1761                 wbxml_wmlc11_attrStart,
1762                 wbxml_wmlc11_attrValue
1763         },
1764         { 0x05, NULL, TRUE, /* SI 1.0 */
1765                 NULL, /* wbxml_sic10_global - does not exist */
1766                 wbxml_sic10_tags,
1767                 wbxml_sic10_attrStart,
1768                 wbxml_sic10_attrValue
1769         },
1770         { 0x06, NULL, TRUE, /* SL 1.0 */
1771                 NULL, /* wbxml_slc10_global - does not exist */
1772                 wbxml_slc10_tags,
1773                 wbxml_slc10_attrStart,
1774                 wbxml_slc10_attrValue
1775         },
1776         { 0x07, NULL, TRUE, /* CO 1.0 */
1777                 NULL, /* wbxml_coc10_global - does not exist */
1778                 wbxml_coc10_tags,
1779                 wbxml_coc10_attrStart,
1780                 wbxml_coc10_attrValue
1781         },
1782         { 0x08, NULL, TRUE, /* CHANNEL 1.0 (deprecated) */
1783                 NULL, /* wbxml_channelc10_global - does not exist */
1784                 wbxml_channelc10_tags,
1785                 wbxml_channelc10_attrStart,
1786                 NULL, /* wbxml_channelc10_attrValue - does not exist */
1787         },
1788         { 0x09, NULL, TRUE, /* WML 1.2 */
1789                 wbxml_wmlc12_global,
1790                 wbxml_wmlc12_tags,
1791                 wbxml_wmlc12_attrStart,
1792                 wbxml_wmlc12_attrValue
1793         },
1794         { 0x0A, NULL, TRUE, /* WML 1.3 */
1795                 wbxml_wmlc13_global,
1796                 wbxml_wmlc13_tags,
1797                 wbxml_wmlc13_attrStart,
1798                 wbxml_wmlc13_attrValue
1799         },
1800         { 0x0B, NULL, TRUE, /* PROV 1.0 */
1801                 NULL, /* wbxml_provc10_global - does not exist */
1802                 wbxml_provc10_tags,
1803                 wbxml_provc10_attrStart,
1804                 wbxml_provc10_attrValue
1805         },
1806 #ifdef remove_directive_and_set_TRUE_if_mapping_available
1807         { 0x0C, NULL, FALSE, /* WTA-WML 1.2 */
1808                 NULL, NULL, NULL, NULL
1809         },
1810 #endif
1811         { 0x0D, NULL, TRUE, /* EMN 1.0 */
1812                 NULL, /* wbxml_emnc10_global - does not exist */
1813                 wbxml_emnc10_tags,
1814                 wbxml_emnc10_attrStart,
1815                 wbxml_emnc10_attrValue
1816         },
1817 #ifdef remove_directive_and_set_TRUE_if_mapping_available
1818         { 0x0E, NULL, FALSE, /* DRMREL 1.0 */
1819                 NULL, NULL, NULL, NULL
1820         },
1821 #endif
1822         { 0x020B, NULL, TRUE, /* Nokia OTA Provisioning 7.0 */
1823                 NULL, /* wbxml_nokiaprovc70_global - does not exist */
1824                 wbxml_nokiaprovc70_tags,
1825                 wbxml_nokiaprovc70_attrStart,
1826                 NULL, /* wbxml_nokiaprovc70_attrValue - does not exist */
1827         },
1828         { 0x0FD1, NULL, TRUE, /* SyncML 1.0 */
1829                 NULL, /* wbxml_syncmlc10_global - does not exist */
1830                 wbxml_syncmlc10_tags,
1831                 NULL, /* wbxml_syncmlc10_attrStart - does not exist */
1832                 NULL, /* wbxml_syncmlc10_attrValue - does not exist */
1833         },
1834         { 0x0FD3, NULL, TRUE, /* SyncML 1.1 */
1835                 NULL, /* wbxml_syncmlc11_global - does not exist */
1836                 wbxml_syncmlc11_tags,
1837                 NULL, /* wbxml_syncmlc11_attrStart - does not exist */
1838                 NULL, /* wbxml_syncmlc11_attrValue - does not exist */
1839         },
1840         { 0x1108, NULL, TRUE, /* Phone.com - WML+ 1.1 */
1841                 /* Note: I assumed WML+ 1.1 would be not that different from WML 1.1,
1842                  *       the real mapping should come from Phone.com (OpenWave)! */
1843                 wbxml_wmlc11_global, /* Not 100% true */
1844                 wbxml_wmlc11_tags, /* Not 100% true */
1845                 wbxml_wmlc11_attrStart, /* Not 100% true */
1846                 wbxml_wmlc11_attrValue /* Not 100% true */
1847         },
1848         { 0x110D, NULL, TRUE, /* Phone.com - WML+ 1.3 */
1849                 /* Note: I assumed WML+ 1.3 would be not that different from WML 1.3,
1850                  *       the real mapping should come from Phone.com (OpenWave)! */
1851                 wbxml_wmlc13_global, /* Not 100% true */
1852                 wbxml_wmlc13_tags, /* Not 100% true */
1853                 wbxml_wmlc13_attrStart, /* Not 100% true */
1854                 wbxml_wmlc13_attrValue /* Not 100% true */
1855         },
1856         
1857         { 0, NULL, FALSE, NULL, NULL, NULL, NULL }
1858 };
1859
1860 /* The following map contains entries only registered with a media type */
1861 static const wbxml_token_map textual_map[] = {
1862         { 0x00, "application/x-wap-prov.browser-settings", TRUE,
1863                 NULL, /* wbxml_nokiaprovc70_global - does not exist */
1864                 wbxml_nokiaprovc70_tags,
1865                 wbxml_nokiaprovc70_attrStart,
1866                 NULL, /* wbxml_nokiaprovc70_attrValue - does not exist */
1867         },
1868         { 0x00, "application/x-wap-prov.browser-bookmarks", TRUE,
1869                 NULL, /* wbxml_nokiaprovc70_global - does not exist */
1870                 wbxml_nokiaprovc70_tags,
1871                 wbxml_nokiaprovc70_attrStart,
1872                 NULL, /* wbxml_nokiaprovc70_attrValue - does not exist */
1873         },
1874         
1875         { 0, NULL, FALSE, NULL, NULL, NULL, NULL }
1876 };
1877
1878 /* WBXML content token mapping depends on the following parameters:
1879  *   - Content type (guint32)
1880  *   - Token type (global, tags, attrStart, attrValue)
1881  *   - Code page for tag and attribute
1882  *
1883  * This results in the following steps:
1884  *   1. Retrieve content type mapping
1885  *   2. If exists, retrieve token type mapping
1886  *   3. If exists, retrieve required code page
1887  *   4. If exists, retrieve token mapping
1888  */
1889
1890 #define wbxml_UNDEFINED_TOKEN \
1891         "(Requested token not defined for this content type)"
1892 #define wbxml_UNDEFINED_TOKEN_CODE_PAGE \
1893         "(Requested token code page not defined for this content type)"
1894 #define wbxml_UNDEFINED_TOKEN_MAP \
1895         "(Requested token map not defined for this content type)"
1896 /* Return token mapping for a given content mapping entry. */
1897 static const char *
1898 map_token (const value_valuestring *token_map, guint8 codepage, guint8 token) {
1899         const value_string *vs;
1900         const char *s;
1901
1902         if (token_map) { /* Found map */
1903                 if ((vs = val_to_valstr (codepage, token_map))) {
1904                         /* Found codepage map */
1905                         s = match_strval (token, vs);
1906                         if (s) { /* Found valid token */
1907                                 DebugLog(("map_token(codepage = %u, token = %u: [%s]\n", codepage, token, s));
1908                                 return s;
1909                         }
1910                         /* No valid token mapping in specified code page of token map */
1911                         DebugLog(("map_token(codepage = %u, token = %u: "
1912                                                 wbxml_UNDEFINED_TOKEN "\n", codepage, token));
1913                         return wbxml_UNDEFINED_TOKEN;
1914                 }
1915                 /* There is no token map entry for the requested code page */
1916                 DebugLog(("map_token(codepage = %u, token = %u: "
1917                                         wbxml_UNDEFINED_TOKEN_CODE_PAGE "\n", codepage, token));
1918                 return wbxml_UNDEFINED_TOKEN_CODE_PAGE;
1919         }
1920         /* The token map does not exist */
1921         DebugLog(("map_token(codepage = %u, token = %u: "
1922                                 wbxml_UNDEFINED_TOKEN_MAP "\n", codepage, token));
1923         return wbxml_UNDEFINED_TOKEN_MAP;
1924 }
1925
1926
1927 /* Returns a pointer to the WBXML token map for the given WBXML public
1928  * identifier value (see WINA for a table with defined identifiers). */
1929 static const wbxml_token_map *wbxml_content_map (guint32 publicid,
1930                 const char *content_type) {
1931         gint i = 0;
1932
1933         DebugLog(("wbxml_token_map: publicid = %u, content_type = [%s]\n",
1934                                 publicid, content_type));
1935         /* First look whether we have a publicid mapping */
1936         while (map[i].defined) {
1937                 if (map[i].publicid == publicid)
1938                         return &(map[i]);
1939                 i++;
1940         }
1941         /* Then look if the content type has a mapping */
1942         if (content_type && content_type[0]) {
1943                 DebugLog(("wbxml_token_map(no match for publicid = %u;"
1944                                         " looking up content_type = [%s])\n",
1945                                         publicid, content_type));
1946                 i = 0;
1947                 while(textual_map[i].defined) {
1948                         if (strcasecmp(content_type, textual_map[i].content_type) == 0) {
1949                                 return &(textual_map[i]);
1950                         }
1951                         i++;
1952                 }
1953         }
1954         DebugLog(("wbxml_token_map(no match for publicid = %u"
1955                                 " or content_type = [%s])\n",
1956                                 publicid, content_type));
1957         return NULL;
1958 }
1959
1960
1961 /************************** Function prototypes **************************/
1962
1963
1964 static void
1965 dissect_wbxml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
1966
1967 void
1968 proto_register_wbxml(void);
1969
1970 /* Parse and display the WBXML string table */
1971 static void
1972 show_wbxml_string_table (proto_tree *tree, tvbuff_t *tvb, guint32 str_tbl,
1973                 guint32 str_tbl_len);
1974
1975 /* Parse data while in STAG state */
1976 static guint32
1977 parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
1978                 guint32 str_tbl, guint8 *level);
1979
1980 /* Parse data while in STAG state;
1981  * interpret tokens as defined by content type */
1982 static guint32
1983 parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
1984                 guint32 str_tbl, guint8 *level,
1985                 const wbxml_token_map *map);
1986
1987 /* Parse data while in ATTR state */
1988 static guint32
1989 parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
1990                 guint32 offset, guint32 str_tbl, guint8 level);
1991
1992 /* Parse data while in ATTR state;
1993  * interpret tokens as defined by content type */
1994 static guint32
1995 parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
1996                 guint32 offset, guint32 str_tbl, guint8 level,
1997                 const wbxml_token_map *map);
1998
1999
2000 /****************** WBXML protocol dissection functions ******************/
2001
2002
2003 /* Code to actually dissect the packets */
2004 static void
2005 dissect_wbxml(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2006 {
2007         /* Set up structures needed to add the protocol subtree and manage it */
2008         proto_item *ti;
2009         proto_tree *wbxml_tree; /* Main WBXML tree */
2010         proto_tree *wbxml_str_tbl_tree; /* String table subtree */
2011         proto_tree *wbxml_content_tree; /* Content subtree */
2012         guint8 version;
2013         guint offset = 0;
2014         guint32 len;
2015         guint32 charset=0;
2016         guint32 charset_len;
2017         guint32 publicid;
2018         guint32 publicid_index = 0;
2019         guint32 publicid_len;
2020         guint32 str_tbl;
2021         guint32 str_tbl_len;
2022         guint8 level = 0; /* WBXML recursion level */
2023         const wbxml_token_map *content_map = NULL;
2024
2025         DebugLog(("dissect_wbxml: Dissecting packet %u\n", pinfo->fd->num));
2026         /* WBXML format
2027          * 
2028          * Version 1.0: version publicid         strtbl BODY
2029          * Version 1.x: version publicid charset strtbl BODY
2030          *
2031          * Last valid format: WBXML 1.3
2032          */
2033         switch ( version = tvb_get_guint8 (tvb, 0) ) {
2034                 case 0x00: /* WBXML/1.0 */
2035                         break;
2036
2037                 case 0x01: /* WBXML/1.1 */
2038                 case 0x02: /* WBXML/1.2 */
2039                 case 0x03: /* WBXML/1.3 */
2040                         break;
2041
2042                 default:
2043                         return;
2044         }
2045
2046         if (check_col(pinfo->cinfo, COL_INFO))
2047                 col_append_fstr(pinfo->cinfo, COL_INFO, " (WBXML %s:",
2048                                 match_strval (version, vals_wbxml_versions));
2049
2050         /* In the interest of speed, if "tree" is NULL, don't do any work not
2051            necessary to generate protocol tree items. */
2052         if ( tree ) {
2053                 /* create display subtree for the protocol */
2054                 ti = proto_tree_add_item (tree, proto_wbxml, tvb, 0, -1, FALSE);
2055                 wbxml_tree = proto_item_add_subtree(ti, ett_wbxml);
2056
2057                 /* WBXML Version */
2058                 proto_tree_add_uint (wbxml_tree, hf_wbxml_version,
2059                                 tvb, 0, 1, version);
2060
2061                 /* Public ID */
2062                 publicid = tvb_get_guintvar(tvb, 1, &publicid_len);
2063                 if (publicid) { /* Known Public ID */
2064                         if (check_col(pinfo->cinfo, COL_INFO))
2065                                 col_append_fstr(pinfo->cinfo, COL_INFO, " Public ID \"%s\")",
2066                                                 match_strval (publicid, vals_wbxml_public_ids));
2067                         proto_tree_add_uint(wbxml_tree, hf_wbxml_public_id_known,
2068                                         tvb, 1, publicid_len, publicid);
2069                 } else { /* Public identifier in string table */
2070                         publicid_index = tvb_get_guintvar (tvb, 1+publicid_len, &len);
2071                         publicid_len += len;
2072                 }
2073                 offset = 1 + publicid_len;
2074
2075                 /* Version-specific handling of Charset */
2076                 switch ( version ) {
2077                         case 0x00: /* WBXML/1.0 */
2078                                 /* No charset */
2079                                 break;
2080
2081                         case 0x01: /* WBXML/1.1 */
2082                         case 0x02: /* WBXML/1.2 */
2083                         case 0x03: /* WBXML/1.3 */
2084                                 /* Get charset */
2085                                 charset = tvb_get_guintvar (tvb, offset, &charset_len);
2086                                 offset += charset_len;
2087                                 break;
2088
2089                         default: /* Impossible since return already earlier */
2090                                 break;
2091                 }
2092
2093                 /* String table: read string table length in bytes */
2094                 str_tbl_len = tvb_get_guintvar (tvb, offset, &len);
2095                 str_tbl = offset + len; /* Start of 1st string in string table */
2096
2097                 /* Now we can add public ID, charset (if available),
2098                  * and string table */
2099                 if ( ! publicid ) { /* Read Public ID from string table */
2100                         len = tvb_strsize (tvb, str_tbl+publicid_index);
2101                         if (check_col(pinfo->cinfo, COL_INFO))
2102                                 col_append_fstr(pinfo->cinfo, COL_INFO, " Public ID \"%s\")",
2103                                                 tvb_format_text (tvb,
2104                                                     str_tbl+publicid_index,
2105                                                     len-1));
2106                         proto_tree_add_item (wbxml_tree, hf_wbxml_public_id_literal,
2107                                         tvb, 1, publicid_len, FALSE);
2108                 }
2109                 if ( version ) { /* Charset */
2110                         proto_tree_add_uint (wbxml_tree, hf_wbxml_charset,
2111                                         tvb, 1+publicid_len, charset_len, charset);
2112                 }
2113                 /* String Table */
2114                 ti = proto_tree_add_text(wbxml_tree,
2115                                 tvb, offset, len + str_tbl_len, "String table: %u bytes",
2116                                 str_tbl_len);
2117
2118                 if (wbxml_tree && str_tbl_len) { /* Display string table as subtree */
2119                         wbxml_str_tbl_tree = proto_item_add_subtree (ti,
2120                                         ett_wbxml_str_tbl);
2121                         show_wbxml_string_table (wbxml_str_tbl_tree, tvb,
2122                                         str_tbl, str_tbl_len);
2123                 }
2124
2125                 /* Data starts HERE */
2126                 offset += len + str_tbl_len;
2127
2128                 /* The WBXML BODY starts here */
2129                 ti = proto_tree_add_text (wbxml_tree, tvb, offset, -1,
2130                                 "Data representation");
2131                 wbxml_content_tree = proto_item_add_subtree (ti, ett_wbxml_content);
2132
2133                 /* The parse_wbxml_X() functions will process the content correctly,
2134                  * irrespective of the WBXML version used. For the WBXML body, this
2135                  * means that there is a different processing for the global token
2136                  * RESERVED_2 (WBXML 1.0) or OPAQUE (WBXML 1.x with x > 0).  */
2137                 if (wbxml_tree) { /* Show only if visible */
2138                         if (publicid) {
2139                                 /* Retrieve the content token mapping if available */
2140                                 content_map = wbxml_content_map (publicid, pinfo->match_string);
2141                                 if (content_map) {
2142                                         /* Is there a defined token mapping for publicid? */
2143                                         if (content_map->defined) {
2144                                                 if (content_map->content_type) {
2145                                                         proto_item_append_text(ti,
2146                                                                         " is based on Content-Type: %s",
2147                                                                         content_map->content_type);
2148                                                 }
2149                                                 proto_tree_add_text (wbxml_content_tree, tvb,
2150                                                                 offset, -1,
2151                                                                 "Level | State | Codepage "
2152                                                                 "| WBXML Token Description         "
2153                                                                 "| Rendering");
2154                                                 len = parse_wbxml_tag_defined (wbxml_content_tree,
2155                                                                 tvb, offset, str_tbl, &level, content_map);
2156                                                 return;
2157                                         }
2158                                 }
2159                                 proto_tree_add_text (wbxml_content_tree, tvb,
2160                                                 offset, -1,
2161                                                 "[Rendering of this content type"
2162                                                 " not (yet) supported]");
2163                         }
2164                         /* Default: WBXML only, no interpretation of the content */
2165                         proto_tree_add_text (wbxml_content_tree, tvb, offset, -1,
2166                                         "Level | State | Codepage "
2167                                         "| WBXML Token Description         "
2168                                         "| Rendering");
2169                         len = parse_wbxml_tag (wbxml_content_tree, tvb, offset,
2170                                         str_tbl, &level);
2171                         return;
2172                 }
2173                 return;
2174         }
2175 }
2176
2177
2178 /* Parse and display the WBXML string table (in a 3-column table format).
2179  * This function displays:
2180  *  - the offset in the string table,
2181  *  - the length of the string
2182  *  - the string.
2183  */
2184 static void
2185 show_wbxml_string_table (proto_tree *tree, tvbuff_t *tvb, guint32 str_tbl,
2186                 guint32 str_tbl_len)
2187 {
2188         guint32 off = str_tbl;
2189         guint32 len = 0;
2190         guint32 end = str_tbl + str_tbl_len;
2191
2192         proto_tree_add_text (tree, tvb, off, end,
2193                         "Start  | Length | String");
2194         while (off < end) {
2195                 len = tvb_strsize (tvb, off);
2196                 proto_tree_add_text (tree, tvb, off, len,
2197                                 "%6d | %6d | '%s'",
2198                                 off - str_tbl, len,
2199                                 tvb_format_text (tvb, off, len-1));
2200                 off += len;
2201         }
2202 }
2203
2204
2205 /* Indentation code is based on a static const array of space characters.
2206  * At least one single space is returned */
2207 static const char indent_buffer[514] = " "
2208         "                                                                "
2209         "                                                                "
2210         "                                                                "
2211         "                                                                "
2212         "                                                                "
2213         "                                                                "
2214         "                                                                "
2215         "                                                                "
2216         ; /* Generate XML indentation (length = 1 + 2 * 256 + 1 for '\0') */
2217
2218 static const char * Indent (guint8 level) {
2219         return indent_buffer + (512 - 2 * (level));
2220 }
2221
2222
2223 /********************
2224  * WBXML tag tokens *
2225  ********************
2226  * 
2227  * Bit Mask  : Example
2228  * -------------------
2229  * 00.. .... : <tag />
2230  *
2231  * 01.. .... : <tag>
2232  *               CONTENT
2233  *             </tag>
2234  *
2235  * 10.. .... : <tag
2236  *               atrtribute1="value1"
2237  *               atrtribute2="value2"
2238  *             />
2239  * 
2240  * 11.. .... : <tag
2241  *               atrtribute1="value1"
2242  *               atrtribute2="value2"
2243  *             >
2244  *               CONTENT
2245  *             </tag>
2246  *
2247  * NOTES
2248  *   - An XML PI is parsed as an attribute list (same syntax).
2249  *   - A code page switch only applies to the single token that follows.
2250  */
2251
2252
2253 /* This function parses the WBXML and maps known token interpretations
2254  * to the WBXML tokens. As a result, the original XML document can be
2255  * recreated. Indentation is generated in order to ease reading.
2256  *
2257  * Attribute parsing is done in parse_wbxml_attribute_list_defined().
2258  *
2259  * The wbxml_token_map entry *map contains the actual token mapping.
2260  *
2261  * NOTE: In order to parse the content, some recursion is required.
2262  *       However, for performance reasons, recursion has been avoided
2263  *       where possible (tags without content within tags with content).
2264  *       This is achieved by means of the parsing_tag_content and tag_save*
2265  *       variables.
2266  *
2267  * NOTE: See above for known token mappings.
2268  *
2269  * NOTE: As tags can be opened and closed, a tag representation lookup
2270  *       may happen once or twice for a given tag. For efficiency reasons,
2271  *       the literal tag value is stored and used throughout the code.
2272  *       With the introduction of code page support, this solution is robust
2273  *       as the lookup only occurs once, removing the need for storage of
2274  *       the used code page.
2275  */
2276 static guint32
2277 parse_wbxml_tag_defined (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
2278                 guint32 str_tbl, guint8 *level,
2279                 const wbxml_token_map *map)
2280 {
2281         guint32 tvb_len = tvb_reported_length (tvb);
2282         guint32 off = offset;
2283         guint32 len;
2284         guint str_len;
2285         guint32 ent;
2286         guint32 index;
2287         guint8 peek;
2288         guint32 tag_len; /* Length of the index (uintvar) from a LITERAL tag */
2289         guint8 tag_save_known = 0; /* Will contain peek & 0x3F (tag identity) */
2290         guint8 tag_new_known = 0; /* Will contain peek & 0x3F (tag identity) */
2291         const char *tag_save_literal; /* Will contain the LITERAL tag identity */
2292         const char *tag_new_literal; /* Will contain the LITERAL tag identity */
2293         guint8 codepage_stag = 0; /* Initial codepage in state = STAG */
2294         guint8 parsing_tag_content = FALSE; /* Are we parsing content from a
2295                                                                                    tag with content: <x>Content</x>
2296                                                                                    
2297                                                                                    The initial state is FALSE.
2298                                                                                    This state will trigger recursion. */
2299         tag_save_literal = NULL; /* Prevents compiler warning */
2300
2301         DebugLog(("parse_wbxml_tag_defined (level = %u, offset = %u)\n", *level, offset));
2302         while (off < tvb_len) {
2303                 peek = tvb_get_guint8 (tvb, off);
2304                 DebugLog(("STAG: (top of while) level = %3u, peek = 0x%02X, off = %u, tvb_len = %u\n", *level, peek, off, tvb_len));
2305                 if ((peek & 0x3F) < 4) switch (peek) { /* Global tokens in state = STAG
2306                                                                                                   but not the LITERAL tokens */
2307                         case 0x00: /* SWITCH_PAGE */
2308                                 codepage_stag = tvb_get_guint8 (tvb, off+1);
2309                                 proto_tree_add_text (tree, tvb, off, 2,
2310                                                 "      | Tag   | T 0->%3d "
2311                                                 "| SWITCH_PAGE (Tag code page)     "
2312                                                 "|",
2313                                                 codepage_stag);
2314                                 off += 2;
2315                                 break;
2316                         case 0x01: /* END: only possible for Tag with Content */
2317                                 if (tag_save_known) { /* Known TAG */
2318                                         proto_tree_add_text (tree, tvb, off, 1,
2319                                                         "  %3d | Tag   |          "
2320                                                         "| END (Known Tag 0x%02X)            "
2321                                                         "| %s</%s>",
2322                                                         *level, tag_save_known, Indent (*level),
2323                                                         tag_save_literal); /* We already looked it up! */
2324                                 } else { /* Literal TAG */
2325                                         proto_tree_add_text (tree, tvb, off, 1,
2326                                                         "  %3d | Tag   |          "
2327                                                         "| END (Literal Tag)               "
2328                                                         "| %s</%s>",
2329                                                         *level, Indent (*level),
2330                                                         tag_save_literal);
2331                                 }
2332                                 (*level)--;
2333                                 off++;
2334                                 /* Reset code page: not needed as return from recursion */
2335                                 DebugLog(("STAG: level = %u, Return: len = %u\n", *level, off - offset));
2336                                 return (off - offset);
2337                                 break;
2338                         case 0x02: /* ENTITY */
2339                                 ent = tvb_get_guintvar (tvb, off+1, &len);
2340                                 proto_tree_add_text (tree, tvb, off, 1+len,
2341                                                 "  %3d | Tag   |          "
2342                                                 "| ENTITY                          "
2343                                                 "| %s'&#%u;'",
2344                                                 *level, Indent (*level), ent);
2345                                 off += 1+len;
2346                                 break;
2347                         case 0x03: /* STR_I */
2348                                 len = tvb_strsize (tvb, off+1);
2349                                 proto_tree_add_text (tree, tvb, off, 1+len,
2350                                                 "  %3d | Tag   |          "
2351                                                 "| STR_I (Inline string)           "
2352                                                 "| %s\'%s\'",
2353                                                 *level, Indent(*level),
2354                                                 tvb_format_text (tvb, off+1, len-1));
2355                                 off += 1+len;
2356                                 break;
2357                         case 0x40: /* EXT_I_0 */
2358                         case 0x41: /* EXT_I_1 */
2359                         case 0x42: /* EXT_I_2 */
2360                                 /* Extension tokens */
2361                                 len = tvb_strsize (tvb, off+1);
2362                                 if (codepage_stag) { /* Not default code page */
2363                                         proto_tree_add_text (tree, tvb, off, 1+len,
2364                                                         "  %3d | Tag   | T %3d->0 "
2365                                                         "| EXT_I_%1x    (Extension Token)    "
2366                                                         "| %s(%s: \'%s\')",
2367                                                         *level, codepage_stag, peek & 0x0f, Indent (*level),
2368                                                         map_token (map->global, codepage_stag, peek),
2369                                                         tvb_format_text (tvb, off+1, len-1));
2370                                         /* Reset code page */
2371                                         codepage_stag = 0;
2372                                 } else { /* Code page 0 */
2373                                         proto_tree_add_text (tree, tvb, off, 1+len,
2374                                                         "  %3d | Tag   |          "
2375                                                         "| EXT_I_%1x    (Extension Token)    "
2376                                                         "| %s(%s: \'%s\')",
2377                                                         *level, peek & 0x0f, Indent (*level),
2378                                                         map_token (map->global, codepage_stag, peek),
2379                                                         tvb_format_text (tvb, off+1, len-1));
2380                                 }
2381                                 off += 1+len;
2382                                 break;
2383                         case 0x43: /* PI */
2384                                 proto_tree_add_text (tree, tvb, off, 1,
2385                                                 "  %3d | Tag   |          "
2386                                                 "| PI (XML Processing Instruction) "
2387                                                 "| %s<?xml",
2388                                                 *level, Indent (*level));
2389                                 len = parse_wbxml_attribute_list_defined (tree, tvb, off, str_tbl,
2390                                                 *level, map);
2391                                 /* Check that there is still room in packet */
2392                                 off += len;
2393                                 if (off >= tvb_len) {
2394                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
2395                                         THROW(ReportedBoundsError);
2396                                 }
2397                                 proto_tree_add_text (tree, tvb, off-1, 1,
2398                                                 "  %3d | Tag   |          "
2399                                                 "| END (PI)                        "
2400                                                 "| %s?>",
2401                                                 *level, Indent (*level));
2402                                 break;
2403                         case 0x80: /* EXT_T_0 */
2404                         case 0x81: /* EXT_T_1 */
2405                         case 0x82: /* EXT_T_2 */
2406                                 /* Extension tokens */
2407                                 index = tvb_get_guintvar (tvb, off+1, &len);
2408                                 str_len = tvb_strsize (tvb, str_tbl+index);
2409                                 if (codepage_stag) { /* Not default code page */
2410                                         proto_tree_add_text (tree, tvb, off, 1+len,
2411                                                         "  %3d | Tag   | T %3d->0 "
2412                                                         "| EXT_T_%1x    (Extension Token)    "
2413                                                         "| %s(%s: \'%s\')",
2414                                                         *level, codepage_stag, peek & 0x0f, Indent (*level),
2415                                                         map_token (map->global, codepage_stag, peek),
2416                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
2417                                         /* Reset code page */
2418                                         codepage_stag = 0;
2419                                 } else { /* Code page 0 */
2420                                         proto_tree_add_text (tree, tvb, off, 1+len,
2421                                                         "  %3d | Tag   |          "
2422                                                         "| EXT_T_%1x    (Extension Token)    "
2423                                                         "| %s(%s: \'%s\')",
2424                                                         *level, peek & 0x0f, Indent (*level),
2425                                                         map_token (map->global, codepage_stag, peek),
2426                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
2427                                 }
2428                                 off += 1+len;
2429                                 break;
2430                         case 0x83: /* STR_T */
2431                                 index = tvb_get_guintvar (tvb, off+1, &len);
2432                                 str_len = tvb_strsize (tvb, str_tbl+index);
2433                                 proto_tree_add_text (tree, tvb, off, 1+len,
2434                                                 "  %3d | Tag   |          "
2435                                                 "| STR_T (Tableref string)         "
2436                                                 "| %s\'%s\'",
2437                                                 *level, Indent (*level),
2438                                                 tvb_format_text (tvb, str_tbl+index, str_len-1));
2439                                 off += 1+len;
2440                                 break;
2441                         case 0xC0: /* EXT_0 */
2442                         case 0xC1: /* EXT_1 */
2443                         case 0xC2: /* EXT_2 */
2444                                 /* Extension tokens */
2445                                 if (codepage_stag) { /* Not default code page */
2446                                         proto_tree_add_text (tree, tvb, off, 1,
2447                                                         "  %3d | Tag   | T %3d->0 "
2448                                                         "| EXT_%1x      (Extension Token)    "
2449                                                         "| %s(%s)",
2450                                                         *level, codepage_stag, peek & 0x0f, Indent (*level),
2451                                                         map_token (map->global, codepage_stag, peek));
2452                                         /* Reset code page */
2453                                         codepage_stag = 0;
2454                                 } else { /* Code page 0 */
2455                                         proto_tree_add_text (tree, tvb, off, 1,
2456                                                         "  %3d | Tag   |          "
2457                                                         "| EXT_%1x      (Extension Token)    "
2458                                                         "| %s(%s)",
2459                                                         *level, peek & 0x0f, Indent (*level),
2460                                                         map_token (map->global, codepage_stag, peek));
2461                                 }
2462                                 off++;
2463                                 break;
2464                         case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
2465                                 if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
2466                                         index = tvb_get_guintvar (tvb, off+1, &len);
2467                                         proto_tree_add_text (tree, tvb, off, 1 + len + index,
2468                                                         "  %3d | Tag   |          "
2469                                                         "| OPAQUE (Opaque data)            "
2470                                                         "| %s(%d bytes of opaque data)",
2471                                                         *level, Indent (*level), index);
2472                                         off += 1+len+index;
2473                                 } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
2474                                         proto_tree_add_text (tree, tvb, off, 1,
2475                                                         "  %3d | Tag   |          "
2476                                                         "| RESERVED_2     (Invalid Token!) "
2477                                                         "| WBXML 1.0 parsing stops here.",
2478                                                         *level);
2479                                         /* Stop processing as it is impossible to parse now */
2480                                         off = tvb_len;
2481                                         DebugLog(("STAG: level = %u, Return: len = %u\n", *level, off - offset));
2482                                         return (off - offset);
2483                                 }
2484                                 break;
2485
2486                                 /* No default clause, as all cases have been treated */
2487                 } else { /* LITERAL or Known TAG */
2488                         /* We must store the initial tag, and also retrieve the new tag.
2489                          * For efficiency reasons, we store the literal tag representation
2490                          * for known tags too, so we can easily close the tag without the
2491                          * need of a new lookup and avoiding storage of token codepage.
2492                          * 
2493                          * There are 4 possibilities:
2494                          *
2495                          *  1. Known tag followed by a known tag
2496                          *  2. Known tag followed by a LITERAL tag
2497                          *  3. LITERAL tag followed by Known tag
2498                          *  4. LITERAL tag followed by LITERAL tag
2499                          */
2500
2501                         /* Store the new tag */
2502                         tag_len = 0;
2503                         if ((peek & 0x3F) == 4) { /* LITERAL */
2504                                 DebugLog(("STAG: LITERAL tag (peek = 0x%02X, off = %u) - TableRef follows!\n", peek, off));
2505                                 index = tvb_get_guintvar (tvb, off+1, &tag_len);
2506                                 str_len = tvb_strsize (tvb, str_tbl+index);
2507                                 tag_new_literal = tvb_get_ptr (tvb, str_tbl+index, str_len);
2508                                 tag_new_known = 0; /* invalidate known tag_new */
2509                         } else { /* Known tag */
2510                                 tag_new_known = peek & 0x3F;
2511                                 tag_new_literal = map_token (map->tags, codepage_stag,
2512                                                                                 tag_new_known);
2513                                 /* Stored looked up tag name string */
2514                         }
2515
2516                         /* Parsing of TAG starts HERE */
2517                         if (peek & 0x40) { /* Content present */
2518                                 /* Content follows
2519                                  * [!] An explicit END token is expected in these cases!
2520                                  * ==> Recursion possible if we encounter a tag with content;
2521                                  *     recursion will return at the explicit END token.
2522                                  */
2523                                 if (parsing_tag_content) { /* Recurse */
2524                                         DebugLog(("STAG: Tag in Tag - RECURSE! (off = %u)\n", off));
2525                                         /* Do not process the attribute list:
2526                                          * recursion will take care of it */
2527                                         (*level)++;
2528                                         len = parse_wbxml_tag_defined (tree, tvb, off, str_tbl,
2529                                                         level, map);
2530                                         off += len;
2531                                 } else { /* Now we will have content to parse */
2532                                         /* Save the start tag so we can properly close it later. */
2533                                         if ((peek & 0x3F) == 4) { /* Literal tag */
2534                                                 tag_save_literal = tag_new_literal;
2535                                                 tag_save_known = 0;
2536                                         } else { /* Known tag */
2537                                                 tag_save_known = tag_new_known;
2538                                                 tag_save_literal = tag_new_literal;
2539                                                 /* The last statement avoids needless lookups */
2540                                         }
2541                                         /* Process the attribute list if present */
2542                                         if (peek & 0x80) { /* Content and Attribute list present */
2543                                                 if (tag_new_known) { /* Known tag */
2544                                                         if (codepage_stag) { /* Not default code page */
2545                                                                 proto_tree_add_text (tree, tvb, off, 1,
2546                                                                                 "  %3d | Tag   | T %3d->0 "
2547                                                                                 "|   Known Tag 0x%02X           (AC) "
2548                                                                                 "| %s<%s",
2549                                                                                 *level, codepage_stag, tag_new_known,
2550                                                                                 Indent (*level), tag_new_literal);
2551                                                                 /* Tag string already looked up earlier! */
2552                                                                 /* Reset code page */
2553                                                                 codepage_stag = 0;
2554                                                         } else { /* Code page 0 */
2555                                                                 proto_tree_add_text (tree, tvb, off, 1,
2556                                                                                 "  %3d | Tag   |          "
2557                                                                                 "|   Known Tag 0x%02X           (AC) "
2558                                                                                 "| %s<%s",
2559                                                                                 *level, tag_new_known,
2560                                                                                 Indent (*level), tag_new_literal);
2561                                                                 /* Tag string already looked up earlier! */
2562                                                         }
2563                                                         off++;
2564                                                 } else { /* LITERAL tag */
2565                                                         proto_tree_add_text (tree, tvb, off, 1,
2566                                                                         "  %3d | Tag   |          "
2567                                                                         "| LITERAL_AC (Literal tag)   (AC) "
2568                                                                         "| %s<%s",
2569                                                                         *level, Indent (*level), tag_new_literal);
2570                                                         off += 1 + tag_len;
2571                                                 }
2572                                                 len = parse_wbxml_attribute_list_defined (tree, tvb,
2573                                                                 off, str_tbl, *level, map);
2574                                                 /* Check that there is still room in packet */
2575                                                 off += len;
2576                                                 if (off >= tvb_len) {
2577                                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
2578                                                         THROW(ReportedBoundsError);
2579                                                 }
2580                                                 proto_tree_add_text (tree, tvb, off-1, 1,
2581                                                                 "  %3d | Tag   |          "
2582                                                                 "| END (attribute list)            "
2583                                                                 "| %s>",
2584                                                                 *level, Indent (*level));
2585                                         } else { /* Content, no Attribute list */
2586                                                 if (tag_new_known) { /* Known tag */
2587                                                         if (codepage_stag) { /* Not default code page */
2588                                                                 proto_tree_add_text (tree, tvb, off, 1,
2589                                                                                 "  %3d | Tag   | T %3d->0 "
2590                                                                                 "|   Known Tag 0x%02X           (.C) "
2591                                                                                 "| %s<%s>",
2592                                                                                 *level, codepage_stag, tag_new_known,
2593                                                                                 Indent (*level),
2594                                                                                 tag_new_literal);
2595                                                                 /* Tag string already looked up earlier! */
2596                                                                 /* Reset code page */
2597                                                                 codepage_stag = 0;
2598                                                         } else { /* Code page 0 */
2599                                                                 proto_tree_add_text (tree, tvb, off, 1,
2600                                                                                 "  %3d | Tag   |          "
2601                                                                                 "|   Known Tag 0x%02X           (.C) "
2602                                                                                 "| %s<%s>",
2603                                                                                 *level, tag_new_known,
2604                                                                                 Indent (*level),
2605                                                                                 tag_new_literal);
2606                                                                 /* Tag string already looked up earlier! */
2607                                                         }
2608                                                         off++;
2609                                                 } else { /* LITERAL tag */
2610                                                         proto_tree_add_text (tree, tvb, off, 1,
2611                                                                         "  %3d | Tag   |          "
2612                                                                         "| LITERAL_C  (Literal Tag)   (.C) "
2613                                                                         "| %s<%s>",
2614                                                                         *level, Indent (*level), tag_new_literal);
2615                                                         off += 1 + tag_len;
2616                                                 }
2617                                         }
2618                                         /* The data that follows in the parsing process
2619                                          * represents content for the opening tag
2620                                          * we've just processed in the lines above.
2621                                          * Next time we encounter a tag with content: recurse
2622                                          */
2623                                         parsing_tag_content = TRUE;
2624                                         DebugLog(("Tag in Tag - No recursion this time! (off = %u)\n", off));
2625                                 }
2626                         } else { /* No Content */
2627                                 DebugLog(("<Tag/> in Tag - No recursion! (off = %u)\n", off));
2628                                 (*level)++;
2629                                 if (peek & 0x80) { /* No Content, Attribute list present */
2630                                         if (tag_new_known) { /* Known tag */
2631                                                 if (codepage_stag) { /* Not default code page */
2632                                                         proto_tree_add_text (tree, tvb, off, 1,
2633                                                                         "  %3d | Tag   | T %3d->0 "
2634                                                                         "|   Known Tag 0x%02X           (A.) "
2635                                                                         "| %s<%s",
2636                                                                         *level, codepage_stag, tag_new_known,
2637                                                                         Indent (*level), tag_new_literal);
2638                                                         /* Tag string already looked up earlier! */
2639                                                         /* Reset code page */
2640                                                         codepage_stag = 0;
2641                                                 } else { /* Code page 0 */
2642                                                         proto_tree_add_text (tree, tvb, off, 1,
2643                                                                         "  %3d | Tag   |          "
2644                                                                         "|   Known Tag 0x%02X           (A.) "
2645                                                                         "| %s<%s",
2646                                                                         *level, tag_new_known,
2647                                                                         Indent (*level), tag_new_literal);
2648                                                         /* Tag string already looked up earlier! */
2649                                                 }
2650                                                 off++;
2651                                                 len = parse_wbxml_attribute_list_defined (tree, tvb,
2652                                                                 off, str_tbl, *level, map);
2653                                                 /* Check that there is still room in packet */
2654                                                 off += len;
2655                                                 if (off >= tvb_len) {
2656                                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
2657                                                         THROW(ReportedBoundsError);
2658                                                 }
2659                                                 proto_tree_add_text (tree, tvb, off-1, 1,
2660                                                                 "  %3d | Tag   |          "
2661                                                                 "| END (Known Tag)                 "
2662                                                                 "| %s/>",
2663                                                                 *level, Indent (*level));
2664                                         } else { /* LITERAL tag */
2665                                                 proto_tree_add_text (tree, tvb, off, 1,
2666                                                                 "  %3d | Tag   |          "
2667                                                                 "| LITERAL_A  (Literal Tag)   (A.) "
2668                                                                 "| %s<%s",
2669                                                                 *level, Indent (*level), tag_new_literal);
2670                                                 off += 1 + tag_len;
2671                                                 len = parse_wbxml_attribute_list_defined (tree, tvb,
2672                                                                 off, str_tbl, *level, map);
2673                                                 /* Check that there is still room in packet */
2674                                                 off += len;
2675                                                 if (off >= tvb_len) {
2676                                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
2677                                                         THROW(ReportedBoundsError);
2678                                                 }
2679                                                 proto_tree_add_text (tree, tvb, off-1, 1,
2680                                                                 "  %3d | Tag   |          "
2681                                                                 "| END (Literal Tag)               "
2682                                                                 "| %s/>",
2683                                                                 *level, Indent (*level));
2684                                         }
2685                                 } else { /* No Content, No Attribute list */
2686                                         if (tag_new_known) { /* Known tag */
2687                                                 if (codepage_stag) { /* Not default code page */
2688                                                         proto_tree_add_text (tree, tvb, off, 1,
2689                                                                         "  %3d | Tag   | T %3d->0 "
2690                                                                         "|   Known Tag 0x%02x           (..) "
2691                                                                         "| %s<%s />",
2692                                                                         *level, codepage_stag, tag_new_known,
2693                                                                         Indent (*level), tag_new_literal);
2694                                                         /* Tag string already looked up earlier! */
2695                                                         /* Reset code page */
2696                                                         codepage_stag = 0;
2697                                                 } else { /* Code page 0 */
2698                                                         proto_tree_add_text (tree, tvb, off, 1,
2699                                                                         "  %3d | Tag   |          "
2700                                                                         "|   Known Tag 0x%02x           (..) "
2701                                                                         "| %s<%s />",
2702                                                                         *level, tag_new_known,
2703                                                                         Indent (*level), tag_new_literal);
2704                                                         /* Tag string already looked up earlier! */
2705                                                 }
2706                                                 off++;
2707                                         } else { /* LITERAL tag */
2708                                                 proto_tree_add_text (tree, tvb, off, 1,
2709                                                                 "  %3d | Tag   |          "
2710                                                                 "| LITERAL    (Literal Tag)   (..) "
2711                                                                 "| %s<%s />",
2712                                                                 *level, Indent (*level), tag_new_literal);
2713                                                 off += 1 + tag_len;
2714                                         }
2715                                 }
2716                                 (*level)--;
2717                                 /* TODO: Do I have to reset code page here? */
2718                         }
2719                 } /* if (tag & 0x3F) >= 5 */
2720         } /* while */
2721         DebugLog(("STAG: level = %u, Return: len = %u (end of function body)\n", *level, off - offset));
2722         return (off - offset);
2723 }
2724
2725
2726 /* This function performs the WBXML decoding as in parse_wbxml_tag_defined()
2727  * but this time no WBXML mapping is performed.
2728  *
2729  * Attribute parsing is done in parse_wbxml_attribute_list().
2730  */
2731 static guint32
2732 parse_wbxml_tag (proto_tree *tree, tvbuff_t *tvb, guint32 offset,
2733                 guint32 str_tbl, guint8 *level)
2734 {
2735         guint32 tvb_len = tvb_reported_length (tvb);
2736         guint32 off = offset;
2737         guint32 len;
2738         guint str_len;
2739         guint32 ent;
2740         guint32 index;
2741         guint8 peek;
2742         guint32 tag_len; /* Length of the index (uintvar) from a LITERAL tag */
2743         guint8 tag_save_known = 0; /* Will contain peek & 0x3F (tag identity) */
2744         guint8 tag_new_known = 0; /* Will contain peek & 0x3F (tag identity) */
2745         const char *tag_save_literal; /* Will contain the LITERAL tag identity */
2746         const char *tag_new_literal; /* Will contain the LITERAL tag identity */
2747         char tag_save_buf[10]; /* Will contain "tag_0x%02X" */
2748         char tag_new_buf[10]; /* Will contain "tag_0x%02X" */
2749         guint8 codepage_stag = 0; /* Initial codepage in state = STAG */
2750         guint8 parsing_tag_content = FALSE; /* Are we parsing content from a
2751                                                                                    tag with content: <x>Content</x>
2752                                                                                    
2753                                                                                    The initial state is FALSE.
2754                                                                                    This state will trigger recursion. */
2755         tag_save_literal = NULL; /* Prevents compiler warning */
2756
2757         DebugLog(("parse_wbxml_tag (level = %u, offset = %u)\n", *level, offset));
2758         while (off < tvb_len) {
2759                 peek = tvb_get_guint8 (tvb, off);
2760                 DebugLog(("STAG: (top of while) level = %3u, peek = 0x%02X, off = %u, tvb_len = %u\n", *level, peek, off, tvb_len));
2761                 if ((peek & 0x3F) < 4) switch (peek) { /* Global tokens in state = STAG
2762                                                                                                   but not the LITERAL tokens */
2763                         case 0x00: /* SWITCH_PAGE */
2764                                 codepage_stag = tvb_get_guint8 (tvb, off+1);
2765                                 proto_tree_add_text (tree, tvb, off, 2,
2766                                                 "      | Tag   | T 0->%3d "
2767                                                 "| SWITCH_PAGE (Tag code page)     "
2768                                                 "|",
2769                                                 codepage_stag);
2770                                 off += 2;
2771                                 break;
2772                         case 0x01: /* END: only possible for Tag with Content */
2773                                 if (tag_save_known) { /* Known TAG */
2774                                         proto_tree_add_text (tree, tvb, off, 1,
2775                                                         "  %3d | Tag   |          "
2776                                                         "| END (Known Tag 0x%02X)            "
2777                                                         "| %s</%s>",
2778                                                         *level, tag_save_known, Indent (*level),
2779                                                         tag_save_literal); /* We already looked it up! */
2780                                 } else { /* Literal TAG */
2781                                         proto_tree_add_text (tree, tvb, off, 1,
2782                                                         "  %3d | Tag   |          "
2783                                                         "| END (Literal Tag)               "
2784                                                         "| %s</%s>",
2785                                                         *level, Indent (*level),
2786                                                         tag_save_literal);
2787                                 }
2788                                 (*level)--;
2789                                 off++;
2790                                 /* Reset code page: not needed as return from recursion */
2791                                 DebugLog(("STAG: level = %u, Return: len = %u\n", *level, off - offset));
2792                                 return (off - offset);
2793                                 break;
2794                         case 0x02: /* ENTITY */
2795                                 ent = tvb_get_guintvar (tvb, off+1, &len);
2796                                 proto_tree_add_text (tree, tvb, off, 1+len,
2797                                                 "  %3d | Tag   |          "
2798                                                 "| ENTITY                          "
2799                                                 "| %s'&#%u;'",
2800                                                 *level, Indent (*level), ent);
2801                                 off += 1+len;
2802                                 break;
2803                         case 0x03: /* STR_I */
2804                                 len = tvb_strsize (tvb, off+1);
2805                                 proto_tree_add_text (tree, tvb, off, 1+len,
2806                                                 "  %3d | Tag   |          "
2807                                                 "| STR_I (Inline string)           "
2808                                                 "| %s\'%s\'",
2809                                                 *level, Indent(*level),
2810                                                 tvb_format_text (tvb, off+1, len-1));
2811                                 off += 1+len;
2812                                 break;
2813                         case 0x40: /* EXT_I_0 */
2814                         case 0x41: /* EXT_I_1 */
2815                         case 0x42: /* EXT_I_2 */
2816                                 /* Extension tokens */
2817                                 len = tvb_strsize (tvb, off+1);
2818                                 if (codepage_stag) { /* Not default code page */
2819                                         proto_tree_add_text (tree, tvb, off, 1+len,
2820                                                         "  %3d | Tag   | T %3d->0 "
2821                                                         "| EXT_I_%1x    (Extension Token)    "
2822                                                         "| %s(Inline string extension: \'%s\')",
2823                                                         *level, codepage_stag, peek & 0x0f, Indent (*level),
2824                                                         tvb_format_text (tvb, off+1, len-1));
2825                                         /* Reset code page */
2826                                         codepage_stag = 0;
2827                                 } else { /* Code page 0 */
2828                                         proto_tree_add_text (tree, tvb, off, 1+len,
2829                                                         "  %3d | Tag   |          "
2830                                                         "| EXT_I_%1x    (Extension Token)    "
2831                                                         "| %s(Inline string extension: \'%s\')",
2832                                                         *level, peek & 0x0f, Indent (*level),
2833                                                         tvb_format_text (tvb, off+1, len-1));
2834                                 }
2835                                 off += 1+len;
2836                                 break;
2837                         case 0x43: /* PI */
2838                                 proto_tree_add_text (tree, tvb, off, 1,
2839                                                 "  %3d | Tag   |          "
2840                                                 "| PI (XML Processing Instruction) "
2841                                                 "| %s<?xml",
2842                                                 *level, Indent (*level));
2843                                 len = parse_wbxml_attribute_list (tree, tvb, off, str_tbl, *level);
2844                                 /* Check that there is still room in packet */
2845                                 off += len;
2846                                 if (off >= tvb_len) {
2847                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
2848                                         THROW(ReportedBoundsError);
2849                                 }
2850                                 proto_tree_add_text (tree, tvb, off-1, 1,
2851                                                 "  %3d | Tag   |          "
2852                                                 "| END (PI)                        "
2853                                                 "| %s?>",
2854                                                 *level, Indent (*level));
2855                                 break;
2856                         case 0x80: /* EXT_T_0 */
2857                         case 0x81: /* EXT_T_1 */
2858                         case 0x82: /* EXT_T_2 */
2859                                 /* Extension tokens */
2860                                 index = tvb_get_guintvar (tvb, off+1, &len);
2861                                 str_len = tvb_strsize (tvb, str_tbl+index);
2862                                 if (codepage_stag) { /* Not default code page */
2863                                         proto_tree_add_text (tree, tvb, off, 1+len,
2864                                                         "  %3d | Tag   | T %3d->0 "
2865                                                         "| EXT_T_%1x    (Extension Token)    "
2866                                                         "| %s(Tableref string extension: \'%s\')",
2867                                                         *level, codepage_stag, peek & 0x0f, Indent (*level),
2868                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
2869                                         /* Reset code page */
2870                                         codepage_stag = 0;
2871                                 } else { /* Code page 0 */
2872                                         proto_tree_add_text (tree, tvb, off, 1+len,
2873                                                         "  %3d | Tag   |          "
2874                                                         "| EXT_T_%1x    (Extension Token)    "
2875                                                         "| %s(Tableref string extension: \'%s\')",
2876                                                         *level, peek & 0x0f, Indent (*level),
2877                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
2878                                 }
2879                                 off += 1+len;
2880                                 break;
2881                         case 0x83: /* STR_T */
2882                                 index = tvb_get_guintvar (tvb, off+1, &len);
2883                                 str_len = tvb_strsize (tvb, str_tbl+index);
2884                                 proto_tree_add_text (tree, tvb, off, 1+len,
2885                                                 "  %3d | Tag   |          "
2886                                                 "| STR_T (Tableref string)         "
2887                                                 "| %s\'%s\'",
2888                                                 *level, Indent (*level),
2889                                                 tvb_format_text (tvb, str_tbl+index, str_len-1));
2890                                 off += 1+len;
2891                                 break;
2892                         case 0xC0: /* EXT_0 */
2893                         case 0xC1: /* EXT_1 */
2894                         case 0xC2: /* EXT_2 */
2895                                 /* Extension tokens */
2896                                 if (codepage_stag) { /* Not default code page */
2897                                         proto_tree_add_text (tree, tvb, off, 1,
2898                                                         "  %3d | Tag   | T %3d->0 "
2899                                                         "| EXT_%1x      (Extension Token)    "
2900                                                         "| %s(Single-byte extension)",
2901                                                         *level, codepage_stag, peek & 0x0f,
2902                                                         Indent (*level));
2903                                         /* Reset code page */
2904                                         codepage_stag = 0;
2905                                 } else { /* Code page 0 */
2906                                         proto_tree_add_text (tree, tvb, off, 1,
2907                                                         "  %3d | Tag   |          "
2908                                                         "| EXT_%1x      (Extension Token)    "
2909                                                         "| %s(Single-byte extension)",
2910                                                         *level, peek & 0x0f, Indent (*level));
2911                                 }
2912                                 off++;
2913                                 break;
2914                         case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
2915                                 if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
2916                                         index = tvb_get_guintvar (tvb, off+1, &len);
2917                                         proto_tree_add_text (tree, tvb, off, 1 + len + index,
2918                                                         "  %3d | Tag   |          "
2919                                                         "| OPAQUE (Opaque data)            "
2920                                                         "| %s(%d bytes of opaque data)",
2921                                                         *level, Indent (*level), index);
2922                                         off += 1+len+index;
2923                                 } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
2924                                         proto_tree_add_text (tree, tvb, off, 1,
2925                                                         "  %3d | Tag   |          "
2926                                                         "| RESERVED_2     (Invalid Token!) "
2927                                                         "| WBXML 1.0 parsing stops here.",
2928                                                         *level);
2929                                         /* Stop processing as it is impossible to parse now */
2930                                         off = tvb_len;
2931                                         DebugLog(("STAG: level = %u, Return: len = %u\n", *level, off - offset));
2932                                         return (off - offset);
2933                                 }
2934                                 break;
2935
2936                                 /* No default clause, as all cases have been treated */
2937                 } else { /* LITERAL or Known TAG */
2938                         /* We must store the initial tag, and also retrieve the new tag.
2939                          * For efficiency reasons, we store the literal tag representation
2940                          * for known tags too, so we can easily close the tag without the
2941                          * need of a new lookup and avoiding storage of token codepage.
2942                          * 
2943                          * There are 4 possibilities:
2944                          *
2945                          *  1. Known tag followed by a known tag
2946                          *  2. Known tag followed by a LITERAL tag
2947                          *  3. LITERAL tag followed by Known tag
2948                          *  4. LITERAL tag followed by LITERAL tag
2949                          */
2950
2951                         /* Store the new tag */
2952                         tag_len = 0;
2953                         if ((peek & 0x3F) == 4) { /* LITERAL */
2954                                 DebugLog(("STAG: LITERAL tag (peek = 0x%02X, off = %u) - TableRef follows!\n", peek, off));
2955                                 index = tvb_get_guintvar (tvb, off+1, &tag_len);
2956                                 str_len = tvb_strsize (tvb, str_tbl+index);
2957                                 tag_new_literal = tvb_get_ptr (tvb, str_tbl+index, str_len);
2958                                 tag_new_known = 0; /* invalidate known tag_new */
2959                         } else { /* Known tag */
2960                                 tag_new_known = peek & 0x3F;
2961                                 sprintf (tag_new_buf, "Tag_0x%02X",
2962                                                 tag_new_known);
2963                                 tag_new_literal = tag_new_buf;
2964                                 /* Stored looked up tag name string */
2965                         }
2966
2967                         /* Parsing of TAG starts HERE */
2968                         if (peek & 0x40) { /* Content present */
2969                                 /* Content follows
2970                                  * [!] An explicit END token is expected in these cases!
2971                                  * ==> Recursion possible if we encounter a tag with content;
2972                                  *     recursion will return at the explicit END token.
2973                                  */
2974                                 if (parsing_tag_content) { /* Recurse */
2975                                         DebugLog(("STAG: Tag in Tag - RECURSE! (off = %u)\n", off));
2976                                         /* Do not process the attribute list:
2977                                          * recursion will take care of it */
2978                                         (*level)++;
2979                                         len = parse_wbxml_tag (tree, tvb, off, str_tbl, level);
2980                                         off += len;
2981                                 } else { /* Now we will have content to parse */
2982                                         /* Save the start tag so we can properly close it later. */
2983                                         if ((peek & 0x3F) == 4) { /* Literal tag */
2984                                                 tag_save_literal = tag_new_literal;
2985                                                 tag_save_known = 0;
2986                                         } else { /* Known tag */
2987                                                 tag_save_known = tag_new_known;
2988                                                 sprintf (tag_save_buf, "Tag_0x%02X",
2989                                                                 tag_new_known);
2990                                                 tag_save_literal = tag_save_buf;
2991                                                 /* The last statement avoids needless lookups */
2992                                         }
2993                                         /* Process the attribute list if present */
2994                                         if (peek & 0x80) { /* Content and Attribute list present */
2995                                                 if (tag_new_known) { /* Known tag */
2996                                                         if (codepage_stag) { /* Not default code page */
2997                                                                 proto_tree_add_text (tree, tvb, off, 1,
2998                                                                                 "  %3d | Tag   | T %3d->0 "
2999                                                                                 "|   Known Tag 0x%02X           (AC) "
3000                                                                                 "| %s<%s",
3001                                                                                 *level, codepage_stag, tag_new_known,
3002                                                                                 Indent (*level), tag_new_literal);
3003                                                                 /* Tag string already looked up earlier! */
3004                                                                 /* Reset code page */
3005                                                                 codepage_stag = 0;
3006                                                         } else { /* Code page 0 */
3007                                                                 proto_tree_add_text (tree, tvb, off, 1,
3008                                                                                 "  %3d | Tag   |          "
3009                                                                                 "|   Known Tag 0x%02X           (AC) "
3010                                                                                 "| %s<%s",
3011                                                                                 *level, tag_new_known,
3012                                                                                 Indent (*level), tag_new_literal);
3013                                                                 /* Tag string already looked up earlier! */
3014                                                         }
3015                                                         off++;
3016                                                 } else { /* LITERAL tag */
3017                                                         proto_tree_add_text (tree, tvb, off, 1,
3018                                                                         "  %3d | Tag   |          "
3019                                                                         "| LITERAL_AC (Literal tag)   (AC) "
3020                                                                         "| %s<%s",
3021                                                                         *level, Indent (*level), tag_new_literal);
3022                                                         off += 1 + tag_len;
3023                                                 }
3024                                                 len = parse_wbxml_attribute_list (tree, tvb,
3025                                                                 off, str_tbl, *level);
3026                                                 /* Check that there is still room in packet */
3027                                                 off += len;
3028                                                 if (off >= tvb_len) {
3029                                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
3030                                                         THROW(ReportedBoundsError);
3031                                                 }
3032                                                 proto_tree_add_text (tree, tvb, off-1, 1,
3033                                                                 "  %3d | Tag   |          "
3034                                                                 "| END (attribute list)            "
3035                                                                 "| %s>",
3036                                                                 *level, Indent (*level));
3037                                         } else { /* Content, no Attribute list */
3038                                                 if (tag_new_known) { /* Known tag */
3039                                                         if (codepage_stag) { /* Not default code page */
3040                                                                 proto_tree_add_text (tree, tvb, off, 1,
3041                                                                                 "  %3d | Tag   | T %3d->0 "
3042                                                                                 "|   Known Tag 0x%02X           (.C) "
3043                                                                                 "| %s<%s>",
3044                                                                                 *level, codepage_stag, tag_new_known,
3045                                                                                 Indent (*level),
3046                                                                                 tag_new_literal);
3047                                                                 /* Tag string already looked up earlier! */
3048                                                                 /* Reset code page */
3049                                                                 codepage_stag = 0;
3050                                                         } else { /* Code page 0 */
3051                                                                 proto_tree_add_text (tree, tvb, off, 1,
3052                                                                                 "  %3d | Tag   |          "
3053                                                                                 "|   Known Tag 0x%02X           (.C) "
3054                                                                                 "| %s<%s>",
3055                                                                                 *level, tag_new_known,
3056                                                                                 Indent (*level),
3057                                                                                 tag_new_literal);
3058                                                                 /* Tag string already looked up earlier! */
3059                                                         }
3060                                                         off++;
3061                                                 } else { /* LITERAL tag */
3062                                                         proto_tree_add_text (tree, tvb, off, 1,
3063                                                                         "  %3d | Tag   |          "
3064                                                                         "| LITERAL_C  (Literal Tag)   (.C) "
3065                                                                         "| %s<%s>",
3066                                                                         *level, Indent (*level), tag_new_literal);
3067                                                         off += 1 + tag_len;
3068                                                 }
3069                                         }
3070                                         /* The data that follows in the parsing process
3071                                          * represents content for the opening tag
3072                                          * we've just processed in the lines above.
3073                                          * Next time we encounter a tag with content: recurse
3074                                          */
3075                                         parsing_tag_content = TRUE;
3076                                         DebugLog(("Tag in Tag - No recursion this time! (off = %u)\n", off));
3077                                 }
3078                         } else { /* No Content */
3079                                 DebugLog(("<Tag/> in Tag - No recursion! (off = %u)\n", off));
3080                                 (*level)++;
3081                                 if (peek & 0x80) { /* No Content, Attribute list present */
3082                                         if (tag_new_known) { /* Known tag */
3083                                                 if (codepage_stag) { /* Not default code page */
3084                                                         proto_tree_add_text (tree, tvb, off, 1,
3085                                                                         "  %3d | Tag   | T %3d->0 "
3086                                                                         "|   Known Tag 0x%02X           (A.) "
3087                                                                         "| %s<%s",
3088                                                                         *level, codepage_stag, tag_new_known,
3089                                                                         Indent (*level), tag_new_literal);
3090                                                         /* Tag string already looked up earlier! */
3091                                                         /* Reset code page */
3092                                                         codepage_stag = 0;
3093                                                 } else { /* Code page 0 */
3094                                                         proto_tree_add_text (tree, tvb, off, 1,
3095                                                                         "  %3d | Tag   |          "
3096                                                                         "|   Known Tag 0x%02X           (A.) "
3097                                                                         "| %s<%s",
3098                                                                         *level, tag_new_known,
3099                                                                         Indent (*level), tag_new_literal);
3100                                                         /* Tag string already looked up earlier! */
3101                                                 }
3102                                                 off++;
3103                                                 len = parse_wbxml_attribute_list (tree, tvb,
3104                                                                 off, str_tbl, *level);
3105                                                 /* Check that there is still room in packet */
3106                                                 off += len;
3107                                                 if (off >= tvb_len) {
3108                                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
3109                                                         THROW(ReportedBoundsError);
3110                                                 }
3111                                                 proto_tree_add_text (tree, tvb, off-1, 1,
3112                                                                 "  %3d | Tag   |          "
3113                                                                 "| END (Known Tag)                 "
3114                                                                 "| %s/>",
3115                                                                 *level, Indent (*level));
3116                                         } else { /* LITERAL tag */
3117                                                 proto_tree_add_text (tree, tvb, off, 1,
3118                                                                 "  %3d | Tag   |          "
3119                                                                 "| LITERAL_A  (Literal Tag)   (A.) "
3120                                                                 "| %s<%s",
3121                                                                 *level, Indent (*level), tag_new_literal);
3122                                                 off += 1 + tag_len;
3123                                                 len = parse_wbxml_attribute_list (tree, tvb,
3124                                                                 off, str_tbl, *level);
3125                                                 /* Check that there is still room in packet */
3126                                                 off += len;
3127                                                 if (off >= tvb_len) {
3128                                                         DebugLog(("STAG: level = %u, ThrowException: len = %u (short frame)\n", *level, off - offset));
3129                                                         THROW(ReportedBoundsError);
3130                                                 }
3131                                                 proto_tree_add_text (tree, tvb, off-1, 1,
3132                                                                 "  %3d | Tag   |          "
3133                                                                 "| END (Literal Tag)               "
3134                                                                 "| %s/>",
3135                                                                 *level, Indent (*level));
3136                                         }
3137                                 } else { /* No Content, No Attribute list */
3138                                         if (tag_new_known) { /* Known tag */
3139                                                 if (codepage_stag) { /* Not default code page */
3140                                                         proto_tree_add_text (tree, tvb, off, 1,
3141                                                                         "  %3d | Tag   | T %3d->0 "
3142                                                                         "|   Known Tag 0x%02x           (..) "
3143                                                                         "| %s<%s />",
3144                                                                         *level, codepage_stag, tag_new_known,
3145                                                                         Indent (*level), tag_new_literal);
3146                                                         /* Tag string already looked up earlier! */
3147                                                         /* Reset code page */
3148                                                         codepage_stag = 0;
3149                                                 } else { /* Code page 0 */
3150                                                         proto_tree_add_text (tree, tvb, off, 1,
3151                                                                         "  %3d | Tag   |          "
3152                                                                         "|   Known Tag 0x%02x           (..) "
3153                                                                         "| %s<%s />",
3154                                                                         *level, tag_new_known,
3155                                                                         Indent (*level), tag_new_literal);
3156                                                         /* Tag string already looked up earlier! */
3157                                                 }
3158                                                 off++;
3159                                         } else { /* LITERAL tag */
3160                                                 proto_tree_add_text (tree, tvb, off, 1,
3161                                                                 "  %3d | Tag   |          "
3162                                                                 "| LITERAL    (Literal Tag)   (..) "
3163                                                                 "| %s<%s />",
3164                                                                 *level, Indent (*level), tag_new_literal);
3165                                                 off += 1 + tag_len;
3166                                         }
3167                                 }
3168                                 (*level)--;
3169                                 /* TODO: Do I have to reset code page here? */
3170                         }
3171                 } /* if (tag & 0x3F) >= 5 */
3172         } /* while */
3173         DebugLog(("STAG: level = %u, Return: len = %u (end of function body)\n", *level, off - offset));
3174         return (off - offset);
3175 }
3176
3177
3178 /**************************
3179  * WBXML Attribute tokens *
3180  **************************
3181  * Bit Mask  : Example
3182  * -------------------
3183  * 0... .... : attr=             (attribute name)
3184  *             href='http://'    (attribute name with start of attribute value)
3185  * 1... .... : 'www.'            (attribute value, or part of it)
3186  * 
3187  */
3188
3189
3190 /* This function parses the WBXML and maps known token interpretations
3191  * to the WBXML tokens. As a result, the original XML document can be
3192  * recreated. Indentation is generated in order to ease reading.
3193  *
3194  * This function performs attribute list parsing.
3195  * 
3196  * The wbxml_token_map entry *map contains the actual token mapping.
3197  *
3198  * NOTE: See above for known token mappings.
3199  */
3200 static guint32
3201 parse_wbxml_attribute_list_defined (proto_tree *tree, tvbuff_t *tvb,
3202                 guint32 offset, guint32 str_tbl, guint8 level,
3203                 const wbxml_token_map *map)
3204 {
3205         guint32 tvb_len = tvb_reported_length (tvb);
3206         guint32 off = offset;
3207         guint32 len;
3208         guint str_len;
3209         guint32 ent;
3210         guint32 index;
3211         guint8 peek;
3212         guint8 codepage_attr = 0; /* Initial codepage in state = ATTR */
3213
3214         DebugLog(("parse_wbxml_attr_defined (level = %u, offset = %u)\n", level, offset));
3215         /* Parse attributes */
3216         while (off < tvb_len) {
3217                 peek = tvb_get_guint8 (tvb, off);
3218                 DebugLog(("ATTR: (top of while) level = %3u, peek = 0x%02X, off = %u, tvb_len = %u\n", level, peek, off, tvb_len));
3219                 if ((peek & 0x3F) < 5) switch (peek) { /* Global tokens
3220                                                                                                   in state = ATTR */
3221                         case 0x00: /* SWITCH_PAGE */
3222                                 codepage_attr = tvb_get_guint8 (tvb, off+1);
3223                                 proto_tree_add_text (tree, tvb, off, 2,
3224                                                 "      |  Attr | A 0->%3d "
3225                                                 "| SWITCH_PAGE (Attr code page)    |",
3226                                                 codepage_attr);
3227                                 off += 2;
3228                                 break;
3229                         case 0x01: /* END */
3230                                 /* BEWARE
3231                                  *   The Attribute END token means either ">" or "/>"
3232                                  *   and as a consequence both must be treated separately.
3233                                  *   This is done in the TAG state parser.
3234                                  */
3235                                 off++;
3236                                 DebugLog(("ATTR: level = %u, Return: len = %u\n", level, off - offset));
3237                                 return (off - offset);
3238                         case 0x02: /* ENTITY */
3239                                 ent = tvb_get_guintvar (tvb, off+1, &len);
3240                                 proto_tree_add_text (tree, tvb, off, 1+len,
3241                                                 "  %3d |  Attr |          "
3242                                                 "| ENTITY                          "
3243                                                 "|     %s'&#%u;'",
3244                                                 level, Indent (level), ent);
3245                                 off += 1+len;
3246                                 break;
3247                         case 0x03: /* STR_I */
3248                                 len = tvb_strsize (tvb, off+1);
3249                                 proto_tree_add_text (tree, tvb, off, 1+len,
3250                                                 "  %3d |  Attr |          "
3251                                                 "| STR_I (Inline string)           "
3252                                                 "|     %s\'%s\'",
3253                                                 level, Indent (level),
3254                                                 tvb_format_text (tvb, off+1, len-1));
3255                                 off += 1+len;
3256                                 break;
3257                         case 0x04: /* LITERAL */
3258                                 index = tvb_get_guintvar (tvb, off+1, &len);
3259                                 str_len = tvb_strsize (tvb, str_tbl+index);
3260                                 proto_tree_add_text (tree, tvb, off, 1+len,
3261                                                 "  %3d |  Attr |          "
3262                                                 "| LITERAL (Literal Attribute)     "
3263                                                 "|   %s<%s />",
3264                                                 level, Indent (level),
3265                                                 tvb_format_text (tvb, str_tbl+index, str_len-1));
3266                                 off += 1+len;
3267                                 break;
3268                         case 0x40: /* EXT_I_0 */
3269                         case 0x41: /* EXT_I_1 */
3270                         case 0x42: /* EXT_I_2 */
3271                                 /* Extension tokens */
3272                                 len = tvb_strsize (tvb, off+1);
3273                                 if (codepage_attr) { /* Not default code page */
3274                                         proto_tree_add_text (tree, tvb, off, 1+len,
3275                                                         "  %3d |  Attr | A %3d->0 "
3276                                                         "| EXT_I_%1x    (Extension Token)    "
3277                                                         "|     %s(%s: \'%s\')",
3278                                                         level, codepage_attr, peek & 0x0f, Indent (level),
3279                                                         map_token (map->global, codepage_attr, peek),
3280                                                         tvb_format_text (tvb, off+1, len-1));
3281                                         /* Reset code page */
3282                                         codepage_attr = 0;
3283                                 } else { /* Code page 0 */
3284                                         proto_tree_add_text (tree, tvb, off, 1+len,
3285                                                         "  %3d |  Attr |          "
3286                                                         "| EXT_I_%1x    (Extension Token)    "
3287                                                         "|     %s(%s: \'%s\')",
3288                                                         level, peek & 0x0f, Indent (level),
3289                                                         map_token (map->global, codepage_attr, peek),
3290                                                         tvb_format_text (tvb, off+1, len-1));
3291                                 }
3292                                 off += 1+len;
3293                                 break;
3294                         /* 0x43 impossible in ATTR state */
3295                         /* 0x44 impossible in ATTR state */
3296                         case 0x80: /* EXT_T_0 */
3297                         case 0x81: /* EXT_T_1 */
3298                         case 0x82: /* EXT_T_2 */
3299                                 /* Extension tokens */
3300                                 index = tvb_get_guintvar (tvb, off+1, &len);
3301                                 str_len = tvb_strsize (tvb, str_tbl+index);
3302                                 if (codepage_attr) { /* Not default code page */
3303                                         proto_tree_add_text (tree, tvb, off, 1+len,
3304                                                         "  %3d |  Attr | A %3d->0 "
3305                                                         "| EXT_T_%1x    (Extension Token)    "
3306                                                         "|     %s(%s: \'%s\')",
3307                                                         level, codepage_attr, peek & 0x0f, Indent (level),
3308                                                         map_token (map->global, codepage_attr, peek),
3309                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
3310                                         /* Reset code page */
3311                                         codepage_attr = 0;
3312                                 } else { /* Code page 0 */
3313                                         proto_tree_add_text (tree, tvb, off, 1+len,
3314                                                         "  %3d |  Attr |          "
3315                                                         "| EXT_T_%1x    (Extension Token)    "
3316                                                         "|     %s(%s: \'%s\')",
3317                                                         level, peek & 0x0f, Indent (level),
3318                                                         map_token (map->global, codepage_attr, peek),
3319                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
3320                                 }
3321                                 off += 1+len;
3322                                 break;
3323                         case 0x83: /* STR_T */
3324                                 index = tvb_get_guintvar (tvb, off+1, &len);
3325                                 str_len = tvb_strsize (tvb, str_tbl+index);
3326                                 proto_tree_add_text (tree, tvb, off, 1+len,
3327                                                 "  %3d |  Attr |          "
3328                                                 "| STR_T (Tableref string)         "
3329                                                 "|     %s\'%s\'",
3330                                                 level, Indent (level),
3331                                                 tvb_format_text (tvb, str_tbl+index, str_len-1));
3332                                 off += 1+len;
3333                                 break;
3334                         /* 0x84 impossible in ATTR state */
3335                         case 0xC0: /* EXT_0 */
3336                         case 0xC1: /* EXT_1 */
3337                         case 0xC2: /* EXT_2 */
3338                                 /* Extension tokens */
3339                                 if (codepage_attr) { /* Not default code page */
3340                                         proto_tree_add_text (tree, tvb, off, 1,
3341                                                         "  %3d |  Attr | A %3d->0 "
3342                                                         "| EXT_%1x      (Extension Token)    "
3343                                                         "|     %s(%s)",
3344                                                         level, codepage_attr, peek & 0x0f, Indent (level),
3345                                                         map_token (map->global, codepage_attr, peek));
3346                                         /* Reset code page */
3347                                         codepage_attr = 0;
3348                                 } else { /* Code page 0 */
3349                                         proto_tree_add_text (tree, tvb, off, 1,
3350                                                         "  %3d |  Attr |          "
3351                                                         "| EXT_%1x      (Extension Token)    "
3352                                                         "|     %s(%s)",
3353                                                         level, peek & 0x0f, Indent (level),
3354                                                         map_token (map->global, codepage_attr, peek));
3355                                 }
3356                                 off++;
3357                                 break;
3358                         case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
3359                                 if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
3360                                         index = tvb_get_guintvar (tvb, off+1, &len);
3361                                         proto_tree_add_text (tree, tvb, off, 1 + len + index,
3362                                                         "  %3d |  Attr |          "
3363                                                         "| OPAQUE (Opaque data)            "
3364                                                         "|       %s(%d bytes of opaque data)",
3365                                                         level, Indent (level), index);
3366                                         off += 1+len+index;
3367                                 } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
3368                                         proto_tree_add_text (tree, tvb, off, 1,
3369                                                         "  %3d |  Attr |          "
3370                                                         "| RESERVED_2     (Invalid Token!) "
3371                                                         "| WBXML 1.0 parsing stops here.",
3372                                                         level);
3373                                         /* Stop processing as it is impossible to parse now */
3374                                         off = tvb_len;
3375                                         DebugLog(("ATTR: level = %u, Return: len = %u\n", level, off - offset));
3376                                         return (off - offset);
3377                                 }
3378                                 break;
3379                         /* 0xC4 impossible in ATTR state */
3380                         default:
3381                                 proto_tree_add_text (tree, tvb, off, 1,
3382                                                 "  %3d |  Attr |          "
3383                                                 "| %-10s     (Invalid Token!) "
3384                                                 "| WBXML parsing stops here.",
3385                                                 level, match_strval (peek, vals_wbxml1x_global_tokens));
3386                                 /* Move to end of buffer */
3387                                 off = tvb_len;
3388                                 break;
3389                 } else { /* Known atribute token */
3390                         if (peek & 0x80) { /* attrValue */
3391                                 if (codepage_attr) { /* Not default code page */
3392                                         proto_tree_add_text (tree, tvb, off, 1,
3393                                                         "  %3d |  Attr | A %3d->0 "
3394                                                         "|   Known attrValue 0x%02X          "
3395                                                         "|       %s%s",
3396                                                         level, codepage_attr, peek & 0x7f, Indent (level),
3397                                                         map_token (map->attrValue, codepage_attr, peek));
3398                                         /* Reset code page */
3399                                         codepage_attr = 0;
3400                                 } else { /* Code page 0 */
3401                                         proto_tree_add_text (tree, tvb, off, 1,
3402                                                         "  %3d |  Attr |          "
3403                                                         "|   Known attrValue 0x%02X          "
3404                                                         "|       %s%s",
3405                                                         level, peek & 0x7f, Indent (level),
3406                                                         map_token (map->attrValue, codepage_attr, peek));
3407                                 }
3408                                 off++;
3409                         } else { /* attrStart */
3410                                 if (codepage_attr) { /* Not default code page */
3411                                         proto_tree_add_text (tree, tvb, off, 1,
3412                                                         "  %3d |  Attr | A %3d->0 "
3413                                                         "|   Known attrStart 0x%02X          "
3414                                                         "|   %s%s",
3415                                                         level, codepage_attr, peek & 0x7f, Indent (level),
3416                                                         map_token (map->attrStart, codepage_attr, peek));
3417                                         /* Reset code page */
3418                                         codepage_attr = 0;
3419                                 } else { /* Code page 0 */
3420                                         proto_tree_add_text (tree, tvb, off, 1,
3421                                                         "  %3d |  Attr |          "
3422                                                         "|   Known attrStart 0x%02X          "
3423                                                         "|   %s%s",
3424                                                         level, peek & 0x7f, Indent (level),
3425                                                         map_token (map->attrStart, codepage_attr, peek));
3426                                 }
3427                                 off++;
3428                         }
3429                 }
3430         } /* End WHILE */
3431         DebugLog(("ATTR: level = %u, Return: len = %u (end of function body)\n", level, off - offset));
3432         return (off - offset);
3433 }
3434
3435
3436 /* This function performs the WBXML attribute decoding as in
3437  * parse_wbxml_attribute_list_defined() but this time no WBXML mapping
3438  * is performed.
3439  *
3440  * This function performs attribute list parsing.
3441  * 
3442  * NOTE: Code page switches not yet processed in the code!
3443  */
3444 static guint32
3445 parse_wbxml_attribute_list (proto_tree *tree, tvbuff_t *tvb,
3446                 guint32 offset, guint32 str_tbl, guint8 level)
3447 {
3448         guint32 tvb_len = tvb_reported_length (tvb);
3449         guint32 off = offset;
3450         guint32 len;
3451         guint str_len;
3452         guint32 ent;
3453         guint32 index;
3454         guint8 peek;
3455         guint8 codepage_attr = 0; /* Initial codepage in state = ATTR */
3456
3457         DebugLog(("parse_wbxml_attr (level = %u, offset = %u)\n", level, offset));
3458         /* Parse attributes */
3459         while (off < tvb_len) {
3460                 peek = tvb_get_guint8 (tvb, off);
3461                 DebugLog(("ATTR: (top of while) level = %3u, peek = 0x%02X, off = %u, tvb_len = %u\n", level, peek, off, tvb_len));
3462                 if ((peek & 0x3F) < 5) switch (peek) { /* Global tokens
3463                                                                                                   in state = ATTR */
3464                         case 0x00: /* SWITCH_PAGE */
3465                                 codepage_attr = tvb_get_guint8 (tvb, off+1);
3466                                 proto_tree_add_text (tree, tvb, off, 2,
3467                                                 "      |  Attr | A 0->%3d "
3468                                                 "| SWITCH_PAGE (Attr code page)    |",
3469                                                 codepage_attr);
3470                                 off += 2;
3471                                 break;
3472                         case 0x01: /* END */
3473                                 /* BEWARE
3474                                  *   The Attribute END token means either ">" or "/>"
3475                                  *   and as a consequence both must be treated separately.
3476                                  *   This is done in the TAG state parser.
3477                                  */
3478                                 off++;
3479                                 DebugLog(("ATTR: level = %u, Return: len = %u\n", level, off - offset));
3480                                 return (off - offset);
3481                         case 0x02: /* ENTITY */
3482                                 ent = tvb_get_guintvar (tvb, off+1, &len);
3483                                 proto_tree_add_text (tree, tvb, off, 1+len,
3484                                                 "  %3d |  Attr |          "
3485                                                 "| ENTITY                          "
3486                                                 "|     %s'&#%u;'",
3487                                                 level, Indent (level), ent);
3488                                 off += 1+len;
3489                                 break;
3490                         case 0x03: /* STR_I */
3491                                 len = tvb_strsize (tvb, off+1);
3492                                 proto_tree_add_text (tree, tvb, off, 1+len,
3493                                                 "  %3d |  Attr |          "
3494                                                 "| STR_I (Inline string)           "
3495                                                 "|     %s\'%s\'",
3496                                                 level, Indent (level),
3497                                                 tvb_format_text (tvb, off+1, len-1));
3498                                 off += 1+len;
3499                                 break;
3500                         case 0x04: /* LITERAL */
3501                                 index = tvb_get_guintvar (tvb, off+1, &len);
3502                                 str_len = tvb_strsize (tvb, str_tbl+index);
3503                                 proto_tree_add_text (tree, tvb, off, 1+len,
3504                                                 "  %3d |  Attr |          "
3505                                                 "| LITERAL (Literal Attribute)     "
3506                                                 "|   %s<%s />",
3507                                                 level, Indent (level),
3508                                                 tvb_format_text (tvb, str_tbl+index, str_len-1));
3509                                 off += 1+len;
3510                                 break;
3511                         case 0x40: /* EXT_I_0 */
3512                         case 0x41: /* EXT_I_1 */
3513                         case 0x42: /* EXT_I_2 */
3514                                 /* Extension tokens */
3515                                 len = tvb_strsize (tvb, off+1);
3516                                 if (codepage_attr) { /* Not default code page */
3517                                         proto_tree_add_text (tree, tvb, off, 1+len,
3518                                                         "  %3d |  Attr | A %3d->0 "
3519                                                         "| EXT_I_%1x    (Extension Token)    "
3520                                                         "|     %s(Inline string extension: \'%s\')",
3521                                                         level, codepage_attr, peek & 0x0f, Indent (level),
3522                                                         tvb_format_text (tvb, off+1, len-1));
3523                                         /* Reset code page */
3524                                         codepage_attr = 0;
3525                                 } else { /* Code page 0 */
3526                                         proto_tree_add_text (tree, tvb, off, 1+len,
3527                                                         "  %3d |  Attr |          "
3528                                                         "| EXT_I_%1x    (Extension Token)    "
3529                                                         "|     %s(Inline string extension: \'%s\')",
3530                                                         level, peek & 0x0f, Indent (level),
3531                                                         tvb_format_text (tvb, off+1, len-1));
3532                                 }
3533                                 off += 1+len;
3534                                 break;
3535                         /* 0x43 impossible in ATTR state */
3536                         /* 0x44 impossible in ATTR state */
3537                         case 0x80: /* EXT_T_0 */
3538                         case 0x81: /* EXT_T_1 */
3539                         case 0x82: /* EXT_T_2 */
3540                                 /* Extension tokens */
3541                                 index = tvb_get_guintvar (tvb, off+1, &len);
3542                                 str_len = tvb_strsize (tvb, str_tbl+index);
3543                                 if (codepage_attr) { /* Not default code page */
3544                                         proto_tree_add_text (tree, tvb, off, 1+len,
3545                                                         "  %3d |  Attr | A %3d->0 "
3546                                                         "| EXT_T_%1x    (Extension Token)    "
3547                                                         "|     %s(Tableref string extension: \'%s\')",
3548                                                         level, codepage_attr, peek & 0x0f, Indent (level),
3549                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
3550                                         /* Reset code page */
3551                                         codepage_attr = 0;
3552                                 } else { /* Code page 0 */
3553                                         proto_tree_add_text (tree, tvb, off, 1+len,
3554                                                         "  %3d |  Attr |          "
3555                                                         "| EXT_T_%1x    (Extension Token)    "
3556                                                         "|     %s(Tableref string extension: \'%s\')",
3557                                                         level, peek & 0x0f, Indent (level),
3558                                                         tvb_format_text (tvb, str_tbl+index, str_len-1));
3559                                 }
3560                                 off += 1+len;
3561                                 break;
3562                         case 0x83: /* STR_T */
3563                                 index = tvb_get_guintvar (tvb, off+1, &len);
3564                                 str_len = tvb_strsize (tvb, str_tbl+index);
3565                                 proto_tree_add_text (tree, tvb, off, 1+len,
3566                                                 "  %3d |  Attr |          "
3567                                                 "| STR_T (Tableref string)         "
3568                                                 "|     %s\'%s\'",
3569                                                 level, Indent (level),
3570                                                 tvb_format_text (tvb, str_tbl+index, str_len-1));
3571                                 off += 1+len;
3572                                 break;
3573                         /* 0x84 impossible in ATTR state */
3574                         case 0xC0: /* EXT_0 */
3575                         case 0xC1: /* EXT_1 */
3576                         case 0xC2: /* EXT_2 */
3577                                 /* Extension tokens */
3578                                 if (codepage_attr) { /* Not default code page */
3579                                         proto_tree_add_text (tree, tvb, off, 1,
3580                                                         "  %3d |  Attr | A %3d->0 "
3581                                                         "| EXT_%1x      (Extension Token)    "
3582                                                         "|     %s(Single-byte extension)",
3583                                                         level, codepage_attr, peek & 0x0f, Indent (level));
3584                                         /* Reset code page */
3585                                         codepage_attr = 0;
3586                                 } else { /* Code page 0 */
3587                                         proto_tree_add_text (tree, tvb, off, 1,
3588                                                         "  %3d |  Attr |          "
3589                                                         "| EXT_%1x      (Extension Token)    "
3590                                                         "|     %s(Single-byte extension)",
3591                                                         level, peek & 0x0f, Indent (level));
3592                                 }
3593                                 off++;
3594                                 break;
3595                         case 0xC3: /* OPAQUE - WBXML 1.1 and newer */
3596                                 if (tvb_get_guint8 (tvb, 0)) { /* WBXML 1.x (x > 0) */
3597                                         index = tvb_get_guintvar (tvb, off+1, &len);
3598                                         proto_tree_add_text (tree, tvb, off, 1 + len + index,
3599                                                         "  %3d |  Attr |          "
3600                                                         "| OPAQUE (Opaque data)            "
3601                                                         "|       %s(%d bytes of opaque data)",
3602                                                         level, Indent (level), index);
3603                                         off += 1+len+index;
3604                                 } else { /* WBXML 1.0 - RESERVED_2 token (invalid) */
3605                                         proto_tree_add_text (tree, tvb, off, 1,
3606                                                         "  %3d |  Attr |          "
3607                                                         "| RESERVED_2     (Invalid Token!) "
3608                                                         "| WBXML 1.0 parsing stops here.",
3609                                                         level);
3610                                         /* Stop processing as it is impossible to parse now */
3611                                         off = tvb_len;
3612                                         DebugLog(("ATTR: level = %u, Return: len = %u\n", level, off - offset));
3613                                         return (off - offset);
3614                                 }
3615                                 break;
3616                         /* 0xC4 impossible in ATTR state */
3617                         default:
3618                                 proto_tree_add_text (tree, tvb, off, 1,
3619                                                 "  %3d |  Attr |          "
3620                                                 "| %-10s     (Invalid Token!) "
3621                                                 "| WBXML parsing stops here.",
3622                                                 level, match_strval (peek, vals_wbxml1x_global_tokens));
3623                                 /* Move to end of buffer */
3624                                 off = tvb_len;
3625                                 break;
3626                 } else { /* Known atribute token */
3627                         if (peek & 0x80) { /* attrValue */
3628                                 if (codepage_attr) { /* Not default code page */
3629                                         proto_tree_add_text (tree, tvb, off, 1,
3630                                                         "  %3d |  Attr | A %3d->0 "
3631                                                         "|   Known attrValue 0x%02X          "
3632                                                         "|       %sattrValue_0x%02X",
3633                                                         level, codepage_attr, peek & 0x7f, Indent (level),
3634                                                         peek);
3635                                         /* Reset code page */
3636                                         codepage_attr = 0;
3637                                 } else { /* Code page 0 */
3638                                         proto_tree_add_text (tree, tvb, off, 1,
3639                                                         "  %3d |  Attr |          "
3640                                                         "|   Known attrValue 0x%02X          "
3641                                                         "|       %sattrValue_0x%02X",
3642                                                         level, peek & 0x7f, Indent (level),
3643                                                         peek);
3644                                 }
3645                                 off++;
3646                         } else { /* attrStart */
3647                                 if (codepage_attr) { /* Not default code page */
3648                                         proto_tree_add_text (tree, tvb, off, 1,
3649                                                         "  %3d |  Attr | A %3d->0 "
3650                                                         "|   Known attrStart 0x%02X          "
3651                                                         "|   %sattrStart_0x%02X",
3652                                                         level, codepage_attr, peek & 0x7f, Indent (level),
3653                                                         peek);
3654                                         /* Reset code page */
3655                                         codepage_attr = 0;
3656                                 } else { /* Code page 0 */
3657                                         proto_tree_add_text (tree, tvb, off, 1,
3658                                                         "  %3d |  Attr |          "
3659                                                         "|   Known attrStart 0x%02X          "
3660                                                         "|   %sattrStart_0x%02X",
3661                                                         level, peek & 0x7f, Indent (level),
3662                                                         peek);
3663                                 }
3664                                 off++;
3665                         }
3666                 }
3667         } /* End WHILE */
3668         DebugLog(("ATTR: level = %u, Return: len = %u (end of function body)\n", level, off - offset));
3669         return (off - offset);
3670 }
3671
3672
3673 /****************** Register the protocol with Ethereal ******************/
3674
3675
3676 /* This format is required because a script is used to build the C function
3677  * that calls the protocol registration. */
3678
3679 void
3680 proto_register_wbxml(void)
3681 { /* Setup list of header fields. See Section 1.6.1 for details. */
3682         static hf_register_info hf[] = {
3683                 { &hf_wbxml_version,
3684                         { "Version",
3685                           "wbxml.version",
3686                           FT_UINT8, BASE_HEX,
3687                           VALS ( vals_wbxml_versions ), 0x00,
3688                           "WBXML Version", HFILL }
3689                 },
3690                 { &hf_wbxml_public_id_known,
3691                         { "Public Identifier (known)",
3692                           "wbxml.public_id.known",
3693                           FT_UINT32, BASE_HEX,
3694                           VALS ( vals_wbxml_public_ids ), 0x00,
3695                           "WBXML Known Public Identifier (integer)", HFILL }
3696                 },
3697                 { &hf_wbxml_public_id_literal,
3698                         { "Public Identifier (literal)",
3699                           "wbxml.public_id.literal",
3700                           FT_STRING, BASE_NONE,
3701                           NULL, 0x00,
3702                           "WBXML Literal Public Identifier (text string)", HFILL }
3703                 },
3704                 { &hf_wbxml_charset,
3705                         { "Character Set",
3706                           "wbxml.charset",
3707                           FT_UINT32, BASE_HEX,
3708                           VALS ( vals_character_sets ), 0x00,
3709                           "WBXML Character Set", HFILL }
3710                 },
3711         };
3712
3713         /* Setup protocol subtree array */
3714         static gint *ett[] = {
3715                 &ett_wbxml,
3716                 &ett_wbxml_str_tbl,
3717                 &ett_wbxml_content,
3718         };
3719
3720         /* Register the protocol name and description */
3721         proto_wbxml = proto_register_protocol(
3722                         "WAP Binary XML",
3723                         "WBXML",
3724                         "wbxml"
3725         );
3726
3727         /* Required function calls to register the header fields
3728          * and subtrees used */
3729         proto_register_field_array(proto_wbxml, hf, array_length(hf));
3730         proto_register_subtree_array(ett, array_length(ett));
3731
3732         register_dissector("wbxml", dissect_wbxml, proto_wbxml);
3733 };
3734
3735
3736 void
3737 proto_reg_handoff_wbxml(void)
3738 {
3739         dissector_handle_t wbxml_handle;
3740
3741         /* Heuristic dissectors would be declared by means of:
3742          * heur_dissector_add("wsp", dissect_wbxml_heur, proto_wbxml);
3743          */
3744
3745         wbxml_handle = create_dissector_handle(dissect_wbxml, proto_wbxml);
3746
3747         /* Register the WSP content types (defined as protocol port)
3748          * for WBXML dissection.
3749          * 
3750          * See http://www.wapforum.org/wina/wsp-content-type.htm
3751          * 
3752          * As the media types for WSP and HTTP are the same, the WSP dissector
3753          * uses the same string dissector table as the HTTP protocol.
3754          */
3755
3756         /**** Well-known WBXML WSP Content-Type values ****/
3757         
3758         dissector_add_string("media_type",
3759                         "application/vnd.wap.wmlc", wbxml_handle);
3760         dissector_add_string("media_type",
3761                         "application/vnd.wap.wta-eventc", wbxml_handle);
3762         dissector_add_string("media_type",
3763                         "application/vnd.wap.wbxml", wbxml_handle);
3764         dissector_add_string("media_type",
3765                         "application/vnd.wap.sic", wbxml_handle);
3766         dissector_add_string("media_type",
3767                         "application/vnd.wap.slc", wbxml_handle);
3768         dissector_add_string("media_type",
3769                         "application/vnd.wap.coc", wbxml_handle);
3770         dissector_add_string("media_type",
3771                         "application/vnd.wap.connectivity-wbxml", wbxml_handle);
3772         dissector_add_string("media_type",
3773                         "application/vnd.wap.locc+wbxml", wbxml_handle);
3774         dissector_add_string("media_type",
3775                         "application/vnd.syncml.dm+wbxml", wbxml_handle);
3776         dissector_add_string("media_type",
3777                         "application/vnd.oma.drm.rights+wbxml", wbxml_handle);
3778
3779         /**** Registered WBXML WSP Content-Type values ****/
3780
3781         dissector_add_string("media_type",
3782                         "application/vnd.uplanet.cacheop-wbxml", wbxml_handle);
3783         dissector_add_string("media_type",
3784                         "application/vnd.uplanet.alert-wbxml", wbxml_handle);
3785         dissector_add_string("media_type",
3786                         "application/vnd.uplanet.list-wbxml", wbxml_handle);
3787         dissector_add_string("media_type",
3788                         "application/vnd.uplanet.listcmd-wbxml", wbxml_handle);
3789         dissector_add_string("media_type",
3790                         "application/vnd.uplanet.channel-wbxml", wbxml_handle);
3791         dissector_add_string("media_type",
3792                         "application/vnd.uplanet.bearer-choice-wbxml", wbxml_handle);
3793         dissector_add_string("media_type",
3794                         "application/vnd.phonecom.mmc-wbxml", wbxml_handle);
3795         dissector_add_string("media_type",
3796                         "application/vnd.nokia.syncset+wbxml", wbxml_handle);
3797
3798         /***** Content types that only have a textual representation *****/
3799         dissector_add_string("media_type",
3800                         "application/x-wap-prov.browser-bookmarks", wbxml_handle);
3801         dissector_add_string("media_type",
3802                         "application/x-wap-prov.browser-settings", wbxml_handle);
3803         /* Same as application/vnd.nokia.syncset+wbxml */
3804         dissector_add_string("media_type",
3805                         "application/x-prov.syncset+wbxml", wbxml_handle);
3806         
3807 }