diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | epan/CMakeLists.txt | 14 | ||||
-rw-r--r-- | epan/Makefile.am | 6 | ||||
-rw-r--r-- | epan/Makefile.nmake | 24 | ||||
-rw-r--r-- | epan/dissectors/packet-json.c | 32 | ||||
-rw-r--r-- | epan/jsmn/Makefile.am | 63 | ||||
-rw-r--r-- | epan/jsmn/Makefile.common | 38 | ||||
-rw-r--r-- | epan/jsmn/Makefile.nmake | 44 | ||||
-rw-r--r-- | epan/jsmn/jsmn.c | 345 | ||||
-rw-r--r-- | wiretap/CMakeLists.txt | 1 | ||||
-rw-r--r-- | wiretap/Makefile.common | 1 | ||||
-rw-r--r-- | wiretap/file_access.c | 8 | ||||
-rw-r--r-- | wiretap/json.c | 138 | ||||
-rw-r--r-- | wiretap/json.h | 55 | ||||
-rw-r--r-- | wiretap/wtap.c | 3 | ||||
-rw-r--r-- | wiretap/wtap.h | 2 | ||||
-rw-r--r-- | wsutil/CMakeLists.txt | 1 | ||||
-rw-r--r-- | wsutil/Makefile.common | 2 | ||||
-rw-r--r-- | wsutil/jsmn.c | 387 | ||||
-rw-r--r-- | wsutil/jsmn.h (renamed from epan/jsmn/jsmn.h) | 56 |
20 files changed, 662 insertions, 559 deletions
diff --git a/configure.ac b/configure.ac index 4b7db7e165..dd0b50234b 100644 --- a/configure.ac +++ b/configure.ac @@ -3107,7 +3107,6 @@ AC_OUTPUT( epan/dissectors/dcerpc/Makefile epan/dissectors/pidl/Makefile epan/ftypes/Makefile - epan/jsmn/Makefile epan/nghttp2/Makefile epan/wmem/Makefile epan/wslua/Makefile diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index bdc988ca53..371f623eea 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -1517,11 +1517,6 @@ set(WMEM_FILES ) source_group(wmem FILES ${WMEM_FILES}) -set(JSMN_FILES - jsmn/jsmn.c -) -source_group(jsmn FILES ${JSMN_FILES}) - set(NGHTTP2_FILES nghttp2/nghttp2_buf.c nghttp2/nghttp2_hd.c @@ -1690,7 +1685,6 @@ set(CLEAN_FILES ${DISSECTOR_SUPPORT_SRC} ${LIBWIRESHARK_ASM_FILES} ${WMEM_FILES} - ${JSMN_FILES} ${NGHTTP2_FILES} ${WSLUA_FILES} ) @@ -1713,7 +1707,6 @@ add_library(epan ${LINK_MODE_LIB} ${DFILTER_FILES} ${FTYPE_FILES} ${WMEM_FILES} - ${JSMN_FILES} ${NGHTTP2_FILES} ${WSLUA_FILES} ${DISSECTOR_FILES} @@ -1743,7 +1736,6 @@ file(GLOB DFILTER_HEADERS dfilter/*.h ../tools/lemon/cppmagic.h) file(GLOB D_HEADERS dissectors/*.h) file(GLOB FTYPES_HEADERS ftypes/*.h) file(GLOB WMEM_HEADERS wmem/*.h) -file(GLOB JSMN_HEADERS jsmn/*.h) file(GLOB NGHTTP2_HEADERS nghttp2/*.h) file(MAKE_DIRECTORY ${ABICHECK_TMPDIR} ${ABICHECK_TMPDIR}/epan @@ -1753,7 +1745,6 @@ file(MAKE_DIRECTORY ${ABICHECK_TMPDIR} ${ABICHECK_TMPDIR}/dissectors ${ABICHECK_TMPDIR}/ftypes ${ABICHECK_TMPDIR}/wmem - ${ABICHECK_TMPDIR}/jsmn ${ABICHECK_TMPDIR}/nghttp2) file(COPY ../color.h ../register.h DESTINATION ${ABICHECK_TMPDIR}) @@ -1764,7 +1755,6 @@ file(COPY ${DFILTER_HEADERS} DESTINATION ${ABICHECK_TMPDIR}/dfilter) file(COPY ${D_HEADERS} DESTINATION ${ABICHECK_TMPDIR}/dissectors) file(COPY ${FTYPES_HEADERS} DESTINATION ${ABICHECK_TMPDIR}/ftypes) file(COPY ${WMEM_HEADERS} DESTINATION ${ABICHECK_TMPDIR}/wmem) -file(COPY ${JSMN_HEADERS} DESTINATION ${ABICHECK_TMPDIR}/jsmn) file(COPY ${NGHTTP2_HEADERS} DESTINATION ${ABICHECK_TMPDIR}/nghttp2) add_custom_command(OUTPUT libwireshark.abi.tar.gz @@ -1781,10 +1771,10 @@ add_custom_command(OUTPUT libwireshark.abi.tar.gz ${ABICHECK_TMPDIR}/epan/* ${ABICHECK_TMPDIR}/compress/* ${ABICHECK_TMPDIR}/dfilter/* ${ABICHECK_TMPDIR}/dissectors/* ${ABICHECK_TMPDIR}/ftypes/* ${ABICHECK_TMPDIR}/wmem/* - ${ABICHECK_TMPDIR}/jsmn/* ${ABICHECK_TMPDIR}/nghttp2/* + ${ABICHECK_TMPDIR}/nghttp2/* DEPENDS ${HEADERS} ${CRYPT_HEADERS} ${COMPRESS_HEADERS} ${DFILTER_HEADERS} ${D_HEADERS} - ${FTYPES_HEADERS} ${WMEM_HEADERS} ${JSMN_HEADERS} ${NGHTTP2_HEADERS} epan) + ${FTYPES_HEADERS} ${WMEM_HEADERS} ${NGHTTP2_HEADERS} epan) # By default the name for a library with target name epan will be libepan, # but Ethereal is now named Wireshark diff --git a/epan/Makefile.am b/epan/Makefile.am index cbbfac3ef4..ac19b3f7a1 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -33,7 +33,7 @@ wslua_dir = wslua_dist_dir = wslua endif # HAVE_LIBLUA -SUBDIRS = compress crypt ftypes dfilter dissectors jsmn nghttp2 wmem $(wslua_dir) +SUBDIRS = compress crypt ftypes dfilter dissectors nghttp2 wmem $(wslua_dir) DIST_SUBDIRS = $(SUBDIRS) $(wslua_dist_dir) @@ -127,7 +127,7 @@ libwireshark_la_LIBADD = \ libwireshark_asmopt.la crypt/libairpdcap.la \ ftypes/libftypes.la dfilter/libdfilter.la dissectors/libdissectors.la \ dissectors/libdirtydissectors.la dissectors/libfiledissectors.la \ - jsmn/libjsmn.la nghttp2/libnghttp2.la wmem/libwmem.la $(wslua_lib) \ + nghttp2/libnghttp2.la wmem/libwmem.la $(wslua_lib) \ @SOCKET_LIBS@ @NSL_LIBS@ \ @C_ARES_LIBS@ @ADNS_LIBS@ @LIBGCRYPT_LIBS@ @LIBGNUTLS_LIBS@ \ @KRB5_LIBS@ @SSL_LIBS@ @LIBSMI_LDFLAGS@ @GEOIP_LIBS@ \ @@ -138,7 +138,7 @@ libwireshark_la_DEPENDENCIES = \ libwireshark_generated.la compress/liblzxpress.la\ libwireshark_asmopt.la crypt/libairpdcap.la \ ftypes/libftypes.la dfilter/libdfilter.la dissectors/libdissectors.la \ - dissectors/libdirtydissectors.la jsmn/libjsmn.la nghttp2/libnghttp2.la \ + dissectors/libdirtydissectors.la nghttp2/libnghttp2.la \ wmem/libwmem.la $(wslua_lib) \ ${top_builddir}/wsutil/libwsutil.la \ ${top_builddir}/wiretap/libwiretap.la diff --git a/epan/Makefile.nmake b/epan/Makefile.nmake index 47d5bcca4b..f0ad957250 100644 --- a/epan/Makefile.nmake +++ b/epan/Makefile.nmake @@ -71,7 +71,6 @@ libwireshark_LIBS = \ dfilter\dfilter.lib \ wmem\wmem.lib \ $(WSLUA_LIB) \ - jsmn\jsmn.lib \ nghttp2\nghttp2.lib \ dissectors\dissectors.lib @@ -92,17 +91,17 @@ DOXYGEN_DEP=doxygen !ENDIF !IFDEF ENABLE_LIBWIRESHARK -all: compress crypt ftypes dfilter wmem $(WSLUA_DIR) jsmn nghttp2 dissectors libwireshark.dll +all: compress crypt ftypes dfilter wmem $(WSLUA_DIR) nghttp2 dissectors libwireshark.dll !ELSE -all: compress crypt ftypes dfilter wmem $(WSLUA_DIR) jsmn nghttp2 dissectors libwireshark.lib +all: compress crypt ftypes dfilter wmem $(WSLUA_DIR) nghttp2 dissectors libwireshark.lib !ENDIF # For use when making libwireshark.dll libwireshark.lib: libwireshark.dll libwireshark.exp: libwireshark.dll -libwireshark.dll: ..\config.h $(LIBWIRESHARK_OBJECTS) compress crypt ftypes dfilter wmem $(WSLUA_DIR) jsmn nghttp2 dissectors $(DOXYGEN_DEP) $(EXTRA_OBJECTS) \ - crypt\airpdcap.lib ftypes\ftypes.lib dfilter\dfilter.lib wmem\wmem.lib dissectors\dissectors.lib $(WSLUA_LIB) jsmn\jsmn.lib nghttp2\nghttp2.lib ..\image\libwireshark.res +libwireshark.dll: ..\config.h $(LIBWIRESHARK_OBJECTS) compress crypt ftypes dfilter wmem $(WSLUA_DIR) nghttp2 dissectors $(DOXYGEN_DEP) $(EXTRA_OBJECTS) \ + crypt\airpdcap.lib ftypes\ftypes.lib dfilter\dfilter.lib wmem\wmem.lib dissectors\dissectors.lib $(WSLUA_LIB) nghttp2\nghttp2.lib ..\image\libwireshark.res @echo Linking libwireshark.dll $(link) $(dlllflags) $(conlibsdll) shell32.lib psapi.lib \ $(LOCAL_LDFLAGS) $(DLL_LDFLAGS) \ @@ -112,8 +111,8 @@ libwireshark.dll: ..\config.h $(LIBWIRESHARK_OBJECTS) compress crypt ftypes dfil dissectors\register.obj \ $(EXTRA_OBJECTS) -libwireshark.lib : ..\config.h $(LIBWIRESHARK_OBJECTS) compress crypt ftypes dfilter wmem $(WSLUA_DIR) jsmn nghttp2 dissectors $(DOXYGEN_DEP) $(EXTRA_OBJECTS) \ - crypt\airpdcap.lib ftypes\ftypes.lib dfilter\dfilter.lib wmem\wmem.lib $(WSLUA_LIB) jsmn\jsmn.lib nghttp2\nghttp2.lib dissectors\dissectors.lib +libwireshark.lib : ..\config.h $(LIBWIRESHARK_OBJECTS) compress crypt ftypes dfilter wmem $(WSLUA_DIR) nghttp2 dissectors $(DOXYGEN_DEP) $(EXTRA_OBJECTS) \ + crypt\airpdcap.lib ftypes\ftypes.lib dfilter\dfilter.lib wmem\wmem.lib $(WSLUA_LIB) nghttp2\nghttp2.lib dissectors\dissectors.lib link /lib /out:libwireshark.lib $(LIBWIRESHARK_OBJECTS) \ $(EXTRA_OBJECTS) @@ -144,8 +143,6 @@ clean: clean-local $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean cd ../wslua $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean - cd ../jsmn - $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean cd ../nghttp2 $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake clean cd .. @@ -182,8 +179,6 @@ distclean: distclean-local $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake distclean cd ../wslua $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake distclean - cd ../jsmn - $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake distclean cd ../nghttp2 $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake distclean cd .. @@ -205,8 +200,6 @@ maintainer-clean: maintainer-clean-local $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake maintainer-clean cd ../wslua $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake maintainer-clean - cd ../jsmn - $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake maintainer-clean cd ../nghttp2 $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake maintainer-clean cd .. @@ -246,11 +239,6 @@ wslua:: ..\config.h $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake cd .. -jsmn:: ..\config.h - cd jsmn - $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake - cd .. - nghttp2:: ..\config.h cd nghttp2 $(MAKE) /$(MAKEFLAGS) -f Makefile.nmake diff --git a/epan/dissectors/packet-json.c b/epan/dissectors/packet-json.c index 745ef7076f..4451b7de03 100644 --- a/epan/dissectors/packet-json.c +++ b/epan/dissectors/packet-json.c @@ -31,11 +31,13 @@ #include <epan/packet.h> #include <epan/tvbparse.h> -#include <epan/jsmn/jsmn.h> +#include <wsutil/jsmn.h> #include <wsutil/str_util.h> #include <wsutil/unicode-utils.h> +#include <wiretap/wtap.h> + void proto_register_json(void); void proto_reg_handoff_json(void); @@ -119,6 +121,20 @@ dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) const char *data_name; int offset; + /* JSON dissector can be called in a JSON native file or when transported + * by another protocol. We set the column values only if they've not been + * already set by someone else. + */ + wmem_list_frame_t *proto = wmem_list_frame_prev(wmem_list_tail(pinfo->layers)); + if (proto) { + const char *name = proto_get_protocol_filter_name(GPOINTER_TO_INT(wmem_list_frame_data(proto))); + + if (!strcmp(name, "frame")) { + col_set_str(pinfo->cinfo, COL_PROTOCOL, "JSON"); + col_set_str(pinfo->cinfo, COL_INFO, "JavaScript Object Notation"); + } + } + data_name = pinfo->match_string; if (! (data_name && data_name[0])) { /* @@ -572,19 +588,12 @@ static void init_json_parser(void) { static gboolean dissect_json_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { - /* We expect no more than 1024 tokens */ - const guint max_tokens = 1024; guint len = tvb_captured_length(tvb); - guint8* buf = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, len, ENC_ASCII); + const guint8* buf = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, len, ENC_ASCII); - jsmn_parser p; - - jsmntok_t* t = (jsmntok_t*)wmem_alloc_array(wmem_packet_scope(), jsmntok_t, max_tokens); - - jsmn_init(&p); - if (jsmn_parse(&p, buf, len, t, max_tokens) < 0) { + if (jsmn_is_json(buf, len) == FALSE) return FALSE; - } + return (dissect_json(tvb, pinfo, tree, data) != 0); } @@ -628,6 +637,7 @@ proto_reg_handoff_json(void) { heur_dissector_add("hpfeeds", dissect_json_heur, proto_json); heur_dissector_add("db-lsp", dissect_json_heur, proto_json); + dissector_add_uint("wtap_encap", WTAP_ENCAP_JSON, json_handle); dissector_add_string("media_type", "application/json", json_handle); /* RFC 4627 */ dissector_add_string("media_type", "application/json-rpc", json_handle); /* JSON-RPC over HTTP */ diff --git a/epan/jsmn/Makefile.am b/epan/jsmn/Makefile.am deleted file mode 100644 index 60e824e8aa..0000000000 --- a/epan/jsmn/Makefile.am +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile.am -# Automake file for libjsmn library -# -# Wireshark - Network traffic analyzer -# By Gerald Combs <gerald@wireshark.org> -# Copyright 1998 Gerald Combs -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -if HAVE_WARNINGS_AS_ERRORS -AM_CFLAGS = -Werror -endif - -include Makefile.common - -AM_CPPFLAGS = \ - -I$(top_srcdir) \ - $(LIBJSMN_CFLAGS) - -noinst_LTLIBRARIES = libjsmn.la - -CLEANFILES = \ - libjsmn.a \ - libjsmn.la \ - *~ - -DISTCLEANFILES = - -MAINTAINERCLEANFILES = \ - Makefile.in - -libjsmn_la_SOURCES = \ - $(LIBJSMN_SRC) \ - $(LIBJSMN_INCLUDES) - -EXTRA_DIST = \ - Makefile.common \ - Makefile.nmake - -# -# Editor modelines - https://www.wireshark.org/tools/modelines.html -# -# Local variables: -# c-basic-offset: 8 -# tab-width: 8 -# indent-tabs-mode: t -# End: -# -# vi: set shiftwidth=8 tabstop=8 noexpandtab: -# :indentSize=8:tabSize=8:noTabs=false: -# diff --git a/epan/jsmn/Makefile.common b/epan/jsmn/Makefile.common deleted file mode 100644 index 1e9548f3b8..0000000000 --- a/epan/jsmn/Makefile.common +++ /dev/null @@ -1,38 +0,0 @@ -# Makefile.common -# Contains the stuff from Makefile.am and Makefile.nmake that is -# a) common to both files and -# b) portable between both files -# -# Wireshark - Network traffic analyzer -# By Gerald Combs <gerald@wireshark.org> -# Copyright 1998 Gerald Combs -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -LIBJSMN_SRC = jsmn.c -LIBJSMN_INCLUDES = jsmn.h - -# -# Editor modelines - https://www.wireshark.org/tools/modelines.html -# -# Local variables: -# c-basic-offset: 8 -# tab-width: 8 -# indent-tabs-mode: t -# End: -# -# vi: set shiftwidth=8 tabstop=8 noexpandtab: -# :indentSize=8:tabSize=8:noTabs=false: -# diff --git a/epan/jsmn/Makefile.nmake b/epan/jsmn/Makefile.nmake deleted file mode 100644 index f657ea5f6d..0000000000 --- a/epan/jsmn/Makefile.nmake +++ /dev/null @@ -1,44 +0,0 @@ -## Makefile for building jsmn.lib with Microsoft C and nmake -## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake -# - -include ..\..\config.nmake - -include Makefile.common - -############### no need to modify below this line ######### - -CFLAGS=$(WARNINGS_ARE_ERRORS) $(STANDARD_CFLAGS) \ - /I. /Ijsmn /I../.. $(GLIB_CFLAGS) -DWS_BUILD_DLL - -.c.obj:: - $(CC) $(CFLAGS) -Fd.\ -c $< - -OBJECTS = $(LIBJSMN_SRC:.c=.obj) - -jsmn.lib: $(OBJECTS) - link /lib /out:jsmn.lib $(OBJECTS) - -clean: - rm -f $(OBJECTS) jsmn.lib *.nativecodeanalysis.xml *.pdb *.sbr - -distclean: clean - -maintainer-clean: distclean - -checkapi: - $(PERL) ../../tools/checkAPIs.pl -g termoutput -build \ - $(LIBJSMN_INCLUDES) - -# -# Editor modelines - https://www.wireshark.org/tools/modelines.html -# -# Local variables: -# c-basic-offset: 8 -# tab-width: 8 -# indent-tabs-mode: t -# End: -# -# vi: set shiftwidth=8 tabstop=8 noexpandtab: -# :indentSize=8:tabSize=8:noTabs=false: -# diff --git a/epan/jsmn/jsmn.c b/epan/jsmn/jsmn.c deleted file mode 100644 index 30014239ea..0000000000 --- a/epan/jsmn/jsmn.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) 2010 Serge A. Zaitsev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include <stdlib.h> - -#include "jsmn.h" - -/** - * Allocates a fresh unused token from the token pull. - */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, - jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; -#ifdef JSMN_PARENT_LINKS - tok->parent = -1; -#endif - return tok; -} - -/** - * Fills token type and boundaries. - */ -static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - int start, int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; -} - -/** - * Fills next available token with JSON primitive. - */ -static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; - int start; - - start = parser->pos; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { -#ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': -#endif - case '\t' : case '\r' : case '\n' : case ' ' : - case ',' : case ']' : case '}' : - goto found; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } -#ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; -#endif - -found: - if (tokens == NULL) { - parser->pos--; - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - parser->pos--; - return 0; -} - -/** - * Filsl next token with JSON string. - */ -static int jsmn_parse_string(jsmn_parser *parser, const char *js, - size_t len, jsmntok_t *tokens, size_t num_tokens) { - jsmntok_t *token; - - int start = parser->pos; - - parser->pos++; - - /* Skip starting quote */ - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; - - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - return 0; - } - - /* Backslash: Quoted symbol expected */ - if (c == '\\' && parser->pos + 1 < len) { - int i; - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': case '/' : case '\\' : case 'b' : - case 'f' : case 'r' : case 'n' : case 't' : - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { - /* If it isn't a hex character we have an error */ - if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } - } - parser->pos = start; - return JSMN_ERROR_PART; -} - -/** - * Parse JSON string and fill tokens. - */ -int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens) { - int r; - int i; - jsmntok_t *token; - int count = 0; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; - - c = js[parser->pos]; - switch (c) { - case '{': case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) - return JSMN_ERROR_NOMEM; - if (parser->toksuper != -1) { - tokens[parser->toksuper].size++; -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': case ']': - if (tokens == NULL) - break; - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); -#ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - break; - } - token = &tokens[token->parent]; - } -#else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) return JSMN_ERROR_INVAL; - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } -#endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - case '\t' : case '\r' : case '\n' : case ' ': - break; - case ':': - parser->toksuper = parser->toknext - 1; - break; - case ',': - if (tokens != NULL && parser->toksuper != -1 && - tokens[parser->toksuper].type != JSMN_ARRAY && - tokens[parser->toksuper].type != JSMN_OBJECT) { -#ifdef JSMN_PARENT_LINKS - parser->toksuper = tokens[parser->toksuper].parent; -#else - for (i = parser->toknext - 1; i >= 0; i--) { - if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { - if (tokens[i].start != -1 && tokens[i].end == -1) { - parser->toksuper = i; - break; - } - } - } -#endif - } - break; -#ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': case '0': case '1' : case '2': case '3' : case '4': - case '5': case '6': case '7' : case '8': case '9': - case 't': case 'f': case 'n' : - /* And they must not be keys of the object */ - if (tokens != NULL && parser->toksuper != -1) { - jsmntok_t *t = &tokens[parser->toksuper]; - if (t->type == JSMN_OBJECT || - (t->type == JSMN_STRING && t->size != 0)) { - return JSMN_ERROR_INVAL; - } - } -#else - /* In non-strict mode every unquoted value is a primitive */ - default: -#endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) return r; - count++; - if (parser->toksuper != -1 && tokens != NULL) - tokens[parser->toksuper].size++; - break; - -#ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; -#endif - } - } - - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } - } - - return count; -} - -/** - * Creates a new parser based over a given buffer with an array of tokens - * available. - */ -void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; -} - -/* - * Editor modelines - http://www.wireshark.org/tools/modelines.html - * - * Local variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * vi: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=8:noTabs=true: - */ diff --git a/wiretap/CMakeLists.txt b/wiretap/CMakeLists.txt index 1e7ead3ad8..52b3738320 100644 --- a/wiretap/CMakeLists.txt +++ b/wiretap/CMakeLists.txt @@ -46,6 +46,7 @@ set(CLEAN_FILES ipfix.c iptrace.c iseries.c + json.c k12.c lanalyzer.c libpcap.c diff --git a/wiretap/Makefile.common b/wiretap/Makefile.common index f1f30b0352..9bd64db3d4 100644 --- a/wiretap/Makefile.common +++ b/wiretap/Makefile.common @@ -52,6 +52,7 @@ NONGENERATED_C_FILES = \ iptrace.c \ iseries.c \ mime_file.c \ + json.c \ k12.c \ lanalyzer.c \ logcat_text.c \ diff --git a/wiretap/file_access.c b/wiretap/file_access.c index 9006e4862c..898f17e078 100644 --- a/wiretap/file_access.c +++ b/wiretap/file_access.c @@ -65,6 +65,7 @@ #include "hcidump.h" #include "logcat.h" #include "logcat_text.h" +#include "json.h" #include "network_instruments.h" #include "k12.h" #include "ber.h" @@ -156,6 +157,7 @@ static const struct file_extension_info file_type_extensions_base[] = { { "MPEG2 transport stream", "mp2t;ts;mpg" }, { "Ixia IxVeriWave .vwr Raw 802.11 Capture", "vwr" }, { "CAM Inspector file", "camins" }, + { "JavaScript Object Notation file", "json" } }; #define N_FILE_TYPE_EXTENSIONS (sizeof file_type_extensions_base / sizeof file_type_extensions_base[0]) @@ -395,6 +397,7 @@ static struct open_info open_info_base[] = { /* Extremely weak heuristics - put them at the end. */ { "Ixia IxVeriWave .vwr Raw Capture", OPEN_INFO_HEURISTIC, vwr_open, "vwr", NULL, NULL }, { "CAM Inspector file", OPEN_INFO_HEURISTIC, camins_open, "camins", NULL, NULL }, + { "JavaScript Object Notation", OPEN_INFO_HEURISTIC, json_open, "json", NULL, NULL } }; /* this is only used to build the dynamic array on load, do NOT use this @@ -1488,6 +1491,11 @@ static const struct file_type_subtype_info dump_open_table_base[] = { FALSE, FALSE, 0, logcat_dump_can_write_encap, logcat_binary_dump_open, NULL }, + /* WTAP_FILE_TYPE_SUBTYPE_JSON */ + { "JavaScript Object Notation", "json", "json", "NULL", + FALSE, FALSE, 0, + NULL, NULL, NULL }, + /* WTAP_FILE_TYPE_SUBTYPE_LOGCAT_BRIEF */ { "Android Logcat Brief text format", "logcat-brief", NULL, NULL, FALSE, FALSE, 0, diff --git a/wiretap/json.c b/wiretap/json.c new file mode 100644 index 0000000000..9e81f2e56d --- /dev/null +++ b/wiretap/json.c @@ -0,0 +1,138 @@ +/* json.c + * + * Copyright 2015, Dario Lombardo <lomato@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <string.h> + +#include "wtap-int.h" +#include "file_wrappers.h" + +#include <json.h> +#include <wsutil/jsmn.h> + +static gboolean json_read_file(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr, + Buffer *buf, int *err, gchar **err_info) +{ + gint64 file_size; + int packet_size; + + if ((file_size = wtap_file_size(wth, err)) == -1) + return FALSE; + + if (file_size > MAX_FILE_SIZE) { + /* + * Don't blow up trying to allocate space for an + * immensely-large file. + */ + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("mime_file: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u", + file_size, MAX_FILE_SIZE); + return FALSE; + } + packet_size = (int)file_size; + + phdr->rec_type = REC_TYPE_PACKET; + phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */ + + phdr->caplen = packet_size; + phdr->len = packet_size; + + phdr->ts.secs = 0; + phdr->ts.nsecs = 0; + + return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info); +} + +static gboolean json_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr, Buffer *buf, + int *err, gchar **err_info) +{ + /* there is only one packet */ + if (seek_off > 0) { + *err = 0; + return FALSE; + } + + if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) + return FALSE; + + return json_read_file(wth, wth->random_fh, phdr, buf, err, err_info); +} + +static gboolean json_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset) +{ + gint64 offset; + + *err = 0; + + offset = file_tell(wth->fh); + + /* there is only ever one packet */ + if (offset != 0) + return FALSE; + + *data_offset = offset; + + return json_read_file(wth, wth->fh, &wth->phdr, wth->frame_buffer, err, err_info); +} + +wtap_open_return_val json_open(wtap *wth, int *err, gchar **err_info _U_) +{ + guint8* filebuf; + guint read; + + filebuf = (guint8*)g_malloc0(MAX_FILE_SIZE); + if (!filebuf) + return WTAP_OPEN_ERROR; + + read = file_read(filebuf, MAX_FILE_SIZE, wth->fh); + + if (jsmn_is_json(filebuf, read) == FALSE) { + g_free(filebuf); + return WTAP_OPEN_NOT_MINE; + } + + if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) { + g_free(filebuf); + return WTAP_OPEN_ERROR; + } + + wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_JSON; + wth->file_encap = WTAP_ENCAP_JSON; + wth->file_tsprec = WTAP_TSPREC_SEC; + wth->subtype_read = json_read; + wth->subtype_seek_read = json_seek_read; + wth->snapshot_length = 0; + + g_free(filebuf); + return WTAP_OPEN_MINE; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/wiretap/json.h b/wiretap/json.h new file mode 100644 index 0000000000..8c233cb771 --- /dev/null +++ b/wiretap/json.h @@ -0,0 +1,55 @@ +/* json.h + * + * Copyright 2015, Dario Lombardo <lomato@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef __JSON_H__ +#define __JSON_H__ + +#include <glib.h> + +#include "wtap.h" + +/* + * Impose a not-too-large limit on the maximum file size, to avoid eating + * up 99% of the (address space, swap partition, disk space for swap/page + * files); if we were to return smaller chunks and let the dissector do + * reassembly, it would *still* have to allocate a buffer the size of + * the file, so it's not as if we'd neve try to allocate a buffer the + * size of the file. + * + * For now, go for 50MB. + */ +#define MAX_FILE_SIZE (50*1024*1024) + +wtap_open_return_val json_open(wtap *wth, int *err, gchar **err_info); + +#endif + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/wiretap/wtap.c b/wiretap/wtap.c index 6b0cf92610..4de71ee723 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -740,6 +740,9 @@ static struct encap_type_info encap_table_base[] = { /* WTAP_ENCAP_LOOP */ { "OpenBSD loopback", "loop" }, + + /* WTAP_ENCAP_JSON */ + { "JavaScript Object Notation", "json" } }; WS_DLL_LOCAL diff --git a/wiretap/wtap.h b/wiretap/wtap.h index 1570466579..f5aaebfa61 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -266,6 +266,7 @@ extern "C" { #define WTAP_ENCAP_EPON 173 #define WTAP_ENCAP_IPMI_TRACE 174 #define WTAP_ENCAP_LOOP 175 +#define WTAP_ENCAP_JSON 176 /* After adding new item here, please also add new item to encap_table_base array */ #define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types() @@ -352,6 +353,7 @@ extern "C" { #define WTAP_FILE_TYPE_SUBTYPE_LOGCAT_LONG 74 #define WTAP_FILE_TYPE_SUBTYPE_COLASOFT_CAPSA 75 #define WTAP_FILE_TYPE_SUBTYPE_COLASOFT_PACKET_BUILDER 76 +#define WTAP_FILE_TYPE_SUBTYPE_JSON 77 #define WTAP_NUM_FILE_TYPES_SUBTYPES wtap_get_num_file_types_subtypes() diff --git a/wsutil/CMakeLists.txt b/wsutil/CMakeLists.txt index c7e8138efc..fe2d662eac 100644 --- a/wsutil/CMakeLists.txt +++ b/wsutil/CMakeLists.txt @@ -53,6 +53,7 @@ set(WSUTIL_FILES eax.c filesystem.c g711.c + jsmn.c md4.c md5.c mpeg-audio.c diff --git a/wsutil/Makefile.common b/wsutil/Makefile.common index aa050da5de..5385c8a7a9 100644 --- a/wsutil/Makefile.common +++ b/wsutil/Makefile.common @@ -50,6 +50,7 @@ LIBWSUTIL_SRC = \ eax.c \ filesystem.c \ g711.c \ + jsmn.c \ md4.c \ md5.c \ mpeg-audio.c \ @@ -98,6 +99,7 @@ libwsutil_nonrepl_INCLUDES = \ eax.h \ filesystem.h \ g711.h \ + jsmn.h \ md4.h \ md5.h \ mpeg-audio.h \ diff --git a/wsutil/jsmn.c b/wsutil/jsmn.c new file mode 100644 index 0000000000..834e4b1ee9 --- /dev/null +++ b/wsutil/jsmn.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2010 Serge A. Zaitsev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdlib.h> + +#include "jsmn.h" + +#include "log.h" + +/** + * Allocates a fresh unused token from the token pull. + */ +static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, + jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *tok; + if (parser->toknext >= num_tokens) { + return NULL; + } + tok = &tokens[parser->toknext++]; + tok->start = tok->end = -1; + tok->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + return tok; +} + +/** + * Fills token type and boundaries. + */ +static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, + int start, int end) { + token->type = type; + token->start = start; + token->end = end; + token->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + int start; + + start = parser->pos; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + switch (js[parser->pos]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + case '\t' : case '\r' : case '\n' : case ' ' : + case ',' : case ']' : case '}' : + goto found; + } + if (js[parser->pos] < 32 || js[parser->pos] >= 127) { + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +found: + if (tokens == NULL) { + parser->pos--; + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Filsl next token with JSON string. + */ +static int jsmn_parse_string(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + jsmntok_t *token; + + int start = parser->pos; + + parser->pos++; + + /* Skip starting quote */ + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c = js[parser->pos]; + + /* Quote: end of string */ + if (c == '\"') { + if (tokens == NULL) { + return 0; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) { + parser->pos = start; + return JSMN_ERROR_NOMEM; + } + jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + return 0; + } + + /* Backslash: Quoted symbol expected */ + if (c == '\\' && parser->pos + 1 < len) { + int i; + parser->pos++; + switch (js[parser->pos]) { + /* Allowed escaped symbols */ + case '\"': case '/' : case '\\' : case 'b' : + case 'f' : case 'r' : case 'n' : case 't' : + break; + /* Allows escaped symbol \uXXXX */ + case 'u': + parser->pos++; + for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { + /* If it isn't a hex character we have an error */ + if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ + (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ + (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ + parser->pos = start; + return JSMN_ERROR_INVAL; + } + parser->pos++; + } + parser->pos--; + break; + /* Unexpected symbol */ + default: + parser->pos = start; + return JSMN_ERROR_INVAL; + } + } + } + parser->pos = start; + return JSMN_ERROR_PART; +} + +/** + * Parse JSON string and fill tokens. + */ +int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) { + int r; + int i; + jsmntok_t *token; + int count = 0; + + for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { + char c; + jsmntype_t type; + + c = js[parser->pos]; + switch (c) { + case '{': case '[': + count++; + if (tokens == NULL) { + break; + } + token = jsmn_alloc_token(parser, tokens, num_tokens); + if (token == NULL) + return JSMN_ERROR_NOMEM; + if (parser->toksuper != -1) { + tokens[parser->toksuper].size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + if (parser->toknext < 1) { + return JSMN_ERROR_INVAL; + } + token = &tokens[parser->toknext - 1]; + for (;;) { + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + token->end = parser->pos + 1; + parser->toksuper = token->parent; + break; + } + if (token->parent == -1) { + break; + } + token = &tokens[token->parent]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t' : case '\r' : case '\n' : case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && parser->toksuper != -1 && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* In strict mode primitives are: numbers and booleans */ + case '-': case '0': case '1' : case '2': case '3' : case '4': + case '5': case '6': case '7' : case '8': case '9': + case 't': case 'f': case 'n' : + /* And they must not be keys of the object */ + if (tokens != NULL && parser->toksuper != -1) { + jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + for (i = parser->toknext - 1; i >= 0; i--) { + /* Unmatched opened object or array */ + if (tokens[i].start != -1 && tokens[i].end == -1) { + return JSMN_ERROR_PART; + } + } + + return count; +} + +/** + * Creates a new parser based over a given buffer with an array of tokens + * available. + */ +void jsmn_init(jsmn_parser *parser) { + parser->pos = 0; + parser->toknext = 0; + parser->toksuper = -1; +} + +gboolean jsmn_is_json(const guint8* buf, const size_t len) +{ + /* We expect no more than 1024 tokens */ + guint max_tokens = 1024; + jsmntok_t* t; + jsmn_parser p; + gboolean ret = TRUE; + int rcode; + + t = g_new0(jsmntok_t, max_tokens); + + if (!t) + return FALSE; + + jsmn_init(&p); + rcode = jsmn_parse(&p, buf, len, t, max_tokens); + if (rcode < 0) { + switch (rcode) { + case JSMN_ERROR_NOMEM: + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "jsmn: not enough tokens were provided"); + break; + case JSMN_ERROR_INVAL: + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "jsmn: invalid character inside JSON string"); + break; + case JSMN_ERROR_PART: + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "jsmn: the string is not a full JSON packet, " + "more bytes expected"); + break; + default: + g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "jsmn: unexpected error"); + break; + } + ret = FALSE; + } + + g_free(t); + + return ret; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: t + * End: + * + * vi: set shiftwidth=4 tabstop=4 noexpandtab: + * :indentSize=4:tabSize=4:noTabs=false: + */ diff --git a/epan/jsmn/jsmn.h b/wsutil/jsmn.h index 458e7d447b..e4817dac5b 100644 --- a/epan/jsmn/jsmn.h +++ b/wsutil/jsmn.h @@ -25,6 +25,9 @@ #include <stddef.h> +#include <glib.h> +#include <ws_symbol_export.h> + #ifdef __cplusplus extern "C" { #endif @@ -37,19 +40,19 @@ extern "C" { * o Other primitive: number, boolean (true/false) or null */ typedef enum { - JSMN_PRIMITIVE = 0, - JSMN_OBJECT = 1, - JSMN_ARRAY = 2, - JSMN_STRING = 3 + JSMN_PRIMITIVE = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3 } jsmntype_t; typedef enum { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3 + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 } jsmnerr_t; /** @@ -60,12 +63,12 @@ typedef enum { * size the size of the token */ typedef struct { - jsmntype_t type; - int start; - int end; - int size; + jsmntype_t type; + int start; + int end; + int size; #ifdef JSMN_PARENT_LINKS - int parent; + int parent; #endif } jsmntok_t; @@ -74,22 +77,27 @@ typedef struct { * the string being parsed now and current position in that string */ typedef struct { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g parent object or array */ + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; /** * Create JSON parser over an array of tokens */ -void jsmn_init(jsmn_parser *parser); +WS_DLL_PUBLIC void jsmn_init(jsmn_parser *parser); /** * Run JSON parser. It parses a JSON data string into and array of tokens, each describing * a single JSON object. */ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, - jsmntok_t *tokens, unsigned int num_tokens); + jsmntok_t *tokens, unsigned int num_tokens); + +/** + * Check if a buffer is json an returns true if it is. + */ +WS_DLL_PUBLIC gboolean jsmn_is_json(const guint8* buf, const size_t len); #ifdef __cplusplus } @@ -102,10 +110,10 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, * * Local variables: * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil + * tab-width: 4 + * indent-tabs-mode: t * End: * - * vi: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=9:noTabs=true: + * vi: set shiftwidth=4 tabstop=4 noexpandtab: + * :indentSize=4:tabSize=8:noTabs=false: */ |