PageRenderTime 62ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 2ms

/epan/dissectors/packet-wbxml.c

https://github.com/labx-technologies-llc/wireshark
C | 8705 lines | 6865 code | 677 blank | 1163 comment | 394 complexity | 7de3a2300939154d1ec9467566c53d61 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /* packet-wbxml.c
  2. *
  3. * Routines for WAP Binary XML dissection
  4. * Copyright 2003, 2004, Olivier Biot.
  5. *
  6. * Routines for WV-CSP 1.3 dissection
  7. * Copyright 2007, Andrei Rubaniuk.
  8. *
  9. * $Id$
  10. *
  11. * Refer to the AUTHORS file or the AUTHORS section in the man page
  12. * for contacting the author(s) of this file.
  13. *
  14. * Wireshark - Network traffic analyzer
  15. * By Gerald Combs <gerald@wireshark.org>
  16. * Copyright 1998 Gerald Combs
  17. *
  18. * WAP Binary XML decoding functionality provided by Olivier Biot.
  19. * WV-CSP 1.2 updated to Release version and WV-CSP 1.3 protocol
  20. * decoding functionality provided by Andrei Rubaniuk.
  21. *
  22. * The WAP specifications used to be found at the WAP Forum:
  23. * <http://www.wapforum.org/what/Technical.htm>
  24. * But now the correct link is at the Open Mobile Alliance:
  25. * <http://www.openmobilealliance.org/tech/affiliates/wap/wapindex.html>
  26. * Media types defined by OMA affiliates will have their standards at:
  27. * <http://www.openmobilealliance.org/tech/affiliates/index.html>
  28. * <http://www.openmobilealliance.org/release_program/index.html>
  29. *
  30. * This program is free software; you can redistribute it and/or
  31. * modify it under the terms of the GNU General Public License
  32. * as published by the Free Software Foundation; either version 2
  33. * of the License, or (at your option) any later version.
  34. *
  35. * This program is distributed in the hope that it will be useful,
  36. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  37. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  38. * GNU General Public License for more details.
  39. *
  40. * You should have received a copy of the GNU General Public License
  41. * along with this program; if not, write to the Free Software
  42. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  43. */
  44. /* Edit this file with 4-space tabulation */
  45. #include "config.h"
  46. #include <string.h>
  47. #include <glib.h>
  48. #include <epan/packet.h>
  49. #include <epan/prefs.h>
  50. #include <epan/emem.h>
  51. /* We need the function tvb_get_guintvar() */
  52. #include "packet-wap.h"
  53. /* General-purpose debug logger.
  54. * Requires double parentheses because of variable arguments of printf().
  55. *
  56. * Enable debug logging for WBXML by defining AM_FLAGS
  57. * so that it contains "-DDEBUG_wbxml"
  58. */
  59. #ifdef DEBUG_wbxml
  60. #define DebugLog(x) \
  61. g_print("%s:%u: ", __FILE__, __LINE__); \
  62. g_print x
  63. #else
  64. #define DebugLog(x) ;
  65. #endif
  66. /* The code in this source file dissects the WAP Binary XML content,
  67. * and if possible renders it. WBXML mappings are defined in the
  68. * "wbxml_decoding" structure.
  69. *
  70. * NOTES:
  71. *
  72. * - Some WBXML content is *not* backwards compatible across minor versions.
  73. * This painful remark is true for:
  74. * o WMLC 1.0 with respect to later WMLC 1.x
  75. * o All WV-CSP versions (never backwards compatible)
  76. * The only way of correctly rendering the WBXML is to let the end-user
  77. * choose from the possible renderings. This only applies to the case when
  78. * the WBXML DocType is not included in the WBXML header (unknown/missing).
  79. *
  80. * - Some WBXML content uses EXT_T_* in a non-tableref manner. This is the
  81. * case with WV-CSP 1.1 and up, where the index points to a value_string
  82. * containing WV-CSP specific token values. This is allowed as it is not
  83. * explicitly forbidden in the WBXML specifications. Hence the global token
  84. * map for content must also contain a function pointer if no tableref
  85. * string is used.
  86. *
  87. * - Code page switches apply until a new code page switch. In the WBXML/1.x
  88. * ABNF notation, it can be proven that the switch_page can only precede
  89. * the following tokens:
  90. * o stag : TAG | LITERAL | LITERAL_A | LITERAL_C | LITERAL_AC
  91. * o attr : ATTRSTART | ATTRVALUE
  92. * o extension : EXT_I | EXT_T | EXT
  93. * Code page switches are displayed in a separate column.
  94. *
  95. * - The WBXML spec states that code pages are static to both the tag and the
  96. * attribute state parser. A SWITCH_PAGE within a state switches the code
  97. * page of the active state only. Note that code page 255 is reserved for
  98. * application-specific (read: testing) purposes.
  99. *
  100. * - In order to render the XML content, recursion is inevitable at some
  101. * point (when a tag with content occurs in the content of a tag with
  102. * content). The code will however not recurse if this is not strictly
  103. * required (e.g., tag without content in the content of a tag with
  104. * content).
  105. *
  106. * - I found it useful to display the XML nesting level as a first "column",
  107. * followed by the abbreviated WBXML token interpretation. When a mapping
  108. * is defined for the parsed WBXML content, then the XML rendering is
  109. * displayed with appropriate indentation (maximum nesting level = 255,
  110. * after which the nesting and level will safely roll-over to 0).
  111. *
  112. * - The WAP Forum defines the order of precedence for finding out the
  113. * WBXML content type (same rules for charset) as follows:
  114. * 1. Look in the Content-Type WSP header
  115. * 2. Look in the WBXML header
  116. * Currently there is no means of using content type parameters:
  117. * o Type=<some_type>
  118. * o Charset=<charset_of_the_content>
  119. * So it is possible some WBXML content types are incorrectly parsed.
  120. * This would only be the case when the content type declaration in the
  121. * WSP Content-Type header would be different (or would have parameters
  122. * which are relevant to the WBXML decoding) from the content type
  123. * identifier specified in the WBXML header. This has to do with the
  124. * decoding of terminated text strings in the different character codings.
  125. * TODO: investigate this and provide correct decoding at all times.
  126. */
  127. typedef struct _value_valuestring {
  128. guint32 value;
  129. const value_string *valstrptr;
  130. } value_valuestring;
  131. /* Tries to match val against each element in the value_value_string array vvs.
  132. * Returns the associated value_string ptr on a match, or NULL on failure. */
  133. static const value_string *
  134. val_to_valstr(guint32 val, const value_valuestring *vvs)
  135. {
  136. gint i = 0;
  137. while (vvs[i].valstrptr) {
  138. if (vvs[i].value == val)
  139. return(vvs[i].valstrptr);
  140. i++;
  141. }
  142. return(NULL);
  143. }
  144. /* Note on Token mapping
  145. * ---------------------
  146. *
  147. * The WBXML dissector will try mapping the token decoding to their textual
  148. * representation if the media type has a defined token representation. The
  149. * following logic applies:
  150. *
  151. * a. Inspect the WBXML PublicID
  152. * This means that I need a list { PublicID, decoding }
  153. *
  154. * b. Inspect the literal media type
  155. * This requires a list { "media/type", discriminator, { decodings } }
  156. *
  157. * b.1. Use a discriminator to choose an appropriate token mapping;
  158. * The disciminator needs a small number of bytes from the data tvbuff_t.
  159. *
  160. * else
  161. * b.2. Provide a list to the end-user with all possible token mappings.
  162. *
  163. * c. If none match then only show the tokens without mapping.
  164. *
  165. */
  166. /* ext_t_func_ptr is a pointer to a function handling the EXT_T_i tokens:
  167. *
  168. * char * ext_t_function(tvbuff_t *tvb, guint32 value, guint32 strtbl);
  169. */
  170. typedef char * (* ext_t_func_ptr)(tvbuff_t *, guint32, guint32);
  171. /* Note on parsing of OPAQUE data
  172. * ------------------------------
  173. *
  174. * The WBXML encapsulation allows the insertion of opaque binary data in the
  175. * WBXML body. Although this opaque data has no meaning in WBXML, the media
  176. * type itself may define compact encoding of given input by encoding it in
  177. * such a OPAQUE blob of bytes.
  178. *
  179. * The WBXML dissector now supports dissection of OPAQUE data by means of a
  180. * mapping function that will operate based on the token (well-known or literal)
  181. * and the active code page.
  182. *
  183. * For well-known tokens the simplest approach is to use a switch for the code
  184. * pages and another switch for the relevant tokens within a code page.
  185. *
  186. * For literal tokens (tags and attribute names), the only approach is a string
  187. * comparison with the literal representation of the given tag or attribute
  188. * name.
  189. *
  190. * opaque_token_func_ptr is a pointer to a function handling OPAQUE values
  191. * for binary tokens representing tags or attribute starts.
  192. * opaque_literal_func_ptr is a pointer to a function handling OPAQUE values
  193. * for literal tokens representing tags or attribute starts.
  194. *
  195. * The length field of the OPAQUE entry starts at offset (not offset + 1).
  196. *
  197. * The length of the processed OPAQUE value is returned by reference.
  198. *
  199. * char * opaque_token_function(tvbuff_t *tvb, guint32 offset,
  200. * guint8 token, guint8 codepage, guint32 *length);
  201. * char * opaque_literal_function(tvbuff_t *tvb, guint32 offset,
  202. * const char *token, guint8 codepage, guint32 *length);
  203. */
  204. typedef char * (* opaque_token_func_ptr)(tvbuff_t *, guint32, guint8, guint8, guint32 *);
  205. typedef char * (* opaque_literal_func_ptr)(tvbuff_t *, guint32, const char *, guint8, guint32 *);
  206. static char *
  207. default_opaque_binary_tag(tvbuff_t *tvb, guint32 offset,
  208. guint8 token _U_, guint8 codepage _U_, guint32 *length)
  209. {
  210. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  211. char *str = ep_strdup_printf("(%d bytes of opaque data)", data_len);
  212. *length += data_len;
  213. return str;
  214. }
  215. static char *
  216. default_opaque_literal_tag(tvbuff_t *tvb, guint32 offset,
  217. const char *token _U_, guint8 codepage _U_, guint32 *length)
  218. {
  219. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  220. char *str = ep_strdup_printf("(%d bytes of opaque data)", data_len);
  221. *length += data_len;
  222. return str;
  223. }
  224. static char *
  225. default_opaque_binary_attr(tvbuff_t *tvb, guint32 offset,
  226. guint8 token _U_, guint8 codepage _U_, guint32 *length)
  227. {
  228. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  229. char *str = ep_strdup_printf("(%d bytes of opaque data)", data_len);
  230. *length += data_len;
  231. return str;
  232. }
  233. static char *
  234. default_opaque_literal_attr(tvbuff_t *tvb, guint32 offset,
  235. const char *token _U_, guint8 codepage _U_, guint32 *length)
  236. {
  237. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  238. char *str = ep_strdup_printf("(%d bytes of opaque data)", data_len);
  239. *length += data_len;
  240. return str;
  241. }
  242. /* Render a hex %dateTime encoded timestamp as a string.
  243. * 0x20011231123456 becomes "2001-12-31T12:34:56Z" */
  244. static char *
  245. date_time_from_opaque(tvbuff_t *tvb, guint32 offset, guint32 data_len)
  246. {
  247. char *str;
  248. switch (data_len) {
  249. case 4: /* YYYY-MM-DD[T00:00:00Z] */
  250. str = ep_strdup_printf("%%DateTime: "
  251. "%02x%02x-%02x-%02xT00:00:00Z",
  252. tvb_get_guint8(tvb, offset),
  253. tvb_get_guint8(tvb, offset + 1),
  254. tvb_get_guint8(tvb, offset + 2),
  255. tvb_get_guint8(tvb, offset + 3));
  256. break;
  257. case 5: /* YYYY-MM-DDThh[:00:00Z] */
  258. str = ep_strdup_printf("%%DateTime: "
  259. "%02x%02x-%02x-%02xT%02x:00:00Z",
  260. tvb_get_guint8(tvb, offset),
  261. tvb_get_guint8(tvb, offset + 1),
  262. tvb_get_guint8(tvb, offset + 2),
  263. tvb_get_guint8(tvb, offset + 3),
  264. tvb_get_guint8(tvb, offset + 4));
  265. break;
  266. case 6: /* YYYY-MM-DDThh:mm[:00Z] */
  267. str = ep_strdup_printf("%%DateTime: "
  268. "%02x%02x-%02x-%02xT%02x:%02x:00Z",
  269. tvb_get_guint8(tvb, offset),
  270. tvb_get_guint8(tvb, offset + 1),
  271. tvb_get_guint8(tvb, offset + 2),
  272. tvb_get_guint8(tvb, offset + 3),
  273. tvb_get_guint8(tvb, offset + 4),
  274. tvb_get_guint8(tvb, offset + 5));
  275. break;
  276. case 7: /* YYYY-MM-DDThh:mm[:00Z] */
  277. str = ep_strdup_printf("%%DateTime: "
  278. "%02x%02x-%02x-%02xT%02x:%02x:%02xZ",
  279. tvb_get_guint8(tvb, offset),
  280. tvb_get_guint8(tvb, offset + 1),
  281. tvb_get_guint8(tvb, offset + 2),
  282. tvb_get_guint8(tvb, offset + 3),
  283. tvb_get_guint8(tvb, offset + 4),
  284. tvb_get_guint8(tvb, offset + 5),
  285. tvb_get_guint8(tvb, offset + 6));
  286. break;
  287. default:
  288. str = ep_strdup_printf("<Error: invalid binary %%DateTime "
  289. "(%d bytes of opaque data)>", data_len);
  290. break;
  291. }
  292. return str;
  293. }
  294. /* Is ALWAYS 6 bytes long:
  295. * 00YY YYYY YYYY YYMM MMDD DDDh hhhh mmmm mmss ssss ZZZZ ZZZZ */
  296. static char *
  297. wv_datetime_from_opaque(tvbuff_t *tvb, guint32 offset, guint32 data_len)
  298. {
  299. char *str;
  300. guint16 year;
  301. guint8 month, day, hour, minute, second, time_zone;
  302. guint8 peek;
  303. if (data_len == 6) { /* Valid */
  304. /* Octet 1: 00YY YYYY */
  305. year = tvb_get_guint8(tvb, offset) & 0x3F; /* ..11 1111 */
  306. year <<=6;
  307. /* Octet 2: YYYY YYMM */
  308. peek = tvb_get_guint8(tvb, offset + 1);
  309. year += (peek >> 2); /* 1111 11.. */
  310. month = (peek & 0x03) << 2; /* .... ..11 */
  311. /* Octet 3: MMDD DDDh */
  312. peek = tvb_get_guint8(tvb, offset + 2);
  313. month += (peek >> 6); /* 11.. .... */
  314. day = (peek & 0x3E) >> 1; /* ..11 111. */
  315. hour = (peek & 0x01) << 4; /* .... ...1 */
  316. /* Octet 4: hhhh mmmm */
  317. peek = tvb_get_guint8(tvb, offset + 3);
  318. hour += (peek >> 4);
  319. minute = (peek & 0x0F) << 2; /* .... 1111 */
  320. /* Octet 5: mmss ssss */
  321. peek = tvb_get_guint8(tvb, offset + 4);
  322. minute += (peek >> 6); /* 11.. .... */
  323. second = peek & 0x3F; /* ..11 1111 */
  324. /* octet 6: ZZZZZZZZ */
  325. time_zone = tvb_get_guint8(tvb, offset + 5);
  326. /* Now construct the string */
  327. str = ep_strdup_printf("WV-CSP DateTime: "
  328. "%04d-%02d-%02dT%02d:%02d:%02d%c",
  329. year, month, day, hour, minute, second, time_zone);
  330. } else { /* Invalid length for a WV-CSP DateTime tag value */
  331. str = ep_strdup_printf("<Error: invalid binary WV-CSP DateTime value "
  332. "(%d bytes of opaque data)>", data_len);
  333. }
  334. return str;
  335. }
  336. /* WV-CSP integer values for tag content is encoded in a fashion similar
  337. * to a Long-Integer in WSP */
  338. static char *
  339. wv_integer_from_opaque(tvbuff_t *tvb, guint32 offset, guint32 data_len)
  340. {
  341. char *str;
  342. switch (data_len) {
  343. case 1:
  344. str = ep_strdup_printf("WV-CSP Integer: %d",
  345. tvb_get_guint8(tvb, offset));
  346. break;
  347. case 2:
  348. str = ep_strdup_printf("WV-CSP Integer: %d",
  349. tvb_get_ntohs(tvb, offset));
  350. break;
  351. case 3:
  352. str = ep_strdup_printf("WV-CSP Integer: %d",
  353. tvb_get_ntoh24(tvb, offset));
  354. break;
  355. case 4:
  356. str = ep_strdup_printf("WV-CSP Integer: %d",
  357. tvb_get_ntohl(tvb, offset));
  358. break;
  359. default:
  360. str = ep_strdup_printf("<Error: invalid binary WV-CSP Integer value "
  361. "(%d bytes of opaque data)>", data_len);
  362. break;
  363. }
  364. return str;
  365. }
  366. static char *
  367. wv_csp10_opaque_binary_tag(tvbuff_t *tvb, guint32 offset,
  368. guint8 token, guint8 codepage, guint32 *length)
  369. {
  370. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  371. char *str = NULL;
  372. switch (codepage) {
  373. case 0: /* Common code page */
  374. switch (token) {
  375. case 0x0B: /* <Code> */
  376. case 0x0F: /* <ContentSize> */
  377. case 0x1A: /* <MessageCount> */
  378. case 0x3C: /* <Validity> */
  379. str = wv_integer_from_opaque(tvb,
  380. offset + *length, data_len);
  381. break;
  382. case 0x11: /* <DateTime> */
  383. str = wv_datetime_from_opaque(tvb,
  384. offset + *length, data_len);
  385. break;
  386. default:
  387. break;
  388. }
  389. break;
  390. case 1: /* Access code page */
  391. switch (token) {
  392. case 0x1C: /* <KeepAliveTime> */
  393. case 0x32: /* <TimeToLive> */
  394. str = wv_integer_from_opaque(tvb,
  395. offset + *length, data_len);
  396. break;
  397. default:
  398. break;
  399. }
  400. break;
  401. case 3: /* Client capability code page */
  402. switch (token) {
  403. case 0x06: /* <AcceptedContentLength> */
  404. case 0x0C: /* <MultiTrans> */
  405. case 0x0D: /* <ParserSize> */
  406. case 0x0E: /* <ServerPollMin> */
  407. case 0x11: /* <TCPAddress> */
  408. case 0x12: /* <TCPPort> */
  409. case 0x13: /* <UDPPort> */
  410. str = wv_integer_from_opaque(tvb,
  411. offset + *length, data_len);
  412. break;
  413. default:
  414. break;
  415. }
  416. break;
  417. default:
  418. break;
  419. }
  420. if (str == NULL) { /* Error, or not parsed */
  421. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  422. }
  423. *length += data_len;
  424. return str;
  425. }
  426. static char *
  427. wv_csp10_opaque_literal_tag(tvbuff_t *tvb, guint32 offset,
  428. const char *token, guint8 codepage _U_, guint32 *length)
  429. {
  430. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  431. char *str = NULL;
  432. if ( token && ( (strcmp(token, "Code") == 0)
  433. || (strcmp(token, "ContentSize") == 0)
  434. || (strcmp(token, "MessageCount") == 0)
  435. || (strcmp(token, "Validity") == 0)
  436. || (strcmp(token, "KeepAliveTime") == 0)
  437. || (strcmp(token, "TimeToLive") == 0)
  438. || (strcmp(token, "AcceptedContentLength") == 0)
  439. || (strcmp(token, "MultiTrans") == 0)
  440. || (strcmp(token, "ParserSize") == 0)
  441. || (strcmp(token, "ServerPollMin") == 0)
  442. || (strcmp(token, "TCPAddress") == 0)
  443. || (strcmp(token, "TCPPort") == 0)
  444. || (strcmp(token, "UDPPort") == 0) ) )
  445. {
  446. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  447. }
  448. else if ( token && ( strcmp(token, "DateTime") == 0) )
  449. {
  450. str = wv_datetime_from_opaque(tvb, offset + *length, data_len);
  451. }
  452. if (str == NULL) { /* Error, or not parsed */
  453. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  454. }
  455. *length += data_len;
  456. return str;
  457. }
  458. static char *
  459. wv_csp11_opaque_binary_tag(tvbuff_t *tvb, guint32 offset,
  460. guint8 token, guint8 codepage, guint32 *length)
  461. {
  462. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  463. char *str = NULL;
  464. switch (codepage) {
  465. case 0: /* Common code page */
  466. switch (token) {
  467. case 0x0B: /* <Code> */
  468. case 0x0F: /* <ContentSize> */
  469. case 0x1A: /* <MessageCount> */
  470. case 0x3C: /* <Validity> */
  471. str = wv_integer_from_opaque(tvb,
  472. offset + *length, data_len);
  473. break;
  474. case 0x11: /* <DateTime> */
  475. str = wv_datetime_from_opaque(tvb,
  476. offset + *length, data_len);
  477. break;
  478. default:
  479. break;
  480. }
  481. break;
  482. case 1: /* Access code page */
  483. switch (token) {
  484. case 0x1C: /* <KeepAliveTime> */
  485. case 0x32: /* <TimeToLive> */
  486. str = wv_integer_from_opaque(tvb,
  487. offset + *length, data_len);
  488. break;
  489. default:
  490. break;
  491. }
  492. break;
  493. case 3: /* Client capability code page */
  494. switch (token) {
  495. case 0x06: /* <AcceptedContentLength> */
  496. case 0x0C: /* <MultiTrans> */
  497. case 0x0D: /* <ParserSize> */
  498. case 0x0E: /* <ServerPollMin> */
  499. case 0x12: /* <TCPPort> */
  500. case 0x13: /* <UDPPort> */
  501. str = wv_integer_from_opaque(tvb,
  502. offset + *length, data_len);
  503. break;
  504. default:
  505. break;
  506. }
  507. break;
  508. case 6: /* Messaging code page */
  509. switch (token) {
  510. case 0x1A: /* <DeliveryTime> - not in 1.0 */
  511. str = wv_datetime_from_opaque(tvb,
  512. offset + *length, data_len);
  513. break;
  514. default:
  515. break;
  516. }
  517. break;
  518. default:
  519. break;
  520. }
  521. if (str == NULL) { /* Error, or not parsed */
  522. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  523. }
  524. *length += data_len;
  525. return str;
  526. }
  527. static char *
  528. wv_csp11_opaque_literal_tag(tvbuff_t *tvb, guint32 offset,
  529. const char *token, guint8 codepage _U_, guint32 *length)
  530. {
  531. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  532. char *str = NULL;
  533. if ( token && ( (strcmp(token, "Code") == 0)
  534. || (strcmp(token, "ContentSize") == 0)
  535. || (strcmp(token, "MessageCount") == 0)
  536. || (strcmp(token, "Validity") == 0)
  537. || (strcmp(token, "KeepAliveTime") == 0)
  538. || (strcmp(token, "TimeToLive") == 0)
  539. || (strcmp(token, "AcceptedContentLength") == 0)
  540. || (strcmp(token, "MultiTrans") == 0)
  541. || (strcmp(token, "ParserSize") == 0)
  542. || (strcmp(token, "ServerPollMin") == 0)
  543. || (strcmp(token, "TCPPort") == 0)
  544. || (strcmp(token, "UDPPort") == 0) ) )
  545. {
  546. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  547. }
  548. else
  549. if ( token && ( (strcmp(token, "DateTime") == 0)
  550. || (strcmp(token, "DeliveryTime") == 0) ) )
  551. {
  552. str = wv_datetime_from_opaque(tvb, offset + *length, data_len);
  553. }
  554. if (str == NULL) { /* Error, or not parsed */
  555. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  556. }
  557. *length += data_len;
  558. return str;
  559. }
  560. static char *
  561. wv_csp12_opaque_binary_tag(tvbuff_t *tvb, guint32 offset,
  562. guint8 token, guint8 codepage, guint32 *length)
  563. {
  564. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  565. char *str = NULL;
  566. switch (codepage) {
  567. case 0: /* Common code page */
  568. switch (token) {
  569. case 0x0B: /* <Code> */
  570. case 0x0F: /* <ContentSize> */
  571. case 0x1A: /* <MessageCount> */
  572. case 0x3C: /* <Validity> */
  573. str = wv_integer_from_opaque(tvb,
  574. offset + *length, data_len);
  575. break;
  576. case 0x11: /* <DateTime> */
  577. str = wv_datetime_from_opaque(tvb,
  578. offset + *length, data_len);
  579. break;
  580. default:
  581. break;
  582. }
  583. break;
  584. case 1: /* Access code page */
  585. switch (token) {
  586. case 0x1C: /* <KeepAliveTime> */
  587. case 0x32: /* <TimeToLive> */
  588. str = wv_integer_from_opaque(tvb,
  589. offset + *length, data_len);
  590. break;
  591. default:
  592. break;
  593. }
  594. break;
  595. case 3: /* Client capability code page */
  596. switch (token) {
  597. case 0x06: /* <AcceptedContentLength> */
  598. case 0x0C: /* <MultiTrans> */
  599. case 0x0D: /* <ParserSize> */
  600. case 0x0E: /* <ServerPollMin> */
  601. case 0x12: /* <TCPPort> */
  602. case 0x13: /* <UDPPort> */
  603. str = wv_integer_from_opaque(tvb,
  604. offset + *length, data_len);
  605. break;
  606. default:
  607. break;
  608. }
  609. break;
  610. case 6: /* Messaging code page */
  611. switch (token) {
  612. case 0x1A: /* <DeliveryTime> - not in 1.0 */
  613. str = wv_datetime_from_opaque(tvb,
  614. offset + *length, data_len);
  615. break;
  616. default:
  617. break;
  618. }
  619. break;
  620. case 9: /* Common code page (continued) */
  621. switch (token) {
  622. case 0x08: /* <HistoryPeriod> - 1.2 only */
  623. case 0x0A: /* <MaxWatcherList> - 1.2 only */
  624. str = wv_integer_from_opaque(tvb,
  625. offset + *length, data_len);
  626. break;
  627. default:
  628. break;
  629. }
  630. break;
  631. default:
  632. break;
  633. }
  634. if (str == NULL) { /* Error, or not parsed */
  635. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  636. }
  637. *length += data_len;
  638. return str;
  639. }
  640. static char *
  641. wv_csp12_opaque_literal_tag(tvbuff_t *tvb, guint32 offset,
  642. const char *token, guint8 codepage _U_, guint32 *length)
  643. {
  644. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  645. char *str = NULL;
  646. if ( token && ( (strcmp(token, "Code") == 0)
  647. || (strcmp(token, "ContentSize") == 0)
  648. || (strcmp(token, "MessageCount") == 0)
  649. || (strcmp(token, "Validity") == 0)
  650. || (strcmp(token, "KeepAliveTime") == 0)
  651. || (strcmp(token, "TimeToLive") == 0)
  652. || (strcmp(token, "AcceptedContentLength") == 0)
  653. || (strcmp(token, "MultiTrans") == 0)
  654. || (strcmp(token, "ParserSize") == 0)
  655. || (strcmp(token, "ServerPollMin") == 0)
  656. || (strcmp(token, "TCPPort") == 0)
  657. || (strcmp(token, "UDPPort") == 0)
  658. || (strcmp(token, "HistoryPeriod") == 0)
  659. || (strcmp(token, "MaxWatcherList") == 0) ) )
  660. {
  661. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  662. }
  663. else
  664. if ( token && ( (strcmp(token, "DateTime") == 0)
  665. || (strcmp(token, "DeliveryTime") == 0) ) )
  666. {
  667. str = wv_datetime_from_opaque(tvb, offset + *length, data_len);
  668. }
  669. if (str == NULL) { /* Error, or not parsed */
  670. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  671. }
  672. *length += data_len;
  673. return str;
  674. }
  675. static char *
  676. wv_csp13_opaque_binary_tag(tvbuff_t *tvb, guint32 offset,
  677. guint8 token, guint8 codepage, guint32 *length)
  678. {
  679. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  680. char *str = NULL;
  681. switch (codepage)
  682. {
  683. case 0: /* Common code page */
  684. switch (token)
  685. {
  686. case 0x0B: /* <Code> */
  687. case 0x0F: /* <ContentSize> */
  688. case 0x1A: /* <MessageCount> */
  689. case 0x3C: /* <Validity> */
  690. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  691. break;
  692. case 0x11: /* <DateTime> */
  693. str = wv_datetime_from_opaque(tvb, offset + *length, data_len);
  694. break;
  695. default:
  696. break;
  697. }
  698. break;
  699. case 1: /* Access code page */
  700. switch (token)
  701. {
  702. case 0x1C: /* <KeepAliveTime> */
  703. case 0x25: /* <SearchFindings> */
  704. case 0x26: /* <SearchID> */
  705. case 0x27: /* <SearchIndex> */
  706. case 0x28: /* <SearchLimit> */
  707. case 0x32: /* <TimeToLive> */
  708. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  709. break;
  710. default:
  711. break;
  712. }
  713. break;
  714. case 3: /* Client capability code page */
  715. switch (token)
  716. {
  717. case 0x06: /* <AcceptedContentLength> */
  718. case 0x0C: /* <MultiTrans> */
  719. case 0x0D: /* <ParserSize> */
  720. case 0x0E: /* <ServerPollMin> */
  721. case 0x12: /* <TCPPort> */
  722. case 0x13: /* <UDPPort> */
  723. /* New in WV-CSP 1.3*/
  724. case 0x16: /* <AcceptedPullLength> */
  725. case 0x17: /* <AcceptedPushLength> */
  726. case 0x18: /* <AcceptedRichContentLength> */
  727. case 0x19: /* <AcceptedTextContentLength> */
  728. case 0x1B: /* <PlainTextCharset> MIBenum number - character set, i.e. UTF-8, windows-1251, etc. */
  729. case 0x1C: /* <SessionPriority> */
  730. case 0x1F: /* <UserSessionLimit> */
  731. case 0x21: /* <MultiTransPerMessage> */
  732. case 0x24: /* <ContentPolicyLimit> */
  733. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  734. break;
  735. default:
  736. break;
  737. }
  738. break;
  739. case 5: /* Presence attribute code page */
  740. switch (token)
  741. {
  742. /* New in WV-CSP 1.3*/
  743. /* case 0x3B: */ /* <ClientContentLimit> */
  744. case 0x3C: /* <ClientIMPriority> */
  745. case 0x3D: /* <MaxPullLength> */
  746. case 0x3E: /* <MaxPushLength> */
  747. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  748. break;
  749. default:
  750. break;
  751. }
  752. break;
  753. case 6: /* Messaging code page */
  754. switch (token)
  755. {
  756. case 0x1A: /* <DeliveryTime> - not in 1.0 */
  757. /* New in WV-CSP 1.3*/
  758. case 0x1C: /* <AnswerOptionID> */
  759. str = wv_datetime_from_opaque(tvb, offset + *length, data_len);
  760. break;
  761. default:
  762. break;
  763. }
  764. break;
  765. case 9: /* Common code page (continued) */
  766. switch (token)
  767. {
  768. case 0x08: /* <HistoryPeriod> - 1.2 only */
  769. case 0x0A: /* <MaxWatcherList> - 1.2 only */
  770. /* New in WV-CSP 1.3*/
  771. case 0x25: /* <SegmentCount> */
  772. case 0x28: /* <SegmentReference> */
  773. case 0x30: /* <TryAgainTimeout> */
  774. case 0x3A: /* <GroupContentLimit> */
  775. case 0x3B: /* <MessageTotalCount> */
  776. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  777. break;
  778. default:
  779. break;
  780. }
  781. break;
  782. case 10:
  783. switch (token)
  784. {
  785. /* New in WV-CSP 1.3*/
  786. case 0x0C: /* <PairID> */
  787. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  788. break;
  789. default:
  790. break;
  791. }
  792. break;
  793. default:
  794. break;
  795. }
  796. if (str == NULL)
  797. { /* Error, or not parsed */
  798. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  799. }
  800. *length += data_len;
  801. return str;
  802. }
  803. static char *
  804. wv_csp13_opaque_literal_tag(tvbuff_t *tvb, guint32 offset,
  805. const char *token, guint8 codepage _U_, guint32 *length)
  806. {
  807. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  808. char *str = NULL;
  809. if ( token && ( (strcmp(token, "Code") == 0)
  810. || (strcmp(token, "ContentSize") == 0)
  811. || (strcmp(token, "MessageCount") == 0)
  812. || (strcmp(token, "Validity") == 0)
  813. || (strcmp(token, "KeepAliveTime") == 0)
  814. || (strcmp(token, "TimeToLive") == 0)
  815. || (strcmp(token, "AcceptedContentLength") == 0)
  816. || (strcmp(token, "MultiTrans") == 0)
  817. || (strcmp(token, "ParserSize") == 0)
  818. || (strcmp(token, "ServerPollMin") == 0)
  819. || (strcmp(token, "TCPPort") == 0)
  820. || (strcmp(token, "UDPPort") == 0)
  821. || (strcmp(token, "HistoryPeriod") == 0)
  822. || (strcmp(token, "MaxWatcherList") == 0)
  823. /* New in WV-CSP 1.3*/
  824. || (strcmp(token, "SearchFindings") == 0)
  825. || (strcmp(token, "SearchID") == 0)
  826. || (strcmp(token, "SearchIndex") == 0)
  827. || (strcmp(token, "SearchLimit") == 0)
  828. || (strcmp(token, "AcceptedPullLength") == 0)
  829. || (strcmp(token, "AcceptedPushLength") == 0)
  830. || (strcmp(token, "AcceptedRichContentLength") == 0)
  831. || (strcmp(token, "AcceptedTextContentLength") == 0)
  832. || (strcmp(token, "SessionPriority") == 0)
  833. || (strcmp(token, "UserSessionLimit") == 0)
  834. || (strcmp(token, "MultiTransPerMessage") == 0)
  835. || (strcmp(token, "ContentPolicyLimit") == 0)
  836. || (strcmp(token, "AnswerOptionID") == 0)
  837. || (strcmp(token, "SegmentCount") == 0)
  838. || (strcmp(token, "SegmentReference") == 0)
  839. || (strcmp(token, "TryAgainTimeout") == 0)
  840. || (strcmp(token, "GroupContentLimit") == 0)
  841. || (strcmp(token, "MessageTotalCount") == 0)
  842. || (strcmp(token, "PairID") == 0) ) )
  843. {
  844. str = wv_integer_from_opaque(tvb, offset + *length, data_len);
  845. }
  846. else
  847. if ( token && ( (strcmp(token, "DateTime") == 0)
  848. || (strcmp(token, "DeliveryTime") == 0) ) )
  849. {
  850. str = wv_datetime_from_opaque(tvb, offset + *length, data_len);
  851. }
  852. if (str == NULL) { /* Error, or not parsed */
  853. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  854. }
  855. *length += data_len;
  856. return str;
  857. }
  858. static char *
  859. sic10_opaque_literal_attr(tvbuff_t *tvb, guint32 offset,
  860. const char *token, guint8 codepage _U_, guint32 *length)
  861. {
  862. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  863. char *str = NULL;
  864. if ( token && ( (strcmp(token, "created") == 0)
  865. || (strcmp(token, "si-expires") == 0) ) )
  866. {
  867. str = date_time_from_opaque(tvb, offset + *length, data_len);
  868. }
  869. if (str == NULL) { /* Error, or not parsed */
  870. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  871. }
  872. *length += data_len;
  873. return str;
  874. }
  875. static char *
  876. sic10_opaque_binary_attr(tvbuff_t *tvb, guint32 offset,
  877. guint8 token, guint8 codepage, guint32 *length)
  878. {
  879. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  880. char *str = NULL;
  881. switch (codepage) {
  882. case 0: /* Only valid codepage for SI */
  883. switch (token) {
  884. case 0x0A: /* created= */
  885. case 0x10: /* si-expires= */
  886. str = date_time_from_opaque(tvb,
  887. offset + *length, data_len);
  888. break;
  889. default:
  890. break;
  891. }
  892. break;
  893. default:
  894. break;
  895. }
  896. if (str == NULL) { /* Error, or not parsed */
  897. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  898. }
  899. *length += data_len;
  900. return str;
  901. }
  902. static char *
  903. emnc10_opaque_literal_attr(tvbuff_t *tvb, guint32 offset,
  904. const char *token, guint8 codepage _U_, guint32 *length)
  905. {
  906. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  907. char *str = NULL;
  908. if ( token && (strcmp(token, "timestamp") == 0) )
  909. {
  910. str = date_time_from_opaque(tvb, offset + *length, data_len);
  911. }
  912. if (str == NULL) { /* Error, or not parsed */
  913. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  914. }
  915. *length += data_len;
  916. return str;
  917. }
  918. static char *
  919. emnc10_opaque_binary_attr(tvbuff_t *tvb, guint32 offset,
  920. guint8 token, guint8 codepage, guint32 *length)
  921. {
  922. guint32 data_len = tvb_get_guintvar(tvb, offset, length);
  923. char *str = NULL;
  924. switch (codepage) {
  925. case 0: /* Only valid codepage for EMN */
  926. switch (token) {
  927. case 0x05: /* timestamp= */
  928. str = date_time_from_opaque(tvb,
  929. offset + *length, data_len);
  930. break;
  931. default:
  932. break;
  933. }
  934. break;
  935. default:
  936. break;
  937. }
  938. if (str == NULL) { /* Error, or not parsed */
  939. str = ep_strdup_printf("(%d bytes of unparsed opaque data)", data_len);
  940. }
  941. *length += data_len;
  942. return str;
  943. }
  944. typedef struct _wbxml_decoding {
  945. const char *name;
  946. const char *abbrev;
  947. ext_t_func_ptr ext_t[3];
  948. opaque_token_func_ptr opaque_binary_tag;
  949. opaque_literal_func_ptr opaque_literal_tag;
  950. opaque_token_func_ptr opaque_binary_attr;
  951. opaque_literal_func_ptr opaque_literal_attr;
  952. const value_valuestring *global;
  953. const value_valuestring *tags;
  954. const value_valuestring *attrStart;
  955. const value_valuestring *attrValue;
  956. } wbxml_decoding;
  957. /* Define a pointer to a discriminator function taking a tvb and the start
  958. * offset of the WBXML tokens in the body as arguments.
  959. */
  960. typedef const wbxml_decoding * (* discriminator_func_ptr)(tvbuff_t *, guint32);
  961. /* For the decoding lists based on the known WBXML public ID */
  962. typedef struct _wbxml_integer_list {
  963. guint32 public_id;
  964. const wbxml_decoding *map;
  965. } wbxml_integer_list;
  966. /* For the decoding lists on the literal content type */
  967. typedef struct _wbxml_literal_list {
  968. const char *content_type;
  969. discriminator_func_ptr discriminator; /* TODO */
  970. const wbxml_decoding *map;
  971. } wbxml_literal_list;
  972. /************************** Variable declarations **************************/
  973. /* Initialize the protocol and registered fields */
  974. static int proto_wbxml = -1;
  975. static int hf_wbxml_version = -1;
  976. static int hf_wbxml_public_id_known = -1;
  977. static int hf_wbxml_public_id_literal = -1;
  978. static int hf_wbxml_charset = -1;
  979. /* Initialize the subtree pointers */
  980. static gint ett_wbxml = -1;
  981. static gint ett_wbxml_str_tbl = -1;
  982. static gint ett_wbxml_content = -1;
  983. /* WBXML Preferences */
  984. static gboolean skip_wbxml_token_mapping = FALSE;
  985. static gboolean disable_wbxml_token_parsing = FALSE;
  986. /**************** WBXML related declarations and definitions ****************/
  987. /* WBXML public ID mappings. For an up-to-date list, see
  988. * http://www.openmobilealliance.org/tech/omna/ */
  989. static const value_string vals_wbxml_public_ids[] = {
  990. /* 0x00 = literal public identifier */
  991. { 0x01, "Unknown or missing Public Identifier" },
  992. { 0x02, "-//WAPFORUM//DTD WML 1.0//EN (WML 1.0)" },
  993. { 0x03, "-//WAPFORUM//DTD WTA 1.0//EN (WTA Event 1.0) - Deprecated" },
  994. { 0x04, "-//WAPFORUM//DTD WML 1.1//EN (WML 1.1)" },
  995. { 0x05, "-//WAPFORUM//DTD SI 1.0//EN (Service Indication 1.0)" },
  996. { 0x06, "-//WAPFORUM//DTD SL 1.0//EN (Service Loading 1.0)" },
  997. { 0x07, "-//WAPFORUM//DTD CO 1.0//EN (Cache Operation 1.0)" },
  998. { 0x08, "-//WAPFORUM//DTD CHANNEL 1.1//EN (Channel 1.1)" },
  999. { 0x09, "-//WAPFORUM//DTD WML 1.2//EN (WML 1.2)" },
  1000. { 0x0a, "-//WAPFORUM//DTD WML 1.3//EN (WML 1.3)" },
  1001. { 0x0b, "-//WAPFORUM//DTD PROV 1.0//EN (Provisioning 1.0)" },
  1002. { 0x0c, "-//WAPFORUM//DTD WTA-WML 1.2//EN (WTA-WML 1.2)" },
  1003. { 0x0d, "-//WAPFORUM//DTD EMN 1.0//EN (Email Notification 1.0)" },
  1004. { 0x0e, "-//WAPFORUM//DTD DRMREL 1.0//EN (DRMREL 1.0)" },
  1005. { 0x0f, "-//WIRELESSVILLAGE//DTD CSP 1.0//EN"
  1006. " (Wireless Village Client-Server Protocol DTD v1.0)" },
  1007. { 0x10, "-//WIRELESSVILLAGE//DTD CSP 1.1//EN"
  1008. " (Wireless Village Client-Server Protocol DTD v1.1)" },
  1009. { 0x11, "-//OMA//DTD WV-CSP 1.2//EN (OMA IMPS - CSP protocol DTD v1.2)" },
  1010. { 0x12, "-//OMA//DTD IMPS-CSP 1.3//EN (OMA IMPS - CSP protocol DTD v1.3)" },
  1011. { 0x13, "-//OMA//DRM 2.1//EN (OMA DRM 2.1)" },
  1012. /* 0x14 -- 0x7F: reserved */
  1013. /* Registered values - www.syncml.org */
  1014. { 0x0fd1, "-//SYNCML//DTD SyncML 1.0//EN (SyncML 1.0)" },
  1015. { 0x0fd3, "-//SYNCML//DTD SyncML 1.1//EN (SyncML 1.1)" },
  1016. /* Registered values - www.wapforum.org/wina/ */
  1017. { 0x1100, "-//PHONE.COM//DTD ALERT 1.0//EN" },
  1018. { 0x1101, "-//PHONE.COM//DTD CACHE-OPERATION 1.0//EN" },
  1019. { 0x1102, "-//PHONE.COM//DTD SIGNAL 1.0//EN" },
  1020. { 0x1103, "-//PHONE.COM//DTD LIST 1.0//EN" },
  1021. { 0x1104, "-//PHONE.COM//DTD LISTCMD 1.0//EN" },
  1022. { 0x1105, "-//PHONE.COM//DTD CHANNEL 1.0//EN" },
  1023. { 0x1106, "-//PHONE.COM//DTD MMC 1.0//EN" },
  1024. { 0x1107, "-//PHONE.COM//DTD BEARER-CHOICE 1.0//EN" },
  1025. { 0x1108, "-//PHONE.COM//DTD WML 1.1//EN (WML+ 1.1)" },
  1026. { 0x1109, "-//PHONE.COM//DTD CHANNEL 1.1//EN" },
  1027. { 0x110a, "-//PHONE.COM//DTD LIST 1.1//EN" },
  1028. { 0x110b, "-//PHONE.COM//DTD LISTCMD 1.1//EN" },
  1029. { 0x110c, "-//PHONE.COM//DTD MMC 1.1//EN" },
  1030. { 0x110d, "-//PHONE.COM//DTD WML 1.3//EN (WML+ 1.3)" },
  1031. { 0x110e, "-//PHONE.COM//DTD MMC 2.0//EN" },
  1032. /* 0x110F -- 0x11FF: unassigned */
  1033. { 0x1200, "-//3GPP2.COM//DTD IOTA 1.0//EN" },
  1034. { 0x1201, "-//SYNCML//DTD SyncML 1.2//EN" },
  1035. { 0x1202, "-//SYNCML//DTD MetaInf 1.2//EN" },
  1036. { 0x1203, "-//SYNCML//DTD DevInf 1.2//EN" },
  1037. { 0x1204, "-//NOKIA//DTD LANDMARKS 1.0//EN" },
  1038. { 0x00, NULL }
  1039. };
  1040. static value_string_ext vals_wbxml_public_ids_ext = VALUE_STRING_EXT_INIT(vals_wbxml_public_ids);
  1041. static const value_string vals_wbxml_versions[] = {
  1042. { 0x00, "1.0" }, /* WAP-104-WBXML */
  1043. { 0x01, "1.1" }, /* WAP-135-WBXML */
  1044. { 0x02, "1.2" }, /* WAP-154-WBXML */
  1045. { 0x03, "1.3" }, /* WAP-192-WBXML */
  1046. { 0x00, NULL }
  1047. };
  1048. static value_string_ext vals_wbxml_versions_ext = VALUE_STRING_EXT_INIT(vals_wbxml_versions);
  1049. /* WBXML 1.0 global tokens: WAP-104-WBXML
  1050. * Same token mapping as in vals_wbxml1x_global_tokens, but:
  1051. * { 0xC3, "RESERVED_2" }
  1052. */
  1053. /* WBXML 1.x (x>0) global tokens: WAP-135-WBXML, WAP-154-WBXML, WAP-192-WBXML
  1054. */
  1055. static const value_string vals_wbxml1x_global_tokens[] = {
  1056. { 0x00, "SWITCH_PAGE" },
  1057. { 0x01, "END" },
  1058. { 0x02, "ENTITY" },
  1059. { 0x03, "STR_I" },
  1060. { 0x04, "LITERAL" },
  1061. { 0x40, "EXT_I_0" },
  1062. { 0x41, "EXT_I_1" },
  1063. { 0x42, "EXT_I_2" },
  1064. { 0x43, "PI" },
  1065. { 0x44, "LITERAL_C" },
  1066. { 0x80, "EXT_T_0" },
  1067. { 0x81, "EXT_T_1" },
  1068. { 0x82, "EXT_T_2" },
  1069. { 0x83, "STR_T" },
  1070. { 0x84, "LITERAL_A" },
  1071. { 0xC0, "EXT_0" },
  1072. { 0xC1, "EXT_1" },
  1073. { 0xC2, "EXT_2" },
  1074. { 0xC3, "OPAQUE" },
  1075. { 0xC4, "LITERAL_AC" },
  1076. { 0x00, NULL }
  1077. };
  1078. static value_string_ext vals_wbxml1x_global_tokens_ext = VALUE_STRING_EXT_INIT(vals_wbxml1x_global_tokens);
  1079. /********************** WBXML token mapping definition **********************/
  1080. /*
  1081. * NOTE: Please make sure the Attribute Start values all contain an equal sign
  1082. * even in cases where they do not contain the start of an Attribute
  1083. * Value.
  1084. */
  1085. /* WML 1.0
  1086. *
  1087. * Wireless Markup Language
  1088. ***************************************/
  1089. static char *
  1090. ext_t_0_wml_10(tvbuff_t *tvb, guint32 value, guint32 str_tbl)
  1091. {
  1092. char *str = ep_strdup_printf("Variable substitution - escaped: '%s'",
  1093. tvb_get_const_stringz(tvb, str_tbl + value, NULL));
  1094. return str;
  1095. }
  1096. static char *
  1097. ext_t_1_wml_10(tvbuff_t *tvb, guint32 value, guint32 str_tbl)
  1098. {
  1099. char *str = ep_strdup_printf("Variable substitution - unescaped: '%s'",
  1100. tvb_get_const_stringz(tvb, str_tbl + value, NULL));
  1101. return str;
  1102. }
  1103. static char *
  1104. ext_t_2_wml_10(tvbuff_t *tvb, guint32 value, guint32 str_tbl)
  1105. {
  1106. char *str = ep_strdup_printf("Variable substitution - no transformation: '%s'",
  1107. tvb_get_const_stringz(tvb, str_tbl + value, NULL));
  1108. return str;
  1109. }
  1110. /***** Global extension tokens *****/
  1111. static const value_string wbxml_wmlc10_global_cp0[] = {
  1112. { 0x40, "Variable substitution - escaped" },
  1113. { 0x41, "Variable substitution - unescaped" },
  1114. { 0x42, "Variable substitution - no transformation" },
  1115. { 0x80, "Variable substitution - escaped" },
  1116. { 0x81, "Variable substitution - unescaped" },
  1117. { 0x82, "Variable substitution - no transformation" },
  1118. { 0xC0, "Reserved" },
  1119. { 0xC1, "Reserved" },
  1120. { 0xC2, "Reserved" },
  1121. { 0x00, NULL }
  1122. };
  1123. /***** Tag tokens *****/
  1124. static const value_string wbxml_wmlc10_tags_cp0[] = {
  1125. /* 0x00 -- 0x04 GLOBAL */
  1126. /* 0x05 -- 0x21 */
  1127. { 0x22, "A" },
  1128. { 0x23, "ACCESS" },
  1129. { 0x24, "B" },
  1130. { 0x25, "BIG" },
  1131. { 0x26, "BR" },
  1132. { 0x27, "CARD" },
  1133. { 0x28, "DO" },
  1134. { 0x29, "EM" },
  1135. { 0x2A, "FIELDSET" },
  1136. { 0x2B, "GO" },
  1137. { 0x2C, "HEAD" },
  1138. { 0x2D, "I" },
  1139. { 0x2E, "IMG" },
  1140. { 0x2F, "INPUT" },
  1141. { 0x30, "META" },
  1142. { 0x31, "NOOP" },
  1143. { 0x32, "PREV" },
  1144. { 0x33, "ONEVENT" },
  1145. { 0x34, "OPTGROUP" },
  1146. { 0x35, "OPTION" },
  1147. { 0x36, "REFRESH" },
  1148. { 0x37, "SELECT" },
  1149. { 0x38, "SMALL" },
  1150. { 0x39, "STRONG" },
  1151. { 0x3A, "TAB" },
  1152. { 0x3B, "TEMPLATE" },
  1153. { 0x3C, "TIMER" },
  1154. { 0x3D, "U" },
  1155. { 0x3E, "VAR" },
  1156. { 0x3F, "WML" },
  1157. { 0x00, NULL }
  1158. };
  1159. /***** Attribute Start tokens *****/
  1160. static const value_string wbxml_wmlc10_attrStart_cp0[] = {
  1161. /* 0x00 -- 0x04 GLOBAL */
  1162. { 0x05, "ACCEPT-CHARSET=" },
  1163. { 0x06, "ALIGN='BOTTOM'" },
  1164. { 0x07, "ALIGN='CENTER'" },
  1165. { 0x08, "ALIGN='LEFT'" },
  1166. { 0x09, "ALIGN='MIDDLE'" },
  1167. { 0x0A, "ALIGN='RIGHT'" },
  1168. { 0x0B, "ALIGN='TOP'" },
  1169. { 0x0C, "ALT=" },
  1170. { 0x0D, "CONTENT=" },
  1171. { 0x0E, "DEFAULT=" },
  1172. { 0x0F, "DOMAIN=" },
  1173. { 0x10, "EMPTYOK='FALSE'" },
  1174. { 0x11, "EMPTYOK='TRUE'" },
  1175. { 0x12, "FORMAT=" },
  1176. { 0x13, "HEIGHT=" },
  1177. { 0x14, "HSPACE=" },
  1178. { 0x15, "IDEFAULT=" },
  1179. { 0x16, "IKEY=" },
  1180. { 0x17, "KEY=" },
  1181. { 0x18, "LABEL=" },
  1182. { 0x19, "LOCALSRC=" },
  1183. { 0x1A, "MAXLENGTH=" },
  1184. { 0x1B, "METHOD='GET'" },
  1185. { 0x1C, "METHOD='POST'" },
  1186. { 0x1D, "MODE='NOWRAP'" },
  1187. { 0x1E, "MODE='WRAP'" },
  1188. { 0x1F, "MULTIPLE='FALSE'" },
  1189. { 0x20, "MULTIPLE='TRUE'" },
  1190. { 0x21, "NAME=" },
  1191. { 0x22, "NEWCONTEXT='FALSE'" },
  1192. { 0x23, "NEWCONTEXT='TRUE'" },
  1193. { 0x24, "ONCLICK=" },
  1194. { 0x25, "ONENTERBACKWARD=" },
  1195. { 0x26, "ONENTERFORWARD=" },
  1196. { 0x27, "ONTIMER=" },
  1197. { 0x28, "OPTIONAL='FALSE'" },
  1198. { 0x29, "OPTIONAL='TRUE'" },
  1199. { 0x2A, "PATH=" },
  1200. { 0x2B, "POSTDATA=" },
  1201. { 0x2C, "PUBLIC='FALSE'" },
  1202. { 0x2D, "PUBLIC='TRUE'" },
  1203. { 0x2E, "SCHEME=" },
  1204. { 0x2F, "SENDREFERER='FALSE'" },
  1205. { 0x30, "SENDREFERER='TRUE'" },
  1206. { 0x31, "SIZE=" },
  1207. { 0x32, "SRC=" },
  1208. { 0x33, "STYLE='LIST'" },
  1209. { 0x34, "STYLE='SET'" },
  1210. { 0x35, "TABINDEX=" },
  1211. { 0x36, "TITLE=" },
  1212. { 0x37, "TYPE=" },
  1213. { 0x38, "TYPE='ACCEPT'" },
  1214. { 0x39, "TYPE='DELETE'" },
  1215. { 0x3A, "TYPE='HELP'" },
  1216. { 0x3B, "TYPE='PASSWORD'" },
  1217. { 0x3C, "TYPE='ONCLICK'" },
  1218. { 0x3D, "TYPE='ONENTERBACKWARD'" },
  1219. { 0x3E, "TYPE='ONENTERFORWARD'" },
  1220. { 0x3F, "TYPE='ONTIMER'" },
  1221. /* 0x40 -- 0x44 GLOBAL */
  1222. { 0x45, "TYPE='OPTIONS'" },
  1223. { 0x46, "TYPE='PREV'" },
  1224. { 0x47, "TYPE='RESET'" },
  1225. { 0x48, "TYPE='TEXT'" },
  1226. { 0x49, "TYPE='vnd.'" },
  1227. { 0x4A, "URL=" },
  1228. { 0x4B, "URL='http://'" },
  1229. { 0x4C, "URL='https://'" },
  1230. { 0x4D, "USER-AGENT=" },
  1231. { 0x4E, "VALUE=" },
  1232. { 0x4F, "VSPACE=" },
  1233. { 0x50, "WIDTH=" },
  1234. { 0x51, "xml:lang=" },
  1235. { 0x00, NULL }
  1236. };
  1237. /***** Attribute Value tokens *****/
  1238. static const value_string wbxml_wmlc10_attrValue_cp0[] = {
  1239. /* 0x80 -- 0x84 GLOBAL */
  1240. { 0x85, "'.com/'" },
  1241. { 0x86, "'.edu/'" },
  1242. { 0x87, "'.net/'" },
  1243. { 0x88, "'.org/'" },
  1244. { 0x89, "'ACCEPT'" },
  1245. { 0x8A, "'BOTTOM'" },
  1246. { 0x8B, "'CLEAR'" },
  1247. { 0x8C, "'DELETE'" },
  1248. { 0x8D, "'HELP'" },
  1249. { 0x8E, "'http://'" },
  1250. { 0x8F, "'http://www.'" },
  1251. { 0x90, "'https://'" },
  1252. { 0x91, "'https://www.'" },
  1253. { 0x92, "'LIST'" },
  1254. { 0x93, "'MIDDLE'" },
  1255. { 0x94, "'NOWRAP'" },
  1256. { 0x95, "'ONCLICK'" },
  1257. { 0x96, "'ONENTERBACKWARD'" },
  1258. { 0x97, "'ONENTERFORWARD'" },
  1259. { 0x98, "'ONTIMER'" },
  1260. { 0x99, "'OPTIONS'" },
  1261. { 0x9A, "'PASSWORD'" },
  1262. { 0x9B, "'RESET'" },
  1263. { 0x9C, "'SET'" },
  1264. { 0x9D, "'TEXT'" },
  1265. { 0x9E, "'TOP'" },
  1266. { 0x9F, "'UNKNOWN'" },
  1267. { 0xA0, "'WRAP'" },
  1268. { 0xA1, "'www.'" },
  1269. { 0x00, NULL }
  1270. };
  1271. /***** Token code page aggregation *****/
  1272. static const value_valuestring wbxml_wmlc10_global[] = {
  1273. { 0, wbxml_wmlc10_global_cp0 },
  1274. { 0, NULL }
  1275. };
  1276. static const value_valuestring wbxml_wmlc10_tags[] = {
  1277. { 0, wbxml_wmlc10_tags_cp0 },
  1278. { 0, NULL }
  1279. };
  1280. static const value_valuestring wbxml_wmlc10_attrStart[] = {
  1281. { 0, wbxml_wmlc10_attrStart_cp0 },
  1282. { 0, NULL }
  1283. };
  1284. static const value_valuestring wbxml_wmlc10_attrValue[] = {
  1285. { 0, wbxml_wmlc10_attrValue_cp0 },
  1286. { 0, NULL }
  1287. };
  1288. static const wbxml_decoding decode_wmlc_10 = {
  1289. "Wireless Markup Language 1.0",
  1290. "WML 1.0",
  1291. { ext_t_0_wml_10, ext_t_1_wml_10, ext_t_2_wml_10 },
  1292. default_opaque_binary_tag,
  1293. default_opaque_literal_tag,
  1294. default_opaque_binary_attr,
  1295. default_opaque_literal_attr,
  1296. wbxml_wmlc10_global,
  1297. wbxml_wmlc10_tags,
  1298. wbxml_wmlc10_attrStart,
  1299. wbxml_wmlc10_attrValue
  1300. };
  1301. /* WML 1.1
  1302. *
  1303. * Wireless Markup Language
  1304. ***************************************/
  1305. /***** Global extension tokens *****/
  1306. /* Same as in WML 1.0 */
  1307. /***** Tag tokens *****/
  1308. static const value_string wbxml_wmlc11_tags_cp0[] = {
  1309. /* 0x00 -- 0x04 GLOBAL */
  1310. /* 0x05 -- 0x1B */
  1311. { 0x1C, "a" },
  1312. { 0x1D, "td" },
  1313. { 0x1E, "tr" },
  1314. { 0x1F, "table" },
  1315. { 0x20, "p" },
  1316. { 0x21, "postfield" },
  1317. { 0x22, "anchor" },
  1318. { 0x23, "access" },
  1319. { 0x24, "b" },
  1320. { 0x25, "big" },
  1321. { 0x26, "br" },
  1322. { 0x27, "card" },
  1323. { 0x28, "do" },
  1324. { 0x29, "em" },
  1325. { 0x2A, "fieldset" },
  1326. { 0x2B, "go" },
  1327. { 0x2C, "head" },
  1328. { 0x2D, "i" },
  1329. { 0x2E, "img" },
  1330. { 0x2F, "input" },
  1331. { 0x30, "meta" },
  1332. { 0x31, "noop" },
  1333. { 0x32, "prev" },
  1334. { 0x33, "onevent" },
  1335. { 0x34, "optgroup" },
  1336. { 0x35, "option" },
  1337. { 0x36, "refresh" },
  1338. { 0x37, "select" },
  1339. { 0x38, "small" },
  1340. { 0x39, "strong" },
  1341. /* 0x3A */
  1342. { 0x3B, "template" },
  1343. { 0x3C, "timer" },
  1344. { 0x3D, "u" },
  1345. { 0x3E, "setvar" },
  1346. { 0x3F, "wml" },
  1347. { 0x00, NULL }
  1348. };
  1349. /***** Attribute Start tokens *****/
  1350. static const value_string wbxml_wmlc11_attrStart_cp0[] = {
  1351. /* 0x00 -- 0x04 GLOBAL */
  1352. { 0x05, "accept-charset=" },
  1353. { 0x06, "align='bottom'" },
  1354. { 0x07, "align='center'" },
  1355. { 0x08, "align='left'" },
  1356. { 0x09, "align='middle'" },
  1357. { 0x0A, "align='right'" },
  1358. { 0x0B, "align='top'" },
  1359. { 0x0C, "alt=" },
  1360. { 0x0D, "content=" },
  1361. /* 0x0E */
  1362. { 0x0F, "domain=" },
  1363. { 0x10, "emptyok='false'" },
  1364. { 0x11, "emptyok='true'" },
  1365. { 0x12, "format=" },
  1366. { 0x13, "height=" },
  1367. { 0x14, "hspace=" },
  1368. { 0x15, "ivalue=" },
  1369. { 0x16, "iname=" },
  1370. /* 0x17 */
  1371. { 0x18, "label=" },
  1372. { 0x19, "localsrc=" },
  1373. { 0x1A, "maxlength=" },
  1374. { 0x1B, "method='get'" },
  1375. { 0x1C, "method='post'" },
  1376. { 0x1D, "mode='nowrap'" },
  1377. { 0x1E, "mode='wrap'" },
  1378. { 0x1F, "multiple='false'" },
  1379. { 0x20, "multiple='true'" },
  1380. { 0x21, "name=" },
  1381. { 0x22, "newcontext='false'" },
  1382. { 0x23, "newcontext='true'" },
  1383. { 0x24, "onpick=" },
  1384. { 0x25, "onenterbackward=" },
  1385. { 0x26, "onenterforward=" },
  1386. { 0x27, "ontimer=" },
  1387. { 0x28, "optional='false'" },
  1388. { 0x29, "optional='true'" },
  1389. { 0x2A, "path=" },
  1390. /* 0x2B -- 0x2D */
  1391. { 0x2E, "scheme=" },
  1392. { 0x2F, "sendreferer='false'" },
  1393. { 0x30, "sendreferer='true'" },
  1394. { 0x31, "size=" },
  1395. { 0x32, "src=" },
  1396. { 0x33, "ordered='false'" },
  1397. { 0x34, "ordered='true'" },
  1398. { 0x35, "tabindex=" },
  1399. { 0x36, "title=" },
  1400. { 0x37, "type=" },
  1401. { 0x38, "type='accept'" },
  1402. { 0x39, "type='delete'" },
  1403. { 0x3A, "type='help'" },
  1404. { 0x3B, "type='password'" },
  1405. { 0x3C, "type='onpick'" },
  1406. { 0x3D, "type='onenterbackward'" },
  1407. { 0x3E, "type='onenterforward'" },
  1408. { 0x3F, "type='ontimer'" },
  1409. /* 0x40 -- 0x44 GLOBAL */
  1410. { 0x45, "type='options'" },
  1411. { 0x46, "type='prev'" },
  1412. { 0x47, "type='reset'" },
  1413. { 0x48, "type='text'" },
  1414. { 0x49, "type='vnd.'" },
  1415. { 0x4A, "href=" },
  1416. { 0x4B, "href='http://'" },
  1417. { 0x4C, "href='https://'" },
  1418. { 0x4D, "value=" },
  1419. { 0x4E, "vspace=" },
  1420. { 0x4F, "width=" },
  1421. { 0x50, "xml:lang=" },
  1422. /* 0x51 */
  1423. { 0x52, "align=" },
  1424. { 0x53, "columns=" },
  1425. { 0x54, "class=" },
  1426. { 0x55, "id=" },
  1427. { 0x56, "forua='false'" },
  1428. { 0x57, "forua='true'" },
  1429. { 0x58, "src='http://'" },
  1430. { 0x59, "src='https://'" },
  1431. { 0x5A, "http-equiv=" },
  1432. { 0x5B, "http-equiv='Content-Type'" },
  1433. { 0x5C, "content='application/vnd.wap.wmlc;charset='" },
  1434. { 0x5D, "http-equiv='Expires'" },
  1435. { 0x00, NULL }
  1436. };
  1437. /***** Attribute Value tokens *****/
  1438. static const value_string wbxml_wmlc11_attrValue_cp0[] = {
  1439. /* 0x80 -- 0x84 GLOBAL */
  1440. { 0x85, "'.com/'" },
  1441. { 0x86, "'.edu/'" },
  1442. { 0x87, "'.net/'" },
  1443. { 0x88, "'.org/'" },
  1444. { 0x89, "'accept'" },
  1445. { 0x8A, "'bottom'" },
  1446. { 0x8B, "'clear'" },
  1447. { 0x8C, "'delete'" },
  1448. { 0x8D, "'help'" },
  1449. { 0x8E, "'http://'" },
  1450. { 0x8F, "'http://www.'" },
  1451. { 0x90, "'https://'" },
  1452. { 0x91, "'https://www.'" },
  1453. /* 0x92 */
  1454. { 0x93, "'middle'" },
  1455. { 0x94, "'nowrap'" },
  1456. { 0x95, "'onpick'" },
  1457. { 0x96, "'onenterbackward'" },
  1458. { 0x97, "'onenterforward'" },
  1459. { 0x98, "'ontimer'" },
  1460. { 0x99, "'options'" },
  1461. { 0x9A, "'password'" },
  1462. { 0x9B, "'reset'" },
  1463. /* 0x9C */
  1464. { 0x9D, "'text'" },
  1465. { 0x9E, "'top'" },
  1466. { 0x9F, "'unknown'" },
  1467. { 0xA0, "'wrap'" },
  1468. { 0xA1, "'www.'" },
  1469. { 0x00, NULL }
  1470. };
  1471. /***** Token code page aggregation *****/
  1472. static const value_valuestring wbxml_wmlc11_global[] = {
  1473. { 0, wbxml_wmlc10_global_cp0 }, /* Same as WML 1.0 */
  1474. { 0, NULL }
  1475. };
  1476. static const value_valuestring wbxml_wmlc11_tags[] = {
  1477. { 0, wbxml_wmlc11_tags_cp0 },
  1478. { 0, NULL }
  1479. };
  1480. static const value_valuestring wbxml_wmlc11_attrStart[] = {
  1481. { 0, wbxml_wmlc11_attrStart_cp0 },
  1482. { 0, NULL }
  1483. };
  1484. static const value_valuestring wbxml_wmlc11_attrValue[] = {
  1485. { 0, wbxml_wmlc11_attrValue_cp0 },
  1486. { 0, NULL }
  1487. };
  1488. static const wbxml_decoding decode_wmlc_11 = {
  1489. "Wireless Markup Language 1.1",
  1490. "WML 1.1",
  1491. { ext_t_0_wml_10, ext_t_1_wml_10, ext_t_2_wml_10 },
  1492. default_opaque_binary_tag,
  1493. default_opaque_literal_tag,
  1494. default_opaque_binary_attr,
  1495. default_opaque_literal_attr,
  1496. wbxml_wmlc11_global,
  1497. wbxml_wmlc11_tags,
  1498. wbxml_wmlc11_attrStart,
  1499. wbxml_wmlc11_attrValue
  1500. };
  1501. /* WML 1.2
  1502. *
  1503. * Wireless Markup Language
  1504. ***************************************/
  1505. /***** Global extension tokens *****/
  1506. /* Same as in WML 1.0 */
  1507. /***** Tag tokens *****/
  1508. static const value_string wbxml_wmlc12_tags_cp0[] = {
  1509. /* 0x00 -- 0x04 GLOBAL */
  1510. /* 0x05 -- 0x1A */
  1511. { 0x1B, "pre" },
  1512. { 0x1C, "a" },
  1513. { 0x1D, "td" },
  1514. { 0x1E, "tr" },
  1515. { 0x1F, "table" },
  1516. { 0x20, "p" },
  1517. { 0x21, "postfield" },
  1518. { 0x22, "anchor" },
  1519. { 0x23, "access" },
  1520. { 0x24, "b" },
  1521. { 0x25, "big" },
  1522. { 0x26, "br" },
  1523. { 0x27, "card" },
  1524. { 0x28, "do" },
  1525. { 0x29, "em" },
  1526. { 0x2A, "fieldset" },
  1527. { 0x2B, "go" },
  1528. { 0x2C, "head" },
  1529. { 0x2D, "i" },
  1530. { 0x2E, "img" },
  1531. { 0x2F, "input" },
  1532. { 0x30, "meta" },
  1533. { 0x31, "noop" },
  1534. { 0x32, "prev" },
  1535. { 0x33, "onevent" },
  1536. { 0x34, "optgroup" },
  1537. { 0x35, "option" },
  1538. { 0x36, "refresh" },
  1539. { 0x37, "select" },
  1540. { 0x38, "small" },
  1541. { 0x39, "strong" },
  1542. /* 0x3A */
  1543. { 0x3B, "template" },
  1544. { 0x3C, "timer" },
  1545. { 0x3D, "u" },
  1546. { 0x3E, "setvar" },
  1547. { 0x3F, "wml" },
  1548. { 0x00, NULL }
  1549. };
  1550. /***** Attribute Start tokens *****/
  1551. static const value_string wbxml_wmlc12_attrStart_cp0[] = {
  1552. /* 0x00 -- 0x04 GLOBAL */
  1553. { 0x05, "accept-charset=" },
  1554. { 0x06, "align='bottom'" },
  1555. { 0x07, "align='center'" },
  1556. { 0x08, "align='left'" },
  1557. { 0x09, "align='middle'" },
  1558. { 0x0A, "align='right'" },
  1559. { 0x0B, "align='top'" },
  1560. { 0x0C, "alt=" },
  1561. { 0x0D, "content=" },
  1562. /* 0x0E */
  1563. { 0x0F, "domain=" },
  1564. { 0x10, "emptyok='false'" },
  1565. { 0x11, "emptyok='true'" },
  1566. { 0x12, "format=" },
  1567. { 0x13, "height=" },
  1568. { 0x14, "hspace=" },
  1569. { 0x15, "ivalue=" },
  1570. { 0x16, "iname=" },
  1571. /* 0x17 */
  1572. { 0x18, "label=" },
  1573. { 0x19, "localsrc=" },
  1574. { 0x1A, "maxlength=" },
  1575. { 0x1B, "method='get'" },
  1576. { 0x1C, "method='post'" },
  1577. { 0x1D, "mode='nowrap'" },
  1578. { 0x1E, "mode='wrap'" },
  1579. { 0x1F, "multiple='false'" },
  1580. { 0x20, "multiple='true'" },
  1581. { 0x21, "name=" },
  1582. { 0x22, "newcontext='false'" },
  1583. { 0x23, "newcontext='true'" },
  1584. { 0x24, "onpick=" },
  1585. { 0x25, "onenterbackward=" },
  1586. { 0x26, "onenterforward=" },
  1587. { 0x27, "ontimer=" },
  1588. { 0x28, "optional='false'" },
  1589. { 0x29, "optional='true'" },
  1590. { 0x2A, "path=" },
  1591. /* 0x2B -- 0x2D */
  1592. { 0x2E, "scheme=" },
  1593. { 0x2F, "sendreferer='false'" },
  1594. { 0x30, "sendreferer='true'" },
  1595. { 0x31, "size=" },
  1596. { 0x32, "src=" },
  1597. { 0x33, "ordered='false'" },
  1598. { 0x34, "ordered='true'" },
  1599. { 0x35, "tabindex=" },
  1600. { 0x36, "title=" },
  1601. { 0x37, "type=" },
  1602. { 0x38, "type='accept'" },
  1603. { 0x39, "type='delet…

Large files files are truncated, but you can click here to view the full file