PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/epan/value_string.c

https://github.com/labx-technologies-llc/wireshark
C | 615 lines | 359 code | 104 blank | 152 comment | 86 complexity | 8fde32dafd8fb14ef8195edb23c887e7 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. /* value_string.c
  2. * Routines for value_strings
  3. *
  4. * $Id$
  5. *
  6. * Wireshark - Network traffic analyzer
  7. * By Gerald Combs <gerald@wireshark.org>
  8. * Copyright 1998 Gerald Combs
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  23. */
  24. #include "config.h"
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "emem.h"
  28. #include "wmem/wmem.h"
  29. #include "proto.h"
  30. #include "to_str.h"
  31. #include "value_string.h"
  32. /* REGULAR VALUE STRING */
  33. /* Tries to match val against each element in the value_string array vs.
  34. Returns the associated string ptr on a match.
  35. Formats val with fmt, and returns the resulting string, on failure. */
  36. const gchar*
  37. val_to_str(const guint32 val, const value_string *vs, const char *fmt)
  38. {
  39. const gchar *ret;
  40. DISSECTOR_ASSERT(fmt != NULL);
  41. ret = try_val_to_str(val, vs);
  42. if (ret != NULL)
  43. return ret;
  44. return ep_strdup_printf(fmt, val);
  45. }
  46. /* Tries to match val against each element in the value_string array vs.
  47. Returns the associated string ptr on a match.
  48. Returns 'unknown_str', on failure. */
  49. const gchar*
  50. val_to_str_const(const guint32 val, const value_string *vs,
  51. const char *unknown_str)
  52. {
  53. const gchar *ret;
  54. DISSECTOR_ASSERT(unknown_str != NULL);
  55. ret = try_val_to_str(val, vs);
  56. if (ret != NULL)
  57. return ret;
  58. return unknown_str;
  59. }
  60. /* Tries to match val against each element in the value_string array vs.
  61. Returns the associated string ptr, and sets "*idx" to the index in
  62. that table, on a match, and returns NULL, and sets "*idx" to -1,
  63. on failure. */
  64. const gchar*
  65. try_val_to_str_idx(const guint32 val, const value_string *vs, gint *idx)
  66. {
  67. gint i = 0;
  68. DISSECTOR_ASSERT(idx != NULL);
  69. if(vs) {
  70. while (vs[i].strptr) {
  71. if (vs[i].value == val) {
  72. *idx = i;
  73. return(vs[i].strptr);
  74. }
  75. i++;
  76. }
  77. }
  78. *idx = -1;
  79. return NULL;
  80. }
  81. /* Like try_val_to_str_idx(), but doesn't return the index. */
  82. const gchar*
  83. try_val_to_str(const guint32 val, const value_string *vs)
  84. {
  85. gint ignore_me;
  86. return try_val_to_str_idx(val, vs, &ignore_me);
  87. }
  88. /* 64-BIT VALUE STRING */
  89. const gchar*
  90. val64_to_str(const guint64 val, const val64_string *vs, const char *fmt)
  91. {
  92. const gchar *ret;
  93. DISSECTOR_ASSERT(fmt != NULL);
  94. ret = try_val64_to_str(val, vs);
  95. if (ret != NULL)
  96. return ret;
  97. return ep_strdup_printf(fmt, val);
  98. }
  99. const gchar*
  100. val64_to_str_const(const guint64 val, const val64_string *vs,
  101. const char *unknown_str)
  102. {
  103. const gchar *ret;
  104. DISSECTOR_ASSERT(unknown_str != NULL);
  105. ret = try_val64_to_str(val, vs);
  106. if (ret != NULL)
  107. return ret;
  108. return unknown_str;
  109. }
  110. const gchar*
  111. try_val64_to_str_idx(const guint64 val, const val64_string *vs, gint *idx)
  112. {
  113. gint i = 0;
  114. DISSECTOR_ASSERT(idx != NULL);
  115. if(vs) {
  116. while (vs[i].strptr) {
  117. if (vs[i].value == val) {
  118. *idx = i;
  119. return(vs[i].strptr);
  120. }
  121. i++;
  122. }
  123. }
  124. *idx = -1;
  125. return NULL;
  126. }
  127. const gchar*
  128. try_val64_to_str(const guint64 val, const val64_string *vs)
  129. {
  130. gint ignore_me;
  131. return try_val64_to_str_idx(val, vs, &ignore_me);
  132. }
  133. /* REVERSE VALUE STRING */
  134. /* We use the same struct as for regular value strings, but we look up strings
  135. * and return values instead */
  136. /* Like val_to_str except backwards */
  137. guint32
  138. str_to_val(const gchar *val, const value_string *vs, const guint32 err_val)
  139. {
  140. gint i;
  141. i = str_to_val_idx(val, vs);
  142. if (i >= 0) {
  143. return vs[i].value;
  144. }
  145. return err_val;
  146. }
  147. /* Find the index of a string in a value_string, or -1 when not present */
  148. gint
  149. str_to_val_idx(const gchar *val, const value_string *vs)
  150. {
  151. gint i = 0;
  152. if(vs) {
  153. while (vs[i].strptr) {
  154. if (strcmp(vs[i].strptr, val) == 0) {
  155. return i;
  156. }
  157. i++;
  158. }
  159. }
  160. return -1;
  161. }
  162. /* EXTENDED VALUE STRING */
  163. /* Extended value strings allow fast(er) value_string array lookups by
  164. * using (if possible) direct access or a binary search of the array.
  165. *
  166. * If the values in the value_string array are a contiguous range of values
  167. * from min to max, the value will be used as as a direct index into the array.
  168. *
  169. * If the values in the array are not contiguous (ie: there are "gaps"),
  170. * but are in assending order a binary search will be used.
  171. *
  172. * If direct access or binary search cannot be used, then a linear search
  173. * is used and a warning is emitted.
  174. *
  175. * Note that the value_string array used with VALUE_STRING_EXT_INIT
  176. * *must* be terminated with {0, NULL}).
  177. *
  178. * Extended value strings are defined at compile time as follows:
  179. * static const value_string vs[] = { {value1, "string1"},
  180. * {value2, "string2"},
  181. * ...,
  182. * {0, NULL}};
  183. * static value_string_ext vse = VALUE_STRING_EXT_INIT(vs);
  184. *
  185. * Extended value strings can be created at runtime by calling
  186. * value_string_ext_new(<ptr to value_string array>,
  187. * <total number of entries in the value_string_array>,
  188. * <value_string_name>);
  189. * Note: The <total number of entries in the value_string_array> should include
  190. * the {0, NULL} entry.
  191. */
  192. /* Create a value_string_ext given a ptr to a value_string array and the total
  193. * number of entries. Note that the total number of entries should include the
  194. * required {0, NULL} terminating entry of the array.
  195. * Returns a pointer to an epan-scoped'd and initialized value_string_ext
  196. * struct. */
  197. value_string_ext *
  198. value_string_ext_new(value_string *vs, guint vs_tot_num_entries,
  199. const gchar *vs_name)
  200. {
  201. value_string_ext *vse;
  202. DISSECTOR_ASSERT (vs_name != NULL);
  203. DISSECTOR_ASSERT (vs_tot_num_entries > 0);
  204. /* Null-terminated value-string ? */
  205. DISSECTOR_ASSERT (vs[vs_tot_num_entries-1].strptr == NULL);
  206. vse = wmem_new(wmem_epan_scope(), value_string_ext);
  207. vse->_vs_p = vs;
  208. vse->_vs_num_entries = vs_tot_num_entries - 1;
  209. /* We set our 'match' function to the init function, which finishes by
  210. * setting the match function properly and then calling it. This is a
  211. * simple way to do lazy initialization of extended value strings.
  212. * The init function also sets up _vs_first_value for us. */
  213. vse->_vs_first_value = 0;
  214. vse->_vs_match2 = _try_val_to_str_ext_init;
  215. vse->_vs_name = vs_name;
  216. return vse;
  217. }
  218. /* Like try_val_to_str for extended value strings */
  219. const gchar*
  220. try_val_to_str_ext(const guint32 val, const value_string_ext *vse)
  221. {
  222. if (vse) {
  223. const value_string *vs = vse->_vs_match2(val, vse);
  224. if (vs) {
  225. return vs->strptr;
  226. }
  227. }
  228. return NULL;
  229. }
  230. /* Like try_val_to_str_idx for extended value strings */
  231. const gchar*
  232. try_val_to_str_idx_ext(const guint32 val, value_string_ext *vse, gint *idx)
  233. {
  234. if (vse) {
  235. const value_string *vs = vse->_vs_match2(val, vse);
  236. if (vs) {
  237. *idx = (gint) (vs - vse->_vs_p);
  238. return vs->strptr;
  239. }
  240. }
  241. *idx = -1;
  242. return NULL;
  243. }
  244. /* Like val_to_str for extended value strings */
  245. const gchar*
  246. val_to_str_ext(const guint32 val, const value_string_ext *vse, const char *fmt)
  247. {
  248. const gchar *ret;
  249. DISSECTOR_ASSERT(fmt != NULL);
  250. ret = try_val_to_str_ext(val, vse);
  251. if (ret != NULL)
  252. return ret;
  253. return ep_strdup_printf(fmt, val);
  254. }
  255. /* Like val_to_str_const for extended value strings */
  256. const gchar*
  257. val_to_str_ext_const(const guint32 val, const value_string_ext *vse,
  258. const char *unknown_str)
  259. {
  260. const gchar *ret;
  261. DISSECTOR_ASSERT(unknown_str != NULL);
  262. ret = try_val_to_str_ext(val, vse);
  263. if (ret != NULL)
  264. return ret;
  265. return unknown_str;
  266. }
  267. /* Fallback linear matching algorithm for extended value strings */
  268. static const value_string *
  269. _try_val_to_str_linear(const guint32 val, const value_string_ext *vse)
  270. {
  271. const value_string *vs_p = vse->_vs_p;
  272. guint i;
  273. for (i=0; i<vse->_vs_num_entries; i++) {
  274. if (vs_p[i].value == val)
  275. return &(vs_p[i]);
  276. }
  277. return NULL;
  278. }
  279. /* Constant-time matching algorithm for contiguous extended value strings */
  280. static const value_string *
  281. _try_val_to_str_index(const guint32 val, const value_string_ext *vse)
  282. {
  283. guint i;
  284. i = val - vse->_vs_first_value;
  285. if (i < vse->_vs_num_entries) {
  286. g_assert (val == vse->_vs_p[i].value);
  287. return &(vse->_vs_p[i]);
  288. }
  289. return NULL;
  290. }
  291. /* log(n)-time matching algorithm for sorted extended value strings */
  292. static const value_string *
  293. _try_val_to_str_bsearch(const guint32 val, const value_string_ext *vse)
  294. {
  295. guint low, i, max;
  296. guint32 item;
  297. for (low = 0, max = vse->_vs_num_entries; low < max; ) {
  298. i = (low + max) / 2;
  299. item = vse->_vs_p[i].value;
  300. if (val < item)
  301. max = i;
  302. else if (val > item)
  303. low = i + 1;
  304. else
  305. return &(vse->_vs_p[i]);
  306. }
  307. return NULL;
  308. }
  309. /* Initializes an extended value string. Behaves like a match function to
  310. * permit lazy initialization of extended value strings.
  311. * - Goes through the value_string array to determine the fastest possible
  312. * access method.
  313. * - Verifies that the value_string contains no NULL string pointers.
  314. * - Verifies that the value_string is terminated by {0, NULL}
  315. */
  316. const value_string *
  317. _try_val_to_str_ext_init(const guint32 val, const value_string_ext *a_vse)
  318. {
  319. /* Cast away the constness!
  320. * It's better if the prototype for this function matches the other
  321. * _try_val_to_str_* functions (so we don't have to cast it when storing it
  322. * in _try_val_to_str so the compiler will notice if the prototypes get out
  323. * of sync), but the init function is unique in that it does actually
  324. * modify the vse.
  325. */
  326. value_string_ext *vse = (value_string_ext *)a_vse;
  327. const value_string *vs_p = vse->_vs_p;
  328. const guint vs_num_entries = vse->_vs_num_entries;
  329. /* The matching algorithm used:
  330. * VS_SEARCH - slow sequential search (as in a normal value string)
  331. * VS_BIN_TREE - log(n)-time binary search, the values must be sorted
  332. * VS_INDEX - constant-time index lookup, the values must be contiguous
  333. */
  334. enum { VS_SEARCH, VS_BIN_TREE, VS_INDEX } type = VS_INDEX;
  335. /* Note: The value_string 'value' is *unsigned*, but we do a little magic
  336. * to help with value strings that have negative values.
  337. *
  338. * { -3, -2, -1, 0, 1, 2 }
  339. * will be treated as "ascending ordered" (although it isn't technically),
  340. * thus allowing constant-time index search
  341. *
  342. * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 }
  343. * will both be considered as "out-of-order with gaps", thus falling
  344. * back to the slow linear search
  345. *
  346. * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 }
  347. * will be considered "ascending ordered with gaps" thus allowing
  348. * a log(n)-time 'binary' search
  349. *
  350. * If you're confused, think of how negative values are represented, or
  351. * google two's complement.
  352. */
  353. guint32 prev_value;
  354. guint first_value;
  355. guint i;
  356. DISSECTOR_ASSERT((vs_p[vs_num_entries].value == 0) &&
  357. (vs_p[vs_num_entries].strptr == NULL));
  358. vse->_vs_first_value = vs_p[0].value;
  359. first_value = vs_p[0].value;
  360. prev_value = first_value;
  361. for (i = 0; i < vs_num_entries; i++) {
  362. DISSECTOR_ASSERT(vs_p[i].strptr != NULL);
  363. if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) {
  364. type = VS_BIN_TREE;
  365. }
  366. /* XXX: Should check for dups ?? */
  367. if (type == VS_BIN_TREE) {
  368. if (prev_value > vs_p[i].value) {
  369. g_warning("Extended value string %s forced to fall back to linear search: entry %u, value %u < previous entry, value %u",
  370. vse->_vs_name, i, vs_p[i].value, prev_value);
  371. type = VS_SEARCH;
  372. break;
  373. }
  374. if (first_value > vs_p[i].value) {
  375. g_warning("Extended value string %s forced to fall back to linear search: entry %u, value %u < first entry, value %u",
  376. vse->_vs_name, i, vs_p[i].value, first_value);
  377. type = VS_SEARCH;
  378. break;
  379. }
  380. }
  381. prev_value = vs_p[i].value;
  382. }
  383. switch (type) {
  384. case VS_SEARCH:
  385. vse->_vs_match2 = _try_val_to_str_linear;
  386. break;
  387. case VS_BIN_TREE:
  388. vse->_vs_match2 = _try_val_to_str_bsearch;
  389. break;
  390. case VS_INDEX:
  391. vse->_vs_match2 = _try_val_to_str_index;
  392. break;
  393. default:
  394. g_assert_not_reached();
  395. break;
  396. }
  397. return vse->_vs_match2(val, vse);
  398. }
  399. /* STRING TO STRING MATCHING */
  400. /* string_string is like value_string except the values being matched are
  401. * also strings (instead of unsigned integers) */
  402. /* Like val_to_str except for string_string */
  403. const gchar*
  404. str_to_str(const gchar *val, const string_string *vs, const char *fmt)
  405. {
  406. const gchar *ret;
  407. DISSECTOR_ASSERT(fmt != NULL);
  408. ret = try_str_to_str(val, vs);
  409. if (ret != NULL)
  410. return ret;
  411. return ep_strdup_printf(fmt, val);
  412. }
  413. /* Like try_val_to_str_idx except for string_string */
  414. const gchar*
  415. try_str_to_str_idx(const gchar *val, const string_string *vs, gint *idx)
  416. {
  417. gint i = 0;
  418. if(vs) {
  419. while (vs[i].strptr) {
  420. if (!strcmp(vs[i].value,val)) {
  421. *idx = i;
  422. return(vs[i].strptr);
  423. }
  424. i++;
  425. }
  426. }
  427. *idx = -1;
  428. return NULL;
  429. }
  430. /* Like try_val_to_str except for string_string */
  431. const gchar*
  432. try_str_to_str(const gchar *val, const string_string *vs)
  433. {
  434. gint ignore_me;
  435. return try_str_to_str_idx(val, vs, &ignore_me);
  436. }
  437. /* RANGE TO STRING MATCHING */
  438. /* range_string is like value_string except the values being matched are
  439. * integer ranges (for example, 0-10, 11-19, etc.) instead of single values. */
  440. /* Like val_to_str except for range_string */
  441. const gchar *
  442. rval_to_str(const guint32 val, const range_string *rs, const char *fmt)
  443. {
  444. const gchar *ret = NULL;
  445. DISSECTOR_ASSERT(fmt != NULL);
  446. ret = try_rval_to_str(val, rs);
  447. if(ret != NULL)
  448. return ret;
  449. return ep_strdup_printf(fmt, val);
  450. }
  451. /* Like try_val_to_str_idx except for range_string */
  452. const gchar *
  453. try_rval_to_str_idx(const guint32 val, const range_string *rs, gint *idx)
  454. {
  455. gint i = 0;
  456. if(rs) {
  457. while(rs[i].strptr) {
  458. if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) {
  459. *idx = i;
  460. return (rs[i].strptr);
  461. }
  462. i++;
  463. }
  464. }
  465. *idx = -1;
  466. return NULL;
  467. }
  468. /* Like try_val_to_str except for range_string */
  469. const gchar *
  470. try_rval_to_str(const guint32 val, const range_string *rs)
  471. {
  472. gint ignore_me = 0;
  473. return try_rval_to_str_idx(val, rs, &ignore_me);
  474. }
  475. /* MISC */
  476. /* Functions for use by proto_registrar_dump_values(), see proto.c */
  477. gboolean
  478. value_string_ext_validate(const value_string_ext *vse)
  479. {
  480. if (vse == NULL)
  481. return FALSE;
  482. if ((vse->_vs_match2 == _try_val_to_str_ext_init) ||
  483. (vse->_vs_match2 == _try_val_to_str_linear) ||
  484. (vse->_vs_match2 == _try_val_to_str_bsearch) ||
  485. (vse->_vs_match2 == _try_val_to_str_index))
  486. return TRUE;
  487. return FALSE;
  488. }
  489. const gchar *
  490. value_string_ext_match_type_str(const value_string_ext *vse)
  491. {
  492. if (vse->_vs_match2 == _try_val_to_str_linear)
  493. return "[Linear Search]";
  494. if (vse->_vs_match2 == _try_val_to_str_bsearch)
  495. return "[Binary Search]";
  496. if (vse->_vs_match2 == _try_val_to_str_index)
  497. return "[Direct (indexed) Access]";
  498. return "[Match Type not initialized or invalid]";
  499. }
  500. /*
  501. * Editor modelines - http://www.wireshark.org/tools/modelines.html
  502. *
  503. * Local variables:
  504. * c-basic-offset: 4
  505. * tab-width: 8
  506. * indent-tabs-mode: nil
  507. * End:
  508. *
  509. * vi: set shiftwidth=4 tabstop=8 expandtab:
  510. * :indentSize=4:tabSize=8:noTabs=true:
  511. */