summaryrefslogtreecommitdiffstats
path: root/src/parser
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:48:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:48:59 +0000
commitc484829272cd13a738e35412498e12f2c9a194ac (patch)
treea1f5ec09629ee895bd3963fa8820b45f2f4c574b /src/parser
parentInitial commit. (diff)
downloadliborcus-upstream/0.19.2.tar.xz
liborcus-upstream/0.19.2.zip
Adding upstream version 0.19.2.upstream/0.19.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/parser/Makefile.am338
-rw-r--r--src/parser/Makefile.in2328
-rw-r--r--src/parser/base64.cpp70
-rw-r--r--src/parser/base64_test.cpp44
-rw-r--r--src/parser/cell_buffer.cpp61
-rw-r--r--src/parser/css_parser_base.cpp337
-rw-r--r--src/parser/css_parser_test.cpp28
-rw-r--r--src/parser/css_types.cpp198
-rw-r--r--src/parser/csv_parser_base.cpp47
-rw-r--r--src/parser/csv_parser_test.cpp29
-rw-r--r--src/parser/exception.cpp141
-rw-r--r--src/parser/json_global.cpp46
-rw-r--r--src/parser/json_parser_base.cpp104
-rw-r--r--src/parser/json_parser_test.cpp28
-rw-r--r--src/parser/json_parser_thread.cpp294
-rw-r--r--src/parser/parser_base.cpp222
-rw-r--r--src/parser/parser_base_test.cpp74
-rw-r--r--src/parser/parser_global.cpp515
-rw-r--r--src/parser/parser_global_test.cpp175
-rw-r--r--src/parser/parser_test_json_validation.cpp439
-rw-r--r--src/parser/parser_test_numeric.cpp105
-rw-r--r--src/parser/parser_test_xml_validation.cpp95
-rw-r--r--src/parser/sax_ns_parser_test.cpp78
-rw-r--r--src/parser/sax_parser_base.cpp421
-rw-r--r--src/parser/sax_parser_test.cpp67
-rw-r--r--src/parser/sax_token_parser.cpp110
-rw-r--r--src/parser/sax_token_parser_test.cpp239
-rw-r--r--src/parser/sax_token_parser_thread.cpp204
-rw-r--r--src/parser/stream.cpp447
-rw-r--r--src/parser/stream_test.cpp144
-rw-r--r--src/parser/string_pool.cpp137
-rw-r--r--src/parser/string_pool_test.cpp134
-rw-r--r--src/parser/threaded_json_parser_test.cpp187
-rw-r--r--src/parser/threaded_sax_token_parser_test.cpp190
-rw-r--r--src/parser/tokens.cpp44
-rw-r--r--src/parser/types.cpp1454
-rw-r--r--src/parser/types_test.cpp47
-rw-r--r--src/parser/utf8.cpp524
-rw-r--r--src/parser/utf8.hpp28
-rw-r--r--src/parser/utf8_test.cpp170
-rw-r--r--src/parser/win_stdint.h46
-rw-r--r--src/parser/xml_namespace.cpp490
-rw-r--r--src/parser/xml_namespace_test.cpp239
-rw-r--r--src/parser/xml_writer.cpp326
-rw-r--r--src/parser/xml_writer_test.cpp106
-rw-r--r--src/parser/yaml_parser_base.cpp512
-rw-r--r--src/parser/yaml_parser_test.cpp32
-rw-r--r--src/parser/zip_archive.cpp601
-rw-r--r--src/parser/zip_archive_stream.cpp113
-rw-r--r--src/parser/zip_archive_test.cpp98
50 files changed, 12906 insertions, 0 deletions
diff --git a/src/parser/Makefile.am b/src/parser/Makefile.am
new file mode 100644
index 0000000..c5c534c
--- /dev/null
+++ b/src/parser/Makefile.am
@@ -0,0 +1,338 @@
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src/include \
+ -DSRCDIR=\""$(top_srcdir)"\" \
+ $(BOOST_CPPFLAGS) \
+ -D__ORCUS_PSR_BUILDING_DLL
+
+if HAVE_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_FILESYSTEM=1"
+endif
+
+if HAVE_EXPERIMENTAL_FILESYSTEM
+AM_CPPFLAGS += "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+endif
+
+lib_LTLIBRARIES = liborcus-parser-@ORCUS_API_VERSION@.la
+liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES = \
+ win_stdint.h \
+ base64.cpp \
+ cell_buffer.cpp \
+ css_parser_base.cpp \
+ css_types.cpp \
+ csv_parser_base.cpp \
+ exception.cpp \
+ json_global.cpp \
+ json_parser_base.cpp \
+ json_parser_thread.cpp \
+ parser_base.cpp \
+ parser_global.cpp \
+ sax_parser_base.cpp \
+ sax_token_parser.cpp \
+ sax_token_parser_thread.cpp \
+ stream.cpp \
+ string_pool.cpp \
+ tokens.cpp \
+ types.cpp \
+ utf8.hpp \
+ utf8.cpp \
+ xml_namespace.cpp \
+ xml_writer.cpp \
+ yaml_parser_base.cpp \
+ zip_archive.cpp \
+ zip_archive_stream.cpp
+
+
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS = \
+ -no-undefined \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD = \
+ $(BOOST_SYSTEM_LIBS) \
+ $(ZLIB_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS += -lstdc++fs
+else
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+EXTRA_PROGRAMS = \
+ css-parser-test \
+ csv-parser-test \
+ json-parser-test \
+ parser-global-test \
+ parser-test-base \
+ parser-test-base64 \
+ parser-test-json-validation \
+ parser-test-numeric \
+ parser-test-stream \
+ parser-test-string-pool \
+ parser-test-threaded-json-parser \
+ parser-test-threaded-sax-token-parser \
+ parser-test-xml-namespace \
+ parser-test-xml-validation \
+ parser-test-zip-archive \
+ sax-ns-parser-test \
+ sax-parser-test \
+ sax-token-parser-test \
+ types-test \
+ utf8-test \
+ yaml-parser-test \
+ xml-writer-test
+
+# parser-test-string-pool
+
+parser_test_string_pool_SOURCES = \
+ string_pool.cpp \
+ string_pool_test.cpp
+
+parser_test_string_pool_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_string_pool_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-namespace
+
+parser_test_xml_namespace_SOURCES = \
+ xml_namespace.cpp \
+ xml_namespace_test.cpp
+
+parser_test_xml_namespace_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_xml_namespace_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-validation
+
+parser_test_xml_validation_SOURCES = \
+ parser_test_xml_validation.cpp
+
+parser_test_xml_validation_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_xml_validation_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+parser_test_xml_validation_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+parser_test_xml_validation_LDFLAGS += -lstdc++fs
+else
+parser_test_xml_validation_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+parser_test_xml_validation_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+# parser-test-base64
+
+parser_test_base64_SOURCES = \
+ base64.cpp \
+ base64_test.cpp
+
+parser_test_base64_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base64_CPPFLAGS = $(AM_CPPFLAGS)
+
+# css-parser-test
+
+css_parser_test_SOURCES = \
+ css_parser_test.cpp
+
+css_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+css_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# csv-parser-test
+
+csv_parser_test_SOURCES = \
+ csv_parser_test.cpp
+
+csv_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+csv_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# json-parser-test
+
+json_parser_test_SOURCES = \
+ json_parser_test.cpp
+
+json_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+json_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# yaml-parser-test
+
+yaml_parser_test_SOURCES = \
+ yaml_parser_test.cpp
+
+yaml_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+yaml_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-parser-test
+
+sax_parser_test_SOURCES = \
+ sax_parser_test.cpp
+
+sax_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-ns-parser-test
+
+sax_ns_parser_test_SOURCES = \
+ sax_ns_parser_test.cpp
+
+sax_ns_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_ns_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-token-parser-test
+
+sax_token_parser_test_SOURCES = \
+ sax_token_parser_test.cpp
+
+sax_token_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_token_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-sax-token-parser
+
+parser_test_threaded_sax_token_parser_SOURCES = \
+ threaded_sax_token_parser_test.cpp
+
+parser_test_threaded_sax_token_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_sax_token_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-json-parser
+
+parser_test_threaded_json_parser_SOURCES = \
+ threaded_json_parser_test.cpp
+
+parser_test_threaded_json_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_json_parser_LDFLAGS = -pthread
+parser_test_threaded_json_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-stream
+
+parser_test_stream_SOURCES = \
+ stream_test.cpp
+
+parser_test_stream_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+parser_test_stream_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-zip-archive
+
+parser_test_zip_archive_SOURCES = \
+ zip_archive_test.cpp
+
+parser_test_zip_archive_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_zip_archive_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+parser_test_zip_archive_LDFLAGS = \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+if !HAVE_FILESYSTEM
+if HAVE_EXPERIMENTAL_FILESYSTEM
+parser_test_zip_archive_LDFLAGS += -lstdc++fs
+else
+parser_test_zip_archive_LDFLAGS += $(BOOST_FILESYSTEM_LDFLAGS)
+parser_test_zip_archive_LDADD += $(BOOST_FILESYSTEM_LIBS)
+endif
+endif
+
+
+
+# parser-test-base
+
+parser_test_base_SOURCES = \
+ parser_base_test.cpp
+
+parser_test_base_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-global-test
+
+parser_global_test_SOURCES = \
+ parser_global_test.cpp
+
+parser_global_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+parser_global_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-json-validation
+
+parser_test_json_validation_SOURCES = \
+ parser_test_json_validation.cpp
+
+parser_test_json_validation_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_json_validation_CPPFLAGS = $(AM_CPPFLAGS)
+
+# types-test
+
+types_test_SOURCES = types_test.cpp
+
+types_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+types_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# utf8-test
+
+utf8_test_SOURCES = \
+ utf8.cpp \
+ utf8_test.cpp
+
+utf8_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+utf8_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# xml-writer-test
+
+xml_writer_test_SOURCES = xml_writer_test.cpp
+
+xml_writer_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+xml_writer_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-numeric
+
+parser_test_numeric_SOURCES = \
+ parser_test_numeric.cpp
+
+parser_test_numeric = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_CPPFLAGS = $(AM_CPPFLAGS)
+
+TESTS = \
+ css-parser-test \
+ csv-parser-test \
+ json-parser-test \
+ parser-global-test \
+ parser-test-base \
+ parser-test-base64 \
+ parser-test-json-validation \
+ parser-test-numeric \
+ parser-test-stream \
+ parser-test-string-pool \
+ parser-test-threaded-json-parser \
+ parser-test-threaded-sax-token-parser \
+ parser-test-xml-namespace \
+ parser-test-xml-validation \
+ parser-test-zip-archive \
+ sax-ns-parser-test \
+ sax-parser-test \
+ sax-token-parser-test \
+ types-test \
+ utf8-test \
+ yaml-parser-test \
+ xml-writer-test
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
diff --git a/src/parser/Makefile.in b/src/parser/Makefile.in
new file mode 100644
index 0000000..8ac6054
--- /dev/null
+++ b/src/parser/Makefile.in
@@ -0,0 +1,2328 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_FILESYSTEM_TRUE@am__append_1 = "-DHAVE_FILESYSTEM=1"
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@am__append_2 = "-DHAVE_EXPERIMENTAL_FILESYSTEM=1"
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_3 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_4 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_5 = $(BOOST_FILESYSTEM_LIBS)
+EXTRA_PROGRAMS = css-parser-test$(EXEEXT) csv-parser-test$(EXEEXT) \
+ json-parser-test$(EXEEXT) parser-global-test$(EXEEXT) \
+ parser-test-base$(EXEEXT) parser-test-base64$(EXEEXT) \
+ parser-test-json-validation$(EXEEXT) \
+ parser-test-numeric$(EXEEXT) parser-test-stream$(EXEEXT) \
+ parser-test-string-pool$(EXEEXT) \
+ parser-test-threaded-json-parser$(EXEEXT) \
+ parser-test-threaded-sax-token-parser$(EXEEXT) \
+ parser-test-xml-namespace$(EXEEXT) \
+ parser-test-xml-validation$(EXEEXT) \
+ parser-test-zip-archive$(EXEEXT) sax-ns-parser-test$(EXEEXT) \
+ sax-parser-test$(EXEEXT) sax-token-parser-test$(EXEEXT) \
+ types-test$(EXEEXT) utf8-test$(EXEEXT) \
+ yaml-parser-test$(EXEEXT) xml-writer-test$(EXEEXT)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_6 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_7 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_8 = $(BOOST_FILESYSTEM_LIBS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_TRUE@@HAVE_FILESYSTEM_FALSE@am__append_9 = -lstdc++fs
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_10 = $(BOOST_FILESYSTEM_LDFLAGS)
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__append_11 = $(BOOST_FILESYSTEM_LIBS)
+TESTS = css-parser-test$(EXEEXT) csv-parser-test$(EXEEXT) \
+ json-parser-test$(EXEEXT) parser-global-test$(EXEEXT) \
+ parser-test-base$(EXEEXT) parser-test-base64$(EXEEXT) \
+ parser-test-json-validation$(EXEEXT) \
+ parser-test-numeric$(EXEEXT) parser-test-stream$(EXEEXT) \
+ parser-test-string-pool$(EXEEXT) \
+ parser-test-threaded-json-parser$(EXEEXT) \
+ parser-test-threaded-sax-token-parser$(EXEEXT) \
+ parser-test-xml-namespace$(EXEEXT) \
+ parser-test-xml-validation$(EXEEXT) \
+ parser-test-zip-archive$(EXEEXT) sax-ns-parser-test$(EXEEXT) \
+ sax-parser-test$(EXEEXT) sax-token-parser-test$(EXEEXT) \
+ types-test$(EXEEXT) utf8-test$(EXEEXT) \
+ yaml-parser-test$(EXEEXT) xml-writer-test$(EXEEXT)
+subdir = src/parser
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/m4_ax_valgrind_check.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@HAVE_EXPERIMENTAL_FILESYSTEM_FALSE@@HAVE_FILESYSTEM_FALSE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+liborcus_parser_@ORCUS_API_VERSION@_la_DEPENDENCIES = \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+am_liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS = base64.lo \
+ cell_buffer.lo css_parser_base.lo css_types.lo \
+ csv_parser_base.lo exception.lo json_global.lo \
+ json_parser_base.lo json_parser_thread.lo parser_base.lo \
+ parser_global.lo sax_parser_base.lo sax_token_parser.lo \
+ sax_token_parser_thread.lo stream.lo string_pool.lo tokens.lo \
+ types.lo utf8.lo xml_namespace.lo xml_writer.lo \
+ yaml_parser_base.lo zip_archive.lo zip_archive_stream.lo
+liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS = \
+ $(am_liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liborcus_parser_@ORCUS_API_VERSION@_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+am_css_parser_test_OBJECTS = \
+ css_parser_test-css_parser_test.$(OBJEXT)
+css_parser_test_OBJECTS = $(am_css_parser_test_OBJECTS)
+css_parser_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_csv_parser_test_OBJECTS = \
+ csv_parser_test-csv_parser_test.$(OBJEXT)
+csv_parser_test_OBJECTS = $(am_csv_parser_test_OBJECTS)
+csv_parser_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_json_parser_test_OBJECTS = \
+ json_parser_test-json_parser_test.$(OBJEXT)
+json_parser_test_OBJECTS = $(am_json_parser_test_OBJECTS)
+json_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_global_test_OBJECTS = \
+ parser_global_test-parser_global_test.$(OBJEXT)
+parser_global_test_OBJECTS = $(am_parser_global_test_OBJECTS)
+parser_global_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a
+am_parser_test_base_OBJECTS = \
+ parser_test_base-parser_base_test.$(OBJEXT)
+parser_test_base_OBJECTS = $(am_parser_test_base_OBJECTS)
+parser_test_base_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_base64_OBJECTS = parser_test_base64-base64.$(OBJEXT) \
+ parser_test_base64-base64_test.$(OBJEXT)
+parser_test_base64_OBJECTS = $(am_parser_test_base64_OBJECTS)
+parser_test_base64_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_json_validation_OBJECTS = parser_test_json_validation-parser_test_json_validation.$(OBJEXT)
+parser_test_json_validation_OBJECTS = \
+ $(am_parser_test_json_validation_OBJECTS)
+parser_test_json_validation_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_numeric_OBJECTS = \
+ parser_test_numeric-parser_test_numeric.$(OBJEXT)
+parser_test_numeric_OBJECTS = $(am_parser_test_numeric_OBJECTS)
+parser_test_numeric_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_stream_OBJECTS = \
+ parser_test_stream-stream_test.$(OBJEXT)
+parser_test_stream_OBJECTS = $(am_parser_test_stream_OBJECTS)
+parser_test_stream_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a
+am_parser_test_string_pool_OBJECTS = \
+ parser_test_string_pool-string_pool.$(OBJEXT) \
+ parser_test_string_pool-string_pool_test.$(OBJEXT)
+parser_test_string_pool_OBJECTS = \
+ $(am_parser_test_string_pool_OBJECTS)
+parser_test_string_pool_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la $(am__DEPENDENCIES_1)
+am_parser_test_threaded_json_parser_OBJECTS = parser_test_threaded_json_parser-threaded_json_parser_test.$(OBJEXT)
+parser_test_threaded_json_parser_OBJECTS = \
+ $(am_parser_test_threaded_json_parser_OBJECTS)
+parser_test_threaded_json_parser_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_json_parser_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(parser_test_threaded_json_parser_LDFLAGS) $(LDFLAGS) -o $@
+am_parser_test_threaded_sax_token_parser_OBJECTS = parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.$(OBJEXT)
+parser_test_threaded_sax_token_parser_OBJECTS = \
+ $(am_parser_test_threaded_sax_token_parser_OBJECTS)
+parser_test_threaded_sax_token_parser_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_parser_test_xml_namespace_OBJECTS = \
+ parser_test_xml_namespace-xml_namespace.$(OBJEXT) \
+ parser_test_xml_namespace-xml_namespace_test.$(OBJEXT)
+parser_test_xml_namespace_OBJECTS = \
+ $(am_parser_test_xml_namespace_OBJECTS)
+parser_test_xml_namespace_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(am__DEPENDENCIES_1)
+am_parser_test_xml_validation_OBJECTS = parser_test_xml_validation-parser_test_xml_validation.$(OBJEXT)
+parser_test_xml_validation_OBJECTS = \
+ $(am_parser_test_xml_validation_OBJECTS)
+parser_test_xml_validation_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+parser_test_xml_validation_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(parser_test_xml_validation_LDFLAGS) $(LDFLAGS) -o $@
+am_parser_test_zip_archive_OBJECTS = \
+ parser_test_zip_archive-zip_archive_test.$(OBJEXT)
+parser_test_zip_archive_OBJECTS = \
+ $(am_parser_test_zip_archive_OBJECTS)
+parser_test_zip_archive_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+parser_test_zip_archive_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(parser_test_zip_archive_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_sax_ns_parser_test_OBJECTS = \
+ sax_ns_parser_test-sax_ns_parser_test.$(OBJEXT)
+sax_ns_parser_test_OBJECTS = $(am_sax_ns_parser_test_OBJECTS)
+sax_ns_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_sax_parser_test_OBJECTS = \
+ sax_parser_test-sax_parser_test.$(OBJEXT)
+sax_parser_test_OBJECTS = $(am_sax_parser_test_OBJECTS)
+sax_parser_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_sax_token_parser_test_OBJECTS = \
+ sax_token_parser_test-sax_token_parser_test.$(OBJEXT)
+sax_token_parser_test_OBJECTS = $(am_sax_token_parser_test_OBJECTS)
+sax_token_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+am_types_test_OBJECTS = types_test-types_test.$(OBJEXT)
+types_test_OBJECTS = $(am_types_test_OBJECTS)
+types_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+am_utf8_test_OBJECTS = utf8_test-utf8.$(OBJEXT) \
+ utf8_test-utf8_test.$(OBJEXT)
+utf8_test_OBJECTS = $(am_utf8_test_OBJECTS)
+utf8_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_xml_writer_test_OBJECTS = \
+ xml_writer_test-xml_writer_test.$(OBJEXT)
+xml_writer_test_OBJECTS = $(am_xml_writer_test_OBJECTS)
+xml_writer_test_DEPENDENCIES = liborcus-parser-@ORCUS_API_VERSION@.la
+am_yaml_parser_test_OBJECTS = \
+ yaml_parser_test-yaml_parser_test.$(OBJEXT)
+yaml_parser_test_OBJECTS = $(am_yaml_parser_test_OBJECTS)
+yaml_parser_test_DEPENDENCIES = \
+ liborcus-parser-@ORCUS_API_VERSION@.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/base64.Plo \
+ ./$(DEPDIR)/cell_buffer.Plo ./$(DEPDIR)/css_parser_base.Plo \
+ ./$(DEPDIR)/css_parser_test-css_parser_test.Po \
+ ./$(DEPDIR)/css_types.Plo ./$(DEPDIR)/csv_parser_base.Plo \
+ ./$(DEPDIR)/csv_parser_test-csv_parser_test.Po \
+ ./$(DEPDIR)/exception.Plo ./$(DEPDIR)/json_global.Plo \
+ ./$(DEPDIR)/json_parser_base.Plo \
+ ./$(DEPDIR)/json_parser_test-json_parser_test.Po \
+ ./$(DEPDIR)/json_parser_thread.Plo ./$(DEPDIR)/parser_base.Plo \
+ ./$(DEPDIR)/parser_global.Plo \
+ ./$(DEPDIR)/parser_global_test-parser_global_test.Po \
+ ./$(DEPDIR)/parser_test_base-parser_base_test.Po \
+ ./$(DEPDIR)/parser_test_base64-base64.Po \
+ ./$(DEPDIR)/parser_test_base64-base64_test.Po \
+ ./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po \
+ ./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po \
+ ./$(DEPDIR)/parser_test_stream-stream_test.Po \
+ ./$(DEPDIR)/parser_test_string_pool-string_pool.Po \
+ ./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po \
+ ./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po \
+ ./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po \
+ ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po \
+ ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po \
+ ./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po \
+ ./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po \
+ ./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po \
+ ./$(DEPDIR)/sax_parser_base.Plo \
+ ./$(DEPDIR)/sax_parser_test-sax_parser_test.Po \
+ ./$(DEPDIR)/sax_token_parser.Plo \
+ ./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po \
+ ./$(DEPDIR)/sax_token_parser_thread.Plo ./$(DEPDIR)/stream.Plo \
+ ./$(DEPDIR)/string_pool.Plo ./$(DEPDIR)/tokens.Plo \
+ ./$(DEPDIR)/types.Plo ./$(DEPDIR)/types_test-types_test.Po \
+ ./$(DEPDIR)/utf8.Plo ./$(DEPDIR)/utf8_test-utf8.Po \
+ ./$(DEPDIR)/utf8_test-utf8_test.Po \
+ ./$(DEPDIR)/xml_namespace.Plo ./$(DEPDIR)/xml_writer.Plo \
+ ./$(DEPDIR)/xml_writer_test-xml_writer_test.Po \
+ ./$(DEPDIR)/yaml_parser_base.Plo \
+ ./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po \
+ ./$(DEPDIR)/zip_archive.Plo ./$(DEPDIR)/zip_archive_stream.Plo
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES) \
+ $(css_parser_test_SOURCES) $(csv_parser_test_SOURCES) \
+ $(json_parser_test_SOURCES) $(parser_global_test_SOURCES) \
+ $(parser_test_base_SOURCES) $(parser_test_base64_SOURCES) \
+ $(parser_test_json_validation_SOURCES) \
+ $(parser_test_numeric_SOURCES) $(parser_test_stream_SOURCES) \
+ $(parser_test_string_pool_SOURCES) \
+ $(parser_test_threaded_json_parser_SOURCES) \
+ $(parser_test_threaded_sax_token_parser_SOURCES) \
+ $(parser_test_xml_namespace_SOURCES) \
+ $(parser_test_xml_validation_SOURCES) \
+ $(parser_test_zip_archive_SOURCES) \
+ $(sax_ns_parser_test_SOURCES) $(sax_parser_test_SOURCES) \
+ $(sax_token_parser_test_SOURCES) $(types_test_SOURCES) \
+ $(utf8_test_SOURCES) $(xml_writer_test_SOURCES) \
+ $(yaml_parser_test_SOURCES)
+DIST_SOURCES = $(liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES) \
+ $(css_parser_test_SOURCES) $(csv_parser_test_SOURCES) \
+ $(json_parser_test_SOURCES) $(parser_global_test_SOURCES) \
+ $(parser_test_base_SOURCES) $(parser_test_base64_SOURCES) \
+ $(parser_test_json_validation_SOURCES) \
+ $(parser_test_numeric_SOURCES) $(parser_test_stream_SOURCES) \
+ $(parser_test_string_pool_SOURCES) \
+ $(parser_test_threaded_json_parser_SOURCES) \
+ $(parser_test_threaded_sax_token_parser_SOURCES) \
+ $(parser_test_xml_namespace_SOURCES) \
+ $(parser_test_xml_validation_SOURCES) \
+ $(parser_test_zip_archive_SOURCES) \
+ $(sax_ns_parser_test_SOURCES) $(sax_parser_test_SOURCES) \
+ $(sax_token_parser_test_SOURCES) $(types_test_SOURCES) \
+ $(utf8_test_SOURCES) $(xml_writer_test_SOURCES) \
+ $(yaml_parser_test_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = check-valgrind-recursive \
+ check-valgrind-memcheck-recursive \
+ check-valgrind-helgrind-recursive check-valgrind-drd-recursive \
+ check-valgrind-sgcheck-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_DATE_TIME_LDFLAGS = @BOOST_DATE_TIME_LDFLAGS@
+BOOST_DATE_TIME_LDPATH = @BOOST_DATE_TIME_LDPATH@
+BOOST_DATE_TIME_LIBS = @BOOST_DATE_TIME_LIBS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
+BOOST_IOSTREAMS_LDFLAGS = @BOOST_IOSTREAMS_LDFLAGS@
+BOOST_IOSTREAMS_LDPATH = @BOOST_IOSTREAMS_LDPATH@
+BOOST_IOSTREAMS_LIBS = @BOOST_IOSTREAMS_LIBS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_VALGRIND_drd = @ENABLE_VALGRIND_drd@
+ENABLE_VALGRIND_helgrind = @ENABLE_VALGRIND_helgrind@
+ENABLE_VALGRIND_memcheck = @ENABLE_VALGRIND_memcheck@
+ENABLE_VALGRIND_sgcheck = @ENABLE_VALGRIND_sgcheck@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IXION_REQUIRED_API_VERSION = @IXION_REQUIRED_API_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBIXION_CFLAGS = @LIBIXION_CFLAGS@
+LIBIXION_LIBS = @LIBIXION_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+ORCUS_API_VERSION = @ORCUS_API_VERSION@
+ORCUS_MAJOR_VERSION = @ORCUS_MAJOR_VERSION@
+ORCUS_MICRO_VERSION = @ORCUS_MICRO_VERSION@
+ORCUS_MINOR_VERSION = @ORCUS_MINOR_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARQUET_CFLAGS = @PARQUET_CFLAGS@
+PARQUET_LIBS = @PARQUET_LIBS@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VALGRIND = @VALGRIND@
+VALGRIND_ENABLED = @VALGRIND_ENABLED@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+valgrind_enabled_tools = @valgrind_enabled_tools@
+valgrind_tools = @valgrind_tools@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/include \
+ -DSRCDIR=\""$(top_srcdir)"\" $(BOOST_CPPFLAGS) \
+ -D__ORCUS_PSR_BUILDING_DLL $(am__append_1) $(am__append_2)
+lib_LTLIBRARIES = liborcus-parser-@ORCUS_API_VERSION@.la
+liborcus_parser_@ORCUS_API_VERSION@_la_SOURCES = \
+ win_stdint.h \
+ base64.cpp \
+ cell_buffer.cpp \
+ css_parser_base.cpp \
+ css_types.cpp \
+ csv_parser_base.cpp \
+ exception.cpp \
+ json_global.cpp \
+ json_parser_base.cpp \
+ json_parser_thread.cpp \
+ parser_base.cpp \
+ parser_global.cpp \
+ sax_parser_base.cpp \
+ sax_token_parser.cpp \
+ sax_token_parser_thread.cpp \
+ stream.cpp \
+ string_pool.cpp \
+ tokens.cpp \
+ types.cpp \
+ utf8.hpp \
+ utf8.cpp \
+ xml_namespace.cpp \
+ xml_writer.cpp \
+ yaml_parser_base.cpp \
+ zip_archive.cpp \
+ zip_archive_stream.cpp
+
+liborcus_parser_@ORCUS_API_VERSION@_la_LDFLAGS = -no-undefined \
+ $(BOOST_SYSTEM_LDFLAGS) $(am__append_3) $(am__append_4)
+liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD = $(BOOST_SYSTEM_LIBS) \
+ $(ZLIB_LIBS) $(am__append_5)
+
+# parser-test-string-pool
+parser_test_string_pool_SOURCES = \
+ string_pool.cpp \
+ string_pool_test.cpp
+
+parser_test_string_pool_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_string_pool_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-namespace
+parser_test_xml_namespace_SOURCES = \
+ xml_namespace.cpp \
+ xml_namespace_test.cpp
+
+parser_test_xml_namespace_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS)
+
+parser_test_xml_namespace_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-xml-validation
+parser_test_xml_validation_SOURCES = \
+ parser_test_xml_validation.cpp
+
+parser_test_xml_validation_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_xml_validation_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS) \
+ $(am__append_6) $(am__append_7)
+parser_test_xml_validation_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS) $(am__append_8)
+
+# parser-test-base64
+parser_test_base64_SOURCES = \
+ base64.cpp \
+ base64_test.cpp
+
+parser_test_base64_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base64_CPPFLAGS = $(AM_CPPFLAGS)
+
+# css-parser-test
+css_parser_test_SOURCES = \
+ css_parser_test.cpp
+
+css_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+css_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# csv-parser-test
+csv_parser_test_SOURCES = \
+ csv_parser_test.cpp
+
+csv_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+csv_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# json-parser-test
+json_parser_test_SOURCES = \
+ json_parser_test.cpp
+
+json_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+json_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# yaml-parser-test
+yaml_parser_test_SOURCES = \
+ yaml_parser_test.cpp
+
+yaml_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+yaml_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-parser-test
+sax_parser_test_SOURCES = \
+ sax_parser_test.cpp
+
+sax_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-ns-parser-test
+sax_ns_parser_test_SOURCES = \
+ sax_ns_parser_test.cpp
+
+sax_ns_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_ns_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# sax-token-parser-test
+sax_token_parser_test_SOURCES = \
+ sax_token_parser_test.cpp
+
+sax_token_parser_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+sax_token_parser_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-sax-token-parser
+parser_test_threaded_sax_token_parser_SOURCES = \
+ threaded_sax_token_parser_test.cpp
+
+parser_test_threaded_sax_token_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_sax_token_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-threaded-json-parser
+parser_test_threaded_json_parser_SOURCES = \
+ threaded_json_parser_test.cpp
+
+parser_test_threaded_json_parser_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_threaded_json_parser_LDFLAGS = -pthread
+parser_test_threaded_json_parser_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-stream
+parser_test_stream_SOURCES = \
+ stream_test.cpp
+
+parser_test_stream_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+parser_test_stream_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-zip-archive
+parser_test_zip_archive_SOURCES = \
+ zip_archive_test.cpp
+
+parser_test_zip_archive_CPPFLAGS = $(AM_CPPFLAGS)
+parser_test_zip_archive_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la ../test/liborcus-test.a \
+ $(BOOST_SYSTEM_LIBS) $(am__append_11)
+parser_test_zip_archive_LDFLAGS = $(BOOST_SYSTEM_LDFLAGS) \
+ $(am__append_9) $(am__append_10)
+
+# parser-test-base
+parser_test_base_SOURCES = \
+ parser_base_test.cpp
+
+parser_test_base_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_base_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-global-test
+parser_global_test_SOURCES = \
+ parser_global_test.cpp
+
+parser_global_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+parser_global_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-json-validation
+parser_test_json_validation_SOURCES = \
+ parser_test_json_validation.cpp
+
+parser_test_json_validation_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_json_validation_CPPFLAGS = $(AM_CPPFLAGS)
+
+# types-test
+types_test_SOURCES = types_test.cpp
+types_test_LDADD = \
+ liborcus-parser-@ORCUS_API_VERSION@.la \
+ ../test/liborcus-test.a
+
+types_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# utf8-test
+utf8_test_SOURCES = \
+ utf8.cpp \
+ utf8_test.cpp
+
+utf8_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+utf8_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# xml-writer-test
+xml_writer_test_SOURCES = xml_writer_test.cpp
+xml_writer_test_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+xml_writer_test_CPPFLAGS = $(AM_CPPFLAGS)
+
+# parser-test-numeric
+parser_test_numeric_SOURCES = \
+ parser_test_numeric.cpp
+
+parser_test_numeric = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_LDADD = liborcus-parser-@ORCUS_API_VERSION@.la
+parser_test_numeric_CPPFLAGS = $(AM_CPPFLAGS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/parser/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/parser/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liborcus-parser-@ORCUS_API_VERSION@.la: $(liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_parser_@ORCUS_API_VERSION@_la_DEPENDENCIES) $(EXTRA_liborcus_parser_@ORCUS_API_VERSION@_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liborcus_parser_@ORCUS_API_VERSION@_la_LINK) -rpath $(libdir) $(liborcus_parser_@ORCUS_API_VERSION@_la_OBJECTS) $(liborcus_parser_@ORCUS_API_VERSION@_la_LIBADD) $(LIBS)
+
+css-parser-test$(EXEEXT): $(css_parser_test_OBJECTS) $(css_parser_test_DEPENDENCIES) $(EXTRA_css_parser_test_DEPENDENCIES)
+ @rm -f css-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(css_parser_test_OBJECTS) $(css_parser_test_LDADD) $(LIBS)
+
+csv-parser-test$(EXEEXT): $(csv_parser_test_OBJECTS) $(csv_parser_test_DEPENDENCIES) $(EXTRA_csv_parser_test_DEPENDENCIES)
+ @rm -f csv-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(csv_parser_test_OBJECTS) $(csv_parser_test_LDADD) $(LIBS)
+
+json-parser-test$(EXEEXT): $(json_parser_test_OBJECTS) $(json_parser_test_DEPENDENCIES) $(EXTRA_json_parser_test_DEPENDENCIES)
+ @rm -f json-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(json_parser_test_OBJECTS) $(json_parser_test_LDADD) $(LIBS)
+
+parser-global-test$(EXEEXT): $(parser_global_test_OBJECTS) $(parser_global_test_DEPENDENCIES) $(EXTRA_parser_global_test_DEPENDENCIES)
+ @rm -f parser-global-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_global_test_OBJECTS) $(parser_global_test_LDADD) $(LIBS)
+
+parser-test-base$(EXEEXT): $(parser_test_base_OBJECTS) $(parser_test_base_DEPENDENCIES) $(EXTRA_parser_test_base_DEPENDENCIES)
+ @rm -f parser-test-base$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_base_OBJECTS) $(parser_test_base_LDADD) $(LIBS)
+
+parser-test-base64$(EXEEXT): $(parser_test_base64_OBJECTS) $(parser_test_base64_DEPENDENCIES) $(EXTRA_parser_test_base64_DEPENDENCIES)
+ @rm -f parser-test-base64$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_base64_OBJECTS) $(parser_test_base64_LDADD) $(LIBS)
+
+parser-test-json-validation$(EXEEXT): $(parser_test_json_validation_OBJECTS) $(parser_test_json_validation_DEPENDENCIES) $(EXTRA_parser_test_json_validation_DEPENDENCIES)
+ @rm -f parser-test-json-validation$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_json_validation_OBJECTS) $(parser_test_json_validation_LDADD) $(LIBS)
+
+parser-test-numeric$(EXEEXT): $(parser_test_numeric_OBJECTS) $(parser_test_numeric_DEPENDENCIES) $(EXTRA_parser_test_numeric_DEPENDENCIES)
+ @rm -f parser-test-numeric$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_numeric_OBJECTS) $(parser_test_numeric_LDADD) $(LIBS)
+
+parser-test-stream$(EXEEXT): $(parser_test_stream_OBJECTS) $(parser_test_stream_DEPENDENCIES) $(EXTRA_parser_test_stream_DEPENDENCIES)
+ @rm -f parser-test-stream$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_stream_OBJECTS) $(parser_test_stream_LDADD) $(LIBS)
+
+parser-test-string-pool$(EXEEXT): $(parser_test_string_pool_OBJECTS) $(parser_test_string_pool_DEPENDENCIES) $(EXTRA_parser_test_string_pool_DEPENDENCIES)
+ @rm -f parser-test-string-pool$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_string_pool_OBJECTS) $(parser_test_string_pool_LDADD) $(LIBS)
+
+parser-test-threaded-json-parser$(EXEEXT): $(parser_test_threaded_json_parser_OBJECTS) $(parser_test_threaded_json_parser_DEPENDENCIES) $(EXTRA_parser_test_threaded_json_parser_DEPENDENCIES)
+ @rm -f parser-test-threaded-json-parser$(EXEEXT)
+ $(AM_V_CXXLD)$(parser_test_threaded_json_parser_LINK) $(parser_test_threaded_json_parser_OBJECTS) $(parser_test_threaded_json_parser_LDADD) $(LIBS)
+
+parser-test-threaded-sax-token-parser$(EXEEXT): $(parser_test_threaded_sax_token_parser_OBJECTS) $(parser_test_threaded_sax_token_parser_DEPENDENCIES) $(EXTRA_parser_test_threaded_sax_token_parser_DEPENDENCIES)
+ @rm -f parser-test-threaded-sax-token-parser$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_threaded_sax_token_parser_OBJECTS) $(parser_test_threaded_sax_token_parser_LDADD) $(LIBS)
+
+parser-test-xml-namespace$(EXEEXT): $(parser_test_xml_namespace_OBJECTS) $(parser_test_xml_namespace_DEPENDENCIES) $(EXTRA_parser_test_xml_namespace_DEPENDENCIES)
+ @rm -f parser-test-xml-namespace$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(parser_test_xml_namespace_OBJECTS) $(parser_test_xml_namespace_LDADD) $(LIBS)
+
+parser-test-xml-validation$(EXEEXT): $(parser_test_xml_validation_OBJECTS) $(parser_test_xml_validation_DEPENDENCIES) $(EXTRA_parser_test_xml_validation_DEPENDENCIES)
+ @rm -f parser-test-xml-validation$(EXEEXT)
+ $(AM_V_CXXLD)$(parser_test_xml_validation_LINK) $(parser_test_xml_validation_OBJECTS) $(parser_test_xml_validation_LDADD) $(LIBS)
+
+parser-test-zip-archive$(EXEEXT): $(parser_test_zip_archive_OBJECTS) $(parser_test_zip_archive_DEPENDENCIES) $(EXTRA_parser_test_zip_archive_DEPENDENCIES)
+ @rm -f parser-test-zip-archive$(EXEEXT)
+ $(AM_V_CXXLD)$(parser_test_zip_archive_LINK) $(parser_test_zip_archive_OBJECTS) $(parser_test_zip_archive_LDADD) $(LIBS)
+
+sax-ns-parser-test$(EXEEXT): $(sax_ns_parser_test_OBJECTS) $(sax_ns_parser_test_DEPENDENCIES) $(EXTRA_sax_ns_parser_test_DEPENDENCIES)
+ @rm -f sax-ns-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(sax_ns_parser_test_OBJECTS) $(sax_ns_parser_test_LDADD) $(LIBS)
+
+sax-parser-test$(EXEEXT): $(sax_parser_test_OBJECTS) $(sax_parser_test_DEPENDENCIES) $(EXTRA_sax_parser_test_DEPENDENCIES)
+ @rm -f sax-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(sax_parser_test_OBJECTS) $(sax_parser_test_LDADD) $(LIBS)
+
+sax-token-parser-test$(EXEEXT): $(sax_token_parser_test_OBJECTS) $(sax_token_parser_test_DEPENDENCIES) $(EXTRA_sax_token_parser_test_DEPENDENCIES)
+ @rm -f sax-token-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(sax_token_parser_test_OBJECTS) $(sax_token_parser_test_LDADD) $(LIBS)
+
+types-test$(EXEEXT): $(types_test_OBJECTS) $(types_test_DEPENDENCIES) $(EXTRA_types_test_DEPENDENCIES)
+ @rm -f types-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(types_test_OBJECTS) $(types_test_LDADD) $(LIBS)
+
+utf8-test$(EXEEXT): $(utf8_test_OBJECTS) $(utf8_test_DEPENDENCIES) $(EXTRA_utf8_test_DEPENDENCIES)
+ @rm -f utf8-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(utf8_test_OBJECTS) $(utf8_test_LDADD) $(LIBS)
+
+xml-writer-test$(EXEEXT): $(xml_writer_test_OBJECTS) $(xml_writer_test_DEPENDENCIES) $(EXTRA_xml_writer_test_DEPENDENCIES)
+ @rm -f xml-writer-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(xml_writer_test_OBJECTS) $(xml_writer_test_LDADD) $(LIBS)
+
+yaml-parser-test$(EXEEXT): $(yaml_parser_test_OBJECTS) $(yaml_parser_test_DEPENDENCIES) $(EXTRA_yaml_parser_test_DEPENDENCIES)
+ @rm -f yaml-parser-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(yaml_parser_test_OBJECTS) $(yaml_parser_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cell_buffer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_parser_test-css_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/css_types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csv_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csv_parser_test-csv_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_parser_test-json_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_parser_thread.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_global.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_global_test-parser_global_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_base-parser_base_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_base64-base64.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_base64-base64_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_stream-stream_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_string_pool-string_pool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_parser_test-sax_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_token_parser.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sax_token_parser_thread.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string_pool.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tokens.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/types.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/types_test-types_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8_test-utf8.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8_test-utf8_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_namespace.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_writer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_writer_test-xml_writer_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yaml_parser_base.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zip_archive.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zip_archive_stream.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+css_parser_test-css_parser_test.o: css_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT css_parser_test-css_parser_test.o -MD -MP -MF $(DEPDIR)/css_parser_test-css_parser_test.Tpo -c -o css_parser_test-css_parser_test.o `test -f 'css_parser_test.cpp' || echo '$(srcdir)/'`css_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/css_parser_test-css_parser_test.Tpo $(DEPDIR)/css_parser_test-css_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='css_parser_test.cpp' object='css_parser_test-css_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o css_parser_test-css_parser_test.o `test -f 'css_parser_test.cpp' || echo '$(srcdir)/'`css_parser_test.cpp
+
+css_parser_test-css_parser_test.obj: css_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT css_parser_test-css_parser_test.obj -MD -MP -MF $(DEPDIR)/css_parser_test-css_parser_test.Tpo -c -o css_parser_test-css_parser_test.obj `if test -f 'css_parser_test.cpp'; then $(CYGPATH_W) 'css_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/css_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/css_parser_test-css_parser_test.Tpo $(DEPDIR)/css_parser_test-css_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='css_parser_test.cpp' object='css_parser_test-css_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(css_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o css_parser_test-css_parser_test.obj `if test -f 'css_parser_test.cpp'; then $(CYGPATH_W) 'css_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/css_parser_test.cpp'; fi`
+
+csv_parser_test-csv_parser_test.o: csv_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT csv_parser_test-csv_parser_test.o -MD -MP -MF $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo -c -o csv_parser_test-csv_parser_test.o `test -f 'csv_parser_test.cpp' || echo '$(srcdir)/'`csv_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo $(DEPDIR)/csv_parser_test-csv_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_parser_test.cpp' object='csv_parser_test-csv_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o csv_parser_test-csv_parser_test.o `test -f 'csv_parser_test.cpp' || echo '$(srcdir)/'`csv_parser_test.cpp
+
+csv_parser_test-csv_parser_test.obj: csv_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT csv_parser_test-csv_parser_test.obj -MD -MP -MF $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo -c -o csv_parser_test-csv_parser_test.obj `if test -f 'csv_parser_test.cpp'; then $(CYGPATH_W) 'csv_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/csv_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/csv_parser_test-csv_parser_test.Tpo $(DEPDIR)/csv_parser_test-csv_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='csv_parser_test.cpp' object='csv_parser_test-csv_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(csv_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o csv_parser_test-csv_parser_test.obj `if test -f 'csv_parser_test.cpp'; then $(CYGPATH_W) 'csv_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/csv_parser_test.cpp'; fi`
+
+json_parser_test-json_parser_test.o: json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_parser_test-json_parser_test.o -MD -MP -MF $(DEPDIR)/json_parser_test-json_parser_test.Tpo -c -o json_parser_test-json_parser_test.o `test -f 'json_parser_test.cpp' || echo '$(srcdir)/'`json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_parser_test-json_parser_test.Tpo $(DEPDIR)/json_parser_test-json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_parser_test.cpp' object='json_parser_test-json_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_parser_test-json_parser_test.o `test -f 'json_parser_test.cpp' || echo '$(srcdir)/'`json_parser_test.cpp
+
+json_parser_test-json_parser_test.obj: json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT json_parser_test-json_parser_test.obj -MD -MP -MF $(DEPDIR)/json_parser_test-json_parser_test.Tpo -c -o json_parser_test-json_parser_test.obj `if test -f 'json_parser_test.cpp'; then $(CYGPATH_W) 'json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/json_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/json_parser_test-json_parser_test.Tpo $(DEPDIR)/json_parser_test-json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='json_parser_test.cpp' object='json_parser_test-json_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(json_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o json_parser_test-json_parser_test.obj `if test -f 'json_parser_test.cpp'; then $(CYGPATH_W) 'json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/json_parser_test.cpp'; fi`
+
+parser_global_test-parser_global_test.o: parser_global_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_global_test-parser_global_test.o -MD -MP -MF $(DEPDIR)/parser_global_test-parser_global_test.Tpo -c -o parser_global_test-parser_global_test.o `test -f 'parser_global_test.cpp' || echo '$(srcdir)/'`parser_global_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_global_test-parser_global_test.Tpo $(DEPDIR)/parser_global_test-parser_global_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_global_test.cpp' object='parser_global_test-parser_global_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_global_test-parser_global_test.o `test -f 'parser_global_test.cpp' || echo '$(srcdir)/'`parser_global_test.cpp
+
+parser_global_test-parser_global_test.obj: parser_global_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_global_test-parser_global_test.obj -MD -MP -MF $(DEPDIR)/parser_global_test-parser_global_test.Tpo -c -o parser_global_test-parser_global_test.obj `if test -f 'parser_global_test.cpp'; then $(CYGPATH_W) 'parser_global_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_global_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_global_test-parser_global_test.Tpo $(DEPDIR)/parser_global_test-parser_global_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_global_test.cpp' object='parser_global_test-parser_global_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_global_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_global_test-parser_global_test.obj `if test -f 'parser_global_test.cpp'; then $(CYGPATH_W) 'parser_global_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_global_test.cpp'; fi`
+
+parser_test_base-parser_base_test.o: parser_base_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base-parser_base_test.o -MD -MP -MF $(DEPDIR)/parser_test_base-parser_base_test.Tpo -c -o parser_test_base-parser_base_test.o `test -f 'parser_base_test.cpp' || echo '$(srcdir)/'`parser_base_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base-parser_base_test.Tpo $(DEPDIR)/parser_test_base-parser_base_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_base_test.cpp' object='parser_test_base-parser_base_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base-parser_base_test.o `test -f 'parser_base_test.cpp' || echo '$(srcdir)/'`parser_base_test.cpp
+
+parser_test_base-parser_base_test.obj: parser_base_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base-parser_base_test.obj -MD -MP -MF $(DEPDIR)/parser_test_base-parser_base_test.Tpo -c -o parser_test_base-parser_base_test.obj `if test -f 'parser_base_test.cpp'; then $(CYGPATH_W) 'parser_base_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_base_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base-parser_base_test.Tpo $(DEPDIR)/parser_test_base-parser_base_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_base_test.cpp' object='parser_test_base-parser_base_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base-parser_base_test.obj `if test -f 'parser_base_test.cpp'; then $(CYGPATH_W) 'parser_base_test.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_base_test.cpp'; fi`
+
+parser_test_base64-base64.o: base64.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64.o -MD -MP -MF $(DEPDIR)/parser_test_base64-base64.Tpo -c -o parser_test_base64-base64.o `test -f 'base64.cpp' || echo '$(srcdir)/'`base64.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64.Tpo $(DEPDIR)/parser_test_base64-base64.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64.cpp' object='parser_test_base64-base64.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64.o `test -f 'base64.cpp' || echo '$(srcdir)/'`base64.cpp
+
+parser_test_base64-base64.obj: base64.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64.obj -MD -MP -MF $(DEPDIR)/parser_test_base64-base64.Tpo -c -o parser_test_base64-base64.obj `if test -f 'base64.cpp'; then $(CYGPATH_W) 'base64.cpp'; else $(CYGPATH_W) '$(srcdir)/base64.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64.Tpo $(DEPDIR)/parser_test_base64-base64.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64.cpp' object='parser_test_base64-base64.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64.obj `if test -f 'base64.cpp'; then $(CYGPATH_W) 'base64.cpp'; else $(CYGPATH_W) '$(srcdir)/base64.cpp'; fi`
+
+parser_test_base64-base64_test.o: base64_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64_test.o -MD -MP -MF $(DEPDIR)/parser_test_base64-base64_test.Tpo -c -o parser_test_base64-base64_test.o `test -f 'base64_test.cpp' || echo '$(srcdir)/'`base64_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64_test.Tpo $(DEPDIR)/parser_test_base64-base64_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64_test.cpp' object='parser_test_base64-base64_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64_test.o `test -f 'base64_test.cpp' || echo '$(srcdir)/'`base64_test.cpp
+
+parser_test_base64-base64_test.obj: base64_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_base64-base64_test.obj -MD -MP -MF $(DEPDIR)/parser_test_base64-base64_test.Tpo -c -o parser_test_base64-base64_test.obj `if test -f 'base64_test.cpp'; then $(CYGPATH_W) 'base64_test.cpp'; else $(CYGPATH_W) '$(srcdir)/base64_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_base64-base64_test.Tpo $(DEPDIR)/parser_test_base64-base64_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='base64_test.cpp' object='parser_test_base64-base64_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_base64_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_base64-base64_test.obj `if test -f 'base64_test.cpp'; then $(CYGPATH_W) 'base64_test.cpp'; else $(CYGPATH_W) '$(srcdir)/base64_test.cpp'; fi`
+
+parser_test_json_validation-parser_test_json_validation.o: parser_test_json_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_json_validation-parser_test_json_validation.o -MD -MP -MF $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo -c -o parser_test_json_validation-parser_test_json_validation.o `test -f 'parser_test_json_validation.cpp' || echo '$(srcdir)/'`parser_test_json_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_json_validation.cpp' object='parser_test_json_validation-parser_test_json_validation.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_json_validation-parser_test_json_validation.o `test -f 'parser_test_json_validation.cpp' || echo '$(srcdir)/'`parser_test_json_validation.cpp
+
+parser_test_json_validation-parser_test_json_validation.obj: parser_test_json_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_json_validation-parser_test_json_validation.obj -MD -MP -MF $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo -c -o parser_test_json_validation-parser_test_json_validation.obj `if test -f 'parser_test_json_validation.cpp'; then $(CYGPATH_W) 'parser_test_json_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_json_validation.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Tpo $(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_json_validation.cpp' object='parser_test_json_validation-parser_test_json_validation.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_json_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_json_validation-parser_test_json_validation.obj `if test -f 'parser_test_json_validation.cpp'; then $(CYGPATH_W) 'parser_test_json_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_json_validation.cpp'; fi`
+
+parser_test_numeric-parser_test_numeric.o: parser_test_numeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_numeric-parser_test_numeric.o -MD -MP -MF $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo -c -o parser_test_numeric-parser_test_numeric.o `test -f 'parser_test_numeric.cpp' || echo '$(srcdir)/'`parser_test_numeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo $(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_numeric.cpp' object='parser_test_numeric-parser_test_numeric.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_numeric-parser_test_numeric.o `test -f 'parser_test_numeric.cpp' || echo '$(srcdir)/'`parser_test_numeric.cpp
+
+parser_test_numeric-parser_test_numeric.obj: parser_test_numeric.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_numeric-parser_test_numeric.obj -MD -MP -MF $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo -c -o parser_test_numeric-parser_test_numeric.obj `if test -f 'parser_test_numeric.cpp'; then $(CYGPATH_W) 'parser_test_numeric.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_numeric.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_numeric-parser_test_numeric.Tpo $(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_numeric.cpp' object='parser_test_numeric-parser_test_numeric.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_numeric_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_numeric-parser_test_numeric.obj `if test -f 'parser_test_numeric.cpp'; then $(CYGPATH_W) 'parser_test_numeric.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_numeric.cpp'; fi`
+
+parser_test_stream-stream_test.o: stream_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_stream-stream_test.o -MD -MP -MF $(DEPDIR)/parser_test_stream-stream_test.Tpo -c -o parser_test_stream-stream_test.o `test -f 'stream_test.cpp' || echo '$(srcdir)/'`stream_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_stream-stream_test.Tpo $(DEPDIR)/parser_test_stream-stream_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stream_test.cpp' object='parser_test_stream-stream_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_stream-stream_test.o `test -f 'stream_test.cpp' || echo '$(srcdir)/'`stream_test.cpp
+
+parser_test_stream-stream_test.obj: stream_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_stream-stream_test.obj -MD -MP -MF $(DEPDIR)/parser_test_stream-stream_test.Tpo -c -o parser_test_stream-stream_test.obj `if test -f 'stream_test.cpp'; then $(CYGPATH_W) 'stream_test.cpp'; else $(CYGPATH_W) '$(srcdir)/stream_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_stream-stream_test.Tpo $(DEPDIR)/parser_test_stream-stream_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stream_test.cpp' object='parser_test_stream-stream_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_stream_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_stream-stream_test.obj `if test -f 'stream_test.cpp'; then $(CYGPATH_W) 'stream_test.cpp'; else $(CYGPATH_W) '$(srcdir)/stream_test.cpp'; fi`
+
+parser_test_string_pool-string_pool.o: string_pool.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool.o -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool.Tpo -c -o parser_test_string_pool-string_pool.o `test -f 'string_pool.cpp' || echo '$(srcdir)/'`string_pool.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool.Tpo $(DEPDIR)/parser_test_string_pool-string_pool.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool.cpp' object='parser_test_string_pool-string_pool.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool.o `test -f 'string_pool.cpp' || echo '$(srcdir)/'`string_pool.cpp
+
+parser_test_string_pool-string_pool.obj: string_pool.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool.obj -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool.Tpo -c -o parser_test_string_pool-string_pool.obj `if test -f 'string_pool.cpp'; then $(CYGPATH_W) 'string_pool.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool.Tpo $(DEPDIR)/parser_test_string_pool-string_pool.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool.cpp' object='parser_test_string_pool-string_pool.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool.obj `if test -f 'string_pool.cpp'; then $(CYGPATH_W) 'string_pool.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool.cpp'; fi`
+
+parser_test_string_pool-string_pool_test.o: string_pool_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool_test.o -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo -c -o parser_test_string_pool-string_pool_test.o `test -f 'string_pool_test.cpp' || echo '$(srcdir)/'`string_pool_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo $(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool_test.cpp' object='parser_test_string_pool-string_pool_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool_test.o `test -f 'string_pool_test.cpp' || echo '$(srcdir)/'`string_pool_test.cpp
+
+parser_test_string_pool-string_pool_test.obj: string_pool_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_string_pool-string_pool_test.obj -MD -MP -MF $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo -c -o parser_test_string_pool-string_pool_test.obj `if test -f 'string_pool_test.cpp'; then $(CYGPATH_W) 'string_pool_test.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_string_pool-string_pool_test.Tpo $(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='string_pool_test.cpp' object='parser_test_string_pool-string_pool_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_string_pool_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_string_pool-string_pool_test.obj `if test -f 'string_pool_test.cpp'; then $(CYGPATH_W) 'string_pool_test.cpp'; else $(CYGPATH_W) '$(srcdir)/string_pool_test.cpp'; fi`
+
+parser_test_threaded_json_parser-threaded_json_parser_test.o: threaded_json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_json_parser-threaded_json_parser_test.o -MD -MP -MF $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo -c -o parser_test_threaded_json_parser-threaded_json_parser_test.o `test -f 'threaded_json_parser_test.cpp' || echo '$(srcdir)/'`threaded_json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_json_parser_test.cpp' object='parser_test_threaded_json_parser-threaded_json_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_json_parser-threaded_json_parser_test.o `test -f 'threaded_json_parser_test.cpp' || echo '$(srcdir)/'`threaded_json_parser_test.cpp
+
+parser_test_threaded_json_parser-threaded_json_parser_test.obj: threaded_json_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_json_parser-threaded_json_parser_test.obj -MD -MP -MF $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo -c -o parser_test_threaded_json_parser-threaded_json_parser_test.obj `if test -f 'threaded_json_parser_test.cpp'; then $(CYGPATH_W) 'threaded_json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_json_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Tpo $(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_json_parser_test.cpp' object='parser_test_threaded_json_parser-threaded_json_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_json_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_json_parser-threaded_json_parser_test.obj `if test -f 'threaded_json_parser_test.cpp'; then $(CYGPATH_W) 'threaded_json_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_json_parser_test.cpp'; fi`
+
+parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o: threaded_sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o -MD -MP -MF $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o `test -f 'threaded_sax_token_parser_test.cpp' || echo '$(srcdir)/'`threaded_sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_sax_token_parser_test.cpp' object='parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.o `test -f 'threaded_sax_token_parser_test.cpp' || echo '$(srcdir)/'`threaded_sax_token_parser_test.cpp
+
+parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj: threaded_sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj -MD -MP -MF $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj `if test -f 'threaded_sax_token_parser_test.cpp'; then $(CYGPATH_W) 'threaded_sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_sax_token_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Tpo $(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='threaded_sax_token_parser_test.cpp' object='parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_threaded_sax_token_parser_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.obj `if test -f 'threaded_sax_token_parser_test.cpp'; then $(CYGPATH_W) 'threaded_sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/threaded_sax_token_parser_test.cpp'; fi`
+
+parser_test_xml_namespace-xml_namespace.o: xml_namespace.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace.o -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo -c -o parser_test_xml_namespace-xml_namespace.o `test -f 'xml_namespace.cpp' || echo '$(srcdir)/'`xml_namespace.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace.cpp' object='parser_test_xml_namespace-xml_namespace.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace.o `test -f 'xml_namespace.cpp' || echo '$(srcdir)/'`xml_namespace.cpp
+
+parser_test_xml_namespace-xml_namespace.obj: xml_namespace.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace.obj -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo -c -o parser_test_xml_namespace-xml_namespace.obj `if test -f 'xml_namespace.cpp'; then $(CYGPATH_W) 'xml_namespace.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace.cpp' object='parser_test_xml_namespace-xml_namespace.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace.obj `if test -f 'xml_namespace.cpp'; then $(CYGPATH_W) 'xml_namespace.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace.cpp'; fi`
+
+parser_test_xml_namespace-xml_namespace_test.o: xml_namespace_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace_test.o -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo -c -o parser_test_xml_namespace-xml_namespace_test.o `test -f 'xml_namespace_test.cpp' || echo '$(srcdir)/'`xml_namespace_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace_test.cpp' object='parser_test_xml_namespace-xml_namespace_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace_test.o `test -f 'xml_namespace_test.cpp' || echo '$(srcdir)/'`xml_namespace_test.cpp
+
+parser_test_xml_namespace-xml_namespace_test.obj: xml_namespace_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_namespace-xml_namespace_test.obj -MD -MP -MF $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo -c -o parser_test_xml_namespace-xml_namespace_test.obj `if test -f 'xml_namespace_test.cpp'; then $(CYGPATH_W) 'xml_namespace_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Tpo $(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_namespace_test.cpp' object='parser_test_xml_namespace-xml_namespace_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_namespace_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_namespace-xml_namespace_test.obj `if test -f 'xml_namespace_test.cpp'; then $(CYGPATH_W) 'xml_namespace_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_namespace_test.cpp'; fi`
+
+parser_test_xml_validation-parser_test_xml_validation.o: parser_test_xml_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_validation-parser_test_xml_validation.o -MD -MP -MF $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo -c -o parser_test_xml_validation-parser_test_xml_validation.o `test -f 'parser_test_xml_validation.cpp' || echo '$(srcdir)/'`parser_test_xml_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_xml_validation.cpp' object='parser_test_xml_validation-parser_test_xml_validation.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_validation-parser_test_xml_validation.o `test -f 'parser_test_xml_validation.cpp' || echo '$(srcdir)/'`parser_test_xml_validation.cpp
+
+parser_test_xml_validation-parser_test_xml_validation.obj: parser_test_xml_validation.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_xml_validation-parser_test_xml_validation.obj -MD -MP -MF $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo -c -o parser_test_xml_validation-parser_test_xml_validation.obj `if test -f 'parser_test_xml_validation.cpp'; then $(CYGPATH_W) 'parser_test_xml_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_xml_validation.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Tpo $(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='parser_test_xml_validation.cpp' object='parser_test_xml_validation-parser_test_xml_validation.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_xml_validation_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_xml_validation-parser_test_xml_validation.obj `if test -f 'parser_test_xml_validation.cpp'; then $(CYGPATH_W) 'parser_test_xml_validation.cpp'; else $(CYGPATH_W) '$(srcdir)/parser_test_xml_validation.cpp'; fi`
+
+parser_test_zip_archive-zip_archive_test.o: zip_archive_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_zip_archive-zip_archive_test.o -MD -MP -MF $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo -c -o parser_test_zip_archive-zip_archive_test.o `test -f 'zip_archive_test.cpp' || echo '$(srcdir)/'`zip_archive_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='zip_archive_test.cpp' object='parser_test_zip_archive-zip_archive_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_zip_archive-zip_archive_test.o `test -f 'zip_archive_test.cpp' || echo '$(srcdir)/'`zip_archive_test.cpp
+
+parser_test_zip_archive-zip_archive_test.obj: zip_archive_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT parser_test_zip_archive-zip_archive_test.obj -MD -MP -MF $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo -c -o parser_test_zip_archive-zip_archive_test.obj `if test -f 'zip_archive_test.cpp'; then $(CYGPATH_W) 'zip_archive_test.cpp'; else $(CYGPATH_W) '$(srcdir)/zip_archive_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Tpo $(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='zip_archive_test.cpp' object='parser_test_zip_archive-zip_archive_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(parser_test_zip_archive_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o parser_test_zip_archive-zip_archive_test.obj `if test -f 'zip_archive_test.cpp'; then $(CYGPATH_W) 'zip_archive_test.cpp'; else $(CYGPATH_W) '$(srcdir)/zip_archive_test.cpp'; fi`
+
+sax_ns_parser_test-sax_ns_parser_test.o: sax_ns_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_ns_parser_test-sax_ns_parser_test.o -MD -MP -MF $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo -c -o sax_ns_parser_test-sax_ns_parser_test.o `test -f 'sax_ns_parser_test.cpp' || echo '$(srcdir)/'`sax_ns_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_ns_parser_test.cpp' object='sax_ns_parser_test-sax_ns_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_ns_parser_test-sax_ns_parser_test.o `test -f 'sax_ns_parser_test.cpp' || echo '$(srcdir)/'`sax_ns_parser_test.cpp
+
+sax_ns_parser_test-sax_ns_parser_test.obj: sax_ns_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_ns_parser_test-sax_ns_parser_test.obj -MD -MP -MF $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo -c -o sax_ns_parser_test-sax_ns_parser_test.obj `if test -f 'sax_ns_parser_test.cpp'; then $(CYGPATH_W) 'sax_ns_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_ns_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Tpo $(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_ns_parser_test.cpp' object='sax_ns_parser_test-sax_ns_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_ns_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_ns_parser_test-sax_ns_parser_test.obj `if test -f 'sax_ns_parser_test.cpp'; then $(CYGPATH_W) 'sax_ns_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_ns_parser_test.cpp'; fi`
+
+sax_parser_test-sax_parser_test.o: sax_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_parser_test-sax_parser_test.o -MD -MP -MF $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo -c -o sax_parser_test-sax_parser_test.o `test -f 'sax_parser_test.cpp' || echo '$(srcdir)/'`sax_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo $(DEPDIR)/sax_parser_test-sax_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_parser_test.cpp' object='sax_parser_test-sax_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_parser_test-sax_parser_test.o `test -f 'sax_parser_test.cpp' || echo '$(srcdir)/'`sax_parser_test.cpp
+
+sax_parser_test-sax_parser_test.obj: sax_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_parser_test-sax_parser_test.obj -MD -MP -MF $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo -c -o sax_parser_test-sax_parser_test.obj `if test -f 'sax_parser_test.cpp'; then $(CYGPATH_W) 'sax_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_parser_test-sax_parser_test.Tpo $(DEPDIR)/sax_parser_test-sax_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_parser_test.cpp' object='sax_parser_test-sax_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_parser_test-sax_parser_test.obj `if test -f 'sax_parser_test.cpp'; then $(CYGPATH_W) 'sax_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_parser_test.cpp'; fi`
+
+sax_token_parser_test-sax_token_parser_test.o: sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_token_parser_test-sax_token_parser_test.o -MD -MP -MF $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo -c -o sax_token_parser_test-sax_token_parser_test.o `test -f 'sax_token_parser_test.cpp' || echo '$(srcdir)/'`sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_token_parser_test.cpp' object='sax_token_parser_test-sax_token_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_token_parser_test-sax_token_parser_test.o `test -f 'sax_token_parser_test.cpp' || echo '$(srcdir)/'`sax_token_parser_test.cpp
+
+sax_token_parser_test-sax_token_parser_test.obj: sax_token_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sax_token_parser_test-sax_token_parser_test.obj -MD -MP -MF $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo -c -o sax_token_parser_test-sax_token_parser_test.obj `if test -f 'sax_token_parser_test.cpp'; then $(CYGPATH_W) 'sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_token_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Tpo $(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sax_token_parser_test.cpp' object='sax_token_parser_test-sax_token_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(sax_token_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sax_token_parser_test-sax_token_parser_test.obj `if test -f 'sax_token_parser_test.cpp'; then $(CYGPATH_W) 'sax_token_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/sax_token_parser_test.cpp'; fi`
+
+types_test-types_test.o: types_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT types_test-types_test.o -MD -MP -MF $(DEPDIR)/types_test-types_test.Tpo -c -o types_test-types_test.o `test -f 'types_test.cpp' || echo '$(srcdir)/'`types_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/types_test-types_test.Tpo $(DEPDIR)/types_test-types_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='types_test.cpp' object='types_test-types_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o types_test-types_test.o `test -f 'types_test.cpp' || echo '$(srcdir)/'`types_test.cpp
+
+types_test-types_test.obj: types_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT types_test-types_test.obj -MD -MP -MF $(DEPDIR)/types_test-types_test.Tpo -c -o types_test-types_test.obj `if test -f 'types_test.cpp'; then $(CYGPATH_W) 'types_test.cpp'; else $(CYGPATH_W) '$(srcdir)/types_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/types_test-types_test.Tpo $(DEPDIR)/types_test-types_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='types_test.cpp' object='types_test-types_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(types_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o types_test-types_test.obj `if test -f 'types_test.cpp'; then $(CYGPATH_W) 'types_test.cpp'; else $(CYGPATH_W) '$(srcdir)/types_test.cpp'; fi`
+
+utf8_test-utf8.o: utf8.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8.o -MD -MP -MF $(DEPDIR)/utf8_test-utf8.Tpo -c -o utf8_test-utf8.o `test -f 'utf8.cpp' || echo '$(srcdir)/'`utf8.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8.Tpo $(DEPDIR)/utf8_test-utf8.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8.cpp' object='utf8_test-utf8.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8.o `test -f 'utf8.cpp' || echo '$(srcdir)/'`utf8.cpp
+
+utf8_test-utf8.obj: utf8.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8.obj -MD -MP -MF $(DEPDIR)/utf8_test-utf8.Tpo -c -o utf8_test-utf8.obj `if test -f 'utf8.cpp'; then $(CYGPATH_W) 'utf8.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8.Tpo $(DEPDIR)/utf8_test-utf8.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8.cpp' object='utf8_test-utf8.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8.obj `if test -f 'utf8.cpp'; then $(CYGPATH_W) 'utf8.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8.cpp'; fi`
+
+utf8_test-utf8_test.o: utf8_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8_test.o -MD -MP -MF $(DEPDIR)/utf8_test-utf8_test.Tpo -c -o utf8_test-utf8_test.o `test -f 'utf8_test.cpp' || echo '$(srcdir)/'`utf8_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8_test.Tpo $(DEPDIR)/utf8_test-utf8_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8_test.cpp' object='utf8_test-utf8_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8_test.o `test -f 'utf8_test.cpp' || echo '$(srcdir)/'`utf8_test.cpp
+
+utf8_test-utf8_test.obj: utf8_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT utf8_test-utf8_test.obj -MD -MP -MF $(DEPDIR)/utf8_test-utf8_test.Tpo -c -o utf8_test-utf8_test.obj `if test -f 'utf8_test.cpp'; then $(CYGPATH_W) 'utf8_test.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/utf8_test-utf8_test.Tpo $(DEPDIR)/utf8_test-utf8_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='utf8_test.cpp' object='utf8_test-utf8_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(utf8_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o utf8_test-utf8_test.obj `if test -f 'utf8_test.cpp'; then $(CYGPATH_W) 'utf8_test.cpp'; else $(CYGPATH_W) '$(srcdir)/utf8_test.cpp'; fi`
+
+xml_writer_test-xml_writer_test.o: xml_writer_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_writer_test-xml_writer_test.o -MD -MP -MF $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo -c -o xml_writer_test-xml_writer_test.o `test -f 'xml_writer_test.cpp' || echo '$(srcdir)/'`xml_writer_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo $(DEPDIR)/xml_writer_test-xml_writer_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_writer_test.cpp' object='xml_writer_test-xml_writer_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_writer_test-xml_writer_test.o `test -f 'xml_writer_test.cpp' || echo '$(srcdir)/'`xml_writer_test.cpp
+
+xml_writer_test-xml_writer_test.obj: xml_writer_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT xml_writer_test-xml_writer_test.obj -MD -MP -MF $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo -c -o xml_writer_test-xml_writer_test.obj `if test -f 'xml_writer_test.cpp'; then $(CYGPATH_W) 'xml_writer_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_writer_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xml_writer_test-xml_writer_test.Tpo $(DEPDIR)/xml_writer_test-xml_writer_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='xml_writer_test.cpp' object='xml_writer_test-xml_writer_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xml_writer_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o xml_writer_test-xml_writer_test.obj `if test -f 'xml_writer_test.cpp'; then $(CYGPATH_W) 'xml_writer_test.cpp'; else $(CYGPATH_W) '$(srcdir)/xml_writer_test.cpp'; fi`
+
+yaml_parser_test-yaml_parser_test.o: yaml_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_parser_test-yaml_parser_test.o -MD -MP -MF $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo -c -o yaml_parser_test-yaml_parser_test.o `test -f 'yaml_parser_test.cpp' || echo '$(srcdir)/'`yaml_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo $(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_parser_test.cpp' object='yaml_parser_test-yaml_parser_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_parser_test-yaml_parser_test.o `test -f 'yaml_parser_test.cpp' || echo '$(srcdir)/'`yaml_parser_test.cpp
+
+yaml_parser_test-yaml_parser_test.obj: yaml_parser_test.cpp
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT yaml_parser_test-yaml_parser_test.obj -MD -MP -MF $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo -c -o yaml_parser_test-yaml_parser_test.obj `if test -f 'yaml_parser_test.cpp'; then $(CYGPATH_W) 'yaml_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_parser_test.cpp'; fi`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/yaml_parser_test-yaml_parser_test.Tpo $(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='yaml_parser_test.cpp' object='yaml_parser_test-yaml_parser_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(yaml_parser_test_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o yaml_parser_test-yaml_parser_test.obj `if test -f 'yaml_parser_test.cpp'; then $(CYGPATH_W) 'yaml_parser_test.cpp'; else $(CYGPATH_W) '$(srcdir)/yaml_parser_test.cpp'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+check-valgrind-local:
+check-valgrind-memcheck-local:
+check-valgrind-helgrind-local:
+check-valgrind-drd-local:
+check-valgrind-sgcheck-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+css-parser-test.log: css-parser-test$(EXEEXT)
+ @p='css-parser-test$(EXEEXT)'; \
+ b='css-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+csv-parser-test.log: csv-parser-test$(EXEEXT)
+ @p='csv-parser-test$(EXEEXT)'; \
+ b='csv-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+json-parser-test.log: json-parser-test$(EXEEXT)
+ @p='json-parser-test$(EXEEXT)'; \
+ b='json-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-global-test.log: parser-global-test$(EXEEXT)
+ @p='parser-global-test$(EXEEXT)'; \
+ b='parser-global-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-base.log: parser-test-base$(EXEEXT)
+ @p='parser-test-base$(EXEEXT)'; \
+ b='parser-test-base'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-base64.log: parser-test-base64$(EXEEXT)
+ @p='parser-test-base64$(EXEEXT)'; \
+ b='parser-test-base64'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-json-validation.log: parser-test-json-validation$(EXEEXT)
+ @p='parser-test-json-validation$(EXEEXT)'; \
+ b='parser-test-json-validation'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-numeric.log: parser-test-numeric$(EXEEXT)
+ @p='parser-test-numeric$(EXEEXT)'; \
+ b='parser-test-numeric'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-stream.log: parser-test-stream$(EXEEXT)
+ @p='parser-test-stream$(EXEEXT)'; \
+ b='parser-test-stream'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-string-pool.log: parser-test-string-pool$(EXEEXT)
+ @p='parser-test-string-pool$(EXEEXT)'; \
+ b='parser-test-string-pool'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-threaded-json-parser.log: parser-test-threaded-json-parser$(EXEEXT)
+ @p='parser-test-threaded-json-parser$(EXEEXT)'; \
+ b='parser-test-threaded-json-parser'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-threaded-sax-token-parser.log: parser-test-threaded-sax-token-parser$(EXEEXT)
+ @p='parser-test-threaded-sax-token-parser$(EXEEXT)'; \
+ b='parser-test-threaded-sax-token-parser'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-xml-namespace.log: parser-test-xml-namespace$(EXEEXT)
+ @p='parser-test-xml-namespace$(EXEEXT)'; \
+ b='parser-test-xml-namespace'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-xml-validation.log: parser-test-xml-validation$(EXEEXT)
+ @p='parser-test-xml-validation$(EXEEXT)'; \
+ b='parser-test-xml-validation'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+parser-test-zip-archive.log: parser-test-zip-archive$(EXEEXT)
+ @p='parser-test-zip-archive$(EXEEXT)'; \
+ b='parser-test-zip-archive'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sax-ns-parser-test.log: sax-ns-parser-test$(EXEEXT)
+ @p='sax-ns-parser-test$(EXEEXT)'; \
+ b='sax-ns-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sax-parser-test.log: sax-parser-test$(EXEEXT)
+ @p='sax-parser-test$(EXEEXT)'; \
+ b='sax-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+sax-token-parser-test.log: sax-token-parser-test$(EXEEXT)
+ @p='sax-token-parser-test$(EXEEXT)'; \
+ b='sax-token-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+types-test.log: types-test$(EXEEXT)
+ @p='types-test$(EXEEXT)'; \
+ b='types-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+utf8-test.log: utf8-test$(EXEEXT)
+ @p='utf8-test$(EXEEXT)'; \
+ b='utf8-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+yaml-parser-test.log: yaml-parser-test$(EXEEXT)
+ @p='yaml-parser-test$(EXEEXT)'; \
+ b='yaml-parser-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+xml-writer-test.log: xml-writer-test$(EXEEXT)
+ @p='xml-writer-test$(EXEEXT)'; \
+ b='xml-writer-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+install-EXTRAPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+check-valgrind: check-valgrind-am
+
+check-valgrind-am: check-valgrind-local
+
+check-valgrind-drd: check-valgrind-drd-am
+
+check-valgrind-drd-am: check-valgrind-drd-local
+
+check-valgrind-helgrind: check-valgrind-helgrind-am
+
+check-valgrind-helgrind-am: check-valgrind-helgrind-local
+
+check-valgrind-memcheck: check-valgrind-memcheck-am
+
+check-valgrind-memcheck-am: check-valgrind-memcheck-local
+
+check-valgrind-sgcheck: check-valgrind-sgcheck-am
+
+check-valgrind-sgcheck-am: check-valgrind-sgcheck-local
+
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/base64.Plo
+ -rm -f ./$(DEPDIR)/cell_buffer.Plo
+ -rm -f ./$(DEPDIR)/css_parser_base.Plo
+ -rm -f ./$(DEPDIR)/css_parser_test-css_parser_test.Po
+ -rm -f ./$(DEPDIR)/css_types.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_base.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_test-csv_parser_test.Po
+ -rm -f ./$(DEPDIR)/exception.Plo
+ -rm -f ./$(DEPDIR)/json_global.Plo
+ -rm -f ./$(DEPDIR)/json_parser_base.Plo
+ -rm -f ./$(DEPDIR)/json_parser_test-json_parser_test.Po
+ -rm -f ./$(DEPDIR)/json_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/parser_base.Plo
+ -rm -f ./$(DEPDIR)/parser_global.Plo
+ -rm -f ./$(DEPDIR)/parser_global_test-parser_global_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base-parser_base_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+ -rm -f ./$(DEPDIR)/parser_test_stream-stream_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+ -rm -f ./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_parser_base.Plo
+ -rm -f ./$(DEPDIR)/sax_parser_test-sax_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser.Plo
+ -rm -f ./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/stream.Plo
+ -rm -f ./$(DEPDIR)/string_pool.Plo
+ -rm -f ./$(DEPDIR)/tokens.Plo
+ -rm -f ./$(DEPDIR)/types.Plo
+ -rm -f ./$(DEPDIR)/types_test-types_test.Po
+ -rm -f ./$(DEPDIR)/utf8.Plo
+ -rm -f ./$(DEPDIR)/utf8_test-utf8.Po
+ -rm -f ./$(DEPDIR)/utf8_test-utf8_test.Po
+ -rm -f ./$(DEPDIR)/xml_namespace.Plo
+ -rm -f ./$(DEPDIR)/xml_writer.Plo
+ -rm -f ./$(DEPDIR)/xml_writer_test-xml_writer_test.Po
+ -rm -f ./$(DEPDIR)/yaml_parser_base.Plo
+ -rm -f ./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+ -rm -f ./$(DEPDIR)/zip_archive.Plo
+ -rm -f ./$(DEPDIR)/zip_archive_stream.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-local distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/base64.Plo
+ -rm -f ./$(DEPDIR)/cell_buffer.Plo
+ -rm -f ./$(DEPDIR)/css_parser_base.Plo
+ -rm -f ./$(DEPDIR)/css_parser_test-css_parser_test.Po
+ -rm -f ./$(DEPDIR)/css_types.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_base.Plo
+ -rm -f ./$(DEPDIR)/csv_parser_test-csv_parser_test.Po
+ -rm -f ./$(DEPDIR)/exception.Plo
+ -rm -f ./$(DEPDIR)/json_global.Plo
+ -rm -f ./$(DEPDIR)/json_parser_base.Plo
+ -rm -f ./$(DEPDIR)/json_parser_test-json_parser_test.Po
+ -rm -f ./$(DEPDIR)/json_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/parser_base.Plo
+ -rm -f ./$(DEPDIR)/parser_global.Plo
+ -rm -f ./$(DEPDIR)/parser_global_test-parser_global_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base-parser_base_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64.Po
+ -rm -f ./$(DEPDIR)/parser_test_base64-base64_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_json_validation-parser_test_json_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_numeric-parser_test_numeric.Po
+ -rm -f ./$(DEPDIR)/parser_test_stream-stream_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool.Po
+ -rm -f ./$(DEPDIR)/parser_test_string_pool-string_pool_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_json_parser-threaded_json_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_threaded_sax_token_parser-threaded_sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_namespace-xml_namespace_test.Po
+ -rm -f ./$(DEPDIR)/parser_test_xml_validation-parser_test_xml_validation.Po
+ -rm -f ./$(DEPDIR)/parser_test_zip_archive-zip_archive_test.Po
+ -rm -f ./$(DEPDIR)/sax_ns_parser_test-sax_ns_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_parser_base.Plo
+ -rm -f ./$(DEPDIR)/sax_parser_test-sax_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser.Plo
+ -rm -f ./$(DEPDIR)/sax_token_parser_test-sax_token_parser_test.Po
+ -rm -f ./$(DEPDIR)/sax_token_parser_thread.Plo
+ -rm -f ./$(DEPDIR)/stream.Plo
+ -rm -f ./$(DEPDIR)/string_pool.Plo
+ -rm -f ./$(DEPDIR)/tokens.Plo
+ -rm -f ./$(DEPDIR)/types.Plo
+ -rm -f ./$(DEPDIR)/types_test-types_test.Po
+ -rm -f ./$(DEPDIR)/utf8.Plo
+ -rm -f ./$(DEPDIR)/utf8_test-utf8.Po
+ -rm -f ./$(DEPDIR)/utf8_test-utf8_test.Po
+ -rm -f ./$(DEPDIR)/xml_namespace.Plo
+ -rm -f ./$(DEPDIR)/xml_writer.Plo
+ -rm -f ./$(DEPDIR)/xml_writer_test-xml_writer_test.Po
+ -rm -f ./$(DEPDIR)/yaml_parser_base.Plo
+ -rm -f ./$(DEPDIR)/yaml_parser_test-yaml_parser_test.Po
+ -rm -f ./$(DEPDIR)/zip_archive.Plo
+ -rm -f ./$(DEPDIR)/zip_archive_stream.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am check-valgrind-am check-valgrind-drd-am \
+ check-valgrind-drd-local check-valgrind-helgrind-am \
+ check-valgrind-helgrind-local check-valgrind-local \
+ check-valgrind-memcheck-am check-valgrind-memcheck-local \
+ check-valgrind-sgcheck-am check-valgrind-sgcheck-local clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-local distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+distclean-local:
+ rm -rf $(TESTS)
+
+@VALGRIND_CHECK_RULES@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/parser/base64.cpp b/src/parser/base64.cpp
new file mode 100644
index 0000000..31b8267
--- /dev/null
+++ b/src/parser/base64.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/base64.hpp>
+
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+
+using namespace boost::archive::iterators;
+
+namespace orcus {
+
+typedef transform_width<binary_from_base64<std::vector<char>::const_iterator>, 8, 6> to_binary;
+typedef base64_from_binary<transform_width<std::vector<uint8_t>::const_iterator, 6, 8> > to_base64;
+
+std::vector<uint8_t> decode_from_base64(std::string_view base64)
+{
+ if (base64.size() < 4)
+ // Minimum of 4 characters required.
+ return std::vector<uint8_t>{};
+
+ std::vector<char> base64_seq{base64.data(), base64.data() + base64.size()};
+
+ // Check the number of trailing '='s (up to 2).
+ std::size_t pad_size = 0;
+ auto it = base64_seq.rbegin();
+ for (; pad_size < 2; ++pad_size, ++it)
+ {
+ if (*it != '=')
+ break;
+
+ *it = 'A'; // replace it with 'A' which is a base64 encoding of '\0'.
+ }
+
+ std::vector<uint8_t> decoded{to_binary(base64_seq.begin()), to_binary(base64_seq.end())};
+ decoded.erase(decoded.end() - pad_size, decoded.end());
+
+ return decoded;
+}
+
+std::string encode_to_base64(const std::vector<uint8_t>& input)
+{
+ if (input.empty())
+ return std::string{};
+
+ std::vector<uint8_t> inp = input;
+ size_t pad_size = (3 - inp.size() % 3) % 3;
+ inp.resize(inp.size() + pad_size);
+
+ std::string encoded{to_base64(inp.begin()), to_base64(inp.end())};
+
+ auto it = encoded.rbegin();
+ for (size_t i = 0; i < pad_size; ++i, ++it)
+ {
+ // 'A' is a base64 encoding of '\0'
+ // replace them with padding charachters '='
+ if (*it == 'A')
+ *it = '=';
+ }
+
+ return encoded;
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/base64_test.cpp b/src/parser/base64_test.cpp
new file mode 100644
index 0000000..9608aef
--- /dev/null
+++ b/src/parser/base64_test.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/base64.hpp"
+
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include <string>
+#include <iterator>
+
+using namespace orcus;
+using namespace std;
+
+void test_base64_text_input(const char* p)
+{
+ cout << "input: '" << p << "'" << endl;
+ size_t n = strlen(p);
+ std::vector<uint8_t> input(p, p+n);
+ std::string encoded = encode_to_base64(input);
+ cout << "encoded: '" << encoded << "'" << endl;
+
+ std::vector<uint8_t> decoded = decode_from_base64(encoded);
+ cout << "decoded: '";
+ std::copy(decoded.begin(), decoded.end(), std::ostream_iterator<char>(cout, ""));
+ cout << "'" << endl;
+
+ assert(input == decoded);
+}
+
+int main()
+{
+ test_base64_text_input("Hello there");
+ test_base64_text_input("World domination!!!");
+ test_base64_text_input("World domination!!");
+ test_base64_text_input("World domination!");
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/cell_buffer.cpp b/src/parser/cell_buffer.cpp
new file mode 100644
index 0000000..6815d71
--- /dev/null
+++ b/src/parser/cell_buffer.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/cell_buffer.hpp"
+
+#include <cstring>
+
+#define ORCUS_DEBUG_CELL_BUFFER 0
+
+#if ORCUS_DEBUG_CELL_BUFFER
+#include <iostream>
+using std::cout;
+using std::endl;
+#endif
+
+namespace orcus {
+
+cell_buffer::cell_buffer() : m_buf_size(0) {}
+
+cell_buffer::~cell_buffer() = default;
+
+void cell_buffer::append(const char* p, size_t len)
+{
+ if (!len)
+ return;
+
+#if ORCUS_DEBUG_CELL_BUFFER
+ cout << "cell_buffer::append: '" << std::string(p, len) << "'" << endl;
+#endif
+
+ size_t size_needed = m_buf_size + len;
+ if (m_buffer.size() < size_needed)
+ m_buffer.resize(size_needed);
+
+ char* p_dest = &m_buffer[m_buf_size];
+ std::strncpy(p_dest, p, len);
+ m_buf_size += len;
+}
+
+void cell_buffer::reset()
+{
+ m_buf_size = 0;
+}
+
+std::string_view cell_buffer::str() const
+{
+ return std::string_view{m_buffer.data(), m_buf_size};
+}
+
+bool cell_buffer::empty() const
+{
+ return m_buf_size == 0;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/css_parser_base.cpp b/src/parser/css_parser_base.cpp
new file mode 100644
index 0000000..128e5d4
--- /dev/null
+++ b/src/parser/css_parser_base.cpp
@@ -0,0 +1,337 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_parser_base.hpp>
+#include <orcus/parser_global.hpp>
+
+#include "utf8.hpp"
+
+#include <cstring>
+#include <cassert>
+#include <cmath>
+#include <limits>
+
+namespace orcus { namespace css {
+
+parser_base::parser_base(std::string_view content) :
+ orcus::parser_base(content.data(), content.size()),
+ m_simple_selector_count(0),
+ m_combinator(combinator_t::descendant) {}
+
+void parser_base::identifier(const char*& p, size_t& len, std::string_view extra)
+{
+ p = mp_char;
+ len = 1;
+ for (next(); has_char(); next(), ++len)
+ {
+ char c = cur_char();
+ if (is_alpha(c) || is_numeric(c) || is_in(c, "-_"))
+ continue;
+
+ if (!extra.empty())
+ {
+ // See if the character is one of the extra allowed characters.
+ if (is_in(c, extra))
+ continue;
+ }
+ return;
+ }
+}
+
+uint8_t parser_base::parse_uint8()
+{
+ // 0 - 255
+ int val = 0;
+ size_t len = 0;
+ for (; has_char() && len <= 3; next())
+ {
+ char c = cur_char();
+ if (!is_numeric(c))
+ break;
+
+ ++len;
+ val *= 10;
+ val += c - '0';
+ }
+
+ if (!len)
+ throw parse_error("parse_uint8: no digit encountered.", offset());
+
+ int maxval = std::numeric_limits<uint8_t>::max();
+ if (val > maxval)
+ val = maxval;
+
+ return static_cast<uint8_t>(val);
+}
+
+std::string_view parser_base::parse_value()
+{
+ auto throw_invalid = [this](uint8_t n_bytes)
+ {
+ std::ostringstream os;
+ os << "parse_value: invalid utf-8 byte length (" << int(n_bytes) << ")";
+ throw parse_error(os.str(), offset());
+ };
+
+ auto check_byte_length_or_throw = [this](uint8_t n_bytes, std::size_t max_size)
+ {
+ if (std::size_t(n_bytes) > max_size)
+ {
+ std::ostringstream os;
+ os << "parse_value: utf-8 byte length is " << int(n_bytes) << " but only " << max_size << " bytes remaining.";
+ throw parse_error(os.str(), offset());
+ }
+ };
+
+ std::size_t max_size = available_size();
+ if (!max_size)
+ return {};
+
+ const char* p0 = mp_char;
+ std::size_t len = 0;
+
+ char c = cur_char();
+ uint8_t n_bytes = calc_utf8_byte_length(c);
+
+ // any of '-+.#' is allowed as first character, while any of '-_.%' is
+ // allowed as second characters.
+
+ switch (n_bytes)
+ {
+ case 1:
+ {
+ if (!is_alpha(c) && !is_numeric(c) && !is_in(c, "-+.#"))
+ parse_error::throw_with("parse_value: illegal first character of a value '", c, "'", offset());
+ break;
+ }
+ case 2:
+ case 3:
+ case 4:
+ {
+ check_byte_length_or_throw(n_bytes, max_size);
+ break;
+ }
+ default:
+ throw_invalid(n_bytes);
+ }
+
+ len += n_bytes;
+ next(n_bytes);
+
+ while (has_char())
+ {
+ c = cur_char();
+ max_size = available_size();
+ n_bytes = calc_utf8_byte_length(c);
+
+ switch (n_bytes)
+ {
+ case 1:
+ {
+ if (!is_alpha(c) && !is_numeric(c) && !is_in(c, "-_.%"))
+ return {p0, len};
+ break;
+ }
+ case 2:
+ case 3:
+ case 4:
+ {
+ check_byte_length_or_throw(n_bytes, max_size);
+ break;
+ }
+ default:
+ throw_invalid(n_bytes);
+ }
+
+ len += n_bytes;
+ next(n_bytes);
+ }
+
+ return {p0, len};
+}
+
+double parser_base::parse_percent()
+{
+ double v = parse_double_or_throw();
+
+ if (*mp_char != '%')
+ parse_error::throw_with(
+ "parse_percent: '%' expected after the numeric value, but '", *mp_char, "' found.", offset());
+
+ next(); // skip the '%'.
+ return v;
+}
+
+double parser_base::parse_double_or_throw()
+{
+ double v = parse_double();
+ if (std::isnan(v))
+ throw parse_error("parse_double: failed to parse double precision value.", offset());
+ return v;
+}
+
+void parser_base::literal(const char*& p, size_t& len, char quote)
+{
+ assert(cur_char() == quote);
+ next();
+ skip_to(p, len, quote);
+
+ if (cur_char() != quote)
+ throw parse_error("literal: end quote has never been reached.", offset());
+}
+
+void parser_base::skip_to(const char*&p, size_t& len, char c)
+{
+ p = mp_char;
+ len = 0;
+ for (; has_char(); next(), ++len)
+ {
+ if (cur_char() == c)
+ return;
+ }
+}
+
+void parser_base::skip_to_or_blank(const char*&p, size_t& len, std::string_view chars)
+{
+ p = mp_char;
+ len = 0;
+ for (; has_char(); next(), ++len)
+ {
+ if (is_blank(*mp_char) || is_in(*mp_char, chars))
+ return;
+ }
+}
+
+void parser_base::skip_blanks()
+{
+ skip(" \t\r\n");
+}
+
+void parser_base::skip_blanks_reverse()
+{
+ const char* p = mp_char + remaining_size();
+ for (; p != mp_char; --p, --mp_end)
+ {
+ if (!is_blank(*p))
+ break;
+ }
+}
+
+void parser_base::shrink_stream()
+{
+ // Skip any leading blanks.
+ skip_blanks();
+
+ if (!remaining_size())
+ return;
+
+ // Skip any trailing blanks.
+ skip_blanks_reverse();
+
+ // Skip leading <!-- if present.
+
+ const char* com_open = "<!--";
+ size_t com_open_len = std::strlen(com_open);
+ if (remaining_size() < com_open_len)
+ // Not enough stream left. Bail out.
+ return;
+
+ const char* p = mp_char;
+ for (size_t i = 0; i < com_open_len; ++i, ++p)
+ {
+ if (*p != com_open[i])
+ return;
+ next();
+ }
+ mp_char = p;
+
+ // Skip leading blanks once again.
+ skip_blanks();
+
+ // Skip trailing --> if present.
+ const char* com_close = "-->";
+ size_t com_close_len = std::strlen(com_close);
+ size_t n = remaining_size();
+ if (n < com_close_len)
+ // Not enough stream left. Bail out.
+ return;
+
+ p = mp_char + n; // move to the last char.
+ for (size_t i = com_close_len; i > 0; --i, --p)
+ {
+ if (*p != com_close[i-1])
+ return;
+ }
+ mp_end -= com_close_len;
+
+ skip_blanks_reverse();
+}
+
+bool parser_base::skip_comment()
+{
+ char c = cur_char();
+ if (c != '/')
+ return false;
+
+ if (remaining_size() > 2 && peek_char() == '*')
+ {
+ next();
+ comment();
+ skip_blanks();
+ return true;
+ }
+
+ return false;
+}
+
+void parser_base::comment()
+{
+ assert(cur_char() == '*');
+
+ // Parse until we reach either EOF or '*/'.
+ bool has_star = false;
+ for (next(); has_char(); next())
+ {
+ char c = cur_char();
+ if (has_star && c == '/')
+ {
+ next();
+ return;
+ }
+ has_star = (c == '*');
+ }
+
+ // EOF reached.
+}
+
+void parser_base::skip_comments_and_blanks()
+{
+ skip_blanks();
+ while (skip_comment())
+ ;
+}
+
+void parser_base::set_combinator(char c, css::combinator_t combinator)
+{
+ if (!m_simple_selector_count)
+ parse_error::throw_with(
+ "set_combinator: combinator '", c, "' encountered without parent element.", offset());
+
+ m_combinator = combinator;
+ next();
+ skip_comments_and_blanks();
+}
+
+void parser_base::reset_before_block()
+{
+ m_simple_selector_count = 0;
+ m_combinator = css::combinator_t::descendant;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/css_parser_test.cpp b/src/parser/css_parser_test.cpp
new file mode 100644
index 0000000..95f4b1c
--- /dev/null
+++ b/src/parser/css_parser_test.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_parser.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "p { background-color: white; }";
+
+ orcus::css_handler hdl;
+ orcus::css_parser<orcus::css_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/css_types.cpp b/src/parser/css_types.cpp
new file mode 100644
index 0000000..9079159
--- /dev/null
+++ b/src/parser/css_types.cpp
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/css_types.hpp>
+#include <mdds/sorted_string_map.hpp>
+#include <mdds/global.hpp>
+
+#include <sstream>
+
+namespace orcus { namespace css {
+
+const pseudo_element_t pseudo_element_after = 0x0001;
+const pseudo_element_t pseudo_element_before = 0x0002;
+const pseudo_element_t pseudo_element_first_letter = 0x0004;
+const pseudo_element_t pseudo_element_first_line = 0x0008;
+const pseudo_element_t pseudo_element_selection = 0x0010;
+const pseudo_element_t pseudo_element_backdrop = 0x0020;
+
+namespace {
+
+namespace pseudo_elem {
+
+using map_type = mdds::sorted_string_map<pseudo_element_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "after", pseudo_element_after },
+ { "backdrop", pseudo_element_backdrop },
+ { "before", pseudo_element_before },
+ { "first-letter", pseudo_element_first_letter },
+ { "first-line", pseudo_element_first_line },
+ { "selection", pseudo_element_selection },
+};
+
+const map_type& get()
+{
+ static map_type map(entries, std::size(entries), 0);
+ return map;
+}
+
+} // namespace pseudo_elem
+
+}
+
+pseudo_element_t to_pseudo_element(std::string_view s)
+{
+ return pseudo_elem::get().find(s);
+}
+
+const pseudo_class_t pseudo_class_active = 0x0000000000000001;
+const pseudo_class_t pseudo_class_checked = 0x0000000000000002;
+const pseudo_class_t pseudo_class_default = 0x0000000000000004;
+const pseudo_class_t pseudo_class_dir = 0x0000000000000008;
+const pseudo_class_t pseudo_class_disabled = 0x0000000000000010;
+const pseudo_class_t pseudo_class_empty = 0x0000000000000020;
+const pseudo_class_t pseudo_class_enabled = 0x0000000000000040;
+const pseudo_class_t pseudo_class_first = 0x0000000000000080;
+const pseudo_class_t pseudo_class_first_child = 0x0000000000000100;
+const pseudo_class_t pseudo_class_first_of_type = 0x0000000000000200;
+const pseudo_class_t pseudo_class_fullscreen = 0x0000000000000400;
+const pseudo_class_t pseudo_class_focus = 0x0000000000000800;
+const pseudo_class_t pseudo_class_hover = 0x0000000000001000;
+const pseudo_class_t pseudo_class_indeterminate = 0x0000000000002000;
+const pseudo_class_t pseudo_class_in_range = 0x0000000000004000;
+const pseudo_class_t pseudo_class_invalid = 0x0000000000008000;
+const pseudo_class_t pseudo_class_lang = 0x0000000000010000;
+const pseudo_class_t pseudo_class_last_child = 0x0000000000020000;
+const pseudo_class_t pseudo_class_last_of_type = 0x0000000000040000;
+const pseudo_class_t pseudo_class_left = 0x0000000000080000;
+const pseudo_class_t pseudo_class_link = 0x0000000000100000;
+const pseudo_class_t pseudo_class_not = 0x0000000000200000;
+const pseudo_class_t pseudo_class_nth_child = 0x0000000000400000;
+const pseudo_class_t pseudo_class_nth_last_child = 0x0000000000800000;
+const pseudo_class_t pseudo_class_nth_last_of_type = 0x0000000001000000;
+const pseudo_class_t pseudo_class_nth_of_type = 0x0000000002000000;
+const pseudo_class_t pseudo_class_only_child = 0x0000000004000000;
+const pseudo_class_t pseudo_class_only_of_type = 0x0000000008000000;
+const pseudo_class_t pseudo_class_optional = 0x0000000010000000;
+const pseudo_class_t pseudo_class_out_of_range = 0x0000000020000000;
+const pseudo_class_t pseudo_class_read_only = 0x0000000040000000;
+const pseudo_class_t pseudo_class_read_write = 0x0000000080000000;
+const pseudo_class_t pseudo_class_required = 0x0000000100000000;
+const pseudo_class_t pseudo_class_right = 0x0000000200000000;
+const pseudo_class_t pseudo_class_root = 0x0000000400000000;
+const pseudo_class_t pseudo_class_scope = 0x0000000800000000;
+const pseudo_class_t pseudo_class_target = 0x0000001000000000;
+const pseudo_class_t pseudo_class_valid = 0x0000002000000000;
+const pseudo_class_t pseudo_class_visited = 0x0000004000000000;
+
+namespace {
+
+namespace pseudo_class {
+
+using map_type = mdds::sorted_string_map<pseudo_class_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "active", pseudo_class_active },
+ { "checked", pseudo_class_checked },
+ { "default", pseudo_class_default },
+ { "dir", pseudo_class_dir },
+ { "disabled", pseudo_class_disabled },
+ { "empty", pseudo_class_empty },
+ { "enabled", pseudo_class_enabled },
+ { "first", pseudo_class_first },
+ { "first-child", pseudo_class_first_child },
+ { "first-of-type", pseudo_class_first_of_type },
+ { "focus", pseudo_class_focus },
+ { "fullscreen", pseudo_class_fullscreen },
+ { "hover", pseudo_class_hover },
+ { "in-range", pseudo_class_in_range },
+ { "indeterminate", pseudo_class_indeterminate },
+ { "invalid", pseudo_class_invalid },
+ { "lang", pseudo_class_lang },
+ { "last-child", pseudo_class_last_child },
+ { "last-of-type", pseudo_class_last_of_type },
+ { "left", pseudo_class_left },
+ { "link", pseudo_class_link },
+ { "not", pseudo_class_not },
+ { "nth-child", pseudo_class_nth_child },
+ { "nth-last-child", pseudo_class_nth_last_child },
+ { "nth-last-of-type", pseudo_class_nth_last_of_type },
+ { "nth-of-type", pseudo_class_nth_of_type },
+ { "only-child", pseudo_class_only_child },
+ { "only-of-type", pseudo_class_only_of_type },
+ { "optional", pseudo_class_optional },
+ { "out-of-range", pseudo_class_out_of_range },
+ { "read-only", pseudo_class_read_only },
+ { "read-write", pseudo_class_read_write },
+ { "required", pseudo_class_required },
+ { "right", pseudo_class_right },
+ { "root", pseudo_class_root },
+ { "scope", pseudo_class_scope },
+ { "target", pseudo_class_target },
+ { "valid", pseudo_class_valid },
+ { "visited", pseudo_class_visited },
+};
+
+const map_type& get()
+{
+ static map_type map(entries, std::size(entries), 0);
+ return map;
+}
+
+} // namespace pseudo_class
+
+}
+
+pseudo_class_t to_pseudo_class(std::string_view s)
+{
+ return pseudo_class::get().find(s);
+}
+
+std::string pseudo_class_to_string(pseudo_class_t val)
+{
+ std::ostringstream os;
+ std::size_t n = std::size(pseudo_class::entries);
+ const pseudo_class::map_type::entry* p = pseudo_class::entries;
+ const pseudo_class::map_type::entry* p_end = p + n;
+ for (; p != p_end; ++p)
+ {
+ if (val & p->value)
+ os << ":" << p->key;
+ }
+
+ return os.str();
+}
+
+namespace {
+
+typedef mdds::sorted_string_map<property_function_t> propfunc_map_type;
+
+// Keys must be sorted.
+propfunc_map_type::entry propfunc_type_entries[] = {
+ { MDDS_ASCII("hsl"), property_function_t::hsl },
+ { MDDS_ASCII("hsla"), property_function_t::hsla },
+ { MDDS_ASCII("rgb"), property_function_t::rgb },
+ { MDDS_ASCII("rgba"), property_function_t::rgba },
+ { MDDS_ASCII("url"), property_function_t::url }
+};
+
+}
+
+property_function_t to_property_function(std::string_view s)
+{
+ static propfunc_map_type propfunc_map(
+ propfunc_type_entries, std::size(propfunc_type_entries), property_function_t::unknown);
+
+ return propfunc_map.find(s.data(), s.size());
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/csv_parser_base.cpp b/src/parser/csv_parser_base.cpp
new file mode 100644
index 0000000..1bf914c
--- /dev/null
+++ b/src/parser/csv_parser_base.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/csv_parser_base.hpp"
+
+#include <cstring>
+
+namespace orcus { namespace csv {
+
+parser_config::parser_config() :
+ text_qualifier('\0'),
+ trim_cell_value(false) {}
+
+parser_base::parser_base(
+ std::string_view content, const csv::parser_config& config) :
+ ::orcus::parser_base(content.data(), content.size()), m_config(config)
+{
+ skip_bom();
+}
+
+bool parser_base::is_blank(char c) const
+{
+ return is_in(c, " \t");
+}
+
+bool parser_base::is_delim(char c) const
+{
+ return m_config.delimiters.find(c) != std::string::npos;
+}
+
+bool parser_base::is_text_qualifier(char c) const
+{
+ return m_config.text_qualifier == c;
+}
+
+void parser_base::skip_blanks()
+{
+ skip(" \t");
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/csv_parser_test.cpp b/src/parser/csv_parser_test.cpp
new file mode 100644
index 0000000..18470f0
--- /dev/null
+++ b/src/parser/csv_parser_test.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/csv_parser.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "1,2,3,4,5\n6,7,8,9,10\n";
+
+ orcus::csv_handler hdl;
+ orcus::csv::parser_config config;
+ orcus::csv_parser<orcus::csv_handler> parser(test_code, hdl, config);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/exception.cpp b/src/parser/exception.cpp
new file mode 100644
index 0000000..1d958fd
--- /dev/null
+++ b/src/parser/exception.cpp
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/exception.hpp"
+
+#include <sstream>
+
+using namespace std;
+
+namespace orcus {
+
+general_error::general_error(std::string msg) :
+ m_msg(std::move(msg))
+{
+}
+
+general_error::general_error(std::string_view cls, std::string_view msg)
+{
+ std::ostringstream os;
+ os << cls << ": " << msg;
+ m_msg = os.str();
+}
+
+general_error::~general_error() noexcept = default;
+
+const char* general_error::what() const noexcept
+{
+ return m_msg.c_str();
+}
+
+void general_error::append_msg(const std::string& s)
+{
+ m_msg += s;
+}
+
+invalid_arg_error::invalid_arg_error(const std::string& msg) :
+ std::invalid_argument(msg) {}
+
+invalid_arg_error::~invalid_arg_error() noexcept {}
+
+xml_structure_error::xml_structure_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+xml_structure_error::~xml_structure_error() noexcept = default;
+
+json_structure_error::json_structure_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+json_structure_error::~json_structure_error() noexcept = default;
+
+invalid_map_error::invalid_map_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+invalid_map_error::~invalid_map_error() noexcept = default;
+
+value_error::value_error(std::string msg) :
+ general_error(std::move(msg)) {}
+
+value_error::~value_error() noexcept = default;
+
+xpath_error::xpath_error(std::string msg) : general_error(std::move(msg)) {}
+
+xpath_error::~xpath_error() noexcept = default;
+
+interface_error::interface_error(std::string msg) : general_error(std::move(msg)) {}
+
+interface_error::~interface_error() noexcept = default;
+
+namespace {
+
+std::string build_offset_msg(std::ptrdiff_t offset)
+{
+ std::ostringstream os;
+ os << " (offset=" << offset << ')';
+ return os.str();
+}
+
+std::string build_message(std::string_view msg_before, char c, std::string_view msg_after)
+{
+ std::ostringstream os;
+ os << msg_before << c << msg_after;
+ return os.str();
+}
+
+std::string build_message(
+ std::string_view msg_before, std::string_view msg, std::string_view msg_after)
+{
+ std::ostringstream os;
+ os << msg_before << msg << msg_after;
+ return os.str();
+}
+
+}
+
+parse_error::parse_error(std::string_view cls, std::string_view msg, std::ptrdiff_t offset) :
+ general_error(cls, msg), m_offset(offset)
+{
+ append_msg(build_offset_msg(offset));
+}
+
+parse_error::parse_error(std::string msg, std::ptrdiff_t offset) :
+ general_error(std::move(msg)), m_offset(offset)
+{
+ append_msg(build_offset_msg(offset));
+}
+
+std::ptrdiff_t parse_error::offset() const
+{
+ return m_offset;
+}
+
+void parse_error::throw_with(
+ std::string_view msg_before, char c, std::string_view msg_after, std::ptrdiff_t offset)
+{
+ throw parse_error(build_message(msg_before, c, msg_after), offset);
+}
+
+void parse_error::throw_with(
+ std::string_view msg_before, std::string_view msg, std::string_view msg_after, std::ptrdiff_t offset)
+{
+ throw parse_error(build_message(msg_before, msg, msg_after), offset);
+}
+
+malformed_xml_error::malformed_xml_error(std::string_view msg, std::ptrdiff_t offset) :
+ orcus::parse_error("malformed_xml_error", msg, offset) {}
+
+malformed_xml_error::~malformed_xml_error() = default;
+
+zip_error::zip_error(std::string_view msg) : general_error("zip_error", msg)
+{
+}
+
+zip_error::~zip_error() = default;
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_global.cpp b/src/parser/json_global.cpp
new file mode 100644
index 0000000..f01f778
--- /dev/null
+++ b/src/parser/json_global.cpp
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_global.hpp"
+#include "orcus/parser_global.hpp"
+
+#include <sstream>
+
+namespace orcus { namespace json {
+
+namespace {
+
+const char backslash = '\\';
+
+}
+
+std::string escape_string(const std::string& input)
+{
+ std::ostringstream os;
+
+ for (auto it = input.begin(), ite = input.end(); it != ite; ++it)
+ {
+ char c = *it;
+ if (c == '"')
+ // Escape double quote, but not forward slash.
+ os << backslash;
+ else if (c == backslash)
+ {
+ // Escape a '\' if and only if the next character is not one of control characters.
+ auto itnext = it + 1;
+ if (itnext == ite || get_string_escape_char_type(*itnext) != string_escape_char_t::control_char)
+ os << backslash;
+ }
+ os << c;
+ }
+
+ return os.str();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_parser_base.cpp b/src/parser/json_parser_base.cpp
new file mode 100644
index 0000000..0dcdc3b
--- /dev/null
+++ b/src/parser/json_parser_base.cpp
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_parser_base.hpp"
+#include "orcus/cell_buffer.hpp"
+#include "numeric_parser.hpp"
+
+#include <cassert>
+#include <cmath>
+
+namespace orcus { namespace json {
+
+namespace {
+
+const char* parse_numeric_json(const char* p, const char* p_end, double& value)
+{
+ using numeric_parser_type = detail::numeric_parser<detail::json_parser_trait>;
+
+ numeric_parser_type parser(p, p_end);
+ double v = parser.parse();
+ if (!std::isnan(v))
+ p = parser.get_char_position();
+
+ value = v;
+ return p;
+};
+
+} // anonymous namespace
+
+struct parser_base::impl
+{
+ cell_buffer m_buffer;
+};
+
+parser_base::parser_base(std::string_view content) :
+ orcus::parser_base(content.data(), content.size()), mp_impl(std::make_unique<impl>())
+{
+
+ set_numeric_parser(parse_numeric_json);
+}
+
+parser_base::~parser_base() {}
+
+void parser_base::skip_ws()
+{
+ skip(" \n\r\t");
+}
+
+void parser_base::parse_true()
+{
+ if (!parse_expected("true"))
+ throw parse_error("parse_true: boolean 'true' expected.", offset());
+
+ skip_ws();
+}
+
+void parser_base::parse_false()
+{
+ if (!parse_expected("false"))
+ throw parse_error("parse_false: boolean 'false' expected.", offset());
+
+ skip_ws();
+}
+
+void parser_base::parse_null()
+{
+ if (!parse_expected("null"))
+ throw parse_error("parse_null: null expected.", offset());
+
+ skip_ws();
+}
+
+double parser_base::parse_double_or_throw()
+{
+ double v = parse_double();
+ if (std::isnan(v))
+ throw parse_error("parse_double_or_throw: failed to parse double precision value.", offset());
+ return v;
+}
+
+parse_quoted_string_state parser_base::parse_string()
+{
+ assert(cur_char() == '"');
+ size_t max_length = remaining_size();
+ const char* p = mp_char;
+ parse_quoted_string_state ret = parse_double_quoted_string(p, max_length, mp_impl->m_buffer);
+ if (ret.has_control_character)
+ throw parse_error("parse_string: string contains a control character.", offset());
+
+ mp_char = p;
+
+ if (ret.str)
+ skip_ws();
+
+ return ret;
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_parser_test.cpp b/src/parser/json_parser_test.cpp
new file mode 100644
index 0000000..db64861
--- /dev/null
+++ b/src/parser/json_parser_test.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/json_parser.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "{\"key1\": [1,2,3,4,5], \"key2\": 12.3}";
+
+ orcus::json_handler hdl;
+ orcus::json_parser<orcus::json_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/json_parser_thread.cpp b/src/parser/json_parser_thread.cpp
new file mode 100644
index 0000000..a07bb61
--- /dev/null
+++ b/src/parser/json_parser_thread.cpp
@@ -0,0 +1,294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/json_parser_thread.hpp>
+#include <orcus/json_parser.hpp>
+#include <orcus/string_pool.hpp>
+#include <orcus/detail/parser_token_buffer.hpp>
+
+#include <sstream>
+#include <string_view>
+#include <algorithm>
+#include <limits>
+
+namespace orcus { namespace json {
+
+parse_token::parse_token() : type(parse_token_t::unknown), value(0.0) {}
+
+parse_token::parse_token(parse_token_t _type) : type(_type), value(0.0) {}
+
+parse_token::parse_token(parse_token_t _type, std::string_view s) :
+ type(_type), value(s)
+{
+}
+
+parse_token::parse_token(std::string_view s, std::ptrdiff_t offset) :
+ type(parse_token_t::parse_error), value(parse_error_value_t{s, offset})
+{
+ assert(type == parse_token_t::parse_error);
+}
+
+parse_token::parse_token(double v) :
+ type(parse_token_t::number), value(v)
+{
+}
+
+parse_token::parse_token(const parse_token& other) :
+ type(other.type), value(other.value)
+{
+}
+
+bool parse_token::operator== (const parse_token& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+bool parse_token::operator!= (const parse_token& other) const
+{
+ return !operator== (other);
+}
+
+/**
+ * This impl class also acts as a handler for the parser.
+ *
+ */
+struct parser_thread::impl
+{
+ detail::thread::parser_token_buffer<parse_tokens_t> m_token_buffer;
+ string_pool m_pool;
+ parse_tokens_t m_parser_tokens; // token buffer for the parser thread.
+
+ const char* mp_char;
+ size_t m_size;
+
+ impl(const char* p, size_t n, size_t min_token_size, size_t max_token_size) :
+ m_token_buffer(min_token_size, max_token_size),
+ mp_char(p), m_size(n)
+ {
+ m_parser_tokens.reserve(min_token_size);
+ }
+
+ void start()
+ {
+ try
+ {
+ json_parser<parser_thread::impl> parser({mp_char, m_size}, *this);
+ parser.parse();
+ }
+ catch (const parse_error& e)
+ {
+ std::string_view s = m_pool.intern(e.what()).first;
+ m_parser_tokens.emplace_back(s, e.offset());
+ }
+
+ notify_and_finish();
+ }
+
+ void begin_parse()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::begin_parse);
+ check_and_notify();
+ }
+
+ void end_parse()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::end_parse);
+ check_and_notify();
+ }
+
+ void begin_array()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::begin_array);
+ check_and_notify();
+ }
+
+ void end_array()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::end_array);
+ check_and_notify();
+ }
+
+ void begin_object()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::begin_object);
+ check_and_notify();
+ }
+
+ void object_key(std::string_view s, bool transient)
+ {
+ if (transient)
+ s = m_pool.intern(s).first;
+
+ m_parser_tokens.emplace_back(parse_token_t::object_key, s);
+ check_and_notify();
+ }
+
+ void end_object()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::end_object);
+ check_and_notify();
+ }
+
+ void boolean_true()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::boolean_true);
+ check_and_notify();
+ }
+
+ void boolean_false()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::boolean_false);
+ check_and_notify();
+ }
+
+ void null()
+ {
+ m_parser_tokens.emplace_back(parse_token_t::null);
+ check_and_notify();
+ }
+
+ void string(std::string_view s, bool transient)
+ {
+ if (transient)
+ s = m_pool.intern(s).first;
+
+ m_parser_tokens.emplace_back(parse_token_t::string, s);
+ check_and_notify();
+ }
+
+ void number(double val)
+ {
+ m_parser_tokens.emplace_back(val);
+ check_and_notify();
+ }
+
+ void check_and_notify()
+ {
+ m_token_buffer.check_and_notify(m_parser_tokens);
+ }
+
+ void notify_and_finish()
+ {
+ m_token_buffer.notify_and_finish(m_parser_tokens);
+ }
+
+ bool next_tokens(parse_tokens_t& tokens)
+ {
+ return m_token_buffer.next_tokens(tokens);
+ }
+
+ parser_stats get_stats() const
+ {
+ parser_stats stats;
+ stats.token_buffer_size_threshold = m_token_buffer.token_size_threshold();
+ return stats;
+ }
+
+ void swap_string_pool(string_pool& pool)
+ {
+ m_pool.swap(pool);
+ }
+};
+
+std::ostream& operator<< (std::ostream& os, const parse_tokens_t& tokens)
+{
+ using std::endl;
+
+ os << "token size: " << tokens.size() << endl;
+
+ std::for_each(tokens.begin(), tokens.end(),
+ [&](const parse_token& t)
+ {
+ switch (t.type)
+ {
+ case parse_token_t::begin_array:
+ os << "- begin_array" << endl;
+ break;
+ case parse_token_t::begin_object:
+ os << "- begin_object" << endl;
+ break;
+ case parse_token_t::begin_parse:
+ os << "- begin_parse" << endl;
+ break;
+ case parse_token_t::boolean_false:
+ os << "- boolean_false" << endl;
+ break;
+ case parse_token_t::boolean_true:
+ os << "- boolean_true" << endl;
+ break;
+ case parse_token_t::end_array:
+ os << "- end_array" << endl;
+ break;
+ case parse_token_t::end_object:
+ os << "- end_object" << endl;
+ break;
+ case parse_token_t::end_parse:
+ os << "- end_parse" << endl;
+ break;
+ case parse_token_t::null:
+ os << "- null" << endl;
+ break;
+ case parse_token_t::number:
+ os << "- number (v=" << std::get<double>(t.value) << ")" << endl;
+ break;
+ case parse_token_t::object_key:
+ os << "- object_key (v=" << std::get<std::string_view>(t.value) << ")" << endl;
+ break;
+ case parse_token_t::parse_error:
+ {
+ auto v = std::get<parse_error_value_t>(t.value);
+ os << "- parse_error (v=" << v.str << ", offset=" << v.offset << ")" << endl;
+ break;
+ }
+ case parse_token_t::string:
+ os << "- string (" << std::get<std::string_view>(t.value) << ")" << endl;
+ break;
+ case parse_token_t::unknown:
+ os << "- unknown" << endl;
+ break;
+ default:
+ ;
+ }
+ }
+ );
+
+ return os;
+}
+
+parser_thread::parser_thread(const char* p, size_t n, size_t min_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, min_token_size, std::numeric_limits<size_t>::max()/2)) {}
+
+parser_thread::parser_thread(const char* p, size_t n, size_t min_token_size, size_t max_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, min_token_size, max_token_size)) {}
+
+parser_thread::~parser_thread() {}
+
+void parser_thread::start()
+{
+ mp_impl->start();
+}
+
+bool parser_thread::next_tokens(parse_tokens_t& tokens)
+{
+ return mp_impl->next_tokens(tokens);
+}
+
+parser_stats parser_thread::get_stats() const
+{
+ return mp_impl->get_stats();
+}
+
+void parser_thread::swap_string_pool(string_pool& pool)
+{
+ mp_impl->swap_string_pool(pool);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_base.cpp b/src/parser/parser_base.cpp
new file mode 100644
index 0000000..e49af71
--- /dev/null
+++ b/src/parser/parser_base.cpp
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/parser_base.hpp"
+#include "orcus/parser_global.hpp"
+#include "cpu_features.hpp"
+
+#include <sstream>
+#include <cstring>
+#include <limits>
+#include <cassert>
+#include <algorithm>
+
+#ifdef __ORCUS_CPU_FEATURES
+#include <immintrin.h>
+#endif
+
+namespace orcus {
+
+parser_base::parser_base(const char* p, size_t n) :
+ mp_begin(p), mp_char(p), mp_end(p+n),
+ m_func_parse_numeric(parse_numeric)
+{
+}
+
+void parser_base::prev(size_t dec)
+{
+ mp_char -= dec;
+}
+
+char parser_base::peek_char(std::size_t offset) const
+{
+ return *(mp_char + offset);
+}
+
+std::string_view parser_base::peek_chars(std::size_t length) const
+{
+ return {mp_char, length};
+}
+
+void parser_base::skip_bom()
+{
+ // Skip one or more UTF-8 BOM's.
+ constexpr std::string_view BOM = "\xEF\xBB\xBF";
+
+ while (true)
+ {
+ if (available_size() < 3)
+ return;
+
+ if (peek_chars(3) != BOM)
+ return;
+
+ next(3);
+ }
+}
+
+void parser_base::skip(std::string_view chars_to_skip)
+{
+#if defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+ __m128i match = _mm_loadu_si128((const __m128i*)chars_to_skip.data());
+ const int mode = _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_EQUAL_ANY | _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY;
+
+ int n_total = available_size();
+
+ while (n_total)
+ {
+ __m128i char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ // Find position of the first character that is NOT any of the
+ // characters to skip.
+ int n = std::min<int>(16, n_total);
+ int r = _mm_cmpestri(match, chars_to_skip.size(), char_block, n, mode);
+
+ if (!r)
+ // No characters to skip. Bail out.
+ break;
+
+ mp_char += r; // Move the current char position.
+
+ if (r < 16)
+ // No need to move to the next segment. Stop here.
+ break;
+
+ // Skip 16 chars to the next segment.
+ n_total -= 16;
+ }
+#else
+ for (; has_char(); next())
+ {
+ if (!is_in(*mp_char, chars_to_skip))
+ break;
+ }
+#endif
+}
+
+void parser_base::skip_space_and_control()
+{
+#if defined(__ORCUS_CPU_FEATURES) && defined(__AVX2__)
+ size_t n_total = available_size();
+ const __m256i ws = _mm256_set1_epi8(' '); // whitespaces
+ const __m256i sb = _mm256_set1_epi8(0x80); // signed bit on.
+
+ while (n_total)
+ {
+ // The 'results' stores (for each 8-bit int) 0x00 if the char is less
+ // than or equal to whitespace, or the char is "negative" i.e. the
+ // signed bit is on IOW greater than 127.
+ __m256i char_block = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mp_char));
+ __m256i results = _mm256_cmpgt_epi8(char_block, ws); // NB: this is a signed comparison.
+ results = _mm256_or_si256(results, _mm256_and_si256(char_block, sb));
+ int r = _mm256_movemask_epi8(results);
+ r = _tzcnt_u32(r);
+ r = std::min<size_t>(r, n_total);
+
+ if (!r)
+ // No characters to skip. Bail out.
+ break;
+
+ mp_char += r; // Move the current char position.
+
+ if (r < 32)
+ // No need to move to the next segment. Stop here.
+ break;
+
+ n_total -= 32;
+ }
+
+#elif defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+ __m128i match = _mm_loadu_si128((const __m128i*)"\0 ");
+ const int mode = _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY;
+
+ size_t n_total = available_size();
+
+ while (n_total)
+ {
+ __m128i char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ // Find position of the first character that is NOT any of the
+ // characters to skip.
+ int n = std::min<size_t>(16u, n_total);
+ int r = _mm_cmpestri(match, 2, char_block, n, mode);
+
+ if (!r)
+ // No characters to skip. Bail out.
+ break;
+
+ mp_char += r; // Move the current char position.
+
+ if (r < 16)
+ // No need to move to the next segment. Stop here.
+ break;
+
+ // Skip 16 chars to the next segment.
+ n_total -= 16;
+ }
+#else
+ for (; mp_char != mp_end && ((unsigned char)*mp_char) <= (unsigned char)' '; ++mp_char)
+ ;
+#endif
+}
+
+bool parser_base::parse_expected(std::string_view expected)
+{
+ if (expected.size() > available_size())
+ return false;
+
+#if defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+ __m128i v_expected = _mm_loadu_si128((const __m128i*)expected.data());
+ __m128i v_char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ const int mode = _SIDD_CMP_EQUAL_ORDERED | _SIDD_UBYTE_OPS | _SIDD_BIT_MASK;
+ __m128i res = _mm_cmpestrm(v_expected, expected.size(), v_char_block, expected.size(), mode);
+ int mask = _mm_cvtsi128_si32(res);
+
+ if (mask)
+ mp_char += expected.size();
+
+ return mask;
+#else
+ const char* p = expected.data();
+ for (size_t i = 0; i < expected.size(); ++i, ++p, next())
+ {
+ if (cur_char() != *p)
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+double parser_base::parse_double()
+{
+ size_t max_length = available_size();
+ const char* p = mp_char;
+ double val;
+ p = m_func_parse_numeric(p, p + max_length, val);
+ if (p == mp_char)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ mp_char = p;
+ return val;
+}
+
+size_t parser_base::remaining_size() const
+{
+ size_t n = available_size();
+ return n ? (n - 1) : 0;
+}
+
+std::ptrdiff_t parser_base::offset() const
+{
+ return std::distance(mp_begin, mp_char);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_base_test.cpp b/src/parser/parser_base_test.cpp
new file mode 100644
index 0000000..74994da
--- /dev/null
+++ b/src/parser/parser_base_test.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/parser_base.hpp"
+
+using namespace std;
+using namespace orcus;
+
+void test_skip_space_and_control()
+{
+ class _test_type : public orcus::parser_base
+ {
+ public:
+ _test_type(const char* p, size_t n) : orcus::parser_base(p, n) {}
+
+ void run()
+ {
+ skip_space_and_control();
+ }
+
+ bool has_char() const
+ {
+ return orcus::parser_base::has_char();
+ }
+
+ size_t available_size() const
+ {
+ return orcus::parser_base::available_size();
+ }
+
+ char get_char() const
+ {
+ return *mp_char;
+ }
+ };
+
+ // Create a series of variable-legnth blank strings and make sure the
+ // function correctly skips all the empty characters.
+
+ for (size_t i = 0; i < 32; ++i)
+ {
+ std::string s(i, ' ');
+ assert(s.size() == i);
+
+ _test_type test(s.data(), s.size());
+ assert(test.available_size() == s.size());
+
+ test.run();
+ assert(!test.has_char()); // There should be no more characters to parse.
+
+ s.push_back('a');
+
+ _test_type test2(s.data(), s.size());
+ assert(test2.available_size() == s.size());
+
+ test2.run();
+ assert(test2.has_char()); // The current position should be on the 'a'.
+ assert(test2.get_char() == 'a');
+ }
+}
+
+int main()
+{
+ test_skip_space_and_control();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_global.cpp b/src/parser/parser_global.cpp
new file mode 100644
index 0000000..5489e21
--- /dev/null
+++ b/src/parser/parser_global.cpp
@@ -0,0 +1,515 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/parser_global.hpp>
+#include <orcus/cell_buffer.hpp>
+#include <orcus/exception.hpp>
+
+#include "numeric_parser.hpp"
+
+#include <cassert>
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <algorithm>
+#include <cctype>
+
+namespace orcus {
+
+const size_t parse_quoted_string_state::error_no_closing_quote = 1;
+const size_t parse_quoted_string_state::error_illegal_escape_char = 2;
+
+bool is_blank(char c)
+{
+ return is_in(c, " \t\n\r");
+}
+
+bool is_alpha(char c)
+{
+ return std::isalpha(static_cast<unsigned char>(c));
+}
+
+bool is_numeric(char c)
+{
+ return std::isdigit(static_cast<unsigned char>(c));
+}
+
+bool is_in(char c, std::string_view allowed)
+{
+#ifdef __ORCUS_DEBUG_UTILS
+ if (allowed.empty())
+ throw std::invalid_argument("'allowed' string should not be empty.");
+#endif
+ auto f = [c](char c_allowed) { return c == c_allowed; };
+ return std::any_of(allowed.begin(), allowed.end(), f);
+}
+
+const char* parse_numeric(const char* p, const char* p_end, double& value)
+{
+ using numeric_parser_type = detail::numeric_parser<detail::generic_parser_trait>;
+
+ numeric_parser_type parser(p, p_end);
+ double v = parser.parse();
+ if (!std::isnan(v))
+ p = parser.get_char_position();
+
+ value = v;
+ return p;
+}
+
+const char* parse_integer(const char* p, const char* p_end, long& value)
+{
+ if (p >= p_end)
+ return p;
+
+ long result = 0.0;
+ bool negative_sign = false;
+
+ // Check for presence of a sign.
+ if (p != p_end)
+ {
+ switch (*p)
+ {
+ case '+':
+ ++p;
+ break;
+ case '-':
+ negative_sign = true;
+ ++p;
+ break;
+ default:
+ ;
+ }
+ }
+
+ for (; p != p_end; ++p)
+ {
+ if (*p < '0' || '9' < *p)
+ {
+ value = negative_sign ? -result : result;
+ return p;
+ }
+
+ result *= 10;
+ result += *p - '0';
+ }
+
+ value = negative_sign ? -result : result;
+ return p;
+}
+
+string_escape_char_t get_string_escape_char_type(char c)
+{
+ switch (c)
+ {
+ case '"':
+ case '\\':
+ case '/':
+ return string_escape_char_t::valid;
+ case 'b': // backspace
+ case 'f': // formfeed
+ case 'n': // newline
+ case 'r': // carriage return
+ case 't': // horizontal tab
+ return string_escape_char_t::control_char;
+ default:
+ ;
+ }
+
+ return string_escape_char_t::invalid;
+}
+
+namespace {
+
+parse_quoted_string_state parse_string_with_escaped_char(
+ const char*& p, size_t max_length, const char* p_parsed, size_t n_parsed, char c,
+ cell_buffer& buffer)
+{
+ const char* p_end = p + max_length;
+
+ parse_quoted_string_state ret;
+ ret.str = nullptr;
+ ret.length = 0;
+ ret.transient = true;
+ ret.has_control_character = false;
+
+ // Start the buffer with the string we've parsed so far.
+ buffer.reset();
+ if (p_parsed && n_parsed)
+ buffer.append(p_parsed, n_parsed);
+ buffer.append(&c, 1);
+
+ ++p;
+ if (p == p_end)
+ {
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+ }
+
+ size_t len = 0;
+ const char* p_head = p;
+ bool escape = false;
+
+ for (; p != p_end; ++p, ++len)
+ {
+ c = *p;
+
+ if (escape)
+ {
+ escape = false;
+
+ switch (get_string_escape_char_type(c))
+ {
+ case string_escape_char_t::valid:
+ buffer.append(p_head, len-1);
+ buffer.append(&c, 1);
+ ++p;
+ len = 0;
+ p_head = p;
+ break;
+ case string_escape_char_t::control_char:
+ // do nothing on control characters.
+ break;
+ case string_escape_char_t::invalid:
+ default:
+ ret.length = parse_quoted_string_state::error_illegal_escape_char;
+ return ret;
+ }
+ }
+
+ switch (*p)
+ {
+ case '"':
+ {
+ // closing quote.
+ buffer.append(p_head, len);
+ ++p; // skip the quote.
+ std::string_view s = buffer.str();
+ ret.str = s.data();
+ ret.length = s.size();
+ return ret;
+ }
+ case '\\':
+ {
+ escape = true;
+ continue;
+ }
+ default:
+ ;
+ }
+ }
+
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+parse_quoted_string_state parse_single_quoted_string_buffered(
+ const char*& p, const char* p_end, cell_buffer& buffer)
+{
+ const char* p0 = p;
+ size_t len = 0;
+ char last = 0;
+
+ parse_quoted_string_state ret;
+ ret.transient = true;
+ ret.has_control_character = false;
+
+ for (; p != p_end; ++p)
+ {
+ if (!p0)
+ p0 = p;
+
+ char c = *p;
+ switch (c)
+ {
+ case '\'':
+ {
+ if (last == c)
+ {
+ // Second "'" in series. This is an encoded single quote.
+ buffer.append(p0, len);
+ p0 = nullptr;
+ last = 0;
+ len = 0;
+ continue;
+ }
+ }
+ break;
+ default:
+ {
+ if (last == '\'')
+ {
+ buffer.append(p0, len-1);
+ auto s = buffer.str();
+ ret.str = s.data();
+ ret.length = s.size();
+ return ret;
+ }
+ }
+ }
+
+ last = c;
+ ++len;
+ }
+
+ if (last == '\'')
+ {
+ buffer.append(p0, len-1);
+ auto s = buffer.str();
+ ret.str = s.data();
+ ret.length = s.size();
+ return ret;
+ }
+
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+}
+
+parse_quoted_string_state parse_single_quoted_string(
+ const char*& p, size_t max_length, cell_buffer& buffer)
+{
+ assert(*p == '\'');
+ const char* p_end = p + max_length;
+ ++p;
+
+ parse_quoted_string_state ret;
+ ret.str = p;
+ ret.length = 0;
+ ret.transient = false;
+ ret.has_control_character = false;
+
+ if (p == p_end)
+ {
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+ }
+
+ char last = 0;
+ char c = 0;
+ for (; p != p_end; last = c, ++p, ++ret.length)
+ {
+ c = *p;
+ switch (c)
+ {
+ case '\'':
+ {
+ if (last == c)
+ {
+ // Encoded single quote.
+ buffer.reset();
+ buffer.append(ret.str, ret.length);
+ ++p;
+ return parse_single_quoted_string_buffered(p, p_end, buffer);
+ }
+ }
+ break;
+ default:
+ {
+ if (last == '\'')
+ {
+ --ret.length;
+ return ret;
+ }
+ }
+
+ }
+ }
+
+ if (last == '\'')
+ {
+ --ret.length;
+ return ret;
+ }
+
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+const char* parse_to_closing_single_quote(const char* p, size_t max_length)
+{
+ assert(*p == '\'');
+ const char* p_end = p + max_length;
+ ++p;
+
+ if (p == p_end)
+ return nullptr;
+
+ char last = 0;
+ for (; p != p_end; ++p)
+ {
+ char c = *p;
+ switch (c)
+ {
+ case '\'':
+ if (last == '\'')
+ {
+ last = 0;
+ continue;
+ }
+ break;
+ default:
+ {
+ if (last == '\'')
+ return p;
+ }
+ }
+
+ last = c;
+ }
+
+ if (last == '\'')
+ return p;
+
+ return nullptr;
+}
+
+parse_quoted_string_state parse_double_quoted_string(
+ const char*& p, size_t max_length, cell_buffer& buffer)
+{
+ if (max_length == 0 || !p || *p != '"')
+ throw invalid_arg_error("parse_double_quoted_string: invalid input string");
+
+ parse_quoted_string_state ret;
+ ret.str = nullptr;
+ ret.length = 0;
+ ret.transient = false;
+ ret.has_control_character = false;
+
+ const char* p_end = p + max_length;
+ ++p; // skip the opening quote.
+
+ ret.str = p;
+
+ if (p == p_end)
+ {
+ // The string contains only the opening quote.
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+ }
+
+ bool escape = false;
+
+ for (; p != p_end; ++p, ++ret.length)
+ {
+ char c = *p;
+
+ if (escape)
+ {
+ escape = false;
+
+ switch (get_string_escape_char_type(c))
+ {
+ case string_escape_char_t::valid:
+ return parse_string_with_escaped_char(p, max_length, ret.str, ret.length-1, c, buffer);
+ case string_escape_char_t::control_char:
+ // do nothing on control characters.
+ break;
+ case string_escape_char_t::invalid:
+ default:
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_illegal_escape_char;
+ return ret;
+ }
+ }
+
+ switch (*p)
+ {
+ case '"':
+ {
+ // closing quote.
+ ++p; // skip the quote.
+ return ret;
+ }
+ case '\\':
+ {
+ escape = true;
+ continue;
+ }
+ default:
+ ;
+ }
+
+ if (0x00 <= c && c <= 0x1F)
+ {
+ // This is an unescaped control character.
+ ret.has_control_character = true;
+ }
+ }
+
+ ret.str = nullptr;
+ ret.length = parse_quoted_string_state::error_no_closing_quote;
+ return ret;
+}
+
+const char* parse_to_closing_double_quote(const char* p, size_t max_length)
+{
+ assert(*p == '"');
+ const char* p_end = p + max_length;
+ ++p;
+
+ if (p == p_end)
+ return nullptr;
+
+ bool escape = false;
+
+ for (; p != p_end; ++p)
+ {
+ if (escape)
+ {
+ char c = *p;
+ escape = false;
+
+ if (get_string_escape_char_type(c) == string_escape_char_t::invalid)
+ return nullptr;
+ }
+
+ switch (*p)
+ {
+ case '"':
+ // closing quote.
+ ++p; // skip the quote.
+ return p;
+ case '\\':
+ escape = true;
+ break;
+ default:
+ ;
+ }
+ }
+
+ return nullptr;
+}
+
+std::string_view trim(std::string_view str)
+{
+ const char* p = str.data();
+ const char* p_end = p + str.size();
+
+ // Find the first non-space character.
+ p = std::find_if_not(p, p_end, is_blank);
+
+ if (p == p_end)
+ {
+ // This string is empty.
+ return std::string_view{};
+ }
+
+ // Find the last non-space character.
+ auto last = std::find_if_not(std::reverse_iterator(p_end), std::reverse_iterator(p), is_blank);
+ std::size_t n = std::distance(p, last.base());
+
+ return std::string_view{p, n};
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_global_test.cpp b/src/parser/parser_global_test.cpp
new file mode 100644
index 0000000..680a221
--- /dev/null
+++ b/src/parser/parser_global_test.cpp
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/parser_global.hpp>
+#include <orcus/cell_buffer.hpp>
+
+#include <vector>
+#include <cmath>
+#include <cstring>
+#include <limits>
+
+namespace {
+
+void test_parse_numbers()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ struct test_case
+ {
+ const char* str;
+ double val;
+ };
+
+ std::vector<test_case> test_cases = {
+ {"1", 1.0},
+ {"1.0", 1.0},
+ {"-1.0", -1.0},
+ {"2e2", 200.0},
+ {"1.2", 1.2},
+ {"-0.0001", -0.0001},
+ {"-0.0", 0.0},
+ {"+.", std::numeric_limits<double>::signaling_NaN()},
+ {"+e", std::numeric_limits<double>::signaling_NaN()},
+ {"+e1", std::numeric_limits<double>::signaling_NaN()},
+ {"+ ", std::numeric_limits<double>::signaling_NaN()},
+ {"- ", std::numeric_limits<double>::signaling_NaN()}
+ };
+
+ for (const test_case& test_data : test_cases)
+ {
+ const char* str = test_data.str;
+ double val;
+ orcus::parse_numeric(str, str + std::strlen(test_data.str), val);
+ if (std::isnan(test_data.val))
+ {
+ assert(std::isnan(val));
+ }
+ else
+ {
+ assert(val == test_data.val);
+ }
+ }
+}
+
+void test_parse_integers()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ std::string_view test_str = "-100";
+
+ long value;
+ const char* p = test_str.data();
+ const char* p_end = p + test_str.size();
+ const char* p_last = orcus::parse_integer(p, p_end, value);
+
+ assert(value == -100);
+ assert(p_last == p_end);
+
+ --p_end;
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(value == -10);
+ assert(p_last == p_end);
+
+ --p_end;
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(value == -1);
+ assert(p_last == p_end);
+
+ test_str = "13.4"; // the parsing should end on the '.'
+ p = test_str.data();
+ p_end = p + test_str.size();
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(value == 13);
+ assert(p_last == p + 2);
+
+ // What if the p_end points to an earlier address than the p ...
+ std::swap(p, p_end);
+ assert(p > p_end);
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(p == p_last);
+
+ // Empty char range
+ p = test_str.data();
+ p_end = p;
+ p_last = orcus::parse_integer(p, p_end, value);
+ assert(p_last == p);
+}
+
+void test_parse_double_quoted_strings()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ struct test_case
+ {
+ std::string input;
+ const char* expected_p;
+ size_t expected_n;
+ };
+
+ std::vector<test_case> test_cases = {
+ { "\"", nullptr, orcus::parse_quoted_string_state::error_no_closing_quote },
+ { "\"\"", "", 0 },
+ { "\"a\"", "a", 1 },
+
+ };
+
+ for (const test_case& tc : test_cases)
+ {
+ orcus::cell_buffer buf;
+ const char* p = tc.input.data();
+ size_t n = tc.input.size();
+ orcus::parse_quoted_string_state ret = orcus::parse_double_quoted_string(p, n, buf);
+
+ if (tc.expected_p)
+ {
+ std::string expected(tc.expected_p, tc.expected_n);
+ std::string actual(ret.str, ret.length);
+ assert(expected == actual);
+ }
+ else
+ {
+ assert(ret.str == nullptr);
+ assert(ret.length == tc.expected_n);
+ }
+ }
+
+}
+
+void test_trim()
+{
+ // test for trimming.
+ std::string s1("test"), s2(" test"), s3(" test "), s4("test ");
+ std::string_view sv1(s1), sv2(s2), sv3(s3), sv4(s4);
+ assert(sv1 != sv2);
+ assert(sv1 != sv3);
+ assert(sv2 != sv3);
+ assert(sv1 != sv4);
+
+ std::string_view trimmed = orcus::trim(sv1);
+ assert(sv1 == trimmed); // nothing to trim.
+ assert(sv1 == orcus::trim(sv2));
+ assert(sv1 == orcus::trim(sv3));
+ assert(sv1 == orcus::trim(sv4));
+ assert(sv1.size() == orcus::trim(sv2).size());
+ assert(sv1.size() == orcus::trim(sv3).size());
+}
+
+}
+
+int main()
+{
+ test_parse_numbers();
+ test_parse_integers();
+ test_parse_double_quoted_strings();
+ test_trim();
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_test_json_validation.cpp b/src/parser/parser_test_json_validation.cpp
new file mode 100644
index 0000000..a001226
--- /dev/null
+++ b/src/parser/parser_test_json_validation.cpp
@@ -0,0 +1,439 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/json_parser.hpp"
+#include "orcus/stream.hpp"
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+namespace {
+
+// These test cases originate from https://github.com/nst/JSONTestSuite
+//
+// The name of these files tell if their contents should be accepted or
+// rejected.
+//
+// * y_ content must be accepted by parsers
+// * n_ content must be rejected by parsers
+// * i_ parsers are free to accept or reject content
+
+std::vector<const char*> test_files_indeterminate = {
+ "i_number_double_huge_neg_exp.json",
+ "i_number_huge_exp.json",
+ "i_number_neg_int_huge_exp.json",
+ "i_number_pos_double_huge_exp.json",
+ "i_number_real_neg_overflow.json",
+ "i_number_real_pos_overflow.json",
+ "i_number_real_underflow.json",
+ "i_number_too_big_neg_int.json",
+ "i_number_too_big_pos_int.json",
+ "i_number_very_big_negative_int.json",
+ "i_object_key_lone_2nd_surrogate.json",
+ "i_string_1st_surrogate_but_2nd_missing.json",
+ "i_string_1st_valid_surrogate_2nd_invalid.json",
+ "i_string_incomplete_surrogate_and_escape_valid.json",
+ "i_string_incomplete_surrogate_pair.json",
+ "i_string_incomplete_surrogates_escape_valid.json",
+ "i_string_invalid_lonely_surrogate.json",
+ "i_string_invalid_surrogate.json",
+ "i_string_invalid_utf-8.json",
+ "i_string_inverted_surrogates_U+1D11E.json",
+ "i_string_iso_latin_1.json",
+ "i_string_lone_second_surrogate.json",
+ "i_string_lone_utf8_continuation_byte.json",
+ "i_string_not_in_unicode_range.json",
+ "i_string_overlong_sequence_2_bytes.json",
+ "i_string_overlong_sequence_6_bytes.json",
+ "i_string_overlong_sequence_6_bytes_null.json",
+ "i_string_truncated-utf-8.json",
+ "i_string_utf16BE_no_BOM.json",
+ "i_string_utf16LE_no_BOM.json",
+ "i_string_UTF-16LE_with_BOM.json",
+ "i_string_UTF-8_invalid_sequence.json",
+ "i_string_UTF8_surrogate_U+D800.json",
+ "i_structure_500_nested_arrays.json",
+ "i_structure_UTF-8_BOM_empty_object.json"
+};
+
+std::vector<const char*> test_files_failed = {
+ "n_array_1_true_without_comma.json",
+ "n_array_a_invalid_utf8.json",
+ "n_array_colon_instead_of_comma.json",
+ "n_array_comma_after_close.json",
+ "n_array_comma_and_number.json",
+ "n_array_double_comma.json",
+ "n_array_double_extra_comma.json",
+ "n_array_extra_close.json",
+ "n_array_extra_comma.json",
+ "n_array_incomplete_invalid_value.json",
+ "n_array_incomplete.json",
+ "n_array_inner_array_no_comma.json",
+ "n_array_invalid_utf8.json",
+ "n_array_items_separated_by_semicolon.json",
+ "n_array_just_comma.json",
+ "n_array_just_minus.json",
+ "n_array_missing_value.json",
+ "n_array_newlines_unclosed.json",
+ "n_array_number_and_comma.json",
+ "n_array_number_and_several_commas.json",
+ "n_array_spaces_vertical_tab_formfeed.json",
+ "n_array_star_inside.json",
+ "n_array_unclosed.json",
+ "n_array_unclosed_trailing_comma.json",
+ "n_array_unclosed_with_new_lines.json",
+ "n_array_unclosed_with_object_inside.json",
+ "n_incomplete_false.json",
+ "n_incomplete_null.json",
+ "n_incomplete_true.json",
+ "n_multidigit_number_then_00.json",
+ "n_number_0.1.2.json",
+ "n_number_-01.json",
+ "n_number_0.3e.json",
+ "n_number_0.3e+.json",
+ "n_number_0_capital_E.json",
+ "n_number_0_capital_E+.json",
+ "n_number_0.e1.json",
+ "n_number_0e.json",
+ "n_number_0e+.json",
+ "n_number_1_000.json",
+ "n_number_1.0e-.json",
+ "n_number_1.0e.json",
+ "n_number_1.0e+.json",
+ "n_number_-1.0..json",
+ "n_number_1eE2.json",
+ "n_number_.-1.json",
+ "n_number_+1.json",
+ "n_number_.2e-3.json",
+ "n_number_2.e-3.json",
+ "n_number_2.e+3.json",
+ "n_number_2.e3.json",
+ "n_number_-2..json",
+ "n_number_9.e+.json",
+ "n_number_expression.json",
+ "n_number_hex_1_digit.json",
+ "n_number_hex_2_digits.json",
+ "n_number_infinity.json",
+ "n_number_+Inf.json",
+ "n_number_Inf.json",
+ "n_number_invalid+-.json",
+ "n_number_invalid-negative-real.json",
+ "n_number_invalid-utf-8-in-bigger-int.json",
+ "n_number_invalid-utf-8-in-exponent.json",
+ "n_number_invalid-utf-8-in-int.json",
+ "n_number_++.json",
+ "n_number_minus_infinity.json",
+ "n_number_minus_sign_with_trailing_garbage.json",
+ "n_number_minus_space_1.json",
+ "n_number_-NaN.json",
+ "n_number_NaN.json",
+ "n_number_neg_int_starting_with_zero.json",
+ "n_number_neg_real_without_int_part.json",
+ "n_number_neg_with_garbage_at_end.json",
+ "n_number_real_garbage_after_e.json",
+ "n_number_real_with_invalid_utf8_after_e.json",
+ "n_number_real_without_fractional_part.json",
+ "n_number_starting_with_dot.json",
+ "n_number_U+FF11_fullwidth_digit_one.json",
+ "n_number_with_alpha_char.json",
+ "n_number_with_alpha.json",
+ "n_number_with_leading_zero.json",
+ "n_object_bad_value.json",
+ "n_object_bracket_key.json",
+ "n_object_comma_instead_of_colon.json",
+ "n_object_double_colon.json",
+ "n_object_emoji.json",
+ "n_object_garbage_at_end.json",
+ "n_object_key_with_single_quotes.json",
+ "n_object_lone_continuation_byte_in_key_and_trailing_comma.json",
+ "n_object_missing_colon.json",
+ "n_object_missing_key.json",
+ "n_object_missing_semicolon.json",
+ "n_object_missing_value.json",
+ "n_object_no-colon.json",
+ "n_object_non_string_key_but_huge_number_instead.json",
+ "n_object_non_string_key.json",
+ "n_object_repeated_null_null.json",
+ "n_object_several_trailing_commas.json",
+ "n_object_single_quote.json",
+ "n_object_trailing_comma.json",
+ "n_object_trailing_comment.json",
+ "n_object_trailing_comment_open.json",
+ "n_object_trailing_comment_slash_open_incomplete.json",
+ "n_object_trailing_comment_slash_open.json",
+ "n_object_two_commas_in_a_row.json",
+ "n_object_unquoted_key.json",
+ "n_object_unterminated-value.json",
+ "n_object_with_single_string.json",
+ "n_object_with_trailing_garbage.json",
+ "n_single_space.json",
+ "n_string_1_surrogate_then_escape.json",
+ "n_string_1_surrogate_then_escape_u1.json",
+ "n_string_1_surrogate_then_escape_u1x.json",
+ "n_string_1_surrogate_then_escape_u.json",
+ "n_string_accentuated_char_no_quotes.json",
+ "n_string_backslash_00.json",
+ "n_string_escaped_backslash_bad.json",
+ "n_string_escaped_ctrl_char_tab.json",
+ "n_string_escaped_emoji.json",
+ "n_string_escape_x.json",
+ "n_string_incomplete_escaped_character.json",
+ "n_string_incomplete_escape.json",
+ "n_string_incomplete_surrogate_escape_invalid.json",
+ "n_string_incomplete_surrogate.json",
+ "n_string_invalid_backslash_esc.json",
+ "n_string_invalid_unicode_escape.json",
+ "n_string_invalid_utf8_after_escape.json",
+ "n_string_invalid-utf-8-in-escape.json",
+ "n_string_leading_uescaped_thinspace.json",
+ "n_string_no_quotes_with_bad_escape.json",
+ "n_string_single_doublequote.json",
+ "n_string_single_quote.json",
+ "n_string_single_string_no_double_quotes.json",
+ "n_string_start_escape_unclosed.json",
+ "n_string_unescaped_crtl_char.json",
+ "n_string_unescaped_newline.json",
+ "n_string_unescaped_tab.json",
+ "n_string_unicode_CapitalU.json",
+ "n_string_with_trailing_garbage.json",
+ // "n_structure_100000_opening_arrays.json",
+ "n_structure_angle_bracket_..json",
+ "n_structure_angle_bracket_null.json",
+ "n_structure_array_trailing_garbage.json",
+ "n_structure_array_with_extra_array_close.json",
+ "n_structure_array_with_unclosed_string.json",
+ "n_structure_ascii-unicode-identifier.json",
+ "n_structure_capitalized_True.json",
+ "n_structure_close_unopened_array.json",
+ "n_structure_comma_instead_of_closing_brace.json",
+ "n_structure_double_array.json",
+ "n_structure_end_array.json",
+ "n_structure_incomplete_UTF8_BOM.json",
+ "n_structure_lone-invalid-utf-8.json",
+ "n_structure_lone-open-bracket.json",
+ "n_structure_no_data.json",
+ "n_structure_null-byte-outside-string.json",
+ "n_structure_number_with_trailing_garbage.json",
+ "n_structure_object_followed_by_closing_object.json",
+ "n_structure_object_unclosed_no_value.json",
+ "n_structure_object_with_comment.json",
+ "n_structure_object_with_trailing_garbage.json",
+ "n_structure_open_array_apostrophe.json",
+ "n_structure_open_array_comma.json",
+ // "n_structure_open_array_object.json",
+ "n_structure_open_array_open_object.json",
+ "n_structure_open_array_open_string.json",
+ "n_structure_open_array_string.json",
+ "n_structure_open_object_close_array.json",
+ "n_structure_open_object_comma.json",
+ "n_structure_open_object.json",
+ "n_structure_open_object_open_array.json",
+ "n_structure_open_object_open_string.json",
+ "n_structure_open_object_string_with_apostrophes.json",
+ "n_structure_open_open.json",
+ "n_structure_single_eacute.json",
+ "n_structure_single_star.json",
+ "n_structure_trailing_#.json",
+ "n_structure_U+2060_word_joined.json",
+ "n_structure_uescaped_LF_before_string.json",
+ "n_structure_unclosed_array.json",
+ "n_structure_unclosed_array_partial_null.json",
+ "n_structure_unclosed_array_unfinished_false.json",
+ "n_structure_unclosed_array_unfinished_true.json",
+ "n_structure_unclosed_object.json",
+ "n_structure_unicode-identifier.json",
+ "n_structure_UTF8_BOM_no_data.json",
+ "n_structure_whitespace_formfeed.json",
+ "n_structure_whitespace_U+2060_word_joiner.json"
+};
+
+std::vector<const char*> test_files_pass = {
+ "y_array_arraysWithSpaces.json",
+ "y_array_empty.json",
+ "y_array_empty-string.json",
+ "y_array_ending_with_newline.json",
+ "y_array_false.json",
+ "y_array_heterogeneous.json",
+ "y_array_null.json",
+ "y_array_with_1_and_newline.json",
+ "y_array_with_leading_space.json",
+ "y_array_with_several_null.json",
+ "y_array_with_trailing_space.json",
+ "y_number_0e+1.json",
+ "y_number_0e1.json",
+ "y_number_after_space.json",
+ "y_number_double_close_to_zero.json",
+ "y_number_int_with_exp.json",
+ "y_number.json",
+ "y_number_minus_zero.json",
+ "y_number_negative_int.json",
+ "y_number_negative_one.json",
+ "y_number_negative_zero.json",
+ "y_number_real_capital_e.json",
+ "y_number_real_capital_e_neg_exp.json",
+ "y_number_real_capital_e_pos_exp.json",
+ "y_number_real_exponent.json",
+ "y_number_real_fraction_exponent.json",
+ "y_number_real_neg_exp.json",
+ "y_number_real_pos_exponent.json",
+ "y_number_simple_int.json",
+ "y_number_simple_real.json",
+ "y_object_basic.json",
+ "y_object_duplicated_key_and_value.json",
+ "y_object_duplicated_key.json",
+ "y_object_empty.json",
+ "y_object_empty_key.json",
+ // "y_object_escaped_null_in_key.json",
+ "y_object_extreme_numbers.json",
+ "y_object.json",
+ "y_object_long_strings.json",
+ "y_object_simple.json",
+ // "y_object_string_unicode.json",
+ "y_object_with_newlines.json",
+ // "y_string_1_2_3_bytes_UTF-8_sequences.json",
+ // "y_string_accepted_surrogate_pair.json",
+ // "y_string_accepted_surrogate_pairs.json",
+ "y_string_allowed_escapes.json",
+ "y_string_backslash_and_u_escaped_zero.json",
+ "y_string_backslash_doublequotes.json",
+ "y_string_comments.json",
+ "y_string_double_escape_a.json",
+ "y_string_double_escape_n.json",
+ // "y_string_escaped_control_character.json",
+ // "y_string_escaped_noncharacter.json",
+ "y_string_in_array.json",
+ "y_string_in_array_with_leading_space.json",
+ // "y_string_last_surrogates_1_and_2.json",
+ // "y_string_nbsp_uescaped.json",
+ "y_string_nonCharacterInUTF-8_U+10FFFF.json",
+ "y_string_nonCharacterInUTF-8_U+FFFF.json",
+ // "y_string_null_escape.json",
+ // "y_string_one-byte-utf-8.json",
+ "y_string_pi.json",
+ "y_string_reservedCharacterInUTF-8_U+1BFFF.json",
+ "y_string_simple_ascii.json",
+ // "y_string_space.json",
+ // "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json",
+ // "y_string_three-byte-utf-8.json",
+ // "y_string_two-byte-utf-8.json",
+ "y_string_u+2028_line_sep.json",
+ "y_string_u+2029_par_sep.json",
+ // "y_string_uescaped_newline.json",
+ // "y_string_uEscape.json",
+ "y_string_unescaped_char_delete.json",
+ "y_string_unicode_2.json",
+ // "y_string_unicodeEscapedBackslash.json",
+ // "y_string_unicode_escaped_double_quote.json",
+ // "y_string_unicode.json",
+ // "y_string_unicode_U+10FFFE_nonchar.json",
+ // "y_string_unicode_U+1FFFE_nonchar.json",
+ // "y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json",
+ // "y_string_unicode_U+2064_invisible_plus.json",
+ // "y_string_unicode_U+FDD0_nonchar.json",
+ // "y_string_unicode_U+FFFE_nonchar.json",
+ "y_string_utf8.json",
+ "y_string_with_del_character.json",
+ // "y_structure_lonely_false.json",
+ // "y_structure_lonely_int.json",
+ // "y_structure_lonely_negative_real.json",
+ // "y_structure_lonely_null.json",
+ // "y_structure_lonely_string.json",
+ // "y_structure_lonely_true.json",
+ // "y_structure_string_empty.json",
+ "y_structure_trailing_newline.json",
+ "y_structure_true_in_array.json",
+ "y_structure_whitespace_array.json",
+};
+
+std::string load_file(const std::string& file_name)
+{
+ std::string file_path = std::string(SRCDIR) + "/test/json/validation/" + file_name;
+ std::ifstream f(file_path);
+ std::stringstream buffer;
+ buffer << f.rdbuf();
+ return buffer.str();
+}
+
+void test_pass()
+{
+ orcus::json_handler hdl;
+
+ for (const char* test_file_name : test_files_pass)
+ {
+ std::string content = load_file(test_file_name);
+ std::cout << test_file_name << std::endl;
+ try
+ {
+ orcus::json_parser<orcus::json_handler> parser(content, hdl);
+ parser.parse();
+ }
+ catch (const orcus::parse_error& e)
+ {
+ std::cout << e.what() << std::endl;
+ std::cout << orcus::create_parse_error_output(content, e.offset()) << std::endl;
+ assert(false);
+ }
+ }
+}
+
+void test_fail()
+{
+ orcus::json_handler hdl;
+
+ for (const char* test_file_name : test_files_failed)
+ {
+ std::string content = load_file(test_file_name);
+ std::cout << test_file_name << std::endl;
+ bool failed = false;
+ try {
+ orcus::json_parser<orcus::json_handler> parser(content, hdl);
+ parser.parse();
+ }
+ catch (const orcus::parse_error&)
+ {
+ failed = true;
+ }
+
+ if (!failed)
+ {
+ std::cout << "invalid json string has been parsed as valid: content='" << content << "'" << std::endl;
+ assert(false);
+ }
+ }
+}
+
+void test_indeterminate()
+{
+ orcus::json_handler hdl;
+
+ for (const char* test_file_name : test_files_indeterminate)
+ {
+ std::string content = load_file(test_file_name);
+ std::cout << test_file_name << std::endl;
+ try {
+ orcus::json_parser<orcus::json_handler> parser(content, hdl);
+ parser.parse();
+ }
+ catch (const orcus::parse_error&)
+ {
+ }
+
+ }
+}
+
+}
+
+int main()
+{
+ test_pass();
+ test_fail();
+ test_indeterminate();
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_test_numeric.cpp b/src/parser/parser_test_numeric.cpp
new file mode 100644
index 0000000..b16ed9a
--- /dev/null
+++ b/src/parser/parser_test_numeric.cpp
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "numeric_parser.hpp"
+
+#include <cassert>
+#include <iostream>
+#include <vector>
+#include <limits>
+
+using namespace orcus;
+using std::cout;
+using std::endl;
+
+namespace {
+
+struct check
+{
+ std::string_view str;
+ double expected;
+};
+
+const double invalid = std::numeric_limits<double>::quiet_NaN();
+
+template<typename ParserT>
+bool run_checks(const std::vector<check>& checks)
+{
+ for (const check& c : checks)
+ {
+ ParserT parser(c.str.data(), c.str.data() + c.str.size());
+ double v = parser.parse();
+
+ if (std::isnan(c.expected))
+ {
+ if (!std::isnan(v))
+ {
+ cout << "'" << c.str << "' was expected to be invalid, but parser parsed as if it was valid." << endl;
+ return false;
+ }
+ }
+ else
+ {
+ if (v != c.expected)
+ {
+ cout << "'" << c.str << "' was expected to be parsed as (" << c.expected << "), but the parser parsed it as (" << v << ")" << endl;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+}
+
+void test_generic_number_parsing()
+{
+ using parser_type = detail::numeric_parser<detail::generic_parser_trait>;
+
+ std::vector<check> checks = {
+ { "-6.e3", -6e3 },
+ { "true", invalid },
+ { "1", 1.0 },
+ { "1.0", 1.0 },
+ { "-1.0", -1.0 },
+ { "-01", -1.0 },
+ { "2e2", 200.0 },
+ { "1.2", 1.2 },
+ { "-0.0001", -0.0001 },
+ { "-0.0", 0.0 },
+ { "+.", invalid },
+ { "+e", invalid },
+ { "+e1", invalid },
+ { "+ ", invalid },
+ { "- ", invalid }
+ };
+
+ assert(run_checks<parser_type>(checks));
+}
+
+void test_json_number_parsing()
+{
+ using parser_type = detail::numeric_parser<detail::json_parser_trait>;
+
+ std::vector<check> checks = {
+ { "-01", invalid }, // Leading zeros are invalid.
+ };
+
+ assert(run_checks<parser_type>(checks));
+}
+
+int main()
+{
+ test_generic_number_parsing();
+ test_json_number_parsing();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/parser_test_xml_validation.cpp b/src/parser/parser_test_xml_validation.cpp
new file mode 100644
index 0000000..3be1804
--- /dev/null
+++ b/src/parser/parser_test_xml_validation.cpp
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/sax_parser.hpp>
+#include <orcus/stream.hpp>
+
+#include <iostream>
+#include <boost/range/iterator_range.hpp>
+
+#include "filesystem_env.hpp"
+
+void test_valid()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ struct _handler : public orcus::sax_handler {};
+
+ fs::path root_dir = fs::path{SRCDIR} / "test" / "xml" / "valids";
+
+ if (!fs::is_directory(root_dir))
+ return;
+
+ for (const fs::path& entry : boost::make_iterator_range(fs::directory_iterator{root_dir}, {}))
+ {
+ std::cout << "input file: " << entry << std::endl;
+
+ orcus::file_content content(entry.string());
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content.str(), hdl);
+
+ try
+ {
+ parser.parse();
+ }
+ catch (const orcus::malformed_xml_error& e)
+ {
+ std::cerr << orcus::create_parse_error_output(content.str(), e.offset()) << std::endl;
+ std::cerr << e.what() << std::endl;
+ assert(!"This was supposed to be a valid XML!");
+
+ }
+ }
+}
+
+void test_invalid()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ struct _handler : public orcus::sax_handler {};
+
+ fs::path root_dir = fs::path{SRCDIR} / "test" / "xml" / "invalids";
+
+ if (!fs::is_directory(root_dir))
+ return;
+
+ for (const fs::path& entry : boost::make_iterator_range(fs::directory_iterator{root_dir}, {}))
+ {
+ std::cout << "input file: " << entry << std::endl;
+
+ orcus::file_content content(entry.string());
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content.str(), hdl);
+
+ try
+ {
+ parser.parse();
+ assert(!"exception was expected, but one was not thrown.");
+ }
+ catch (const orcus::malformed_xml_error& e)
+ {
+ std::cerr << orcus::create_parse_error_output(content.str(), e.offset()) << std::endl;
+ std::cerr << e.what() << std::endl;
+ }
+ catch (...)
+ {
+ assert(!"wrong exception was thrown.");
+ }
+ }
+}
+
+int main()
+{
+ test_valid();
+ test_invalid();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_ns_parser_test.cpp b/src/parser/sax_ns_parser_test.cpp
new file mode 100644
index 0000000..eb7443f
--- /dev/null
+++ b/src/parser/sax_ns_parser_test.cpp
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/sax_ns_parser.hpp>
+#include <orcus/xml_namespace.hpp>
+
+#include <cstring>
+
+void test_handler()
+{
+ const char* test_code = "<?xml version=\"1.0\"?><root/>";
+ orcus::sax_ns_handler hdl;
+ orcus::xmlns_repository repo;
+ orcus::xmlns_context cxt = repo.create_context();
+
+ orcus::sax_ns_parser<orcus::sax_ns_handler> parser(test_code, cxt, hdl);
+ parser.parse();
+}
+
+/**
+ * Test for unqualified attribute NOT belonging to the default namespace,
+ * according to
+ * https://stackoverflow.com/questions/3312390/xml-default-namespaces-for-unqualified-attribute-names
+ */
+void test_default_attr_ns()
+{
+ const orcus::xmlns_id_t default_ns = "test:foo";
+
+ struct _handler : public orcus::sax_ns_handler
+ {
+ orcus::xmlns_id_t default_ns_expected;
+
+ void start_element(const orcus::sax_ns_parser_element& elem)
+ {
+ // All elements should belong to the default namespace.
+ assert(elem.ns == default_ns_expected);
+ }
+
+ void attribute(std::string_view /*name*/, std::string_view /*val*/) {}
+
+ void attribute(const orcus::sax_ns_parser_attribute& attr)
+ {
+ // Attribute's namespace should be empty.
+ assert(attr.ns == orcus::XMLNS_UNKNOWN_ID);
+ assert(attr.name == "attr");
+ assert(attr.value == "1");
+ }
+ };
+
+ const char* test_code = "<?xml version=\"1.0\"?><root xmlns='test:foo'><elem attr='1'/></root>";
+
+ const orcus::xmlns_id_t predefined[] = { default_ns, nullptr };
+
+ orcus::xmlns_repository repo;
+ repo.add_predefined_values(predefined);
+
+ orcus::xmlns_context cxt = repo.create_context();
+
+ _handler hdl;
+ hdl.default_ns_expected = default_ns;
+
+ orcus::sax_ns_parser<_handler> parser(test_code, cxt, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+ test_default_attr_ns();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_parser_base.cpp b/src/parser/sax_parser_base.cpp
new file mode 100644
index 0000000..58f750e
--- /dev/null
+++ b/src/parser/sax_parser_base.cpp
@@ -0,0 +1,421 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/sax_parser_base.hpp"
+
+#include "utf8.hpp"
+
+#include <cstring>
+#include <vector>
+#include <memory>
+
+#ifdef __ORCUS_CPU_FEATURES
+#include <immintrin.h>
+#endif
+
+namespace orcus { namespace sax {
+
+char decode_xml_encoded_char(const char* p, size_t n)
+{
+ if (n == 2)
+ {
+ if (!std::strncmp(p, "lt", n))
+ return '<';
+ else if (!std::strncmp(p, "gt", n))
+ return '>';
+ else
+ return '\0';
+ }
+ else if (n == 3)
+ {
+ if (!std::strncmp(p, "amp", n))
+ return '&';
+ else
+ return '\0';
+ }
+ else if (n == 4)
+ {
+ if (!std::strncmp(p, "apos", n))
+ return '\'';
+ else if (!std::strncmp(p, "quot", 4))
+ return '"';
+ else
+ return '\0';
+ }
+
+ return '\0';
+}
+
+std::string decode_xml_unicode_char(const char* p, size_t n)
+{
+ if (*p == '#' && n >= 2)
+ {
+ uint32_t point = 0;
+ if (p[1] == 'x')
+ {
+ if (n == 2)
+ throw orcus::xml_structure_error(
+ "invalid number of characters for hexadecimal unicode reference");
+
+ point = std::stoi(std::string(p + 2, n - 2), nullptr, 16);
+ }
+ else
+ point = std::stoi(std::string(p + 1, n - 1), nullptr, 10);
+
+ if (point < 0x80)
+ {
+ // is it really necessary to do the bit manipulation here?
+ std::string s(1, static_cast<char>(point & 0x7F));
+ return s;
+ }
+ else if (point < 0x0800)
+ {
+ std::string s(1, static_cast<char>((point >> 6 & 0x1F) | 0xC0));
+ s += static_cast<char>((point & 0x3F) | 0x80);
+ return s;
+ }
+ else if (point < 0x010000)
+ {
+ std::string s(1, static_cast<char>((point >> 12 & 0x0F) | 0xE0));
+ s += static_cast<char>((point >> 6 & 0x3F) | 0x80);
+ s += static_cast<char>((point & 0x3F) | 0x80);
+ return s;
+ }
+ else if (point < 0x110000)
+ {
+ std::string s(1, static_cast<char>((point >> 18 & 0x07) | 0xF0));
+ s += static_cast<char>((point >> 12 & 0x3F) | 0x80);
+ s += static_cast<char>((point >> 6 & 0x3F) | 0x80);
+ s += static_cast<char>((point & 0x3F) | 0x80);
+ return s;
+ }
+ else
+ {
+ // should not happen as that is not represented by utf-8
+ assert(false);
+ }
+ }
+
+ return std::string();
+}
+
+struct parser_base::impl
+{
+ std::vector<std::unique_ptr<cell_buffer>> m_cell_buffers;
+};
+
+parser_base::parser_base(const char* content, size_t size) :
+ ::orcus::parser_base(content, size),
+ mp_impl(std::make_unique<impl>()),
+ m_nest_level(0),
+ m_buffer_pos(0),
+ m_root_elem_open(true)
+{
+ mp_impl->m_cell_buffers.push_back(std::make_unique<cell_buffer>());
+}
+
+parser_base::~parser_base() {}
+
+void parser_base::inc_buffer_pos()
+{
+ ++m_buffer_pos;
+ if (m_buffer_pos == mp_impl->m_cell_buffers.size())
+ mp_impl->m_cell_buffers.push_back(std::make_unique<cell_buffer>());
+}
+
+cell_buffer& parser_base::get_cell_buffer()
+{
+ return *mp_impl->m_cell_buffers[m_buffer_pos];
+}
+
+void parser_base::comment()
+{
+ // Parse until we reach '-->'.
+ size_t len = available_size();
+ assert(len > 3);
+ char c = cur_char();
+ size_t i = 0;
+ bool hyphen = false;
+ for (; i < len; ++i, c = next_and_char())
+ {
+ if (c == '-')
+ {
+ if (!hyphen)
+ // first hyphen.
+ hyphen = true;
+ else
+ // second hyphen.
+ break;
+ }
+ else
+ hyphen = false;
+ }
+
+ if (len - i < 2 || next_and_char() != '>')
+ throw malformed_xml_error(
+ "'--' should not occur in comment other than in the closing tag.", offset());
+
+ next();
+}
+
+void parser_base::expects_next(const char* p, size_t n)
+{
+ if (available_size() < n+1)
+ throw malformed_xml_error(
+ "not enough stream left to check for an expected string segment.", offset());
+
+ const char* p0 = p;
+ const char* p_end = p + n;
+ char c = next_and_char();
+ for (; p != p_end; ++p, c = next_and_char())
+ {
+ if (c == *p)
+ continue;
+
+ std::ostringstream os;
+ os << "'" << std::string(p0, n) << "' was expected, but not found.";
+ throw malformed_xml_error(os.str(), offset());
+ }
+}
+
+void parser_base::parse_encoded_char(cell_buffer& buf)
+{
+ assert(cur_char() == '&');
+ next();
+ const char* p0 = mp_char;
+ for (; has_char(); next())
+ {
+ if (cur_char() != ';')
+ continue;
+
+ size_t n = mp_char - p0;
+ if (!n)
+ throw malformed_xml_error("empty encoded character.", offset());
+
+#if ORCUS_DEBUG_SAX_PARSER
+ cout << "sax_parser::parse_encoded_char: raw='" << std::string(p0, n) << "'" << endl;
+#endif
+
+ char c = decode_xml_encoded_char(p0, n);
+ if (c)
+ buf.append(&c, 1);
+ else
+ {
+ std::string utf8 = decode_xml_unicode_char(p0, n);
+
+ if (!utf8.empty())
+ {
+ buf.append(utf8.data(), utf8.size());
+ c = '1'; // just to avoid hitting the !c case below
+ }
+ }
+
+ // Move to the character past ';' before returning to the parent call.
+ next();
+
+ if (!c)
+ {
+#if ORCUS_DEBUG_SAX_PARSER
+ cout << "sax_parser::parse_encoded_char: not a known encoding name. Use the original." << endl;
+#endif
+ // Unexpected encoding name. Use the original text.
+ buf.append(p0, mp_char-p0);
+ }
+
+ return;
+ }
+
+ throw malformed_xml_error(
+ "error parsing encoded character: terminating character is not found.", offset());
+}
+
+void parser_base::value_with_encoded_char(cell_buffer& buf, std::string_view& str, char quote_char)
+{
+ assert(cur_char() == '&');
+ parse_encoded_char(buf);
+
+ const char* p0 = mp_char;
+
+ while (has_char())
+ {
+ if (cur_char() == '&')
+ {
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+
+ parse_encoded_char(buf);
+ p0 = mp_char;
+ }
+
+ if (cur_char() == quote_char)
+ break;
+
+ if (cur_char() != '&')
+ next();
+ }
+
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+
+ if (!buf.empty())
+ str = buf.str();
+
+ // Skip the closing quote.
+ assert(!has_char() || cur_char() == quote_char);
+ if (has_char())
+ next();
+}
+
+bool parser_base::value(std::string_view& str, bool decode)
+{
+ char c = cur_char_checked();
+ if (c != '"' && c != '\'')
+ throw malformed_xml_error("value must be quoted", offset());
+
+ char quote_char = c;
+
+ c = next_char_checked();
+
+ const char* p0 = mp_char;
+ for (; c != quote_char; c = next_char_checked())
+ {
+ if (decode && c == '&')
+ {
+ // This value contains one or more encoded characters.
+ cell_buffer& buf = get_cell_buffer();
+ buf.reset();
+ buf.append(p0, mp_char-p0);
+ value_with_encoded_char(buf, str, quote_char);
+ return true;
+ }
+ }
+
+ str = std::string_view(p0, mp_char-p0);
+
+ // Skip the closing quote.
+ next();
+
+ return false;
+}
+
+void parser_base::name(std::string_view& str)
+{
+ const char* p0 = mp_char;
+ mp_char = parse_utf8_xml_name_start_char(mp_char, mp_end);
+ if (mp_char == p0)
+ {
+ ::std::ostringstream os;
+ os << "name must begin with an alphabet, but got this instead '" << cur_char() << "'";
+ throw malformed_xml_error(os.str(), offset());
+ }
+
+#if defined(__ORCUS_CPU_FEATURES) && defined(__SSE4_2__)
+
+ const __m128i match = _mm_loadu_si128((const __m128i*)"azAZ09--__..");
+ const int mode = _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY;
+
+ size_t n_total = available_size();
+
+ while (n_total)
+ {
+ __m128i char_block = _mm_loadu_si128((const __m128i*)mp_char);
+
+ int n = std::min<size_t>(16u, n_total);
+ int r = _mm_cmpestri(match, 12, char_block, n, mode);
+ mp_char += r; // Move the current char position.
+ n_total -= r;
+
+ if (r < 16 && n_total)
+ {
+ // There is a character that does not match the SSE-based ASCII-only check.
+ // It may either by an ascii character that is not allowed, in which case stop,
+ // or it may possibly be an allowed utf-8 character, in which case move over it
+ // using the slow function.
+
+ const char* p = parse_utf8_xml_name_char(mp_char, mp_end);
+ if (p == mp_char)
+ break;
+
+ n_total -= p - mp_char;
+ mp_char = p;
+ }
+
+ }
+ cur_char_checked(); // check end of xml stream
+
+#else
+ for(;;)
+ {
+ cur_char_checked(); // check end of xml stream
+ const char* p = parse_utf8_xml_name_char(mp_char, mp_end);
+
+ if (p == mp_char)
+ break;
+
+ mp_char = p;
+ }
+#endif
+
+ str = std::string_view(p0, mp_char-p0);
+}
+
+void parser_base::element_name(parser_element& elem, std::ptrdiff_t begin_pos)
+{
+ elem.begin_pos = begin_pos;
+ name(elem.name);
+ if (cur_char() == ':')
+ {
+ elem.ns = elem.name;
+ next_check();
+ name(elem.name);
+ }
+}
+
+void parser_base::attribute_name(std::string_view& attr_ns, std::string_view& attr_name)
+{
+ name(attr_name);
+ if (cur_char() == ':')
+ {
+ // Attribute name is namespaced.
+ attr_ns = attr_name;
+ next_check();
+ name(attr_name);
+ }
+}
+
+void parser_base::characters_with_encoded_char(cell_buffer& buf)
+{
+ assert(cur_char() == '&');
+ parse_encoded_char(buf);
+
+ const char* p0 = mp_char;
+
+ while (has_char())
+ {
+ if (cur_char() == '&')
+ {
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+
+ parse_encoded_char(buf);
+ p0 = mp_char;
+ }
+
+ if (cur_char() == '<')
+ break;
+
+ if (cur_char() != '&')
+ next();
+ }
+
+ if (mp_char > p0)
+ buf.append(p0, mp_char-p0);
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_parser_test.cpp b/src/parser/sax_parser_test.cpp
new file mode 100644
index 0000000..ec8b1f1
--- /dev/null
+++ b/src/parser/sax_parser_test.cpp
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/sax_parser.hpp>
+#include <cstring>
+
+using namespace std;
+
+void test_handler()
+{
+ const char* test_code = "<?xml version=\"1.0\"?><root/>";
+
+ orcus::sax_handler hdl;
+ orcus::sax_parser<orcus::sax_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+void test_attr_equal_with_whitespace()
+{
+ struct _handler : public orcus::sax_handler {};
+
+ const char* content =
+ "<?xml version=\"1.0\"?>"
+ "<root attr1='some value' attr2 = \"some value\"/>"
+ ;
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content, hdl);
+ parser.parse();
+}
+
+void test_attr_with_encoded_chars_single_quotes()
+{
+ struct _handler : public orcus::sax_handler
+ {
+ void attribute(const orcus::sax::parser_attribute& attr)
+ {
+ if (attr.name == "attr1")
+ assert(attr.value == "'some value'");
+ }
+ };
+
+ const char* content =
+ "<?xml version=\"1.0\"?>"
+ "<root attr1='&apos;some value&apos;'/>"
+ ;
+
+ _handler hdl;
+ orcus::sax_parser<_handler> parser(content, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+ test_attr_equal_with_whitespace();
+ test_attr_with_encoded_chars_single_quotes();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_token_parser.cpp b/src/parser/sax_token_parser.cpp
new file mode 100644
index 0000000..fdf80c6
--- /dev/null
+++ b/src/parser/sax_token_parser.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/sax_token_parser.hpp"
+#include "orcus/tokens.hpp"
+
+#include <mdds/sorted_string_map.hpp>
+#include <cctype>
+
+namespace orcus {
+
+namespace {
+
+enum class decl_attr_type { unknown, version, encoding, standalone };
+
+namespace decl_attr {
+
+using map_type = mdds::sorted_string_map<decl_attr_type, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "encoding", decl_attr_type::encoding },
+ { "standalone", decl_attr_type::standalone },
+ { "version", decl_attr_type::version },
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), decl_attr_type::unknown);
+ return mt;
+}
+
+} // namespace decl_attr
+
+}
+
+sax_token_handler_wrapper_base::sax_token_handler_wrapper_base(const tokens& _tokens) :
+ m_tokens(_tokens) {}
+
+xml_token_t sax_token_handler_wrapper_base::tokenize(std::string_view name) const
+{
+ xml_token_t token = XML_UNKNOWN_TOKEN;
+ if (!name.empty())
+ token = m_tokens.get_token(name);
+ return token;
+}
+
+void sax_token_handler_wrapper_base::set_element(const sax_ns_parser_element& elem)
+{
+ m_elem.ns = elem.ns;
+ m_elem.name = tokenize(elem.name);
+ m_elem.raw_name = elem.name;
+}
+
+void sax_token_handler_wrapper_base::attribute(std::string_view name, std::string_view val)
+{
+ decl_attr_type dat = decl_attr::get().find(name);
+
+ switch (dat)
+ {
+ case decl_attr_type::version:
+ {
+ const char* p = val.data();
+ const char* p_end = p + val.size();
+
+ long v;
+ const char* endptr = parse_integer(p, p_end, v);
+
+ if (!endptr || endptr >= p_end || *endptr != '.')
+ break;
+
+ m_declaration.version_major = v;
+ p = endptr + 1;
+
+ endptr = parse_integer(p, p_end, v);
+
+ if (!endptr || endptr > p_end)
+ break;
+
+ m_declaration.version_minor = v;
+ break;
+ }
+ case decl_attr_type::encoding:
+ {
+ m_declaration.encoding = to_character_set(val);
+ break;
+ }
+ case decl_attr_type::standalone:
+ m_declaration.standalone = (val == "yes") ? true : false;
+ break;
+ default:
+ ;
+ }
+}
+
+void sax_token_handler_wrapper_base::attribute(const sax_ns_parser_attribute& attr)
+{
+ m_elem.attrs.push_back(
+ xml_token_attr_t(
+ attr.ns, tokenize(attr.name), attr.name,
+ attr.value, attr.transient));
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_token_parser_test.cpp b/src/parser/sax_token_parser_test.cpp
new file mode 100644
index 0000000..d473196
--- /dev/null
+++ b/src/parser/sax_token_parser_test.cpp
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/sax_token_parser.hpp"
+#include "orcus/tokens.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <cstring>
+
+using namespace std;
+using namespace orcus;
+
+void test_handler()
+{
+ const char* test_code = "<?xml version=\"1.0\"?><root/>";
+
+ orcus::sax_token_handler hdl;
+ orcus::tokens token_map(nullptr, 0);
+ orcus::xmlns_repository repo;
+ orcus::xmlns_context cxt = repo.create_context();
+ orcus::sax_token_parser<orcus::sax_token_handler> parser(test_code, token_map, cxt, hdl);
+ parser.parse();
+}
+
+void test_sax_token_parser_1()
+{
+ // Test XML content.
+ const char* content = "<?xml version=\"1.0\"?><root><andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+
+ // Array of tokens to define for this test.
+ const char* token_names[] = {
+ "??", // 0
+ "andy", // 1
+ "bruce", // 2
+ "charlie", // 3
+ "david", // 4
+ "edward" // 5
+ };
+
+ size_t token_count = std::size(token_names);
+
+ // Token constants.
+ const xml_token_t op_andy = 1;
+ const xml_token_t op_bruce = 2;
+ const xml_token_t op_charlie = 3;
+ const xml_token_t op_david = 4;
+ const xml_token_t op_edward = 5;
+
+ struct check
+ {
+ const char* raw_name;
+ xml_token_t token;
+ bool start_element;
+ };
+
+ // Expected outcome.
+ const check checks[] = {
+ { "root", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "andy", op_andy, true },
+ { "andy", op_andy, false },
+ { "bruce", op_bruce, true },
+ { "bruce", op_bruce, false },
+ { "charlie", op_charlie, true },
+ { "charlie", op_charlie, false },
+ { "david", op_david, true },
+ { "david", op_david, false },
+ { "edward", op_edward, true },
+ { "edward", op_edward, false },
+ { "frank", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "frank", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ { "root", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ };
+
+ class handler
+ {
+ const check* mp_head;
+ const check* mp_check;
+ public:
+ handler(const check* p) : mp_head(p), mp_check(p) {}
+
+ void declaration(const orcus::xml_declaration_t&) {}
+
+ void start_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(mp_check->start_element);
+ ++mp_check;
+ }
+
+ void end_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(!mp_check->start_element);
+ ++mp_check;
+ }
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+
+ size_t get_token_count() const
+ {
+ return std::distance(mp_head, mp_check);
+ }
+ };
+
+ handler hdl(checks);
+ tokens token_map(token_names, token_count);
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+ sax_token_parser<handler> parser(content, token_map, ns_cxt, hdl);
+ parser.parse();
+
+ assert(hdl.get_token_count() == std::size(checks));
+}
+
+void test_unicode_string()
+{
+ const char* content1 = "<?xml version=\"1.0\"?><root>&#x0021;</root>";
+ const char* content2 = "<?xml version=\"1.0\"?><root>&#x00B6;</root>";
+ const char* content3 = "<?xml version=\"1.0\"?><root>&#x20B9;</root>";
+
+ class handler
+ {
+ std::string_view str;
+ public:
+ handler(std::string_view _str):
+ str(_str)
+ {}
+
+ void declaration(const orcus::xml_declaration_t&) {}
+
+ void start_element(const orcus::xml_token_element_t& /*elem*/)
+ {
+ }
+
+ void end_element(const orcus::xml_token_element_t& /*elem*/)
+ {
+ }
+
+ void characters(std::string_view val, bool /*transient*/)
+ {
+ std::cout << "charachters:" << std::endl;
+ std::cout << val << std::endl;
+ assert(val == str);
+ }
+ };
+
+ const char* token_names[] = {
+ "???",
+ };
+ size_t token_count = std::size(token_names);
+
+ tokens token_map(token_names, token_count);
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+ handler hdl(u8"\u0021");
+ sax_token_parser<handler> parser1(content1, token_map, ns_cxt, hdl);
+ parser1.parse();
+ hdl = handler(u8"\u00B6");
+ sax_token_parser<handler> parser2(content2, token_map, ns_cxt, hdl);
+ parser2.parse();
+ hdl = handler(u8"\u20B9");
+ sax_token_parser<handler> parser3(content3, token_map, ns_cxt, hdl);
+ parser3.parse();
+}
+
+void test_declaration()
+{
+ class handler
+ {
+ xml_declaration_t& m_decl;
+ public:
+ handler(xml_declaration_t& decl) : m_decl(decl) {}
+
+ void declaration(const xml_declaration_t& decl)
+ {
+ m_decl = decl;
+ }
+
+ void start_element(const xml_token_element_t&) {}
+ void end_element(const xml_token_element_t&) {}
+ void characters(std::string_view, bool) {}
+ };
+
+ std::vector<const char*> token_names = {};
+ tokens token_map(token_names.data(), token_names.size());
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+
+ struct check
+ {
+ std::string content;
+ xml_declaration_t decl;
+ };
+
+ std::vector<check> checks =
+ {
+ {
+ "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?><root/>",
+ { 1, 0, character_set_t::utf_8, false }
+ },
+ {
+ "<?xml version=\"1.1\" encoding=\"windows-1253\" standalone=\"yes\"?><root/>",
+ { 1, 1, character_set_t::windows_1253, true }
+ },
+ {
+ "<?xml version=\"2.0\" encoding=\"US-ASCII\" standalone=\"yes\"?><root/>",
+ { 2, 0, character_set_t::us_ascii, true }
+ },
+ };
+
+ for (const check& c : checks)
+ {
+ xml_declaration_t decl;
+ handler hdl(decl);
+ sax_token_parser<handler> parser(c.content, token_map, ns_cxt, hdl);
+ parser.parse();
+
+ assert(decl == c.decl);
+ }
+}
+
+int main()
+{
+ test_handler();
+ test_sax_token_parser_1();
+ test_unicode_string();
+ test_declaration();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/sax_token_parser_thread.cpp b/src/parser/sax_token_parser_thread.cpp
new file mode 100644
index 0000000..3d7b16b
--- /dev/null
+++ b/src/parser/sax_token_parser_thread.cpp
@@ -0,0 +1,204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/sax_token_parser_thread.hpp"
+#include "orcus/sax_token_parser.hpp"
+#include "orcus/string_pool.hpp"
+#include "orcus/detail/parser_token_buffer.hpp"
+#include "orcus/tokens.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <limits>
+#include <iostream>
+
+namespace orcus { namespace sax {
+
+parse_token::parse_token() : type(parse_token_t::unknown) {}
+
+parse_token::parse_token(std::string_view _characters) :
+ type(parse_token_t::characters),
+ value(_characters)
+{
+}
+
+parse_token::parse_token(parse_token_t _type, const xml_token_element_t* _element) :
+ type(_type), value(_element)
+{
+}
+
+parse_token::parse_token(std::string_view msg, std::ptrdiff_t offset) :
+ type(parse_token_t::parse_error),
+ value(parse_error_value_t{msg, offset})
+{
+}
+
+parse_token::parse_token(const parse_token& other) :
+ type(other.type), value(other.value)
+{
+}
+
+bool parse_token::operator== (const parse_token& other) const
+{
+ return type == other.type && value == other.value;
+}
+
+bool parse_token::operator!= (const parse_token& other) const
+{
+ return !operator==(other);
+}
+
+struct parser_thread::impl
+{
+ orcus::detail::thread::parser_token_buffer<parse_tokens_t> m_token_buffer;
+ string_pool m_pool;
+ std::vector<std::unique_ptr<xml_token_element_t>> m_element_store;
+
+ parse_tokens_t m_parser_tokens; // token buffer for the parser thread.
+
+ const char* mp_char;
+ size_t m_size;
+ const tokens& m_tokens;
+ xmlns_context& m_ns_cxt;
+
+ impl(const char* p, size_t n, const tokens& tks, xmlns_context& ns_cxt, size_t min_token_size, size_t max_token_size) :
+ m_token_buffer(min_token_size, max_token_size),
+ mp_char(p), m_size(n), m_tokens(tks), m_ns_cxt(ns_cxt)
+ {
+ }
+
+ void check_and_notify()
+ {
+ m_token_buffer.check_and_notify(m_parser_tokens);
+ }
+
+ void notify_and_finish()
+ {
+ m_token_buffer.notify_and_finish(m_parser_tokens);
+ }
+
+ void abort()
+ {
+ m_token_buffer.abort();
+ }
+
+ void declaration(const orcus::xml_declaration_t& /*decl*/)
+ {
+ }
+
+ void start_element(const orcus::xml_token_element_t& elem)
+ {
+ m_element_store.emplace_back(std::make_unique<orcus::xml_token_element_t>(elem));
+ orcus::xml_token_element_t& this_elem = *m_element_store.back();
+
+ // Go through all attributes and intern transient strings.
+ std::for_each(this_elem.attrs.begin(), this_elem.attrs.end(),
+ [&](xml_token_attr_t& attr)
+ {
+ if (attr.transient)
+ {
+ attr.value = m_pool.intern(attr.value).first;
+ attr.transient = false;
+ }
+ }
+ );
+
+ m_parser_tokens.emplace_back(parse_token_t::start_element, m_element_store.back().get());
+ check_and_notify();
+ }
+
+ void end_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(elem.attrs.empty());
+
+ m_element_store.emplace_back(std::make_unique<orcus::xml_token_element_t>(elem));
+ m_parser_tokens.emplace_back(parse_token_t::end_element, m_element_store.back().get());
+ check_and_notify();
+ }
+
+ void characters(std::string_view val, bool transient)
+ {
+ if (transient)
+ m_parser_tokens.emplace_back(m_pool.intern(val).first);
+ else
+ m_parser_tokens.emplace_back(val);
+
+ check_and_notify();
+ }
+
+ void start()
+ {
+ try
+ {
+ try
+ {
+ orcus::sax_token_parser<impl> parser({mp_char, m_size}, m_tokens, m_ns_cxt, *this);
+ parser.parse();
+ }
+ catch (const malformed_xml_error& e)
+ {
+ std::string_view s = m_pool.intern(e.what()).first;
+ m_parser_tokens.emplace_back(s, e.offset());
+ }
+
+ // TODO : add more exceptions that need to be tokenized and processed by the client thread.
+
+ notify_and_finish();
+ }
+ catch (const orcus::detail::parsing_aborted_error&)
+ {
+ // This is used only to abort the parsing thread prematurely.
+ }
+ }
+
+ bool next_tokens(parse_tokens_t& tokens)
+ {
+ return m_token_buffer.next_tokens(tokens);
+ }
+
+ void swap_string_pool(string_pool& pool)
+ {
+ m_pool.swap(pool);
+ }
+};
+
+parser_thread::parser_thread(
+ const char* p, size_t n, const orcus::tokens& tks, xmlns_context& ns_cxt, size_t min_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, tks, ns_cxt, min_token_size, std::numeric_limits<size_t>::max()/2)) {}
+
+parser_thread::parser_thread(
+ const char* p, size_t n, const orcus::tokens& tks, xmlns_context& ns_cxt, size_t min_token_size, size_t max_token_size) :
+ mp_impl(std::make_unique<parser_thread::impl>(
+ p, n, tks, ns_cxt, min_token_size, max_token_size)) {}
+
+parser_thread::~parser_thread()
+{
+}
+
+void parser_thread::start()
+{
+ mp_impl->start();
+}
+
+bool parser_thread::next_tokens(parse_tokens_t& tokens)
+{
+ return mp_impl->next_tokens(tokens);
+}
+
+void parser_thread::swap_string_pool(string_pool& pool)
+{
+ mp_impl->swap_string_pool(pool);
+}
+
+void parser_thread::abort()
+{
+ mp_impl->abort();
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/stream.cpp b/src/parser/stream.cpp
new file mode 100644
index 0000000..c0bbb28
--- /dev/null
+++ b/src/parser/stream.cpp
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/stream.hpp>
+#include <orcus/exception.hpp>
+
+#include "utf8.hpp"
+
+#include <sstream>
+#include <fstream>
+#include <tuple>
+#include <cassert>
+#include <algorithm>
+#include <locale>
+#include <codecvt>
+#include <iostream>
+
+#include "filesystem_env.hpp"
+
+#include <boost/interprocess/file_mapping.hpp>
+#include <boost/interprocess/mapped_region.hpp>
+
+namespace bip = boost::interprocess;
+
+namespace orcus {
+
+namespace {
+
+enum class unicode_t
+{
+ unknown,
+ utf16_be,
+ utf16_le
+};
+
+unicode_t check_unicode_type(const char* p, size_t n)
+{
+ if (n > 2)
+ {
+ if (p[0] == '\xFE' && p[1] == '\xFF')
+ return unicode_t::utf16_be;
+
+ if (p[0] == '\xFF' && p[1] == '\xFE')
+ return unicode_t::utf16_le;
+ }
+
+ return unicode_t::unknown;
+}
+
+std::string convert_utf16_to_utf8(const char* p, size_t n, unicode_t ut)
+{
+ assert(ut == unicode_t::utf16_be || ut == unicode_t::utf16_le);
+
+ if (n & 0x01)
+ throw std::invalid_argument("size of a UTF-16 string must be divisible by 2.");
+
+ p += 2; // skip the BOM.
+
+ size_t n_buf = n / 2u - 1;
+ std::u16string buf(n_buf, 0);
+
+ switch (ut)
+ {
+ case unicode_t::utf16_be:
+ {
+ for (size_t i = 0; i < n_buf; ++i)
+ {
+ size_t offset = i * 2;
+ buf[i] = static_cast<char16_t>(p[offset+1] | p[offset] << 8);
+ }
+ break;
+ }
+ case unicode_t::utf16_le:
+ {
+ for (size_t i = 0; i < n_buf; ++i)
+ {
+ size_t offset = i * 2;
+ buf[i] = static_cast<char16_t>(p[offset] | p[offset+1]);
+ }
+ break;
+ }
+ default:
+ ;
+ }
+
+#if defined(_MSC_VER)
+ // char16_t does not work with MSVC just yet. This is a workaround. c.f.
+ // https://stackoverflow.com/questions/32055357/visual-studio-c-2015-stdcodecvt-with-char16-t-or-char32-t
+ const int16_t* pi16 = reinterpret_cast<const int16_t*>(buf.data());
+ const int16_t* pi16_end = pi16 + buf.size();
+ std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> conversion;
+ return conversion.to_bytes(pi16, pi16_end);
+#else
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conversion;
+ return conversion.to_bytes(buf);
+#endif
+}
+
+std::tuple<std::string_view, size_t, size_t> find_line_with_offset(std::string_view strm, std::ptrdiff_t offset)
+{
+ const char* p0 = strm.data();
+ const char* p_end = p0 + strm.size();
+ const char* p_offset = p0 + offset;
+
+ if (p_offset >= p_end)
+ {
+ std::ostringstream os;
+ os << "offset value of " << offset << " is out-of-bound for a stream of length " << strm.size();
+ throw std::invalid_argument(os.str());
+ }
+
+ // Determine the line number.
+ std::size_t line_num = 0;
+ for (const char* p = p0; p != p_offset; ++p)
+ {
+ if (*p == '\n')
+ ++line_num;
+ }
+
+ // Determine the beginning of the line.
+ const char* p_line_start = p_offset;
+
+ // if the error points at the new line character
+ // we have most likely an unterminated quote.
+ // Report the line with the actual error.
+ if (*p_offset == '\n' && offset > 0)
+ --p_line_start;
+
+ for (; p0 <= p_line_start; --p_line_start)
+ {
+ if (*p_line_start == '\n')
+ break;
+ }
+
+ ++p_line_start;
+ assert(p0 <= p_line_start);
+
+ // Determine the end of the line.
+ const char* p_line_end = p_offset;
+ for (; p_line_end < p_end; ++p_line_end)
+ {
+ if (*p_line_end == '\n')
+ // one character after the last character of the line.
+ break;
+ }
+
+ assert(p_line_start <= p_offset);
+ std::size_t offset_on_line = std::distance(p_line_start, p_offset);
+ std::string_view line(p_line_start, p_line_end - p_line_start);
+
+ return std::make_tuple(line, line_num, offset_on_line);
+}
+
+} // anonymous namespace
+
+struct file_content::impl
+{
+ boost::uintmax_t content_size;
+ bip::file_mapping mapped_file;
+ bip::mapped_region mapped_region;
+
+ std::string buffer; // its own buffer in case of stream conversion.
+
+ const char* content;
+
+ impl() : content_size(0), content(nullptr) {}
+
+ impl(std::string_view filepath) :
+ content_size(fs::file_size(std::string{filepath}.c_str())),
+ mapped_file(std::string{filepath}.c_str(), bip::read_only),
+ mapped_region(mapped_file, bip::read_only, 0, content_size),
+ content(nullptr)
+ {
+ content = static_cast<const char*>(mapped_region.get_address());
+ }
+};
+
+file_content::file_content() :
+ mp_impl(std::make_unique<impl>()) {}
+
+file_content::file_content(file_content&& other) = default;
+
+file_content::file_content(std::string_view filepath) :
+ mp_impl(std::make_unique<impl>(filepath)) {}
+
+file_content::~file_content() = default;
+
+const char* file_content::data() const
+{
+ return mp_impl->content;
+}
+
+size_t file_content::size() const
+{
+ return mp_impl->content_size;
+}
+
+bool file_content::empty() const
+{
+ return mp_impl->content_size == 0;
+}
+
+void file_content::swap(file_content& other)
+{
+ std::swap(mp_impl, other.mp_impl);
+}
+
+void file_content::load(std::string_view filepath)
+{
+ file_content tmp(filepath);
+ swap(tmp);
+}
+
+void file_content::convert_to_utf8()
+{
+ unicode_t ut = check_unicode_type(mp_impl->content, mp_impl->content_size);
+
+ switch (ut)
+ {
+ case unicode_t::utf16_be:
+ case unicode_t::utf16_le:
+ {
+ // Convert to utf-8 stream, and reset the content pointer and size.
+ mp_impl->buffer = convert_utf16_to_utf8(mp_impl->content, mp_impl->content_size, ut);
+ mp_impl->content = mp_impl->buffer.data();
+ mp_impl->content_size = mp_impl->buffer.size();
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+std::string_view file_content::str() const
+{
+ return std::string_view(mp_impl->content, mp_impl->content_size);
+}
+
+struct memory_content::impl
+{
+ std::string_view content;
+ std::string buffer; // its own buffer in case of stream conversion.
+
+ impl() {}
+ impl(std::string_view s) : content(s) {}
+};
+
+memory_content::memory_content() : mp_impl(std::make_unique<impl>()) {}
+
+memory_content::memory_content(std::string_view s) :
+ mp_impl(std::make_unique<impl>(s)) {}
+
+memory_content::memory_content(memory_content&& other) = default;
+memory_content::~memory_content() = default;
+
+const char* memory_content::data() const
+{
+ return mp_impl->content.data();
+}
+
+size_t memory_content::size() const
+{
+ return mp_impl->content.size();
+}
+
+bool memory_content::empty() const
+{
+ return mp_impl->content.empty();
+}
+
+void memory_content::swap(memory_content& other)
+{
+ std::swap(mp_impl, other.mp_impl);
+}
+
+void memory_content::convert_to_utf8()
+{
+ unicode_t ut = check_unicode_type(mp_impl->content.data(), mp_impl->content.size());
+
+ switch (ut)
+ {
+ case unicode_t::utf16_be:
+ case unicode_t::utf16_le:
+ {
+ // Convert to utf-8 stream, and reset the content pointer and size.
+ mp_impl->buffer = convert_utf16_to_utf8(mp_impl->content.data(), mp_impl->content.size(), ut);
+ mp_impl->content = mp_impl->buffer;
+ break;
+ }
+ default:
+ ;
+ }
+}
+
+std::string_view memory_content::str() const
+{
+ return mp_impl->content;
+}
+
+line_with_offset::line_with_offset(std::string _line, std::size_t _line_number, std::size_t _offset_on_line) :
+ line(std::move(_line)),
+ line_number(_line_number),
+ offset_on_line(_offset_on_line)
+{}
+
+line_with_offset::line_with_offset(const line_with_offset& other) = default;
+line_with_offset::line_with_offset(line_with_offset&& other) = default;
+line_with_offset::~line_with_offset() = default;
+
+bool line_with_offset::operator== (const line_with_offset& other) const
+{
+ return line == other.line && line_number == other.line_number && offset_on_line == other.offset_on_line;
+}
+
+bool line_with_offset::operator!= (const line_with_offset& other) const
+{
+ return !operator==(other);
+}
+
+std::string create_parse_error_output(std::string_view strm, std::ptrdiff_t offset)
+{
+ if (strm.empty() || offset < 0)
+ return std::string();
+
+ const size_t max_line_length = 60;
+ offset = std::min<std::ptrdiff_t>(strm.size() - 1, offset);
+
+ auto line_info = find_line_with_offset(strm, offset);
+ std::string_view line = std::get<0>(line_info);
+ size_t line_num = std::get<1>(line_info);
+ size_t offset_on_line = std::get<2>(line_info);
+
+ if (offset_on_line < 30)
+ {
+ std::ostringstream os;
+ os << (line_num+1) << ":" << (offset_on_line+1) << ": ";
+ size_t line_num_width = os.str().size();
+
+ // Truncate line if it's too long.
+ if (line.size() > max_line_length)
+ line = std::string_view(line.data(), max_line_length);
+
+ os << line << std::endl;
+
+ for (size_t i = 0; i < (offset_on_line+line_num_width); ++i)
+ os << ' ';
+ os << '^';
+ return os.str();
+ }
+
+ // The error line is too long. Only show a segment of the line where the
+ // error occurred.
+
+ const size_t fixed_offset = 20;
+
+ size_t line_start = offset_on_line - fixed_offset;
+ size_t line_end = line_start + max_line_length;
+ if (line_end > line.size())
+ line_end = line.size();
+
+ size_t line_length = line_end - line_start;
+
+ line = std::string_view(line.data()+line_start, line_length);
+
+ std::ostringstream os;
+ os << line_num << ":" << (line_start+1) << ": ";
+ size_t line_num_width = os.str().size();
+
+ os << line << std::endl;
+
+ for (size_t i = 0; i < (fixed_offset+line_num_width); ++i)
+ os << ' ';
+ os << '^';
+
+ return os.str();
+}
+
+line_with_offset locate_line_with_offset(std::string_view strm, std::ptrdiff_t offset)
+{
+ auto line_info = find_line_with_offset(strm, offset);
+ std::string_view line = std::get<0>(line_info);
+ size_t line_num = std::get<1>(line_info);
+ size_t offset_on_line = std::get<2>(line_info);
+
+ return line_with_offset(std::string{line}, line_num, offset_on_line);
+}
+
+size_t locate_first_different_char(std::string_view left, std::string_view right)
+{
+ if (left.empty() || right.empty())
+ // If one of them is empty, then the first characters are considered
+ // different.
+ return 0;
+
+ size_t n = std::min(left.size(), right.size());
+ const char* p1 = left.data();
+ const char* p2 = right.data();
+ const char* p1_end = p1 + n;
+
+ for (; p1 != p1_end; ++p1, ++p2)
+ {
+ if (*p1 != *p2)
+ return std::distance(left.data(), p1);
+ }
+
+ return n;
+}
+
+std::size_t calc_logical_string_length(std::string_view s)
+{
+ std::size_t length = 0;
+
+ const char* p = s.data();
+ const char* p_end = p + s.size();
+
+ while (p < p_end)
+ {
+ ++length;
+
+ auto n_bytes = calc_utf8_byte_length(*p);
+ if (!n_bytes || n_bytes > 4)
+ {
+ std::ostringstream os;
+ os << "'" << s << "' contains invalid character at position " << std::distance(s.data(), p);
+ throw std::invalid_argument(os.str());
+ }
+
+ p += n_bytes;
+ }
+
+ if (p != p_end)
+ {
+ std::ostringstream os;
+ os << "last character of '" << s << "' ended prematurely";
+ throw std::invalid_argument(os.str());
+ }
+
+ return length;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/stream_test.cpp b/src/parser/stream_test.cpp
new file mode 100644
index 0000000..1a6e9fb
--- /dev/null
+++ b/src/parser/stream_test.cpp
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/stream.hpp"
+
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+using namespace std;
+using namespace orcus;
+
+void test_stream_create_error_output()
+{
+ test::stack_printer __sp__(__func__);
+
+ string output = create_parse_error_output("{}", 1);
+ cout << output << endl;
+ const char* expected = "1:2: {}\n ^";
+ assert(output == expected);
+}
+
+void test_stream_locate_first_different_char()
+{
+ test::stack_printer __sp__(__func__);
+
+ struct test_case
+ {
+ const char* left;
+ const char* right;
+ size_t expected;
+ };
+
+ std::vector<test_case> test_cases = {
+ { "", "a", 0 },
+ { "a", "", 0 },
+ { "", "", 0 },
+ { " ", "b", 0 },
+ { "abc", "abc", 3 },
+ { "abcd", "abce", 3 },
+ { "abc", "bbc", 0 },
+ { "abc", "acc", 1 },
+ };
+
+ for (const test_case& tc : test_cases)
+ {
+ size_t actual = locate_first_different_char(tc.left, tc.right);
+ assert(actual == tc.expected);
+ }
+}
+
+void test_stream_logical_string_length()
+{
+ test::stack_printer __sp__(__func__);
+
+ struct check
+ {
+ std::string_view value;
+ std::size_t length;
+ };
+
+ constexpr check checks[] = {
+ { "東京", 2 },
+ { "大阪は暑い", 5 },
+ { "New York", 8 },
+ { "日本は英語で言うとJapan", 14 },
+ { "fabriqué", 8 },
+ { "garçon", 6 },
+ { "вход", 4 },
+ { "выход", 5 },
+ { "помогите", 8 },
+ { "Nähe", 4 },
+ };
+
+ for (auto [value, expected_len] : checks)
+ {
+ std::size_t len = calc_logical_string_length(value);
+ std::cout << "'" << value << "' (length=" << len << ")" << std::endl;
+ assert(len == expected_len);
+ }
+}
+
+void test_stream_locate_line_with_offset()
+{
+ test::stack_printer __sp__(__func__);
+
+ std::string strm = "one\ntwo\nthree";
+
+ struct check
+ {
+ std::ptrdiff_t offset;
+ line_with_offset expected;
+ };
+
+ const std::vector<check> checks = {
+ { 0, { "one", 0, 0 } },
+ { 1, { "one", 0, 1 } },
+ { 2, { "one", 0, 2 } },
+ { 3, { "one", 0, 3 } }, // on line break
+ { 4, { "two", 1, 0 } },
+ { 5, { "two", 1, 1 } },
+ { 6, { "two", 1, 2 } },
+ { 7, { "two", 1, 3 } }, // on line break
+ { 8, { "three", 2, 0 } },
+ { 9, { "three", 2, 1 } },
+ { 10, { "three", 2, 2 } },
+ { 11, { "three", 2, 3 } },
+ { 12, { "three", 2, 4 } },
+ };
+
+ for (const auto& c : checks)
+ {
+ auto res = locate_line_with_offset(strm, c.offset);
+ assert(res == c.expected);
+ }
+
+ try
+ {
+ auto res = locate_line_with_offset(strm, strm.size());
+ assert(!"exception should have been thrown for out-of-bound offset!");
+ }
+ catch (const std::invalid_argument& e)
+ {
+ // expected
+ cout << "exception thrown as expected: '" << e.what() << "'" << endl;
+ }
+}
+
+int main()
+{
+ test_stream_create_error_output();
+ test_stream_locate_first_different_char();
+ test_stream_logical_string_length();
+ test_stream_locate_line_with_offset();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/string_pool.cpp b/src/parser/string_pool.cpp
new file mode 100644
index 0000000..e438da5
--- /dev/null
+++ b/src/parser/string_pool.cpp
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/string_pool.hpp>
+#include <orcus/exception.hpp>
+
+#include <iostream>
+#include <unordered_set>
+#include <vector>
+#include <memory>
+#include <cassert>
+#include <algorithm>
+#include <string_view>
+
+#include <boost/pool/object_pool.hpp>
+
+namespace orcus {
+
+using std::cout;
+using std::endl;
+
+using string_set_type = std::unordered_set<std::string_view>;
+using string_store_type = boost::object_pool<std::string>;
+using string_stores_type = std::vector<std::unique_ptr<string_store_type>>;
+
+struct string_pool::impl
+{
+ string_stores_type m_stores;
+ string_set_type m_set;
+
+ impl()
+ {
+ // first element is the active store used for the current instance.
+ m_stores.push_back(std::make_unique<string_store_type>(256, 0));
+ }
+};
+
+string_pool::string_pool() : mp_impl(std::make_unique<impl>()) {}
+
+string_pool::string_pool(string_pool&& other) : mp_impl(std::move(other.mp_impl)) {}
+
+string_pool::~string_pool() = default;
+
+std::pair<std::string_view, bool> string_pool::intern(std::string_view str)
+{
+ if (str.empty())
+ return std::pair<std::string_view, bool>(std::string_view(), false);
+
+ string_set_type::const_iterator itr = mp_impl->m_set.find(str);
+ if (itr == mp_impl->m_set.end())
+ {
+ // This string has not been interned. Intern it.
+ string_store_type& store = *mp_impl->m_stores[0];
+ std::string* p = store.construct(str);
+ if (!p)
+ throw general_error("failed to intern a new string instance.");
+
+ std::pair<string_set_type::iterator,bool> r =
+ mp_impl->m_set.emplace(p->data(), p->size());
+ if (!r.second)
+ throw general_error("failed to intern a new string instance.");
+
+ std::string_view ps = *r.first;
+ assert(ps == str);
+
+ return std::pair<std::string_view, bool>(ps, true);
+ }
+
+ // This string has already been interned.
+
+ std::string_view stored_str = *itr;
+ assert(stored_str == str);
+ return std::pair<std::string_view, bool>(stored_str, false);
+}
+
+std::vector<std::string_view> string_pool::get_interned_strings() const
+{
+ std::vector<std::string_view> sorted;
+ sorted.reserve(mp_impl->m_set.size());
+
+ for (std::string_view ps : mp_impl->m_set)
+ sorted.push_back(ps);
+
+ std::sort(sorted.begin(), sorted.end());
+
+ return sorted;
+}
+
+void string_pool::dump() const
+{
+ auto sorted = get_interned_strings();
+
+ cout << "interned string count: " << sorted.size() << endl;
+
+ // Dump them all to stdout.
+ size_t counter = 0;
+ for (std::string_view s : sorted)
+ cout << counter++ << ": '" << s << "'" << endl;
+}
+
+void string_pool::clear()
+{
+ mp_impl = std::make_unique<impl>();
+}
+
+size_t string_pool::size() const
+{
+ return mp_impl->m_set.size();
+}
+
+void string_pool::swap(string_pool& other)
+{
+ std::swap(mp_impl, other.mp_impl);
+}
+
+void string_pool::merge(string_pool& other)
+{
+ while (!other.mp_impl->m_stores.empty())
+ {
+ mp_impl->m_stores.push_back(
+ std::move(other.mp_impl->m_stores.back()));
+ other.mp_impl->m_stores.pop_back();
+ }
+
+ for (std::string_view p : other.mp_impl->m_set)
+ mp_impl->m_set.insert(p);
+
+ other.mp_impl->m_set.clear();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/string_pool_test.cpp b/src/parser/string_pool_test.cpp
new file mode 100644
index 0000000..7d3f864
--- /dev/null
+++ b/src/parser/string_pool_test.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/string_pool.hpp>
+
+#include <type_traits>
+
+using namespace orcus;
+
+void test_basic()
+{
+ const char* static_text = "test";
+
+ string_pool pool;
+ assert(pool.size() == 0);
+
+ std::pair<std::string_view, bool> ret = pool.intern("foo");
+ assert(ret.first == "foo");
+ assert(ret.second); // new instance
+
+ ret = pool.intern("foo");
+ assert(ret.first == "foo");
+ assert(!ret.second); // existing instance.
+
+ // Empty strings should not be interned.
+ ret = pool.intern("");
+ assert(ret.first.empty());
+ assert(!ret.second);
+
+ ret = pool.intern("A");
+ std::cout << "interned string: " << ret.first << std::endl;
+ assert(ret.second);
+ assert(pool.size() == 2);
+
+ // Duplicate string.
+ ret = pool.intern("A");
+ std::cout << "interned string: " << ret.first << std::endl;
+ assert(!ret.second);
+
+ ret = pool.intern("B");
+ std::cout << "interned string: " << ret.first << std::endl;
+ assert(pool.size() == 3);
+
+ // Interning an already-intern string should return a string_view with
+ // identical memory address.
+ std::string_view str = ret.first;
+ std::string_view str2 = pool.intern(str).first;
+ assert(str == str2);
+ assert(pool.size() == 3);
+ assert(str.data() == str2.data()); // their memory address should be identical.
+
+ std::string_view static_str(static_text);
+ ret = pool.intern(static_str);
+ str = ret.first;
+ std::cout << "interned string: " << str << std::endl;
+ assert(pool.size() == 4);
+ assert(str == static_str);
+ assert(str.data() != static_str.data());
+
+ // Make sure that the pool remains usable after calling clear().
+ pool.clear();
+ assert(pool.size() == 0);
+ ret = pool.intern(static_str);
+ assert(ret.second); // it should be a new string
+ assert(ret.first == static_str);
+}
+
+void test_merge()
+{
+ string_pool pool1;
+ std::unique_ptr<string_pool> pool2(std::make_unique<string_pool>());
+
+ pool1.intern("A");
+ pool1.intern("B");
+ pool1.intern("C");
+ std::string_view v1 = pool1.intern("same value").first;
+
+ pool2->intern("D");
+ pool2->intern("E");
+ pool2->intern("F");
+ std::string_view v2 = pool2->intern("same value").first;
+
+ assert(pool1.size() == 4);
+ assert(pool2->size() == 4);
+
+ pool1.merge(*pool2);
+
+ assert(pool1.size() == 7);
+ assert(pool2->size() == 0);
+
+ pool2.reset(); // Delete the pool2 instance altogether.
+
+ // This should not create a new entry.
+ auto r = pool1.intern("F");
+ assert(!r.second);
+
+ // v2 still points to the original string in pool2, which should now be in
+ // the merged store in pool1 (thus valid).
+ assert(v1 == v2);
+
+ std::vector<std::string_view> entries = pool1.get_interned_strings();
+ assert(entries.size() == pool1.size());
+}
+
+void test_move()
+{
+ static_assert(!std::is_copy_constructible_v<orcus::string_pool>);
+ static_assert(std::is_move_constructible_v<orcus::string_pool>);
+
+ string_pool pool1;
+ pool1.intern("A");
+ pool1.intern("B");
+ pool1.intern("C");
+ pool1.intern("D");
+ pool1.intern("E");
+
+ string_pool pool2 = std::move(pool1);
+ assert(pool2.size() == 5);
+}
+
+int main()
+{
+ test_basic();
+ test_merge();
+ test_move();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/threaded_json_parser_test.cpp b/src/parser/threaded_json_parser_test.cpp
new file mode 100644
index 0000000..5ac8053
--- /dev/null
+++ b/src/parser/threaded_json_parser_test.cpp
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/threaded_json_parser.hpp>
+
+#include <cstring>
+
+using namespace orcus;
+using namespace std;
+
+class handler
+{
+ json::parse_tokens_t m_tokens;
+
+public:
+ void begin_parse()
+ {
+ m_tokens.emplace_back(json::parse_token_t::begin_parse);
+ }
+
+ void end_parse()
+ {
+ m_tokens.emplace_back(json::parse_token_t::end_parse);
+ }
+
+ void begin_array()
+ {
+ m_tokens.emplace_back(json::parse_token_t::begin_array);
+ }
+
+ void end_array()
+ {
+ m_tokens.emplace_back(json::parse_token_t::end_array);
+ }
+
+ void begin_object()
+ {
+ m_tokens.emplace_back(json::parse_token_t::begin_object);
+ }
+
+ void object_key(const char* p, size_t len, bool transient)
+ {
+ assert(!transient); // transient is never true with the threaded parser.
+ m_tokens.emplace_back(json::parse_token_t::object_key, std::string_view{p, len});
+ }
+
+ void end_object()
+ {
+ m_tokens.emplace_back(json::parse_token_t::end_object);
+ }
+
+ void boolean_true()
+ {
+ m_tokens.emplace_back(json::parse_token_t::boolean_true);
+ }
+
+ void boolean_false()
+ {
+ m_tokens.emplace_back(json::parse_token_t::boolean_false);
+ }
+
+ void null()
+ {
+ m_tokens.emplace_back(json::parse_token_t::null);
+ }
+
+ void string(const char* p, size_t len, bool transient)
+ {
+ assert(!transient); // transient is never true with the threaded parser.
+ m_tokens.emplace_back(json::parse_token_t::string, std::string_view{p, len});
+ }
+
+ void number(double val)
+ {
+ m_tokens.emplace_back(val);
+ }
+
+ const json::parse_tokens_t& get_tokens() const
+ {
+ return m_tokens;
+ }
+};
+
+void test_parser(const char* src, const json::parse_tokens_t& expected)
+{
+ cout << "source: " << src << endl;
+
+ handler hdl;
+ threaded_json_parser<handler> parser(src, std::strlen(src), hdl, 5, 5);
+ parser.parse();
+
+ if (hdl.get_tokens() != expected)
+ {
+ cout << "Expected tokens:" << endl;
+ cout << expected;
+ cout << "Actual tokens:" << endl;
+ cout << hdl.get_tokens();
+ abort();
+ }
+}
+
+void test_threaded_json_parser_basic()
+{
+ struct test_case
+ {
+ const char* source;
+ json::parse_tokens_t expected;
+ };
+
+ test_case tcs[] =
+ {
+ {
+ "[1,2,3]",
+ {
+ { json::parse_token_t::begin_parse },
+ { json::parse_token_t::begin_array },
+ { 1.0 },
+ { 2.0 },
+ { 3.0 },
+ { json::parse_token_t::end_array },
+ { json::parse_token_t::end_parse },
+ }
+ },
+ {
+ "{\"foo\": [true, false, null]}",
+ {
+ { json::parse_token_t::begin_parse },
+ { json::parse_token_t::begin_object },
+ { json::parse_token_t::object_key, std::string_view{"foo"} },
+ { json::parse_token_t::begin_array },
+ { json::parse_token_t::boolean_true },
+ { json::parse_token_t::boolean_false },
+ { json::parse_token_t::null },
+ { json::parse_token_t::end_array },
+ { json::parse_token_t::end_object },
+ { json::parse_token_t::end_parse },
+ }
+ }
+ };
+
+ for (size_t i = 0, n = std::size(tcs); i < n; ++i)
+ test_parser(tcs[i].source, tcs[i].expected);
+}
+
+void test_threaded_json_parser_invalid()
+{
+ const char* invalids[] = {
+ "[foo]",
+ "[qwerty]",
+ "[1,2] null",
+ "{\"key\" 1: 12}",
+ "[1,,2]",
+ "\"key\": {\"inner\": 12}"
+ };
+
+ for (size_t i = 0; i < std::size(invalids); ++i)
+ {
+ const char* src = invalids[i];
+
+ try
+ {
+ handler hdl;
+ threaded_json_parser<handler> parser(src, std::strlen(src), hdl, 1);
+ parser.parse();
+ assert(false);
+ }
+ catch (const parse_error&)
+ {
+ // works as expected.
+ cout << "invalid source: " << src << endl;
+ }
+ }
+}
+
+int main()
+{
+ test_threaded_json_parser_basic();
+ test_threaded_json_parser_invalid();
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/threaded_sax_token_parser_test.cpp b/src/parser/threaded_sax_token_parser_test.cpp
new file mode 100644
index 0000000..1338b2a
--- /dev/null
+++ b/src/parser/threaded_sax_token_parser_test.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/threaded_sax_token_parser.hpp"
+#include "orcus/tokens.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/parser_base.hpp"
+#include "orcus/stream.hpp"
+
+#include <cstring>
+
+using namespace std;
+using namespace orcus;
+
+void test_sax_token_parser_1()
+{
+ // Array of tokens to define for this test.
+ const char* token_names[] = {
+ "??", // 0
+ "andy", // 1
+ "bruce", // 2
+ "charlie", // 3
+ "david", // 4
+ "edward" // 5
+ };
+
+ size_t token_count = std::size(token_names);
+
+ // Token constants.
+ const xml_token_t op_andy = 1;
+ const xml_token_t op_bruce = 2;
+ const xml_token_t op_charlie = 3;
+ const xml_token_t op_david = 4;
+ const xml_token_t op_edward = 5;
+
+ struct check
+ {
+ const char* raw_name;
+ xml_token_t token;
+ bool start_element;
+ };
+
+ tokens token_map(token_names, token_count);
+ xmlns_repository ns_repo;
+ xmlns_context ns_cxt = ns_repo.create_context();
+
+ {
+ // Test XML content.
+ const char* content = "<?xml version=\"1.0\"?><root><andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+ size_t content_size = strlen(content);
+
+ // Expected outcome.
+ const check checks[] = {
+ { "root", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "andy", op_andy, true },
+ { "andy", op_andy, false },
+ { "bruce", op_bruce, true },
+ { "bruce", op_bruce, false },
+ { "charlie", op_charlie, true },
+ { "charlie", op_charlie, false },
+ { "david", op_david, true },
+ { "david", op_david, false },
+ { "edward", op_edward, true },
+ { "edward", op_edward, false },
+ { "frank", XML_UNKNOWN_TOKEN, true }, // name not on the master token list.
+ { "frank", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ { "root", XML_UNKNOWN_TOKEN, false }, // name not on the master token list.
+ };
+
+ class handler
+ {
+ const check* mp_head;
+ const check* mp_check;
+ public:
+ handler(const check* p) : mp_head(p), mp_check(p) {}
+
+ void start_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(mp_check->start_element);
+ ++mp_check;
+ }
+
+ void end_element(const orcus::xml_token_element_t& elem)
+ {
+ assert(std::string_view(mp_check->raw_name) == elem.raw_name);
+ assert(mp_check->token == elem.name);
+ assert(!mp_check->start_element);
+ ++mp_check;
+ }
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+
+ size_t get_token_count() const
+ {
+ return std::distance(mp_head, mp_check);
+ }
+ };
+
+ handler hdl(checks);
+ threaded_sax_token_parser<handler> parser(content, content_size, token_map, ns_cxt, hdl, 1, 100);
+ parser.parse();
+
+ assert(hdl.get_token_count() == std::size(checks));
+ }
+
+ {
+ // This content intentially contains invalid XML part at offset 28.
+ const char* content = "<?xml version=\"1.0\"?><root><<andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+ size_t content_size = strlen(content);
+
+ class handler
+ {
+ public:
+ handler() {}
+
+ void start_element(const orcus::xml_token_element_t& /*elem*/) {}
+
+ void end_element(const orcus::xml_token_element_t& /*elem*/) {}
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+ };
+
+ try
+ {
+ handler hdl;
+ threaded_sax_token_parser<handler> parser(content, content_size, token_map, ns_cxt, hdl, 1, 100);
+ parser.parse();
+ assert(!"An exception was expected, but one was not thrown.");
+ }
+ catch (const malformed_xml_error& e)
+ {
+ assert(e.offset() == 28u);
+ }
+ catch (const std::exception&)
+ {
+ assert(!"Wrong exception was thrown!");
+ }
+ }
+
+ {
+ // Test XML content.
+ const char* content = "<?xml version=\"1.0\"?><root><andy/><bruce/><charlie/><david/><edward/><frank/></root>";
+ size_t content_size = strlen(content);
+
+ class mock_exception : public std::exception {};
+
+ class handler
+ {
+ public:
+ handler() {}
+
+ void start_element(const orcus::xml_token_element_t& /*elem*/) {}
+
+ void end_element(const orcus::xml_token_element_t& /*elem*/)
+ {
+ throw mock_exception();
+ }
+
+ void characters(std::string_view /*val*/, bool /*transient*/) {}
+ };
+
+ handler hdl;
+ threaded_sax_token_parser<handler> parser(content, content_size, token_map, ns_cxt, hdl, 1, 100);
+
+ try
+ {
+ parser.parse();
+ assert(!"A mock exception was expected but not thrown.");
+ }
+ catch (const mock_exception&)
+ {
+ // expected.
+ }
+ }
+}
+
+int main()
+{
+ test_sax_token_parser_1();
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/tokens.cpp b/src/parser/tokens.cpp
new file mode 100644
index 0000000..5d3c533
--- /dev/null
+++ b/src/parser/tokens.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/tokens.hpp>
+
+namespace orcus {
+
+tokens::tokens(const char** token_names, size_t token_name_count) :
+ m_token_names(token_names),
+ m_token_name_count(token_name_count)
+{
+ for (size_t i = 0; i < m_token_name_count; ++i)
+ m_tokens.emplace(m_token_names[i], xml_token_t(i));
+}
+
+tokens::~tokens() = default;
+
+bool tokens::is_valid_token(xml_token_t token) const
+{
+ return token != XML_UNKNOWN_TOKEN;
+}
+
+xml_token_t tokens::get_token(std::string_view name) const
+{
+ token_map_type::const_iterator itr = m_tokens.find(name);
+ if (itr == m_tokens.end())
+ return XML_UNKNOWN_TOKEN;
+ return itr->second;
+}
+
+std::string_view tokens::get_token_name(xml_token_t token) const
+{
+ if (size_t(token) >= m_token_name_count)
+ return "";
+
+ return m_token_names[token];
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/types.cpp b/src/parser/types.cpp
new file mode 100644
index 0000000..5d469c5
--- /dev/null
+++ b/src/parser/types.cpp
@@ -0,0 +1,1454 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/types.hpp>
+#include <orcus/parser_global.hpp>
+#include <orcus/xml_namespace.hpp>
+
+#include <limits>
+#include <sstream>
+#include <string_view>
+#include <iomanip>
+#include <mdds/sorted_string_map.hpp>
+
+#include "ostream_utils.hpp"
+
+namespace orcus {
+
+parse_error_value_t::parse_error_value_t() :
+ offset(0)
+{
+}
+
+parse_error_value_t::parse_error_value_t(const parse_error_value_t& other) = default;
+
+parse_error_value_t::parse_error_value_t(std::string_view _str, std::ptrdiff_t _offset) :
+ str(_str), offset(_offset)
+{
+}
+
+parse_error_value_t& parse_error_value_t::operator=(const parse_error_value_t& other) = default;
+
+bool parse_error_value_t::operator==(const parse_error_value_t& other) const
+{
+ return str == other.str && offset == other.offset;
+}
+
+bool parse_error_value_t::operator!=(const parse_error_value_t& other) const
+{
+ return !operator==(other);
+}
+
+xml_name_t::xml_name_t() noexcept : ns(XMLNS_UNKNOWN_ID), name() {}
+xml_name_t::xml_name_t(xmlns_id_t _ns, std::string_view _name) : ns(_ns), name(_name) {}
+xml_name_t::xml_name_t(const xml_name_t& other) = default;
+
+xml_name_t& xml_name_t::operator= (const xml_name_t& other) = default;
+
+bool xml_name_t::operator== (const xml_name_t& other) const noexcept
+{
+ return ns == other.ns && name == other.name;
+}
+
+bool xml_name_t::operator!= (const xml_name_t& other) const noexcept
+{
+ return !operator==(other);
+}
+
+std::string xml_name_t::to_string(const xmlns_context& cxt, to_string_type type) const
+{
+ std::ostringstream os;
+
+ if (ns)
+ {
+ std::string_view ns_str;
+ switch (type)
+ {
+ case use_alias:
+ ns_str = cxt.get_alias(ns);
+ break;
+ case use_short_name:
+ ns_str = cxt.get_short_name(ns);
+ break;
+
+ }
+ if (!ns_str.empty())
+ os << ns_str << ':';
+ }
+ os << name;
+
+ return os.str();
+}
+
+std::string xml_name_t::to_string(const xmlns_repository& repo) const
+{
+ std::ostringstream os;
+
+ if (ns)
+ {
+ std::string ns_str = repo.get_short_name(ns);
+ if (!ns_str.empty())
+ os << ns_str << ':';
+ }
+ os << name;
+
+ return os.str();
+}
+
+xml_token_attr_t::xml_token_attr_t() :
+ ns(XMLNS_UNKNOWN_ID), name(XML_UNKNOWN_TOKEN), transient(false) {}
+
+xml_token_attr_t::xml_token_attr_t(const xml_token_attr_t& other) = default;
+
+xml_token_attr_t::xml_token_attr_t(
+ xmlns_id_t _ns, xml_token_t _name, std::string_view _value, bool _transient) :
+ ns(_ns), name(_name), value(_value), transient(_transient) {}
+
+xml_token_attr_t::xml_token_attr_t(
+ xmlns_id_t _ns, xml_token_t _name, std::string_view _raw_name, std::string_view _value, bool _transient) :
+ ns(_ns), name(_name), raw_name(_raw_name), value(_value), transient(_transient) {}
+
+xml_token_attr_t& xml_token_attr_t::operator=(const xml_token_attr_t& other) = default;
+
+xml_token_element_t::xml_token_element_t() : ns(nullptr), name(XML_UNKNOWN_TOKEN) {}
+
+xml_token_element_t::xml_token_element_t(
+ xmlns_id_t _ns, xml_token_t _name, std::string_view _raw_name, std::vector<xml_token_attr_t>&& _attrs) :
+ ns(_ns), name(_name), raw_name(_raw_name), attrs(std::move(_attrs)) {}
+
+xml_token_element_t::xml_token_element_t(const xml_token_element_t& other) :
+ ns(other.ns), name(other.name), raw_name(other.raw_name), attrs(other.attrs) {}
+
+xml_token_element_t::xml_token_element_t(xml_token_element_t&& other) :
+ ns(other.ns), name(other.name), raw_name(other.raw_name), attrs(std::move(other.attrs)) {}
+
+xml_declaration_t::xml_declaration_t() :
+ version_major(1),
+ version_minor(0),
+ encoding(character_set_t::unspecified),
+ standalone(false) {}
+
+xml_declaration_t::xml_declaration_t(uint8_t _version_major, uint8_t _version_minor, character_set_t _encoding, bool _standalone) :
+ version_major(_version_major), version_minor(_version_minor), encoding(_encoding), standalone(_standalone) {}
+
+xml_declaration_t::xml_declaration_t(const xml_declaration_t& other) :
+ version_major(other.version_major),
+ version_minor(other.version_minor),
+ encoding(other.encoding),
+ standalone(other.standalone) {}
+
+xml_declaration_t::~xml_declaration_t() {}
+
+xml_declaration_t& xml_declaration_t::operator= (const xml_declaration_t& other)
+{
+ version_major = other.version_major;
+ version_minor = other.version_minor;
+ encoding = other.encoding;
+ standalone = other.standalone;
+ return *this;
+}
+
+bool xml_declaration_t::operator== (const xml_declaration_t& other) const
+{
+ return version_major == other.version_major && version_minor == other.version_minor &&
+ encoding == other.encoding && standalone == other.standalone;
+}
+
+bool xml_declaration_t::operator!= (const xml_declaration_t& other) const
+{
+ return !operator== (other);
+}
+
+length_t::length_t() : unit(length_unit_t::unknown), value(0.0) {}
+
+length_t::length_t(length_unit_t _unit, double _value) : unit(_unit), value(_value) {}
+
+length_t::length_t(const length_t& other) = default;
+
+length_t& length_t::operator= (const length_t& other) = default;
+
+std::string length_t::to_string() const
+{
+ std::ostringstream os;
+ os << value;
+
+ switch (unit)
+ {
+ case length_unit_t::centimeter:
+ os << " cm";
+ break;
+ case length_unit_t::inch:
+ os << " in";
+ break;
+ case length_unit_t::point:
+ os << " pt";
+ break;
+ case length_unit_t::twip:
+ os << " twip";
+ break;
+ case length_unit_t::unknown:
+ default:
+ ;
+ }
+
+ return os.str();
+}
+
+bool length_t::operator== (const length_t& other) const noexcept
+{
+ return value == other.value && unit == other.unit;
+}
+
+bool length_t::operator!= (const length_t& other) const noexcept
+{
+ return !operator== (other);
+}
+
+date_time_t::date_time_t() :
+ year(0), month(0), day(0), hour(0), minute(0), second(0.0) {}
+
+date_time_t::date_time_t(int _year, int _month, int _day) :
+ year(_year), month(_month), day(_day), hour(0), minute(0), second(0.0) {}
+
+date_time_t::date_time_t(int _year, int _month, int _day, int _hour, int _minute, double _second) :
+ year(_year), month(_month), day(_day), hour(_hour), minute(_minute), second(_second) {}
+
+date_time_t::date_time_t(const date_time_t& other) = default;
+date_time_t::~date_time_t() = default;
+
+date_time_t& date_time_t::operator= (date_time_t other)
+{
+ swap(other);
+ return *this;
+}
+
+void date_time_t::swap(date_time_t& other)
+{
+ std::swap(year, other.year);
+ std::swap(month, other.month);
+ std::swap(day, other.day);
+ std::swap(hour, other.hour);
+ std::swap(minute, other.minute);
+ std::swap(second, other.second);
+}
+
+date_time_t date_time_t::from_chars(std::string_view str)
+{
+ auto flush_int = [](int& store, const char*& digit, size_t& digit_len)
+ {
+ long v;
+ parse_integer(digit, digit + digit_len, v);
+ store = v;
+
+ digit = nullptr;
+ digit_len = 0;
+ };
+
+ auto process_char = [](const char* p, const char*& digit, size_t& digit_len)
+ {
+ if (!digit)
+ {
+ digit = p;
+ digit_len = 1;
+ return;
+ }
+
+ ++digit_len;
+ };
+
+ date_time_t ret;
+ int dash_count = 0, t_count = 0, colon_count = 0;
+
+ const char* p = str.data();
+ const char* p_end = p + str.size();
+ const char* digit = p;
+ size_t digit_len = 0;
+
+ bool valid = true;
+ for (; p != p_end && valid; ++p)
+ {
+ switch (*p)
+ {
+ case '-':
+ {
+ if (t_count || colon_count || !digit)
+ {
+ // Invalid date-time value. All dashes must occur before
+ // any of 'T' and ':' occur.
+ valid = false;
+ break;
+ }
+
+ switch (dash_count)
+ {
+ case 0:
+ // Flush year.
+ flush_int(ret.year, digit, digit_len);
+ break;
+ case 1:
+ // Flush month.
+ flush_int(ret.month, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+ ++dash_count;
+ }
+ break;
+ case 'T':
+ {
+ if (t_count || dash_count != 2 || !digit)
+ {
+ // Invalid date-time value.
+ valid = false;
+ break;
+ }
+
+ // Flush day.
+ flush_int(ret.day, digit, digit_len);
+ ++t_count;
+ }
+ break;
+ case ':':
+ {
+ if (!t_count || !digit)
+ {
+ // Invalid date-time value.
+ valid = false;
+ break;
+ }
+
+ switch (colon_count)
+ {
+ case 0:
+ // Flush hour.
+ flush_int(ret.hour, digit, digit_len);
+ break;
+ case 1:
+ // Flush minute.
+ flush_int(ret.minute, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+
+ ++colon_count;
+ }
+ break;
+ default:
+ {
+ if (t_count)
+ {
+ // Time element.
+ switch (colon_count)
+ {
+ case 0:
+ // Hour
+ process_char(p, digit, digit_len);
+ break;
+ case 1:
+ // Minute
+ process_char(p, digit, digit_len);
+ break;
+ case 2:
+ // Second
+ process_char(p, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+ }
+ else
+ {
+ // Date element.
+ switch (dash_count)
+ {
+ case 0:
+ // Year
+ process_char(p, digit, digit_len);
+ break;
+ case 1:
+ // Month
+ process_char(p, digit, digit_len);
+ break;
+ case 2:
+ // Day
+ process_char(p, digit, digit_len);
+ break;
+ default:
+ valid = false;
+ }
+ }
+ }
+ }
+
+ }
+
+ if (!valid || !digit)
+ return ret;
+
+ if (t_count)
+ {
+ // Flush second.
+ ret.second = strtod(digit, nullptr);
+ }
+ else
+ {
+ // Flush day.
+ flush_int(ret.day, digit, digit_len);
+ }
+
+ return ret;
+}
+
+bool date_time_t::operator== (const date_time_t& other) const
+{
+ return year == other.year && month == other.month && day == other.day &&
+ hour == other.hour && minute == other.minute && second == other.second;
+}
+
+bool date_time_t::operator!= (const date_time_t& other) const
+{
+ return !operator== (other);
+}
+
+bool date_time_t::operator< (const date_time_t& other) const
+{
+ if (year != other.year)
+ return year < other.year;
+
+ if (month != other.month)
+ return month < other.month;
+
+ if (day != other.day)
+ return day < other.day;
+
+ if (hour != other.hour)
+ return hour < other.hour;
+
+ if (minute != other.minute)
+ return minute < other.minute;
+
+ return second < other.second;
+}
+
+std::string date_time_t::to_string() const
+{
+ std::ostringstream os;
+
+ // NB: setfill is sticky for the entire run whereas setw gets reset for each
+ // value.
+ os << std::setfill('0');
+
+ os << std::setw(4) << year
+ << "-" << std::setw(2) << month
+ << "-" << std::setw(2) << day
+ << "T" << std::setw(2) << hour
+ << ":" << std::setw(2) << minute
+ << ":" << std::setw(2) << second;
+
+ return os.str();
+}
+
+namespace {
+
+namespace dump_format {
+
+using map_type = mdds::sorted_string_map<dump_format_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "check", dump_format_t::check },
+ { "csv", dump_format_t::csv },
+ { "debug-state", dump_format_t::debug_state },
+ { "flat", dump_format_t::flat },
+ { "html", dump_format_t::html },
+ { "json", dump_format_t::json },
+ { "none", dump_format_t::none },
+ { "xml", dump_format_t::xml },
+ { "yaml", dump_format_t::yaml },
+};
+
+const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), dump_format_t::unknown);
+ return mt;
+}
+
+} // namespace dump_format
+
+namespace charset {
+
+using map_type = mdds::sorted_string_map<character_set_t, mdds::string_view_map_entry>;
+
+// Keys must be sorted.
+constexpr map_type::entry entries[] = {
+ { "437", character_set_t::ibm437 },
+ { "850", character_set_t::ibm850 },
+ { "851", character_set_t::ibm851 },
+ { "852", character_set_t::ibm852 },
+ { "855", character_set_t::ibm855 },
+ { "857", character_set_t::ibm857 },
+ { "860", character_set_t::ibm860 },
+ { "861", character_set_t::ibm861 },
+ { "862", character_set_t::ibm862 },
+ { "863", character_set_t::ibm863 },
+ { "865", character_set_t::ibm865 },
+ { "866", character_set_t::ibm866 },
+ { "869", character_set_t::ibm869 },
+ { "904", character_set_t::ibm904 },
+ { "adobe-standard-encoding", character_set_t::adobe_standard_encoding },
+ { "adobe-symbol-encoding", character_set_t::adobe_symbol_encoding },
+ { "ami-1251", character_set_t::amiga_1251 },
+ { "ami1251", character_set_t::amiga_1251 },
+ { "amiga-1251", character_set_t::amiga_1251 },
+ { "amiga1251", character_set_t::amiga_1251 },
+ { "ansi_x3.110-1983", character_set_t::ansi_x3_110_1983 },
+ { "ansi_x3.4-1968", character_set_t::us_ascii },
+ { "ansi_x3.4-1986", character_set_t::us_ascii },
+ { "arabic", character_set_t::iso_8859_6 },
+ { "arabic7", character_set_t::asmo_449 },
+ { "asmo-708", character_set_t::iso_8859_6 },
+ { "asmo_449", character_set_t::asmo_449 },
+ { "big5", character_set_t::big5 },
+ { "big5-hkscs", character_set_t::big5_hkscs },
+ { "bocu-1", character_set_t::bocu_1 },
+ { "brf", character_set_t::brf },
+ { "bs_4730", character_set_t::bs_4730 },
+ { "bs_viewdata", character_set_t::bs_viewdata },
+ { "ca", character_set_t::csa_z243_4_1985_1 },
+ { "ccsid00858", character_set_t::ibm00858 },
+ { "ccsid00924", character_set_t::ibm00924 },
+ { "ccsid01140", character_set_t::ibm01140 },
+ { "ccsid01141", character_set_t::ibm01141 },
+ { "ccsid01142", character_set_t::ibm01142 },
+ { "ccsid01143", character_set_t::ibm01143 },
+ { "ccsid01144", character_set_t::ibm01144 },
+ { "ccsid01145", character_set_t::ibm01145 },
+ { "ccsid01146", character_set_t::ibm01146 },
+ { "ccsid01147", character_set_t::ibm01147 },
+ { "ccsid01148", character_set_t::ibm01148 },
+ { "ccsid01149", character_set_t::ibm01149 },
+ { "cesu-8", character_set_t::cesu_8 },
+ { "chinese", character_set_t::gb_2312_80 },
+ { "cn", character_set_t::gb_1988_80 },
+ { "cp-ar", character_set_t::ibm868 },
+ { "cp-gr", character_set_t::ibm869 },
+ { "cp-is", character_set_t::ibm861 },
+ { "cp00858", character_set_t::ibm00858 },
+ { "cp00924", character_set_t::ibm00924 },
+ { "cp01140", character_set_t::ibm01140 },
+ { "cp01141", character_set_t::ibm01141 },
+ { "cp01142", character_set_t::ibm01142 },
+ { "cp01143", character_set_t::ibm01143 },
+ { "cp01144", character_set_t::ibm01144 },
+ { "cp01145", character_set_t::ibm01145 },
+ { "cp01146", character_set_t::ibm01146 },
+ { "cp01147", character_set_t::ibm01147 },
+ { "cp01148", character_set_t::ibm01148 },
+ { "cp01149", character_set_t::ibm01149 },
+ { "cp037", character_set_t::ibm037 },
+ { "cp038", character_set_t::ibm038 },
+ { "cp1026", character_set_t::ibm1026 },
+ { "cp154", character_set_t::ptcp154 },
+ { "cp273", character_set_t::ibm273 },
+ { "cp274", character_set_t::ibm274 },
+ { "cp275", character_set_t::ibm275 },
+ { "cp278", character_set_t::ibm278 },
+ { "cp280", character_set_t::ibm280 },
+ { "cp281", character_set_t::ibm281 },
+ { "cp284", character_set_t::ibm284 },
+ { "cp285", character_set_t::ibm285 },
+ { "cp290", character_set_t::ibm290 },
+ { "cp297", character_set_t::ibm297 },
+ { "cp367", character_set_t::us_ascii },
+ { "cp420", character_set_t::ibm420 },
+ { "cp423", character_set_t::ibm423 },
+ { "cp424", character_set_t::ibm424 },
+ { "cp437", character_set_t::ibm437 },
+ { "cp500", character_set_t::ibm500 },
+ { "cp50220", character_set_t::cp50220 },
+ { "cp51932", character_set_t::cp51932 },
+ { "cp775", character_set_t::ibm775 },
+ { "cp819", character_set_t::iso_8859_1 },
+ { "cp850", character_set_t::ibm850 },
+ { "cp851", character_set_t::ibm851 },
+ { "cp852", character_set_t::ibm852 },
+ { "cp855", character_set_t::ibm855 },
+ { "cp857", character_set_t::ibm857 },
+ { "cp860", character_set_t::ibm860 },
+ { "cp861", character_set_t::ibm861 },
+ { "cp862", character_set_t::ibm862 },
+ { "cp863", character_set_t::ibm863 },
+ { "cp864", character_set_t::ibm864 },
+ { "cp865", character_set_t::ibm865 },
+ { "cp866", character_set_t::ibm866 },
+ { "cp868", character_set_t::ibm868 },
+ { "cp869", character_set_t::ibm869 },
+ { "cp870", character_set_t::ibm870 },
+ { "cp871", character_set_t::ibm871 },
+ { "cp880", character_set_t::ibm880 },
+ { "cp891", character_set_t::ibm891 },
+ { "cp903", character_set_t::ibm903 },
+ { "cp904", character_set_t::ibm904 },
+ { "cp905", character_set_t::ibm905 },
+ { "cp918", character_set_t::ibm918 },
+ { "cp936", character_set_t::gbk },
+ { "csa7-1", character_set_t::csa_z243_4_1985_1 },
+ { "csa7-2", character_set_t::csa_z243_4_1985_2 },
+ { "csa71", character_set_t::csa_z243_4_1985_1 },
+ { "csa72", character_set_t::csa_z243_4_1985_2 },
+ { "csa_t500-1983", character_set_t::ansi_x3_110_1983 },
+ { "csa_z243.4-1985-1", character_set_t::csa_z243_4_1985_1 },
+ { "csa_z243.4-1985-2", character_set_t::csa_z243_4_1985_2 },
+ { "csa_z243.4-1985-gr", character_set_t::csa_z243_4_1985_gr },
+ { "csadobestandardencoding", character_set_t::adobe_standard_encoding },
+ { "csascii", character_set_t::us_ascii },
+ { "csbig5", character_set_t::big5 },
+ { "csbig5hkscs", character_set_t::big5_hkscs },
+ { "csbocu-1", character_set_t::bocu_1 },
+ { "csbocu1", character_set_t::bocu_1 },
+ { "csbrf", character_set_t::brf },
+ { "cscesu-8", character_set_t::cesu_8 },
+ { "cscesu8", character_set_t::cesu_8 },
+ { "cscp50220", character_set_t::cp50220 },
+ { "cscp51932", character_set_t::cp51932 },
+ { "csdecmcs", character_set_t::dec_mcs },
+ { "csdkus", character_set_t::dk_us },
+ { "csebcdicatdea", character_set_t::ebcdic_at_de_a },
+ { "csebcdiccafr", character_set_t::ebcdic_ca_fr },
+ { "csebcdicdkno", character_set_t::ebcdic_dk_no },
+ { "csebcdicdknoa", character_set_t::ebcdic_dk_no_a },
+ { "csebcdices", character_set_t::ebcdic_es },
+ { "csebcdicesa", character_set_t::ebcdic_es_a },
+ { "csebcdicess", character_set_t::ebcdic_es_s },
+ { "csebcdicfise", character_set_t::ebcdic_fi_se },
+ { "csebcdicfisea", character_set_t::ebcdic_fi_se_a },
+ { "csebcdicfr", character_set_t::ebcdic_fr },
+ { "csebcdicit", character_set_t::ebcdic_it },
+ { "csebcdicpt", character_set_t::ebcdic_pt },
+ { "csebcdicuk", character_set_t::ebcdic_uk },
+ { "csebcdicus", character_set_t::ebcdic_us },
+ { "cseucfixwidjapanese", character_set_t::extended_unix_code_fixed_width_for_japanese },
+ { "cseuckr", character_set_t::euc_kr },
+ { "cseucpkdfmtjapanese", character_set_t::euc_jp },
+ { "csgb18030", character_set_t::gb18030 },
+ { "csgb2312", character_set_t::gb2312 },
+ { "csgbk", character_set_t::gbk },
+ { "cshalfwidthkatakana", character_set_t::jis_x0201 },
+ { "cshpdesktop", character_set_t::hp_desktop },
+ { "cshplegal", character_set_t::hp_legal },
+ { "cshpmath8", character_set_t::hp_math8 },
+ { "cshppifont", character_set_t::hp_pi_font },
+ { "cshppsmath", character_set_t::adobe_symbol_encoding },
+ { "cshproman8", character_set_t::hp_roman8 },
+ { "csibbm904", character_set_t::ibm904 },
+ { "csibm00858", character_set_t::ibm00858 },
+ { "csibm00924", character_set_t::ibm00924 },
+ { "csibm01140", character_set_t::ibm01140 },
+ { "csibm01141", character_set_t::ibm01141 },
+ { "csibm01142", character_set_t::ibm01142 },
+ { "csibm01143", character_set_t::ibm01143 },
+ { "csibm01144", character_set_t::ibm01144 },
+ { "csibm01145", character_set_t::ibm01145 },
+ { "csibm01146", character_set_t::ibm01146 },
+ { "csibm01147", character_set_t::ibm01147 },
+ { "csibm01148", character_set_t::ibm01148 },
+ { "csibm01149", character_set_t::ibm01149 },
+ { "csibm037", character_set_t::ibm037 },
+ { "csibm038", character_set_t::ibm038 },
+ { "csibm1026", character_set_t::ibm1026 },
+ { "csibm1047", character_set_t::ibm1047 },
+ { "csibm273", character_set_t::ibm273 },
+ { "csibm274", character_set_t::ibm274 },
+ { "csibm275", character_set_t::ibm275 },
+ { "csibm277", character_set_t::ibm277 },
+ { "csibm278", character_set_t::ibm278 },
+ { "csibm280", character_set_t::ibm280 },
+ { "csibm281", character_set_t::ibm281 },
+ { "csibm284", character_set_t::ibm284 },
+ { "csibm285", character_set_t::ibm285 },
+ { "csibm290", character_set_t::ibm290 },
+ { "csibm297", character_set_t::ibm297 },
+ { "csibm420", character_set_t::ibm420 },
+ { "csibm423", character_set_t::ibm423 },
+ { "csibm424", character_set_t::ibm424 },
+ { "csibm500", character_set_t::ibm500 },
+ { "csibm851", character_set_t::ibm851 },
+ { "csibm855", character_set_t::ibm855 },
+ { "csibm857", character_set_t::ibm857 },
+ { "csibm860", character_set_t::ibm860 },
+ { "csibm861", character_set_t::ibm861 },
+ { "csibm863", character_set_t::ibm863 },
+ { "csibm864", character_set_t::ibm864 },
+ { "csibm865", character_set_t::ibm865 },
+ { "csibm866", character_set_t::ibm866 },
+ { "csibm868", character_set_t::ibm868 },
+ { "csibm869", character_set_t::ibm869 },
+ { "csibm870", character_set_t::ibm870 },
+ { "csibm871", character_set_t::ibm871 },
+ { "csibm880", character_set_t::ibm880 },
+ { "csibm891", character_set_t::ibm891 },
+ { "csibm903", character_set_t::ibm903 },
+ { "csibm905", character_set_t::ibm905 },
+ { "csibm918", character_set_t::ibm918 },
+ { "csibmebcdicatde", character_set_t::ebcdic_at_de },
+ { "csibmsymbols", character_set_t::ibm_symbols },
+ { "csibmthai", character_set_t::ibm_thai },
+ { "csinvariant", character_set_t::invariant },
+ { "csiso102t617bit", character_set_t::t_61_7bit },
+ { "csiso10367box", character_set_t::iso_10367_box },
+ { "csiso103t618bit", character_set_t::t_61_8bit },
+ { "csiso10646utf1", character_set_t::iso_10646_utf_1 },
+ { "csiso10swedish", character_set_t::sen_850200_b },
+ { "csiso111ecmacyrillic", character_set_t::ecma_cyrillic },
+ { "csiso115481", character_set_t::iso_11548_1 },
+ { "csiso11swedishfornames", character_set_t::sen_850200_c },
+ { "csiso121canadian1", character_set_t::csa_z243_4_1985_1 },
+ { "csiso122canadian2", character_set_t::csa_z243_4_1985_2 },
+ { "csiso123csaz24341985gr", character_set_t::csa_z243_4_1985_gr },
+ { "csiso128t101g2", character_set_t::t_101_g2 },
+ { "csiso139csn369103", character_set_t::csn_369103 },
+ { "csiso13jisc6220jp", character_set_t::jis_c6220_1969_jp },
+ { "csiso141jusib1002", character_set_t::jus_i_b1_002 },
+ { "csiso143iecp271", character_set_t::iec_p27_1 },
+ { "csiso146serbian", character_set_t::jus_i_b1_003_serb },
+ { "csiso147macedonian", character_set_t::jus_i_b1_003_mac },
+ { "csiso14jisc6220ro", character_set_t::jis_c6220_1969_ro },
+ { "csiso150", character_set_t::greek_ccitt },
+ { "csiso150greekccitt", character_set_t::greek_ccitt },
+ { "csiso151cuba", character_set_t::nc_nc00_10_81 },
+ { "csiso153gost1976874", character_set_t::gost_19768_74 },
+ { "csiso158lap", character_set_t::latin_lap },
+ { "csiso159jisx02121990", character_set_t::jis_x0212_1990 },
+ { "csiso15italian", character_set_t::it },
+ { "csiso16portuguese", character_set_t::pt },
+ { "csiso17spanish", character_set_t::es },
+ { "csiso18greek7old", character_set_t::greek7_old },
+ { "csiso19latingreek", character_set_t::latin_greek },
+ { "csiso2022cn", character_set_t::iso_2022_cn },
+ { "csiso2022cnext", character_set_t::iso_2022_cn_ext },
+ { "csiso2022jp", character_set_t::iso_2022_jp },
+ { "csiso2022jp2", character_set_t::iso_2022_jp_2 },
+ { "csiso2022kr", character_set_t::iso_2022_kr },
+ { "csiso2033", character_set_t::iso_2033_1983 },
+ { "csiso21german", character_set_t::din_66003 },
+ { "csiso25french", character_set_t::nf_z_62_010_1973 },
+ { "csiso27latingreek1", character_set_t::latin_greek_1 },
+ { "csiso2intlrefversion", character_set_t::iso_646_irv_1983 },
+ { "csiso42jisc62261978", character_set_t::jis_c6226_1978 },
+ { "csiso47bsviewdata", character_set_t::bs_viewdata },
+ { "csiso49inis", character_set_t::inis },
+ { "csiso4unitedkingdom", character_set_t::bs_4730 },
+ { "csiso50inis8", character_set_t::inis_8 },
+ { "csiso51iniscyrillic", character_set_t::inis_cyrillic },
+ { "csiso54271981", character_set_t::iso_5427_1981 },
+ { "csiso5427cyrillic", character_set_t::iso_5427 },
+ { "csiso5428greek", character_set_t::iso_5428_1980 },
+ { "csiso57gb1988", character_set_t::gb_1988_80 },
+ { "csiso58gb231280", character_set_t::gb_2312_80 },
+ { "csiso60danishnorwegian", character_set_t::ns_4551_1 },
+ { "csiso60norwegian1", character_set_t::ns_4551_1 },
+ { "csiso61norwegian2", character_set_t::ns_4551_2 },
+ { "csiso646basic1983", character_set_t::iso_646_basic_1983 },
+ { "csiso646danish", character_set_t::ds_2089 },
+ { "csiso6937add", character_set_t::iso_6937_2_25 },
+ { "csiso69french", character_set_t::nf_z_62_010 },
+ { "csiso70videotexsupp1", character_set_t::videotex_suppl },
+ { "csiso84portuguese2", character_set_t::pt2 },
+ { "csiso85spanish2", character_set_t::es2 },
+ { "csiso86hungarian", character_set_t::msz_7795_3 },
+ { "csiso87jisx0208", character_set_t::jis_c6226_1983 },
+ { "csiso885913", character_set_t::iso_8859_13 },
+ { "csiso885914", character_set_t::iso_8859_14 },
+ { "csiso885915", character_set_t::iso_8859_15 },
+ { "csiso885916", character_set_t::iso_8859_16 },
+ { "csiso88596e", character_set_t::iso_8859_6_e },
+ { "csiso88596i", character_set_t::iso_8859_6_i },
+ { "csiso88598e", character_set_t::iso_8859_8_e },
+ { "csiso88598i", character_set_t::iso_8859_8_i },
+ { "csiso8859supp", character_set_t::iso_8859_supp },
+ { "csiso88greek7", character_set_t::greek7 },
+ { "csiso89asmo449", character_set_t::asmo_449 },
+ { "csiso90", character_set_t::iso_ir_90 },
+ { "csiso91jisc62291984a", character_set_t::jis_c6229_1984_a },
+ { "csiso92jisc62991984b", character_set_t::jis_c6229_1984_b },
+ { "csiso93jis62291984badd", character_set_t::jis_c6229_1984_b_add },
+ { "csiso94jis62291984hand", character_set_t::jis_c6229_1984_hand },
+ { "csiso95jis62291984handadd", character_set_t::jis_c6229_1984_hand_add },
+ { "csiso96jisc62291984kana", character_set_t::jis_c6229_1984_kana },
+ { "csiso99naplps", character_set_t::ansi_x3_110_1983 },
+ { "csisolatin1", character_set_t::iso_8859_1 },
+ { "csisolatin2", character_set_t::iso_8859_2 },
+ { "csisolatin3", character_set_t::iso_8859_3 },
+ { "csisolatin4", character_set_t::iso_8859_4 },
+ { "csisolatin5", character_set_t::iso_8859_9 },
+ { "csisolatin6", character_set_t::iso_8859_10 },
+ { "csisolatinarabic", character_set_t::iso_8859_6 },
+ { "csisolatincyrillic", character_set_t::iso_8859_5 },
+ { "csisolatingreek", character_set_t::iso_8859_7 },
+ { "csisolatinhebrew", character_set_t::iso_8859_8 },
+ { "csisotextcomm", character_set_t::iso_6937_2_add },
+ { "csjisencoding", character_set_t::jis_encoding },
+ { "cskoi7switched", character_set_t::koi7_switched },
+ { "cskoi8r", character_set_t::koi8_r },
+ { "cskoi8u", character_set_t::koi8_u },
+ { "csksc56011987", character_set_t::ks_c_5601_1987 },
+ { "csksc5636", character_set_t::ksc5636 },
+ { "cskz1048", character_set_t::kz_1048 },
+ { "csmacintosh", character_set_t::macintosh },
+ { "csmicrosoftpublishing", character_set_t::microsoft_publishing },
+ { "csmnem", character_set_t::mnem },
+ { "csmnemonic", character_set_t::mnemonic },
+ { "csn_369103", character_set_t::csn_369103 },
+ { "csnatsdano", character_set_t::nats_dano },
+ { "csnatsdanoadd", character_set_t::nats_dano_add },
+ { "csnatssefi", character_set_t::nats_sefi },
+ { "csnatssefiadd", character_set_t::nats_sefi_add },
+ { "csosdebcdicdf03irv", character_set_t::osd_ebcdic_df03_irv },
+ { "csosdebcdicdf041", character_set_t::osd_ebcdic_df04_1 },
+ { "csosdebcdicdf0415", character_set_t::osd_ebcdic_df04_15 },
+ { "cspc775baltic", character_set_t::ibm775 },
+ { "cspc850multilingual", character_set_t::ibm850 },
+ { "cspc862latinhebrew", character_set_t::ibm862 },
+ { "cspc8codepage437", character_set_t::ibm437 },
+ { "cspc8danishnorwegian", character_set_t::pc8_danish_norwegian },
+ { "cspc8turkish", character_set_t::pc8_turkish },
+ { "cspcp852", character_set_t::ibm852 },
+ { "csptcp154", character_set_t::ptcp154 },
+ { "csscsu", character_set_t::scsu },
+ { "csshiftjis", character_set_t::shift_jis },
+ { "cstis620", character_set_t::tis_620 },
+ { "cstscii", character_set_t::tscii },
+ { "csucs4", character_set_t::iso_10646_ucs_4 },
+ { "csunicode", character_set_t::iso_10646_ucs_2 },
+ { "csunicode11", character_set_t::unicode_1_1 },
+ { "csunicode11utf7", character_set_t::unicode_1_1_utf_7 },
+ { "csunicodeascii", character_set_t::iso_10646_ucs_basic },
+ { "csunicodeibm1261", character_set_t::iso_unicode_ibm_1261 },
+ { "csunicodeibm1264", character_set_t::iso_unicode_ibm_1264 },
+ { "csunicodeibm1265", character_set_t::iso_unicode_ibm_1265 },
+ { "csunicodeibm1268", character_set_t::iso_unicode_ibm_1268 },
+ { "csunicodeibm1276", character_set_t::iso_unicode_ibm_1276 },
+ { "csunicodejapanese", character_set_t::iso_10646_j_1 },
+ { "csunicodelatin1", character_set_t::iso_10646_unicode_latin1 },
+ { "csunknown8bit", character_set_t::unknown_8bit },
+ { "csusdk", character_set_t::us_dk },
+ { "csutf16", character_set_t::utf_16 },
+ { "csutf16be", character_set_t::utf_16be },
+ { "csutf16le", character_set_t::utf_16le },
+ { "csutf32", character_set_t::utf_32 },
+ { "csutf32be", character_set_t::utf_32be },
+ { "csutf32le", character_set_t::utf_32le },
+ { "csutf7", character_set_t::utf_7 },
+ { "csutf7imap", character_set_t::utf_7_imap },
+ { "csutf8", character_set_t::utf_8 },
+ { "csventurainternational", character_set_t::ventura_international },
+ { "csventuramath", character_set_t::ventura_math },
+ { "csventuraus", character_set_t::ventura_us },
+ { "csviqr", character_set_t::viqr },
+ { "csviscii", character_set_t::viscii },
+ { "cswindows1250", character_set_t::windows_1250 },
+ { "cswindows1251", character_set_t::windows_1251 },
+ { "cswindows1252", character_set_t::windows_1252 },
+ { "cswindows1253", character_set_t::windows_1253 },
+ { "cswindows1254", character_set_t::windows_1254 },
+ { "cswindows1255", character_set_t::windows_1255 },
+ { "cswindows1256", character_set_t::windows_1256 },
+ { "cswindows1257", character_set_t::windows_1257 },
+ { "cswindows1258", character_set_t::windows_1258 },
+ { "cswindows30latin1", character_set_t::iso_8859_1_windows_3_0_latin_1 },
+ { "cswindows31j", character_set_t::windows_31j },
+ { "cswindows31latin1", character_set_t::iso_8859_1_windows_3_1_latin_1 },
+ { "cswindows31latin2", character_set_t::iso_8859_2_windows_latin_2 },
+ { "cswindows31latin5", character_set_t::iso_8859_9_windows_latin_5 },
+ { "cswindows874", character_set_t::windows_874 },
+ { "cuba", character_set_t::nc_nc00_10_81 },
+ { "cyrillic", character_set_t::iso_8859_5 },
+ { "cyrillic-asian", character_set_t::ptcp154 },
+ { "de", character_set_t::din_66003 },
+ { "dec", character_set_t::dec_mcs },
+ { "dec-mcs", character_set_t::dec_mcs },
+ { "din_66003", character_set_t::din_66003 },
+ { "dk", character_set_t::ds_2089 },
+ { "dk-us", character_set_t::dk_us },
+ { "ds2089", character_set_t::ds_2089 },
+ { "ds_2089", character_set_t::ds_2089 },
+ { "e13b", character_set_t::iso_2033_1983 },
+ { "ebcdic-at-de", character_set_t::ebcdic_at_de },
+ { "ebcdic-at-de-a", character_set_t::ebcdic_at_de_a },
+ { "ebcdic-be", character_set_t::ibm274 },
+ { "ebcdic-br", character_set_t::ibm275 },
+ { "ebcdic-ca-fr", character_set_t::ebcdic_ca_fr },
+ { "ebcdic-cp-ar1", character_set_t::ibm420 },
+ { "ebcdic-cp-ar2", character_set_t::ibm918 },
+ { "ebcdic-cp-be", character_set_t::ibm500 },
+ { "ebcdic-cp-ca", character_set_t::ibm037 },
+ { "ebcdic-cp-ch", character_set_t::ibm500 },
+ { "ebcdic-cp-dk", character_set_t::ibm277 },
+ { "ebcdic-cp-es", character_set_t::ibm284 },
+ { "ebcdic-cp-fi", character_set_t::ibm278 },
+ { "ebcdic-cp-fr", character_set_t::ibm297 },
+ { "ebcdic-cp-gb", character_set_t::ibm285 },
+ { "ebcdic-cp-gr", character_set_t::ibm423 },
+ { "ebcdic-cp-he", character_set_t::ibm424 },
+ { "ebcdic-cp-is", character_set_t::ibm871 },
+ { "ebcdic-cp-it", character_set_t::ibm280 },
+ { "ebcdic-cp-nl", character_set_t::ibm037 },
+ { "ebcdic-cp-no", character_set_t::ibm277 },
+ { "ebcdic-cp-roece", character_set_t::ibm870 },
+ { "ebcdic-cp-se", character_set_t::ibm278 },
+ { "ebcdic-cp-tr", character_set_t::ibm905 },
+ { "ebcdic-cp-us", character_set_t::ibm037 },
+ { "ebcdic-cp-wt", character_set_t::ibm037 },
+ { "ebcdic-cp-yu", character_set_t::ibm870 },
+ { "ebcdic-cyrillic", character_set_t::ibm880 },
+ { "ebcdic-de-273+euro", character_set_t::ibm01141 },
+ { "ebcdic-dk-277+euro", character_set_t::ibm01142 },
+ { "ebcdic-dk-no", character_set_t::ebcdic_dk_no },
+ { "ebcdic-dk-no-a", character_set_t::ebcdic_dk_no_a },
+ { "ebcdic-es", character_set_t::ebcdic_es },
+ { "ebcdic-es-284+euro", character_set_t::ibm01145 },
+ { "ebcdic-es-a", character_set_t::ebcdic_es_a },
+ { "ebcdic-es-s", character_set_t::ebcdic_es_s },
+ { "ebcdic-fi-278+euro", character_set_t::ibm01143 },
+ { "ebcdic-fi-se", character_set_t::ebcdic_fi_se },
+ { "ebcdic-fi-se-a", character_set_t::ebcdic_fi_se_a },
+ { "ebcdic-fr", character_set_t::ebcdic_fr },
+ { "ebcdic-fr-297+euro", character_set_t::ibm01147 },
+ { "ebcdic-gb-285+euro", character_set_t::ibm01146 },
+ { "ebcdic-int", character_set_t::ibm038 },
+ { "ebcdic-international-500+euro", character_set_t::ibm01148 },
+ { "ebcdic-is-871+euro", character_set_t::ibm01149 },
+ { "ebcdic-it", character_set_t::ebcdic_it },
+ { "ebcdic-it-280+euro", character_set_t::ibm01144 },
+ { "ebcdic-jp-e", character_set_t::ibm281 },
+ { "ebcdic-jp-kana", character_set_t::ibm290 },
+ { "ebcdic-latin9--euro", character_set_t::ibm00924 },
+ { "ebcdic-no-277+euro", character_set_t::ibm01142 },
+ { "ebcdic-pt", character_set_t::ebcdic_pt },
+ { "ebcdic-se-278+euro", character_set_t::ibm01143 },
+ { "ebcdic-uk", character_set_t::ebcdic_uk },
+ { "ebcdic-us", character_set_t::ebcdic_us },
+ { "ebcdic-us-37+euro", character_set_t::ibm01140 },
+ { "ecma-114", character_set_t::iso_8859_6 },
+ { "ecma-118", character_set_t::iso_8859_7 },
+ { "ecma-cyrillic", character_set_t::ecma_cyrillic },
+ { "elot_928", character_set_t::iso_8859_7 },
+ { "es", character_set_t::es },
+ { "es2", character_set_t::es2 },
+ { "euc-jp", character_set_t::euc_jp },
+ { "euc-kr", character_set_t::euc_kr },
+ { "extended_unix_code_fixed_width_for_japanese", character_set_t::extended_unix_code_fixed_width_for_japanese },
+ { "extended_unix_code_packed_format_for_japanese", character_set_t::euc_jp },
+ { "fi", character_set_t::sen_850200_b },
+ { "fr", character_set_t::nf_z_62_010 },
+ { "gb", character_set_t::bs_4730 },
+ { "gb18030", character_set_t::gb18030 },
+ { "gb2312", character_set_t::gb2312 },
+ { "gb_1988-80", character_set_t::gb_1988_80 },
+ { "gb_2312-80", character_set_t::gb_2312_80 },
+ { "gbk", character_set_t::gbk },
+ { "gost_19768-74", character_set_t::gost_19768_74 },
+ { "greek", character_set_t::iso_8859_7 },
+ { "greek-ccitt", character_set_t::greek_ccitt },
+ { "greek7", character_set_t::greek7 },
+ { "greek7-old", character_set_t::greek7_old },
+ { "greek8", character_set_t::iso_8859_7 },
+ { "hebrew", character_set_t::iso_8859_8 },
+ { "hp-desktop", character_set_t::hp_desktop },
+ { "hp-legal", character_set_t::hp_legal },
+ { "hp-math8", character_set_t::hp_math8 },
+ { "hp-pi-font", character_set_t::hp_pi_font },
+ { "hp-roman8", character_set_t::hp_roman8 },
+ { "hu", character_set_t::msz_7795_3 },
+ { "hz-gb-2312", character_set_t::hz_gb_2312 },
+ { "ibm-1047", character_set_t::ibm1047 },
+ { "ibm-symbols", character_set_t::ibm_symbols },
+ { "ibm-thai", character_set_t::ibm_thai },
+ { "ibm00858", character_set_t::ibm00858 },
+ { "ibm00924", character_set_t::ibm00924 },
+ { "ibm01140", character_set_t::ibm01140 },
+ { "ibm01141", character_set_t::ibm01141 },
+ { "ibm01142", character_set_t::ibm01142 },
+ { "ibm01143", character_set_t::ibm01143 },
+ { "ibm01144", character_set_t::ibm01144 },
+ { "ibm01145", character_set_t::ibm01145 },
+ { "ibm01146", character_set_t::ibm01146 },
+ { "ibm01147", character_set_t::ibm01147 },
+ { "ibm01148", character_set_t::ibm01148 },
+ { "ibm01149", character_set_t::ibm01149 },
+ { "ibm037", character_set_t::ibm037 },
+ { "ibm038", character_set_t::ibm038 },
+ { "ibm1026", character_set_t::ibm1026 },
+ { "ibm1047", character_set_t::ibm1047 },
+ { "ibm273", character_set_t::ibm273 },
+ { "ibm274", character_set_t::ibm274 },
+ { "ibm275", character_set_t::ibm275 },
+ { "ibm277", character_set_t::ibm277 },
+ { "ibm278", character_set_t::ibm278 },
+ { "ibm280", character_set_t::ibm280 },
+ { "ibm281", character_set_t::ibm281 },
+ { "ibm284", character_set_t::ibm284 },
+ { "ibm285", character_set_t::ibm285 },
+ { "ibm290", character_set_t::ibm290 },
+ { "ibm297", character_set_t::ibm297 },
+ { "ibm367", character_set_t::us_ascii },
+ { "ibm420", character_set_t::ibm420 },
+ { "ibm423", character_set_t::ibm423 },
+ { "ibm424", character_set_t::ibm424 },
+ { "ibm437", character_set_t::ibm437 },
+ { "ibm500", character_set_t::ibm500 },
+ { "ibm775", character_set_t::ibm775 },
+ { "ibm819", character_set_t::iso_8859_1 },
+ { "ibm850", character_set_t::ibm850 },
+ { "ibm851", character_set_t::ibm851 },
+ { "ibm852", character_set_t::ibm852 },
+ { "ibm855", character_set_t::ibm855 },
+ { "ibm857", character_set_t::ibm857 },
+ { "ibm860", character_set_t::ibm860 },
+ { "ibm861", character_set_t::ibm861 },
+ { "ibm862", character_set_t::ibm862 },
+ { "ibm863", character_set_t::ibm863 },
+ { "ibm864", character_set_t::ibm864 },
+ { "ibm865", character_set_t::ibm865 },
+ { "ibm866", character_set_t::ibm866 },
+ { "ibm868", character_set_t::ibm868 },
+ { "ibm869", character_set_t::ibm869 },
+ { "ibm870", character_set_t::ibm870 },
+ { "ibm871", character_set_t::ibm871 },
+ { "ibm880", character_set_t::ibm880 },
+ { "ibm891", character_set_t::ibm891 },
+ { "ibm903", character_set_t::ibm903 },
+ { "ibm904", character_set_t::ibm904 },
+ { "ibm905", character_set_t::ibm905 },
+ { "ibm918", character_set_t::ibm918 },
+ { "iec_p27-1", character_set_t::iec_p27_1 },
+ { "inis", character_set_t::inis },
+ { "inis-8", character_set_t::inis_8 },
+ { "inis-cyrillic", character_set_t::inis_cyrillic },
+ { "invariant", character_set_t::invariant },
+ { "irv", character_set_t::iso_646_irv_1983 },
+ { "iso-10646", character_set_t::iso_10646_unicode_latin1 },
+ { "iso-10646-j-1", character_set_t::iso_10646_j_1 },
+ { "iso-10646-ucs-2", character_set_t::iso_10646_ucs_2 },
+ { "iso-10646-ucs-4", character_set_t::iso_10646_ucs_4 },
+ { "iso-10646-ucs-basic", character_set_t::iso_10646_ucs_basic },
+ { "iso-10646-unicode-latin1", character_set_t::iso_10646_unicode_latin1 },
+ { "iso-10646-utf-1", character_set_t::iso_10646_utf_1 },
+ { "iso-11548-1", character_set_t::iso_11548_1 },
+ { "iso-2022-cn", character_set_t::iso_2022_cn },
+ { "iso-2022-cn-ext", character_set_t::iso_2022_cn_ext },
+ { "iso-2022-jp", character_set_t::iso_2022_jp },
+ { "iso-2022-jp-2", character_set_t::iso_2022_jp_2 },
+ { "iso-2022-kr", character_set_t::iso_2022_kr },
+ { "iso-8859-1", character_set_t::iso_8859_1 },
+ { "iso-8859-1-windows-3.0-latin-1", character_set_t::iso_8859_1_windows_3_0_latin_1 },
+ { "iso-8859-1-windows-3.1-latin-1", character_set_t::iso_8859_1_windows_3_1_latin_1 },
+ { "iso-8859-10", character_set_t::iso_8859_10 },
+ { "iso-8859-11", character_set_t::tis_620 },
+ { "iso-8859-13", character_set_t::iso_8859_13 },
+ { "iso-8859-14", character_set_t::iso_8859_14 },
+ { "iso-8859-15", character_set_t::iso_8859_15 },
+ { "iso-8859-16", character_set_t::iso_8859_16 },
+ { "iso-8859-2", character_set_t::iso_8859_2 },
+ { "iso-8859-2-windows-latin-2", character_set_t::iso_8859_2_windows_latin_2 },
+ { "iso-8859-3", character_set_t::iso_8859_3 },
+ { "iso-8859-4", character_set_t::iso_8859_4 },
+ { "iso-8859-5", character_set_t::iso_8859_5 },
+ { "iso-8859-6", character_set_t::iso_8859_6 },
+ { "iso-8859-6-e", character_set_t::iso_8859_6_e },
+ { "iso-8859-6-i", character_set_t::iso_8859_6_i },
+ { "iso-8859-7", character_set_t::iso_8859_7 },
+ { "iso-8859-8", character_set_t::iso_8859_8 },
+ { "iso-8859-8-e", character_set_t::iso_8859_8_e },
+ { "iso-8859-8-i", character_set_t::iso_8859_8_i },
+ { "iso-8859-9", character_set_t::iso_8859_9 },
+ { "iso-8859-9-windows-latin-5", character_set_t::iso_8859_9_windows_latin_5 },
+ { "iso-celtic", character_set_t::iso_8859_14 },
+ { "iso-ir-10", character_set_t::sen_850200_b },
+ { "iso-ir-100", character_set_t::iso_8859_1 },
+ { "iso-ir-101", character_set_t::iso_8859_2 },
+ { "iso-ir-102", character_set_t::t_61_7bit },
+ { "iso-ir-103", character_set_t::t_61_8bit },
+ { "iso-ir-109", character_set_t::iso_8859_3 },
+ { "iso-ir-11", character_set_t::sen_850200_c },
+ { "iso-ir-110", character_set_t::iso_8859_4 },
+ { "iso-ir-111", character_set_t::ecma_cyrillic },
+ { "iso-ir-121", character_set_t::csa_z243_4_1985_1 },
+ { "iso-ir-122", character_set_t::csa_z243_4_1985_2 },
+ { "iso-ir-123", character_set_t::csa_z243_4_1985_gr },
+ { "iso-ir-126", character_set_t::iso_8859_7 },
+ { "iso-ir-127", character_set_t::iso_8859_6 },
+ { "iso-ir-128", character_set_t::t_101_g2 },
+ { "iso-ir-13", character_set_t::jis_c6220_1969_jp },
+ { "iso-ir-138", character_set_t::iso_8859_8 },
+ { "iso-ir-139", character_set_t::csn_369103 },
+ { "iso-ir-14", character_set_t::jis_c6220_1969_ro },
+ { "iso-ir-141", character_set_t::jus_i_b1_002 },
+ { "iso-ir-142", character_set_t::iso_6937_2_add },
+ { "iso-ir-143", character_set_t::iec_p27_1 },
+ { "iso-ir-144", character_set_t::iso_8859_5 },
+ { "iso-ir-146", character_set_t::jus_i_b1_003_serb },
+ { "iso-ir-147", character_set_t::jus_i_b1_003_mac },
+ { "iso-ir-148", character_set_t::iso_8859_9 },
+ { "iso-ir-149", character_set_t::ks_c_5601_1987 },
+ { "iso-ir-15", character_set_t::it },
+ { "iso-ir-150", character_set_t::greek_ccitt },
+ { "iso-ir-151", character_set_t::nc_nc00_10_81 },
+ { "iso-ir-152", character_set_t::iso_6937_2_25 },
+ { "iso-ir-153", character_set_t::gost_19768_74 },
+ { "iso-ir-154", character_set_t::iso_8859_supp },
+ { "iso-ir-155", character_set_t::iso_10367_box },
+ { "iso-ir-157", character_set_t::iso_8859_10 },
+ { "iso-ir-158", character_set_t::latin_lap },
+ { "iso-ir-159", character_set_t::jis_x0212_1990 },
+ { "iso-ir-16", character_set_t::pt },
+ { "iso-ir-17", character_set_t::es },
+ { "iso-ir-18", character_set_t::greek7_old },
+ { "iso-ir-19", character_set_t::latin_greek },
+ { "iso-ir-199", character_set_t::iso_8859_14 },
+ { "iso-ir-2", character_set_t::iso_646_irv_1983 },
+ { "iso-ir-21", character_set_t::din_66003 },
+ { "iso-ir-226", character_set_t::iso_8859_16 },
+ { "iso-ir-25", character_set_t::nf_z_62_010_1973 },
+ { "iso-ir-27", character_set_t::latin_greek_1 },
+ { "iso-ir-37", character_set_t::iso_5427 },
+ { "iso-ir-4", character_set_t::bs_4730 },
+ { "iso-ir-42", character_set_t::jis_c6226_1978 },
+ { "iso-ir-47", character_set_t::bs_viewdata },
+ { "iso-ir-49", character_set_t::inis },
+ { "iso-ir-50", character_set_t::inis_8 },
+ { "iso-ir-51", character_set_t::inis_cyrillic },
+ { "iso-ir-54", character_set_t::iso_5427_1981 },
+ { "iso-ir-55", character_set_t::iso_5428_1980 },
+ { "iso-ir-57", character_set_t::gb_1988_80 },
+ { "iso-ir-58", character_set_t::gb_2312_80 },
+ { "iso-ir-6", character_set_t::us_ascii },
+ { "iso-ir-60", character_set_t::ns_4551_1 },
+ { "iso-ir-61", character_set_t::ns_4551_2 },
+ { "iso-ir-69", character_set_t::nf_z_62_010 },
+ { "iso-ir-70", character_set_t::videotex_suppl },
+ { "iso-ir-8-1", character_set_t::nats_sefi },
+ { "iso-ir-8-2", character_set_t::nats_sefi_add },
+ { "iso-ir-84", character_set_t::pt2 },
+ { "iso-ir-85", character_set_t::es2 },
+ { "iso-ir-86", character_set_t::msz_7795_3 },
+ { "iso-ir-87", character_set_t::jis_c6226_1983 },
+ { "iso-ir-88", character_set_t::greek7 },
+ { "iso-ir-89", character_set_t::asmo_449 },
+ { "iso-ir-9-1", character_set_t::nats_dano },
+ { "iso-ir-9-2", character_set_t::nats_dano_add },
+ { "iso-ir-90", character_set_t::iso_ir_90 },
+ { "iso-ir-91", character_set_t::jis_c6229_1984_a },
+ { "iso-ir-92", character_set_t::jis_c6229_1984_b },
+ { "iso-ir-93", character_set_t::jis_c6229_1984_b_add },
+ { "iso-ir-94", character_set_t::jis_c6229_1984_hand },
+ { "iso-ir-95", character_set_t::jis_c6229_1984_hand_add },
+ { "iso-ir-96", character_set_t::jis_c6229_1984_kana },
+ { "iso-ir-98", character_set_t::iso_2033_1983 },
+ { "iso-ir-99", character_set_t::ansi_x3_110_1983 },
+ { "iso-unicode-ibm-1261", character_set_t::iso_unicode_ibm_1261 },
+ { "iso-unicode-ibm-1264", character_set_t::iso_unicode_ibm_1264 },
+ { "iso-unicode-ibm-1265", character_set_t::iso_unicode_ibm_1265 },
+ { "iso-unicode-ibm-1268", character_set_t::iso_unicode_ibm_1268 },
+ { "iso-unicode-ibm-1276", character_set_t::iso_unicode_ibm_1276 },
+ { "iso5427cyrillic1981", character_set_t::iso_5427_1981 },
+ { "iso646-ca", character_set_t::csa_z243_4_1985_1 },
+ { "iso646-ca2", character_set_t::csa_z243_4_1985_2 },
+ { "iso646-cn", character_set_t::gb_1988_80 },
+ { "iso646-cu", character_set_t::nc_nc00_10_81 },
+ { "iso646-de", character_set_t::din_66003 },
+ { "iso646-dk", character_set_t::ds_2089 },
+ { "iso646-es", character_set_t::es },
+ { "iso646-es2", character_set_t::es2 },
+ { "iso646-fi", character_set_t::sen_850200_b },
+ { "iso646-fr", character_set_t::nf_z_62_010 },
+ { "iso646-fr1", character_set_t::nf_z_62_010_1973 },
+ { "iso646-gb", character_set_t::bs_4730 },
+ { "iso646-hu", character_set_t::msz_7795_3 },
+ { "iso646-it", character_set_t::it },
+ { "iso646-jp", character_set_t::jis_c6220_1969_ro },
+ { "iso646-jp-ocr-b", character_set_t::jis_c6229_1984_b },
+ { "iso646-kr", character_set_t::ksc5636 },
+ { "iso646-no", character_set_t::ns_4551_1 },
+ { "iso646-no2", character_set_t::ns_4551_2 },
+ { "iso646-pt", character_set_t::pt },
+ { "iso646-pt2", character_set_t::pt2 },
+ { "iso646-se", character_set_t::sen_850200_b },
+ { "iso646-se2", character_set_t::sen_850200_c },
+ { "iso646-us", character_set_t::us_ascii },
+ { "iso646-yu", character_set_t::jus_i_b1_002 },
+ { "iso_10367-box", character_set_t::iso_10367_box },
+ { "iso_11548-1", character_set_t::iso_11548_1 },
+ { "iso_2033-1983", character_set_t::iso_2033_1983 },
+ { "iso_5427", character_set_t::iso_5427 },
+ { "iso_5427:1981", character_set_t::iso_5427_1981 },
+ { "iso_5428:1980", character_set_t::iso_5428_1980 },
+ { "iso_646.basic:1983", character_set_t::iso_646_basic_1983 },
+ { "iso_646.irv:1983", character_set_t::iso_646_irv_1983 },
+ { "iso_646.irv:1991", character_set_t::us_ascii },
+ { "iso_6937-2-25", character_set_t::iso_6937_2_25 },
+ { "iso_6937-2-add", character_set_t::iso_6937_2_add },
+ { "iso_8859-1", character_set_t::iso_8859_1 },
+ { "iso_8859-10:1992", character_set_t::iso_8859_10 },
+ { "iso_8859-14", character_set_t::iso_8859_14 },
+ { "iso_8859-14:1998", character_set_t::iso_8859_14 },
+ { "iso_8859-15", character_set_t::iso_8859_15 },
+ { "iso_8859-16", character_set_t::iso_8859_16 },
+ { "iso_8859-16:2001", character_set_t::iso_8859_16 },
+ { "iso_8859-1:1987", character_set_t::iso_8859_1 },
+ { "iso_8859-2", character_set_t::iso_8859_2 },
+ { "iso_8859-2:1987", character_set_t::iso_8859_2 },
+ { "iso_8859-3", character_set_t::iso_8859_3 },
+ { "iso_8859-3:1988", character_set_t::iso_8859_3 },
+ { "iso_8859-4", character_set_t::iso_8859_4 },
+ { "iso_8859-4:1988", character_set_t::iso_8859_4 },
+ { "iso_8859-5", character_set_t::iso_8859_5 },
+ { "iso_8859-5:1988", character_set_t::iso_8859_5 },
+ { "iso_8859-6", character_set_t::iso_8859_6 },
+ { "iso_8859-6-e", character_set_t::iso_8859_6_e },
+ { "iso_8859-6-i", character_set_t::iso_8859_6_i },
+ { "iso_8859-6:1987", character_set_t::iso_8859_6 },
+ { "iso_8859-7", character_set_t::iso_8859_7 },
+ { "iso_8859-7:1987", character_set_t::iso_8859_7 },
+ { "iso_8859-8", character_set_t::iso_8859_8 },
+ { "iso_8859-8-e", character_set_t::iso_8859_8_e },
+ { "iso_8859-8-i", character_set_t::iso_8859_8_i },
+ { "iso_8859-8:1988", character_set_t::iso_8859_8 },
+ { "iso_8859-9", character_set_t::iso_8859_9 },
+ { "iso_8859-9:1989", character_set_t::iso_8859_9 },
+ { "iso_8859-supp", character_set_t::iso_8859_supp },
+ { "iso_9036", character_set_t::asmo_449 },
+ { "iso_tr_11548-1", character_set_t::iso_11548_1 },
+ { "it", character_set_t::it },
+ { "jis_c6220-1969", character_set_t::jis_c6220_1969_jp },
+ { "jis_c6220-1969-jp", character_set_t::jis_c6220_1969_jp },
+ { "jis_c6220-1969-ro", character_set_t::jis_c6220_1969_ro },
+ { "jis_c6226-1978", character_set_t::jis_c6226_1978 },
+ { "jis_c6226-1983", character_set_t::jis_c6226_1983 },
+ { "jis_c6229-1984-a", character_set_t::jis_c6229_1984_a },
+ { "jis_c6229-1984-b", character_set_t::jis_c6229_1984_b },
+ { "jis_c6229-1984-b-add", character_set_t::jis_c6229_1984_b_add },
+ { "jis_c6229-1984-hand", character_set_t::jis_c6229_1984_hand },
+ { "jis_c6229-1984-hand-add", character_set_t::jis_c6229_1984_hand_add },
+ { "jis_c6229-1984-kana", character_set_t::jis_c6229_1984_kana },
+ { "jis_encoding", character_set_t::jis_encoding },
+ { "jis_x0201", character_set_t::jis_x0201 },
+ { "jis_x0208-1983", character_set_t::jis_c6226_1983 },
+ { "jis_x0212-1990", character_set_t::jis_x0212_1990 },
+ { "jp", character_set_t::jis_c6220_1969_ro },
+ { "jp-ocr-a", character_set_t::jis_c6229_1984_a },
+ { "jp-ocr-b", character_set_t::jis_c6229_1984_b },
+ { "jp-ocr-b-add", character_set_t::jis_c6229_1984_b_add },
+ { "jp-ocr-hand", character_set_t::jis_c6229_1984_hand },
+ { "jp-ocr-hand-add", character_set_t::jis_c6229_1984_hand_add },
+ { "js", character_set_t::jus_i_b1_002 },
+ { "jus_i.b1.002", character_set_t::jus_i_b1_002 },
+ { "jus_i.b1.003-mac", character_set_t::jus_i_b1_003_mac },
+ { "jus_i.b1.003-serb", character_set_t::jus_i_b1_003_serb },
+ { "katakana", character_set_t::jis_c6220_1969_jp },
+ { "koi7-switched", character_set_t::koi7_switched },
+ { "koi8-e", character_set_t::ecma_cyrillic },
+ { "koi8-r", character_set_t::koi8_r },
+ { "koi8-u", character_set_t::koi8_u },
+ { "korean", character_set_t::ks_c_5601_1987 },
+ { "ks_c_5601-1987", character_set_t::ks_c_5601_1987 },
+ { "ks_c_5601-1989", character_set_t::ks_c_5601_1987 },
+ { "ksc5636", character_set_t::ksc5636 },
+ { "ksc_5601", character_set_t::ks_c_5601_1987 },
+ { "kz-1048", character_set_t::kz_1048 },
+ { "l1", character_set_t::iso_8859_1 },
+ { "l10", character_set_t::iso_8859_16 },
+ { "l2", character_set_t::iso_8859_2 },
+ { "l3", character_set_t::iso_8859_3 },
+ { "l4", character_set_t::iso_8859_4 },
+ { "l5", character_set_t::iso_8859_9 },
+ { "l6", character_set_t::iso_8859_10 },
+ { "l8", character_set_t::iso_8859_14 },
+ { "lap", character_set_t::latin_lap },
+ { "latin-9", character_set_t::iso_8859_15 },
+ { "latin-greek", character_set_t::latin_greek },
+ { "latin-greek-1", character_set_t::latin_greek_1 },
+ { "latin-lap", character_set_t::latin_lap },
+ { "latin1", character_set_t::iso_8859_1 },
+ { "latin1-2-5", character_set_t::iso_8859_supp },
+ { "latin10", character_set_t::iso_8859_16 },
+ { "latin2", character_set_t::iso_8859_2 },
+ { "latin3", character_set_t::iso_8859_3 },
+ { "latin4", character_set_t::iso_8859_4 },
+ { "latin5", character_set_t::iso_8859_9 },
+ { "latin6", character_set_t::iso_8859_10 },
+ { "latin8", character_set_t::iso_8859_14 },
+ { "mac", character_set_t::macintosh },
+ { "macedonian", character_set_t::jus_i_b1_003_mac },
+ { "macintosh", character_set_t::macintosh },
+ { "microsoft-publishing", character_set_t::microsoft_publishing },
+ { "mnem", character_set_t::mnem },
+ { "mnemonic", character_set_t::mnemonic },
+ { "ms936", character_set_t::gbk },
+ { "ms_kanji", character_set_t::shift_jis },
+ { "msz_7795.3", character_set_t::msz_7795_3 },
+ { "naplps", character_set_t::ansi_x3_110_1983 },
+ { "nats-dano", character_set_t::nats_dano },
+ { "nats-dano-add", character_set_t::nats_dano_add },
+ { "nats-sefi", character_set_t::nats_sefi },
+ { "nats-sefi-add", character_set_t::nats_sefi_add },
+ { "nc_nc00-10:81", character_set_t::nc_nc00_10_81 },
+ { "nf_z_62-010", character_set_t::nf_z_62_010 },
+ { "nf_z_62-010_(1973)", character_set_t::nf_z_62_010_1973 },
+ { "no", character_set_t::ns_4551_1 },
+ { "no2", character_set_t::ns_4551_2 },
+ { "ns_4551-1", character_set_t::ns_4551_1 },
+ { "ns_4551-2", character_set_t::ns_4551_2 },
+ { "osd_ebcdic_df03_irv", character_set_t::osd_ebcdic_df03_irv },
+ { "osd_ebcdic_df04_1", character_set_t::osd_ebcdic_df04_1 },
+ { "osd_ebcdic_df04_15", character_set_t::osd_ebcdic_df04_15 },
+ { "pc-multilingual-850+euro", character_set_t::ibm00858 },
+ { "pc8-danish-norwegian", character_set_t::pc8_danish_norwegian },
+ { "pc8-turkish", character_set_t::pc8_turkish },
+ { "pt", character_set_t::pt },
+ { "pt154", character_set_t::ptcp154 },
+ { "pt2", character_set_t::pt2 },
+ { "ptcp154", character_set_t::ptcp154 },
+ { "r8", character_set_t::hp_roman8 },
+ { "ref", character_set_t::iso_646_basic_1983 },
+ { "rk1048", character_set_t::kz_1048 },
+ { "roman8", character_set_t::hp_roman8 },
+ { "scsu", character_set_t::scsu },
+ { "se", character_set_t::sen_850200_b },
+ { "se2", character_set_t::sen_850200_c },
+ { "sen_850200_b", character_set_t::sen_850200_b },
+ { "sen_850200_c", character_set_t::sen_850200_c },
+ { "serbian", character_set_t::jus_i_b1_003_serb },
+ { "shift_jis", character_set_t::shift_jis },
+ { "st_sev_358-88", character_set_t::gost_19768_74 },
+ { "strk1048-2002", character_set_t::kz_1048 },
+ { "t.101-g2", character_set_t::t_101_g2 },
+ { "t.61", character_set_t::t_61_8bit },
+ { "t.61-7bit", character_set_t::t_61_7bit },
+ { "t.61-8bit", character_set_t::t_61_8bit },
+ { "tis-620", character_set_t::tis_620 },
+ { "tscii", character_set_t::tscii },
+ { "uk", character_set_t::bs_4730 },
+ { "unicode-1-1", character_set_t::unicode_1_1 },
+ { "unicode-1-1-utf-7", character_set_t::unicode_1_1_utf_7 },
+ { "unknown-8bit", character_set_t::unknown_8bit },
+ { "us", character_set_t::us_ascii },
+ { "us-ascii", character_set_t::us_ascii },
+ { "us-dk", character_set_t::us_dk },
+ { "utf-16", character_set_t::utf_16 },
+ { "utf-16be", character_set_t::utf_16be },
+ { "utf-16le", character_set_t::utf_16le },
+ { "utf-32", character_set_t::utf_32 },
+ { "utf-32be", character_set_t::utf_32be },
+ { "utf-32le", character_set_t::utf_32le },
+ { "utf-7", character_set_t::utf_7 },
+ { "utf-7-imap", character_set_t::utf_7_imap },
+ { "utf-8", character_set_t::utf_8 },
+ { "ventura-international", character_set_t::ventura_international },
+ { "ventura-math", character_set_t::ventura_math },
+ { "ventura-us", character_set_t::ventura_us },
+ { "videotex-suppl", character_set_t::videotex_suppl },
+ { "viqr", character_set_t::viqr },
+ { "viscii", character_set_t::viscii },
+ { "windows-1250", character_set_t::windows_1250 },
+ { "windows-1251", character_set_t::windows_1251 },
+ { "windows-1252", character_set_t::windows_1252 },
+ { "windows-1253", character_set_t::windows_1253 },
+ { "windows-1254", character_set_t::windows_1254 },
+ { "windows-1255", character_set_t::windows_1255 },
+ { "windows-1256", character_set_t::windows_1256 },
+ { "windows-1257", character_set_t::windows_1257 },
+ { "windows-1258", character_set_t::windows_1258 },
+ { "windows-31j", character_set_t::windows_31j },
+ { "windows-874", character_set_t::windows_874 },
+ { "windows-936", character_set_t::gbk },
+ { "x0201", character_set_t::jis_x0201 },
+ { "x0201-7", character_set_t::jis_c6220_1969_jp },
+ { "x0208", character_set_t::jis_c6226_1983 },
+ { "x0212", character_set_t::jis_x0212_1990 },
+ { "yu", character_set_t::jus_i_b1_002 },
+};const map_type& get()
+{
+ static map_type mt(entries, std::size(entries), character_set_t::unspecified);
+ return mt;
+}
+
+} // namespace charset
+
+} // anonymous namespace
+
+dump_format_t to_dump_format_enum(std::string_view s)
+{
+ return dump_format::get().find(s);
+}
+
+character_set_t to_character_set(std::string_view s)
+{
+ // Convert the source encoding string to all lower-case first.
+ std::string val_lower{s};
+ std::transform(val_lower.begin(), val_lower.end(), val_lower.begin(),
+ [](unsigned char c)
+ {
+ return std::tolower(c);
+ }
+ );
+
+ return charset::get().find(val_lower);
+}
+
+std::vector<std::pair<std::string_view, dump_format_t>> get_dump_format_entries()
+{
+ std::vector<std::pair<std::string_view, dump_format_t>> ret;
+ for (const auto& e : dump_format::entries)
+ ret.emplace_back(e.key, e.value);
+
+ return ret;
+}
+
+std::ostream& operator<< (std::ostream& os, const length_t& v)
+{
+ os << v.to_string();
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const date_time_t& v)
+{
+ os << v.to_string();
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, format_t v)
+{
+ static const char* values[] = {
+ "unknown",
+ "ods",
+ "xlsx",
+ "gnumeric",
+ "xls-xml",
+ "csv"
+ };
+
+ size_t vi = static_cast<std::underlying_type_t<format_t>>(v);
+ size_t n = std::size(values);
+
+ if (vi >= n)
+ os << "???";
+ else
+ os << values[vi];
+
+ return os;
+}
+
+const std::size_t INDEX_NOT_FOUND = std::numeric_limits<size_t>::max();
+const xmlns_id_t XMLNS_UNKNOWN_ID = nullptr;
+const xml_token_t XML_UNKNOWN_TOKEN = 0;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/types_test.cpp b/src/parser/types_test.cpp
new file mode 100644
index 0000000..ae22fdd
--- /dev/null
+++ b/src/parser/types_test.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <orcus/types.hpp>
+
+void test_character_set_t()
+{
+ orcus::test::stack_printer __sp__(__func__);
+
+ using orcus::character_set_t;
+
+ struct test_case
+ {
+ std::string_view input;
+ character_set_t expected;
+ };
+
+ constexpr test_case tests[] = {
+ { "utf-8", character_set_t::utf_8 },
+ { "UTF-8", character_set_t::utf_8 },
+ { "EUC-JP", character_set_t::euc_jp },
+ { "GBK", character_set_t::gbk },
+ { "Shift_JIS", character_set_t::shift_jis },
+ { "MS_Kanji", character_set_t::shift_jis },
+ { "csShiftJIS", character_set_t::shift_jis },
+ { "GB2312", character_set_t::gb2312 },
+ };
+
+ for (const auto& test : tests)
+ {
+ assert(orcus::to_character_set(test.input) == test.expected);
+ }
+}
+
+int main()
+{
+ test_character_set_t();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/utf8.cpp b/src/parser/utf8.cpp
new file mode 100644
index 0000000..e02d224
--- /dev/null
+++ b/src/parser/utf8.cpp
@@ -0,0 +1,524 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "utf8.hpp"
+
+#include <cassert>
+#include <stdexcept>
+#include <limits>
+
+// https://en.wikipedia.org/wiki/UTF-8#Encoding
+// https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-NameStartChar
+
+namespace orcus {
+
+namespace {
+
+bool valid_second_byte(uint8_t b)
+{
+ return (b & 0xC0) == 0x80;
+}
+
+bool parse_1b_start_char(uint8_t c1)
+{
+ if (c1 == '_')
+ return true;
+
+ if ('a' <= c1 && c1 <= 'z')
+ return true;
+
+ if ('A' <= c1 && c1 <= 'Z')
+ return true;
+
+ return false;
+}
+
+bool parse_1b_second_char(uint8_t c1)
+{
+ if (c1 == '-' || c1 == '.')
+ return true;
+
+ if ('0' <= c1 && c1 <= '9')
+ return true;
+
+ return false;
+}
+
+// [ #xC0- #xD6]: C3 80 -> C3 96
+// [ #xD8- #xF6]: C3 98 -> C3 B6
+// [ #xF8-#x2FF]: C3 B8 -> CB BF
+// [#x370-#x37D]: CD B0 -> CD BD
+//
+// [#x37F-#x1FFF]: (split)
+// [#x37F-#x07FF]: CD BF -> DF BF
+//
+bool parse_2b_start_char(uint8_t c1, uint8_t c2)
+{
+ if (c1 == 0xC3)
+ {
+ if (0x80 <= c2 && c2 <= 0x96)
+ return true;
+
+ if (0x98 <= c2 && c2 <= 0xB6)
+ return true;
+
+ if (0xB8 <= c2)
+ return true;
+ }
+
+ // C4 80 -> CB BF
+ if (0xC4 <= c1 && c1 <= 0xCB)
+ return 0x80 <= c2 && c2 <= 0xBF;
+
+ // CD B0 -> CD BD
+ // CD BF -> DF BF
+
+ if (c1 == 0xCD)
+ {
+ if (0xB0 <= c2 && c2 <= 0xBD)
+ return true;
+
+ return c2 == 0xBF;
+ }
+
+ // CE xx -> DF xx
+ return 0xCE <= c1 && c1 <= 0xDF;
+}
+
+// #xB7: C2 B7
+// [#x0300-#x036F]: CC 80 -> CD AF
+bool parse_2b_second_char(uint8_t c1, uint8_t c2)
+{
+ // C2 B7
+ if (c1 == 0xC2)
+ return c2 == 0xB7;
+
+ // CC 80 -> CD AF
+ // - CC xx
+ // - CD xx -> CD AF
+
+ if (c1 == 0xCC)
+ return true;
+
+ if (c1 == 0xCD)
+ return c2 <= 0xAF;
+
+ return false;
+}
+
+// [#x800-#x1FFF]: E0 A0 80 -> E1 BF BF
+//
+// [#x200C-#x200D]: E2 80 8C -> E2 80 8D
+// [#x2070-#x218F]: E2 81 B0 -> E2 86 8F
+// [#x2C00-#x2FEF]: E2 B0 80 -> E2 BF AF
+// [#x3001-#xD7FF]: E3 80 81 -> ED 9F BF
+// [#xF900-#xFDCF]: EF A4 80 -> EF B7 8F
+// [#xFDF0-#xFFFD]: EF B7 B0 -> EF BF BD
+bool parse_3b_start_char(uint8_t c1, uint8_t c2, uint8_t c3)
+{
+ // E0 A0 80 -> E1 BF BF
+ // - E0 A0 80 -> E0 BF BF
+ // - E1 xx xx
+
+ if (c1 == 0xE0)
+ {
+ // A0 80 -> BF BF
+ return (0xA0 <= c2 && c2 <= 0xBF && 0x80 <= c3 && c3 <= 0xBF);
+ }
+
+ if (c1 == 0xE1)
+ // entire E1 xx xx range is valid.
+ return true;
+
+ if (c1 == 0xE2)
+ {
+ // E2 80 8C -> E2 80 8D
+ // E2 81 B0 -> E2 86 8F
+ // E2 B0 80 -> E2 BF AF
+
+ if (c2 == 0x80)
+ // 8C -> 8D
+ return c3 == 0x8C || c3 == 0x8D;
+
+ // 81 B0 -> 86 8F
+ if (c2 == 0x81)
+ return c3 >= 0xB0;
+
+ if (0x82 <= c2 && c2 <= 0x85)
+ return true;
+
+ if (c2 == 0x86)
+ return c3 <= 0x8F;
+
+ // B0 80 -> BF AF
+ if (0xB0 <= c2 && c2 <= 0xBE)
+ return true;
+
+ if (c2 == 0xBF)
+ return c3 <= 0xAF;
+ }
+
+ // E3 80 81 -> ED 9F BF
+ // - E3 80 81 -> E3 80 BF
+ // - E3 81 xx
+ // - E4 xx xx -> EC xx xx
+ // - ED xx xx -> ED 9F xx
+ if (c1 == 0xE3)
+ {
+ if (c2 == 0x80)
+ return c3 >= 0x81;
+
+ return 0x81 <= c2;
+ }
+
+ if (0xE4 <= c1 && c1 <= 0xEC)
+ return true;
+
+ if (c1 == 0xED)
+ return c2 <= 0x9F;
+
+ // EF A4 80 -> EF B7 8F
+ // - EF A4 xx
+ // - EF A5 xx -> EF B6 xx
+ // - EF B7 xx -> EF B7 8F
+ // EF B7 B0 -> EF BF BD
+ // - EF B7 B0 -> EF B7 xx
+ // - EF B8 xx -> EF BE xx
+ // - EF BF xx -> EF BF BD
+ if (c1 == 0xEF)
+ {
+ if (c2 == 0xA4)
+ return true;
+
+ if (0xA5 <= c2 && c2 <= 0xB6)
+ return true;
+
+ if (c2 == 0xB7)
+ {
+ if (c3 <= 0x8F)
+ return true;
+
+ return 0xB0 <= c3;
+ }
+
+ if (0xB8 <= c2 && c2 <= 0xBE)
+ return true;
+
+ if (c2 == 0xBF)
+ return c3 <= 0xBD;
+ }
+
+ return false;
+}
+
+// [#x203F-#x2040]: E2 80 BF -> E2 81 80
+bool parse_3b_second_char(uint8_t c1, uint8_t c2, uint8_t c3)
+{
+ if (c1 != 0xE2)
+ return false;
+
+ if (c2 == 0x80)
+ return c3 == 0xBF;
+
+ if (c2 == 0x81)
+ return c3 == 0x80;
+
+ return false;
+}
+
+// [#x10000-#xEFFFF]: F0 90 80 80 -> F3 AF BF BF
+bool parse_4b_char(uint8_t c1, uint8_t c2, uint8_t /*c3*/, uint8_t /*c4*/)
+{
+ // F0 90 80 80 -> F3 AF BF BF
+ // - F0 90 xx xx -> F0 xx xx xx
+ // - F1 xx xx xx -> F2 xx xx xx
+ // - F3 xx xx xx -> F3 AF xx xx
+ if (c1 == 0xF0)
+ return 0x90 <= c2;
+
+ if (0xF1 <= c1 && c1 <= 0xF2)
+ return true;
+
+ if (c1 == 0xF3)
+ return c2 <= 0xAF;
+
+ return false;
+}
+
+uint8_t calc_encoded_length(uint32_t cp)
+{
+ if (cp <= 0x7F)
+ return 1;
+
+ if (0x80 <= cp && cp <= 0x7FF)
+ return 2;
+
+ if (0x800 <= cp && cp <= 0xFFFF)
+ return 3;
+
+ if (0x10000 <= cp && cp <= 0x10FFFF)
+ return 4;
+
+ throw std::runtime_error("invalid utf-8 range.");
+}
+
+// input must be less than or equal to 0x7FF
+//
+// b1: 0b110xxxxx (5)
+// b2: 0b10xxxxxx (6)
+std::vector<char> encode_2b(uint32_t cp)
+{
+ assert(cp <= 0x7FF);
+
+ // Get the lowest 6 bits
+ char low = (cp & 0x3F);
+ low |= 0x80;
+
+ // Get the next 5 bits
+ cp = cp >> 6;
+ char high = (cp & 0x1F);
+ high |= 0xC0;
+
+ std::vector<char> ret = { high, low };
+ return ret;
+}
+
+// input must be less than or equal to 0xFFFF
+//
+// b1: 0b1110xxxx (4)
+// b2: 0b10xxxxxx (6)
+// b3: 0b10xxxxxx (6)
+std::vector<char> encode_3b(uint32_t cp)
+{
+ assert(cp <= 0xFFFF);
+
+ // Get the lowest 6 bits
+ char low = (cp & 0x3F);
+ low |= 0x80;
+ cp = cp >> 6;
+
+ // Get the middle 6 bits
+ char mid = (cp & 0x3F);
+ mid |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 4 bits
+ char high = (cp & 0x0F);
+ high |= 0xE0;
+
+ std::vector<char> ret = { high, mid, low };
+ return ret;
+}
+
+// input must be less than or equal to 0x10FFFF
+//
+// b1: 0b11110xxx (3)
+// b2: 0b10xxxxxx (6)
+// b3: 0b10xxxxxx (6)
+// b4: 0b10xxxxxx (6)
+std::vector<char> encode_4b(uint32_t cp)
+{
+ assert(cp <= 0x10FFFF);
+
+ // Get the lowest 6 bits
+ char low = (cp & 0x3F);
+ low |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 6 bits
+ char mid1 = (cp & 0x3F);
+ mid1 |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 6 bits
+ char mid2 = (cp & 0x3F);
+ mid2 |= 0x80;
+ cp = cp >> 6;
+
+ // Get the next 3 bits
+ char high = (cp & 0x07);
+ high |= 0xF0;
+
+ std::vector<char> ret = { high, mid2, mid1, low };
+ return ret;
+}
+
+} // anonymous namespace
+
+const char* parse_utf8_xml_name_start_char(const char* p, const char* p_end)
+{
+ size_t n_remaining = p_end - p;
+ if (!n_remaining)
+ return p;
+
+ uint8_t n_bytes = calc_utf8_byte_length(*p);
+
+ switch (n_bytes)
+ {
+ case 1:
+ return parse_1b_start_char(*p) ? p + 1 : p;
+ case 2:
+ {
+ if (n_remaining < 2)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+
+ if (!valid_second_byte(c2))
+ return p;
+
+ return parse_2b_start_char(c1, c2) ? p + 2 : p;
+ }
+ case 3:
+ {
+ if (n_remaining < 3)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3))
+ return p;
+
+ return parse_3b_start_char(c1, c2, c3) ? p + 3 : p;
+ }
+ case 4:
+ {
+ if (n_remaining < 4)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+ uint8_t c4 = p[3];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3) || !valid_second_byte(c4))
+ return p;
+
+ return parse_4b_char(c1, c2, c3, c4) ? p + 4 : p;
+ }
+ }
+
+ return p;
+}
+
+const char* parse_utf8_xml_name_char(const char* p, const char* p_end)
+{
+ size_t n_remaining = p_end - p;
+ if (!n_remaining)
+ return p;
+
+ uint8_t n_bytes = calc_utf8_byte_length(*p);
+
+ switch (n_bytes)
+ {
+ case 1:
+ {
+ if (parse_1b_start_char(*p))
+ return p + 1;
+
+ return parse_1b_second_char(*p) ? p + 1 : p;
+ }
+ case 2:
+ {
+ if (n_remaining < 2)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+
+ if (!valid_second_byte(c2))
+ return p;
+
+ if (parse_2b_start_char(c1, c2))
+ return p + 2;
+
+ return parse_2b_second_char(c1, c2) ? p + 2 : p;
+ }
+ case 3:
+ {
+ if (n_remaining < 3)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3))
+ return p;
+
+ if (parse_3b_start_char(c1, c2, c3))
+ return p + 3;
+
+ return parse_3b_second_char(c1, c2, c3) ? p + 3 : p;
+ }
+ case 4:
+ {
+ if (n_remaining < 4)
+ return p;
+
+ uint8_t c1 = p[0];
+ uint8_t c2 = p[1];
+ uint8_t c3 = p[2];
+ uint8_t c4 = p[3];
+
+ if (!valid_second_byte(c2) || !valid_second_byte(c3) || !valid_second_byte(c4))
+ return p;
+
+ return parse_4b_char(c1, c2, c3, c4) ? p + 4 : p;
+ }
+ }
+
+ return p;
+}
+
+std::vector<char> encode_utf8(uint32_t cp)
+{
+ uint8_t n_encoded = calc_encoded_length(cp);
+
+ switch (n_encoded)
+ {
+ case 1:
+ // no conversion
+ return std::vector<char>(1, cp);
+ case 2:
+ return encode_2b(cp);
+ case 3:
+ return encode_3b(cp);
+ case 4:
+ return encode_4b(cp);
+ }
+
+ throw std::logic_error("this should never be reached.");
+}
+
+uint8_t calc_utf8_byte_length(uint8_t c1)
+{
+ if ((c1 & 0x80) == 0x00)
+ // highest bit is not set.
+ return 1;
+
+ if ((c1 & 0xE0) == 0xC0)
+ // highest 3 bits are 110.
+ return 2;
+
+ if ((c1 & 0xF0) == 0xE0)
+ // highest 4 bits are 1110.
+ return 3;
+
+ if ((c1 & 0xFC) == 0xF0)
+ // highest 5 bits are 11110.
+ return 4;
+
+ return std::numeric_limits<uint8_t>::max();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/utf8.hpp b/src/parser/utf8.hpp
new file mode 100644
index 0000000..01457de
--- /dev/null
+++ b/src/parser/utf8.hpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_ORCUS_PARSER_UTF8_HPP
+#define INCLUDED_ORCUS_PARSER_UTF8_HPP
+
+#include <vector>
+#include <cstdint>
+
+namespace orcus {
+
+const char* parse_utf8_xml_name_start_char(const char* p, const char* p_end);
+
+const char* parse_utf8_xml_name_char(const char* p, const char* p_end);
+
+std::vector<char> encode_utf8(uint32_t cp);
+
+uint8_t calc_utf8_byte_length(uint8_t c1);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/utf8_test.cpp b/src/parser/utf8_test.cpp
new file mode 100644
index 0000000..88dcd3e
--- /dev/null
+++ b/src/parser/utf8_test.cpp
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "utf8.hpp"
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <cassert>
+#include <functional>
+#include <iomanip>
+
+using namespace orcus;
+using std::cout;
+using std::endl;
+
+struct cp_range_t
+{
+ uint32_t lower;
+ uint32_t upper;
+ bool valid;
+};
+
+using parse_func_t = std::function<const char*(const char*, const char*)>;
+
+bool check_cp_ranges(parse_func_t parse, std::vector<cp_range_t> ranges)
+{
+ for (const cp_range_t& range : ranges)
+ {
+ for (uint32_t cp = range.lower; cp <= range.upper; ++cp)
+ {
+ std::vector<char> buf;
+
+ try
+ {
+ buf = encode_utf8(cp);
+ }
+ catch (const std::exception& e)
+ {
+ cout << "failed to encode 0x" << std::hex << std::uppercase << cp
+ << " as utf-8: " << e.what() << endl;
+ return false;
+ }
+
+ const char* p = buf.data();
+ const char* p_end = p + buf.size();
+ const char* ret = parse(p, p_end);
+
+ if ((ret == p_end) != range.valid)
+ {
+ cout << "failed to parse 0x" << std::hex << std::uppercase << cp
+ << " (utf-8:";
+
+ for (char b : buf)
+ cout << ' ' << short(0xFF & b);
+ cout << ")" << endl;
+ cout << "expected to be " << (range.valid ? "valid" : "invalid")
+ << ", but was " << (range.valid ? "invalid" : "valid") << endl;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void test_xml_name_start_char()
+{
+ bool res = check_cp_ranges(
+ parse_utf8_xml_name_start_char,
+ {
+ { 0x00, 0x40, false },
+ { 'A', 'Z', true },
+ { '[', '^', false },
+ { '_', '_', true },
+ { '`', '`', false },
+ { 'a', 'z', true },
+ { '{', 0xBF, false },
+ { 0xC0, 0xD6, true },
+ { 0xD7, 0xD7, false },
+ { 0xD8, 0xF6, true },
+ { 0xF7, 0xF7, false },
+ { 0xF8, 0x2FF, true },
+ { 0x300, 0x36F, false },
+ { 0x370, 0x37D, true },
+ { 0x37E, 0x37E, false },
+ { 0x37F, 0x1FFF, true },
+ { 0x2000, 0x200B, false },
+ { 0x200C, 0x200D, true },
+ { 0x200E, 0x206F, false },
+ { 0x2070, 0x218F, true },
+ { 0x2190, 0x2BFF, false },
+ { 0x2C00, 0x2FEF, true },
+ { 0x2FF0, 0x3000, false },
+ { 0x3001, 0xD7FF, true },
+ { 0xD800, 0xF8FF, false },
+ { 0xF900, 0xFDCF, true },
+ { 0xFDD0, 0xFDEF, false },
+ { 0xFDF0, 0xFFFD, true },
+ { 0xFFFE, 0xFFFF, false },
+ { 0x10000, 0xEFFFF, true },
+ { 0xF0000, 0xF0000, false }, // just check one byte past last valid byte.
+ }
+ );
+ assert(res);
+}
+
+void test_xml_name_char()
+{
+ bool res = check_cp_ranges(
+ parse_utf8_xml_name_char,
+ {
+ { 0x00, ',', false },
+ { '-', '.', true }, // 0x2D - 0x2E
+ { '/', '/', false },
+ { '0', '9', true },
+ { ':', '@', false },
+ { 'A', 'Z', true },
+ { '[', '^', false },
+ { '_', '_', true }, // 0x5F
+ { '`', '`', false },
+ { 'a', 'z', true },
+ { '{', 0xB6, false },
+ { 0xB7, 0xB7, true },
+ { 0xB8, 0xBF, false },
+ { 0xC0, 0xD6, true },
+ { 0xD7, 0xD7, false },
+ { 0xD8, 0xF6, true },
+ { 0xF7, 0xF7, false },
+ { 0xF8, 0x2FF, true },
+ { 0x300, 0x36F, true },
+ { 0x370, 0x37D, true },
+ { 0x37E, 0x37E, false },
+ { 0x37F, 0x1FFF, true },
+ { 0x2000, 0x200B, false },
+ { 0x200C, 0x200D, true },
+ { 0x200E, 0x203E, false },
+ { 0x203F, 0x2040, true },
+ { 0x2041, 0x206F, false },
+ { 0x2070, 0x218F, true },
+ { 0x2190, 0x2BFF, false },
+ { 0x2C00, 0x2FEF, true },
+ { 0x2FF0, 0x3000, false },
+ { 0x3001, 0xD7FF, true },
+ { 0xD800, 0xF8FF, false },
+ { 0xF900, 0xFDCF, true },
+ { 0xFDD0, 0xFDEF, false },
+ { 0xFDF0, 0xFFFD, true },
+ { 0xFFFE, 0xFFFF, false },
+ { 0x10000, 0xEFFFF, true },
+ { 0xF0000, 0xF0000, false }, // just check one byte past last valid byte.
+ }
+ );
+ assert(res);
+}
+
+int main()
+{
+ test_xml_name_start_char();
+ test_xml_name_char();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/win_stdint.h b/src/parser/win_stdint.h
new file mode 100644
index 0000000..e51d46f
--- /dev/null
+++ b/src/parser/win_stdint.h
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * Copyright (c) 2013 Markus Mohrhard
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef WIN_STDINT
+#define WIN_STDINT
+
+#if _MSC_VER <= 1500
+
+typedef signed __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#else
+
+#include <stdint.h>
+
+#endif // visual studio version
+
+#endif \ No newline at end of file
diff --git a/src/parser/xml_namespace.cpp b/src/parser/xml_namespace.cpp
new file mode 100644
index 0000000..2aafea3
--- /dev/null
+++ b/src/parser/xml_namespace.cpp
@@ -0,0 +1,490 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/xml_namespace.hpp>
+#include <orcus/exception.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <unordered_map>
+#include <vector>
+#include <limits>
+#include <sstream>
+#include <algorithm>
+#include <cassert>
+
+#define ORCUS_DEBUG_XML_NAMESPACE 0
+
+using namespace std;
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+#include <cstdio>
+#include <iostream>
+#endif
+
+namespace orcus {
+
+namespace {
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+template<typename _MapType>
+void print_map_keys(const _MapType& map_store)
+{
+ cout << "keys: (";
+ bool first = true;
+ typename _MapType::const_iterator it = map_store.begin(), it_end = map_store.end();
+ for (; it != it_end; ++it)
+ {
+ if (first)
+ first = false;
+ else
+ cout << " ";
+ cout << "'" << it->first << "'";
+ }
+ cout << ")";
+};
+#endif
+
+}
+
+typedef std::unordered_map<std::string_view, std::size_t> strid_map_type;
+
+struct xmlns_repository::impl
+{
+ size_t m_predefined_ns_size;
+ string_pool m_pool; /// storage of live string instances.
+ std::vector<std::string_view> m_identifiers; /// map strings to numerical identifiers.
+ strid_map_type m_strid_map; /// string-to-numerical identifiers map for quick lookup.
+
+ impl() : m_predefined_ns_size(0) {}
+};
+
+xmlns_repository::xmlns_repository() : mp_impl(std::make_unique<impl>()) {}
+xmlns_repository::xmlns_repository(xmlns_repository&& other) : mp_impl(std::move(other.mp_impl)) {}
+xmlns_repository::~xmlns_repository() = default;
+
+xmlns_repository& xmlns_repository::operator= (xmlns_repository&& other)
+{
+ mp_impl = std::move(other.mp_impl);
+ return *this;
+}
+
+xmlns_id_t xmlns_repository::intern(std::string_view uri)
+{
+ // See if the uri is already registered.
+ strid_map_type::iterator it = mp_impl->m_strid_map.find(uri);
+ if (it != mp_impl->m_strid_map.end())
+ return it->first.data();
+
+ try
+ {
+ auto r = mp_impl->m_pool.intern(uri);
+ std::string_view uri_interned = r.first;
+
+ if (!uri_interned.empty())
+ {
+ // Intern successful.
+ if (r.second)
+ {
+ // This is a new instance. Assign a numerical identifier.
+ mp_impl->m_strid_map.insert(
+ strid_map_type::value_type(r.first, mp_impl->m_identifiers.size()));
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_repository::intern: uri='" << uri_interned << "' (" << mp_impl->m_identifiers.size() << ")" << endl;
+#endif
+ mp_impl->m_identifiers.push_back(r.first);
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "pool size=" << mp_impl->m_pool.size() << ", predefined ns size=" << mp_impl->m_predefined_ns_size <<
+ ", identifiers size=" << mp_impl->m_identifiers.size() << ", map size=" << mp_impl->m_strid_map.size() << endl;
+#endif
+ assert(mp_impl->m_pool.size()+mp_impl->m_predefined_ns_size == mp_impl->m_identifiers.size());
+ assert(mp_impl->m_pool.size()+mp_impl->m_predefined_ns_size == mp_impl->m_strid_map.size());
+ }
+ return uri_interned.data();
+ }
+ }
+ catch (const general_error&)
+ {
+ }
+
+ return XMLNS_UNKNOWN_ID;
+}
+
+void xmlns_repository::add_predefined_values(const xmlns_id_t* predefined_ns)
+{
+ if (!predefined_ns)
+ return;
+
+ const xmlns_id_t* val = &predefined_ns[0];
+ for (; *val; ++val)
+ {
+ std::string_view s(*val);
+ mp_impl->m_strid_map.insert(
+ strid_map_type::value_type(s, mp_impl->m_identifiers.size()));
+ mp_impl->m_identifiers.push_back(s);
+
+ ++mp_impl->m_predefined_ns_size;
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xlmns_repository: predefined ns='" << s << "'" << endl;
+#endif
+ }
+}
+
+xmlns_context xmlns_repository::create_context()
+{
+ return xmlns_context(*this);
+}
+
+xmlns_id_t xmlns_repository::get_identifier(size_t index) const
+{
+ if (index >= mp_impl->m_identifiers.size())
+ return XMLNS_UNKNOWN_ID;
+
+ // All identifier strings are interned which means they are all null-terminated.
+ return mp_impl->m_identifiers[index].data();
+}
+
+string xmlns_repository::get_short_name(xmlns_id_t ns_id) const
+{
+ size_t index = get_index(ns_id);
+
+ if (index == INDEX_NOT_FOUND)
+ return string("???");
+
+ std::ostringstream os;
+ os << "ns" << index;
+ return os.str();
+}
+
+size_t xmlns_repository::get_index(xmlns_id_t ns_id) const
+{
+ if (!ns_id)
+ return INDEX_NOT_FOUND;
+
+ auto it = mp_impl->m_strid_map.find(std::string_view(ns_id));
+ if (it == mp_impl->m_strid_map.end())
+ return INDEX_NOT_FOUND;
+
+ return it->second;
+}
+
+typedef std::vector<xmlns_id_t> xmlns_list_type;
+typedef std::unordered_map<std::string_view, xmlns_list_type> alias_map_type;
+
+struct xmlns_context::impl
+{
+ xmlns_repository* repo = nullptr;
+ xmlns_list_type m_all_ns; /// all namespaces ever used in this context.
+ xmlns_list_type m_default;
+ alias_map_type m_map;
+
+ bool m_trim_all_ns = true;
+
+ impl() {}
+ impl(xmlns_repository& _repo) : repo(&_repo) {}
+ impl(const impl& r) :
+ repo(r.repo), m_all_ns(r.m_all_ns), m_default(r.m_default), m_map(r.m_map), m_trim_all_ns(r.m_trim_all_ns) {}
+};
+
+xmlns_context::xmlns_context() : mp_impl(std::make_unique<impl>()) {}
+xmlns_context::xmlns_context(xmlns_repository& repo) : mp_impl(std::make_unique<impl>(repo)) {}
+xmlns_context::xmlns_context(const xmlns_context& r) : mp_impl(std::make_unique<impl>(*r.mp_impl)) {}
+xmlns_context::xmlns_context(xmlns_context&& r) : mp_impl(std::move(r.mp_impl))
+{
+ r.mp_impl = std::make_unique<impl>();
+}
+
+xmlns_context::~xmlns_context() = default;
+
+xmlns_context& xmlns_context::operator= (const xmlns_context& r)
+{
+ xmlns_context tmp(r);
+ tmp.swap(*this);
+ return *this;
+}
+
+xmlns_context& xmlns_context::operator= (xmlns_context&& r)
+{
+ xmlns_context tmp(std::move(r));
+ tmp.swap(*this);
+ return *this;
+}
+
+xmlns_id_t xmlns_context::push(std::string_view alias, std::string_view uri)
+{
+ if (!mp_impl->repo)
+ throw general_error("this context is not associated with any repo.");
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::push: key='" << alias << "', uri='" << uri << "'" << endl;
+#endif
+ mp_impl->m_trim_all_ns = true;
+
+ xmlns_id_t id = mp_impl->repo->intern(uri);
+ std::string_view uri_interned = id ? std::string_view(id) : std::string_view();
+
+ if (alias.empty())
+ {
+ // empty alias value is associated with default namespace.
+ mp_impl->m_default.push_back(uri_interned.data());
+ mp_impl->m_all_ns.push_back(uri_interned.data());
+ return mp_impl->m_default.back();
+ }
+
+ // See if this alias already exists.
+ alias_map_type::iterator it = mp_impl->m_map.find(alias);
+ if (it == mp_impl->m_map.end())
+ {
+ // This is the first time this alias is used.
+ xmlns_list_type nslist;
+ nslist.push_back(uri_interned.data());
+ mp_impl->m_all_ns.push_back(uri_interned.data());
+ std::pair<alias_map_type::iterator,bool> r =
+ mp_impl->m_map.insert(alias_map_type::value_type(alias, nslist));
+
+ if (!r.second)
+ // insertion failed.
+ throw general_error("Failed to insert new namespace.");
+
+ return nslist.back();
+ }
+
+ // The alias already exists.
+ xmlns_list_type& nslist = it->second;
+ nslist.push_back(uri_interned.data());
+ mp_impl->m_all_ns.push_back(uri_interned.data());
+ return nslist.back();
+}
+
+void xmlns_context::pop(std::string_view alias)
+{
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::pop: alias='" << alias << "'" << endl;
+#endif
+ if (alias.empty())
+ {
+ // empty alias value is associated with default namespace.
+ if (mp_impl->m_default.empty())
+ throw general_error("default namespace stack is empty.");
+
+ mp_impl->m_default.pop_back();
+ return;
+ }
+
+ // See if this alias really exists.
+ alias_map_type::iterator it = mp_impl->m_map.find(alias);
+ if (it == mp_impl->m_map.end())
+ {
+ std::ostringstream os;
+ os << "alias named '" << alias << "' was attempted to be popped, but was not found in the stack";
+ throw general_error(os.str());
+ }
+
+ xmlns_list_type& nslist = it->second;
+ if (nslist.empty())
+ throw general_error("namespace stack for this key is empty.");
+
+ nslist.pop_back();
+}
+
+xmlns_id_t xmlns_context::get(std::string_view alias) const
+{
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get: alias='" << alias << "', default ns stack size="
+ << mp_impl->m_default.size() << ", non-default alias count=" << mp_impl->m_map.size();
+ cout << ", ";
+ print_map_keys(mp_impl->m_map);
+ cout << endl;
+#endif
+ if (alias.empty())
+ return mp_impl->m_default.empty() ? XMLNS_UNKNOWN_ID : mp_impl->m_default.back();
+
+ alias_map_type::const_iterator it = mp_impl->m_map.find(alias);
+ if (it == mp_impl->m_map.end())
+ {
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get: alias not in this context" << endl;
+#endif
+ return XMLNS_UNKNOWN_ID;
+ }
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get: alias stack size=" << it->second.size() << endl;
+#endif
+ return it->second.empty() ? XMLNS_UNKNOWN_ID : it->second.back();
+}
+
+size_t xmlns_context::get_index(xmlns_id_t ns_id) const
+{
+ if (!mp_impl->repo)
+ throw general_error("this context is not associated with any repo.");
+
+ return mp_impl->repo->get_index(ns_id);
+}
+
+string xmlns_context::get_short_name(xmlns_id_t ns_id) const
+{
+ if (!mp_impl->repo)
+ throw general_error("this context is not associated with any repo.");
+
+ return mp_impl->repo->get_short_name(ns_id);
+}
+
+std::string_view xmlns_context::get_alias(xmlns_id_t ns_id) const
+{
+ alias_map_type::const_iterator it = mp_impl->m_map.begin(), it_end = mp_impl->m_map.end();
+ for (; it != it_end; ++it)
+ {
+ const xmlns_list_type& lst = it->second;
+ if (lst.empty())
+ continue;
+
+ if (lst.back() == ns_id)
+ return it->first;
+ }
+
+ return std::string_view{};
+}
+
+namespace {
+
+#if ORCUS_DEBUG_XML_NAMESPACE
+struct print_ns
+{
+ void operator() (xmlns_id_t ns_id) const
+ {
+ const char* p = ns_id;
+ printf("%p: %s\n", p, p);
+ }
+};
+#endif
+
+struct ns_item
+{
+ size_t index;
+ xmlns_id_t ns;
+
+ ns_item(size_t _index, xmlns_id_t _ns) : index(_index), ns(_ns) {}
+};
+
+struct less_ns_by_index
+{
+ bool operator() (const ns_item& left, const ns_item& right) const
+ {
+ return left.index < right.index;
+ }
+};
+
+class push_back_ns_to_item
+{
+ vector<ns_item>& m_store;
+ const xmlns_context& m_cxt;
+public:
+ push_back_ns_to_item(vector<ns_item>& store, const xmlns_context& cxt) : m_store(store), m_cxt(cxt) {}
+ void operator() (xmlns_id_t ns)
+ {
+ size_t num_id = m_cxt.get_index(ns);
+ if (num_id != INDEX_NOT_FOUND)
+ m_store.push_back(ns_item(num_id, ns));
+ }
+};
+
+class push_back_item_to_ns
+{
+ std::vector<xmlns_id_t>& m_store;
+public:
+ push_back_item_to_ns(std::vector<xmlns_id_t>& store) : m_store(store) {}
+ void operator() (const ns_item& item)
+ {
+ m_store.push_back(item.ns);
+ }
+};
+
+}
+
+std::vector<xmlns_id_t> xmlns_context::get_all_namespaces() const
+{
+#if ORCUS_DEBUG_XML_NAMESPACE
+ cout << "xmlns_context::get_all_namespaces: count=" << mp_impl->m_all_ns.size() << endl;
+ std::for_each(mp_impl->m_all_ns.begin(), mp_impl->m_all_ns.end(), print_ns());
+#endif
+
+ std::vector<xmlns_id_t> nslist;
+
+ if (mp_impl->m_trim_all_ns)
+ {
+ xmlns_list_type& all_ns = mp_impl->m_all_ns;
+
+ nslist.assign(mp_impl->m_all_ns.begin(), mp_impl->m_all_ns.end());
+
+ // Sort it and remove duplicate.
+ std::sort(all_ns.begin(), all_ns.end());
+ xmlns_list_type::iterator it_unique_end =
+ std::unique(all_ns.begin(), all_ns.end());
+ all_ns.erase(it_unique_end, all_ns.end());
+
+ // Now, sort by indices.
+ vector<ns_item> items;
+ std::for_each(all_ns.begin(), all_ns.end(), push_back_ns_to_item(items, *this));
+ std::sort(items.begin(), items.end(), less_ns_by_index());
+
+ all_ns.clear();
+ std::for_each(items.begin(), items.end(), push_back_item_to_ns(all_ns));
+
+ mp_impl->m_trim_all_ns = false;
+ }
+
+ nslist.assign(mp_impl->m_all_ns.begin(), mp_impl->m_all_ns.end());
+ return nslist;
+}
+
+void xmlns_context::dump(std::ostream& os) const
+{
+ vector<xmlns_id_t> nslist = get_all_namespaces();
+ vector<xmlns_id_t>::const_iterator it = nslist.begin(), it_end = nslist.end();
+ for (; it != it_end; ++it)
+ {
+ xmlns_id_t ns_id = *it;
+ size_t num_id = get_index(ns_id);
+ if (num_id == INDEX_NOT_FOUND)
+ continue;
+
+ os << "ns" << num_id << "=\"" << ns_id << '"' << endl;
+ }
+}
+
+void xmlns_context::dump_state(std::ostream& os) const
+{
+ os << "namespaces:" << std::endl;
+ for (xmlns_id_t ns_id : get_all_namespaces())
+ {
+ size_t num_id = get_index(ns_id);
+ if (num_id == INDEX_NOT_FOUND)
+ continue;
+
+ os << " ns" << num_id << ": \"" << ns_id << '"' << std::endl;
+ }
+
+ os << "aliases:" << std::endl;
+ for (const auto& [alias, ns_list] : mp_impl->m_map)
+ {
+ os << " " << alias << ":" << std::endl;
+
+ for (const xmlns_id_t ns : ns_list)
+ os << " - " << ns << std::endl;
+ }
+}
+
+void xmlns_context::swap(xmlns_context& other) noexcept
+{
+ mp_impl.swap(other.mp_impl);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/xml_namespace_test.cpp b/src/parser/xml_namespace_test.cpp
new file mode 100644
index 0000000..de3891e
--- /dev/null
+++ b/src/parser/xml_namespace_test.cpp
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/xml_namespace.hpp"
+
+#include <cstdlib>
+#include <vector>
+#include <algorithm>
+
+using namespace orcus;
+
+namespace {
+
+void test_basic()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view xmlns1("http://some.xmlns/");
+ std::string_view xmlns2("http://other.xmlns/");
+
+ xmlns_repository repo;
+ xmlns_context cxt1 = repo.create_context();
+ xmlns_context cxt2 = repo.create_context();
+
+ std::string_view empty, myns("myns");
+ {
+ // context 1
+ xmlns_id_t test1 = cxt1.push(empty, xmlns1); // register default namespace.
+ assert(cxt1.get(empty) == test1);
+ xmlns_id_t test2 = cxt1.push(myns, xmlns2);
+ assert(cxt1.get(myns) == test2);
+ assert(test1 != test2);
+ }
+
+ {
+ // context 2
+ xmlns_id_t test1 = cxt2.push(empty, xmlns2); // register default namespace.
+ assert(cxt2.get(empty) == test1);
+ xmlns_id_t test2 = cxt2.push(myns, xmlns1);
+ assert(cxt2.get(myns) == test2);
+ assert(test1 != test2);
+ }
+
+ // Now, compare the registered namespaces between the two namespaces.
+ assert(cxt1.get(empty) == cxt2.get(myns));
+ assert(cxt1.get(myns) == cxt2.get(empty));
+}
+
+void test_all_namespaces()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ std::string_view key1("a"), key2("b"), key3("c");
+ std::string_view ns1("foo"), ns2("baa"), ns3("hmm");
+
+ xmlns_repository repo;
+ xmlns_context cxt = repo.create_context();
+ xmlns_id_t ns;
+
+ ns = cxt.push(key1, ns1);
+ assert(ns1 == ns);
+ ns = cxt.push(key2, ns2);
+ assert(ns2 == ns);
+ ns = cxt.push(key3, ns3);
+ assert(ns3 == ns);
+
+ std::vector<xmlns_id_t> all_ns = cxt.get_all_namespaces();
+ assert(all_ns.size() == 3);
+ assert(ns1 == all_ns[0]);
+ assert(ns2 == all_ns[1]);
+ assert(ns3 == all_ns[2]);
+}
+
+const xmlns_id_t NS_test_name1 = "test:name:1";
+const xmlns_id_t NS_test_name2 = "test:name:2";
+const xmlns_id_t NS_test_name3 = "test:name:3";
+
+xmlns_id_t NS_test_all[] = {
+ NS_test_name1,
+ NS_test_name2,
+ NS_test_name3,
+ nullptr
+};
+
+xmlns_id_t NS_test_all_reverse[] = {
+ NS_test_name3,
+ NS_test_name2,
+ NS_test_name1,
+ nullptr
+};
+
+void test_predefined_ns()
+{
+ xmlns_repository ns_repo;
+ ns_repo.add_predefined_values(NS_test_all);
+ xmlns_context cxt = ns_repo.create_context();
+ xmlns_id_t ns_id = cxt.push("tn1", "test:name:1");
+ assert(ns_id == NS_test_name1);
+ ns_id = cxt.push("tn2", "test:name:2");
+ assert(ns_id == NS_test_name2);
+ ns_id = cxt.push("tn3", "test:name:3");
+ assert(ns_id == NS_test_name3);
+ assert(cxt.get("tn1") == NS_test_name1);
+ assert(cxt.get("tn2") == NS_test_name2);
+ assert(cxt.get("tn3") == NS_test_name3);
+}
+
+void test_xml_name_t()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xml_name_t name1;
+ name1.ns = NS_test_name1;
+ name1.name = "foo";
+
+ xml_name_t name2 = name1;
+ assert(name1 == name2);
+
+ name2.name = "foo2";
+ assert(name1 != name2);
+
+ xml_name_t name3 = name1;
+ name3.ns = NS_test_name2;
+ assert(name1 != name3);
+}
+
+void test_ns_context()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ xmlns_repository repo;
+ repo.add_predefined_values(NS_test_all);
+
+ xmlns_repository repo2;
+ repo2.add_predefined_values(NS_test_all_reverse);
+
+ xmlns_context cxt;
+ cxt = repo.create_context(); // copy assignment
+ size_t id1 = cxt.get_index(NS_test_name3);
+ xmlns_context cxt2 = cxt; // copy ctor
+ size_t id2 = cxt2.get_index(NS_test_name3);
+
+ assert(id1 == id2);
+
+ xmlns_context cxt3 = repo2.create_context();
+ id2 = cxt3.get_index(NS_test_name3);
+
+ assert(id1 != id2);
+
+ cxt3 = std::move(cxt2); // move assignment
+ id2 = cxt3.get_index(NS_test_name3);
+
+ assert(id1 == id2);
+
+ try
+ {
+ id1 = cxt2.get_index(NS_test_name2);
+ assert(!"exception was supposed to be thrown due to no associated repos.");
+ }
+ catch (const std::exception&)
+ {
+ // expected
+ }
+
+ xmlns_context cxt4(std::move(cxt3)); // move ctor
+ id1 = cxt4.get_index(NS_test_name3);
+
+ xmlns_context cxt5 = repo.create_context();
+ id2 = cxt5.get_index(NS_test_name3);
+
+ assert(id1 == id2);
+
+ try
+ {
+ id1 = cxt3.get_index(NS_test_name2);
+ assert(!"exception was supposed to be thrown due to no associated repos.");
+ }
+ catch (const std::exception&)
+ {
+ // expected
+ }
+
+ cxt4 = repo.create_context();
+ cxt5 = repo2.create_context();
+ id1 = cxt4.get_index(NS_test_name1);
+ id2 = cxt5.get_index(NS_test_name1);
+
+ assert(id1 != id2);
+
+ cxt3 = repo.create_context();
+ cxt5.swap(cxt3);
+ id2 = cxt5.get_index(NS_test_name1);
+
+ assert(id1 == id2);
+}
+
+void test_repo_move()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ static_assert(!std::is_copy_constructible_v<xmlns_repository>);
+ static_assert(std::is_move_constructible_v<xmlns_repository>);
+
+ xmlns_repository repo;
+ repo.add_predefined_values(NS_test_all);
+
+ xmlns_repository repo_moved = std::move(repo); // move construction
+ xmlns_repository repo_moved2;
+ repo_moved2 = std::move(repo_moved); // move assignment
+
+ xmlns_id_t ns_id = repo_moved2.get_identifier(0);
+ assert(ns_id != XMLNS_UNKNOWN_ID);
+ ns_id = repo_moved2.get_identifier(1);
+ assert(ns_id != XMLNS_UNKNOWN_ID);
+ ns_id = repo_moved2.get_identifier(2);
+ assert(ns_id != XMLNS_UNKNOWN_ID);
+ ns_id = repo_moved2.get_identifier(3);
+ assert(ns_id == XMLNS_UNKNOWN_ID);
+}
+
+} // anonymous namespace
+
+int main()
+{
+ test_basic();
+ test_all_namespaces();
+ test_predefined_ns();
+ test_xml_name_t();
+ test_ns_context();
+ test_repo_move();
+
+ return EXIT_SUCCESS;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/xml_writer.cpp b/src/parser/xml_writer.cpp
new file mode 100644
index 0000000..a2f6c2f
--- /dev/null
+++ b/src/parser/xml_writer.cpp
@@ -0,0 +1,326 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/xml_writer.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <vector>
+
+/** To markup code that coverity warns might throw exceptions
+ which won't throw in practice, or where std::terminate is
+ an acceptable response if they do
+*/
+#if defined(__COVERITY__)
+#define suppress_fun_call_w_exception(expr) \
+ do \
+ { \
+ try \
+ { \
+ expr; \
+ } \
+ catch (const std::exception& e) \
+ { \
+ std::cerr << "Fatal exception: " << e.what() << std::endl; \
+ std::terminate(); \
+ } \
+ } while (false)
+#else
+#define suppress_fun_call_w_exception(expr) \
+ do \
+ { \
+ expr; \
+ } while (false)
+#endif
+
+namespace orcus {
+
+namespace {
+
+struct _elem
+{
+ xml_name_t name;
+ std::vector<std::string_view> ns_aliases;
+ bool open;
+
+ _elem(const xml_name_t& _name) : name(_name), open(true) {}
+};
+
+struct _attr
+{
+ xml_name_t name;
+ std::string_view value;
+
+ _attr(const xml_name_t& _name, std::string_view _value) :
+ name(_name),
+ value(_value)
+ {}
+};
+
+void write_content_encoded(std::string_view content, std::ostream& os)
+{
+ auto _flush = [&os](const char*& p0, const char* p)
+ {
+ size_t n = std::distance(p0, p);
+ os.write(p0, n);
+ p0 = nullptr;
+ };
+
+ constexpr std::string_view cv_lt = "&lt;";
+ constexpr std::string_view cv_gt = "&gt;";
+ constexpr std::string_view cv_amp = "&amp;";
+ constexpr std::string_view cv_apos = "&apos;";
+ constexpr std::string_view cv_quot = "&quot;";
+
+ const char* p = content.data();
+ const char* p_end = p + content.size();
+ const char* p0 = nullptr;
+
+ for (; p != p_end; ++p)
+ {
+ if (!p0)
+ p0 = p;
+
+ switch (*p)
+ {
+ case '<':
+ _flush(p0, p);
+ os.write(cv_lt.data(), cv_lt.size());
+ break;
+ case '>':
+ _flush(p0, p);
+ os.write(cv_gt.data(), cv_gt.size());
+ break;
+ case '&':
+ _flush(p0, p);
+ os.write(cv_amp.data(), cv_amp.size());
+ break;
+ case '\'':
+ _flush(p0, p);
+ os.write(cv_apos.data(), cv_apos.size());
+ break;
+ case '"':
+ _flush(p0, p);
+ os.write(cv_quot.data(), cv_quot.size());
+ break;
+ }
+ }
+
+ if (p0)
+ _flush(p0, p);
+}
+
+} // anonymous namespace
+
+struct xml_writer::scope::impl
+{
+ xml_writer* parent;
+ xml_name_t elem;
+
+ impl() : parent(nullptr) {}
+
+ impl(xml_writer* _parent, const xml_name_t& _elem) :
+ parent(_parent),
+ elem(_elem)
+ {
+ parent->push_element(elem);
+ }
+
+ ~impl()
+ {
+ suppress_fun_call_w_exception(parent->pop_element());
+ }
+};
+
+xml_writer::scope::scope(xml_writer* parent, const xml_name_t& elem) :
+ mp_impl(std::make_unique<impl>(parent, elem))
+{
+}
+
+xml_writer::scope::scope(scope&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+ // NB: we shouldn't have to create an impl instance for the other object
+ // since everything happens in the impl, and the envelop class doesn't
+ // access the impl internals.
+}
+
+xml_writer::scope::~scope() {}
+
+xml_writer::scope& xml_writer::scope::operator= (scope&& other)
+{
+ scope tmp(std::move(other));
+ mp_impl.swap(tmp.mp_impl);
+ return *this;
+}
+
+struct xml_writer::impl
+{
+ xmlns_repository& ns_repo;
+ std::ostream& os;
+ std::vector<_elem> elem_stack;
+ std::vector<std::string_view> ns_decls;
+ std::vector<_attr> attrs;
+
+ string_pool str_pool;
+ xmlns_repository repo;
+ xmlns_context cxt;
+
+ impl(xmlns_repository& _ns_repo, std::ostream& _os) :
+ ns_repo(_ns_repo),
+ os(_os),
+ cxt(ns_repo.create_context())
+ {}
+
+ void print(const xml_name_t& name)
+ {
+ std::string_view alias = cxt.get_alias(name.ns);
+ if (!alias.empty())
+ os << alias << ':';
+ os << name.name;
+ }
+
+ xml_name_t intern(const xml_name_t& name)
+ {
+ xml_name_t interned = name;
+ interned.name = str_pool.intern(interned.name).first;
+ return interned;
+ }
+
+ std::string_view intern(std::string_view value)
+ {
+ return str_pool.intern(value).first;
+ }
+};
+
+xml_writer::xml_writer(xmlns_repository& ns_repo, std::ostream& os) :
+ mp_impl(std::make_unique<impl>(ns_repo, os))
+{
+ os << "<?xml version=\"1.0\"?>";
+}
+
+xml_writer::xml_writer(xml_writer&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+ other.mp_impl = std::make_unique<impl>(mp_impl->ns_repo, mp_impl->os);
+}
+
+xml_writer& xml_writer::operator= (xml_writer&& other)
+{
+ xml_writer tmp(std::move(other));
+ mp_impl.swap(tmp.mp_impl);
+ return *this;
+}
+
+void xml_writer::pop_elements()
+{
+ // Pop all the elements currently on the stack.
+ while (!mp_impl->elem_stack.empty())
+ pop_element();
+}
+
+xml_writer::~xml_writer()
+{
+ suppress_fun_call_w_exception(pop_elements());
+}
+
+void xml_writer::close_current_element()
+{
+ if (!mp_impl->elem_stack.empty() && mp_impl->elem_stack.back().open)
+ {
+ mp_impl->os << '>';
+ mp_impl->elem_stack.back().open = false;
+ }
+}
+
+xml_writer::scope xml_writer::push_element_scope(const xml_name_t& name)
+{
+ return scope(this, name);
+}
+
+void xml_writer::push_element(const xml_name_t& _name)
+{
+ close_current_element();
+
+ auto& os = mp_impl->os;
+ xml_name_t name = mp_impl->intern(_name);
+
+ os << '<';
+ mp_impl->print(name);
+
+ for (std::string_view alias : mp_impl->ns_decls)
+ {
+ os << " xmlns";
+ if (!alias.empty())
+ os << ':' << alias;
+ os << "=\"";
+ xmlns_id_t ns = mp_impl->cxt.get(alias);
+ os << ns << '"';
+ }
+
+ for (const _attr& attr : mp_impl->attrs)
+ {
+ os << ' ';
+ mp_impl->print(attr.name);
+ os << "=\"";
+ os << attr.value << '"';
+ }
+
+ mp_impl->attrs.clear();
+ mp_impl->ns_decls.clear();
+
+ mp_impl->elem_stack.emplace_back(name);
+}
+
+xmlns_id_t xml_writer::add_namespace(std::string_view alias, std::string_view value)
+{
+ std::string_view alias_safe = mp_impl->intern(alias);
+ xmlns_id_t ns = mp_impl->cxt.push(alias_safe, mp_impl->intern(value));
+ mp_impl->ns_decls.push_back(alias_safe);
+ return ns;
+}
+
+void xml_writer::add_attribute(const xml_name_t& name, std::string_view value)
+{
+ mp_impl->attrs.emplace_back(mp_impl->intern(name), mp_impl->intern(value));
+}
+
+void xml_writer::add_content(std::string_view content)
+{
+ close_current_element();
+ write_content_encoded(content, mp_impl->os);
+}
+
+xml_name_t xml_writer::pop_element()
+{
+ auto& os = mp_impl->os;
+
+ const _elem& elem = mp_impl->elem_stack.back();
+ auto name = elem.name;
+
+ if (elem.open)
+ {
+ // self-closing element.
+ os << "/>";
+ }
+ else
+ {
+ os << "</";
+ mp_impl->print(name);
+ os << '>';
+ }
+
+ for (std::string_view alias : mp_impl->elem_stack.back().ns_aliases)
+ mp_impl->cxt.pop(alias);
+
+ mp_impl->elem_stack.pop_back();
+ return name;
+}
+
+} // namespace orcus
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/xml_writer_test.cpp b/src/parser/xml_writer_test.cpp
new file mode 100644
index 0000000..a6e4bed
--- /dev/null
+++ b/src/parser/xml_writer_test.cpp
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include "orcus/xml_writer.hpp"
+#include "orcus/xml_namespace.hpp"
+#include "orcus/sax_parser.hpp"
+
+#include <iostream>
+#include <sstream>
+
+using namespace orcus;
+
+void test_encoded_content()
+{
+ const std::vector<std::string> test_contents = {
+ "1 < 2 but 3 > 2",
+ "ladies & gentlemen",
+ "'testing single quotes'",
+ "\"testing double quotes\"",
+ };
+
+ struct _handler : public sax_handler
+ {
+ std::ostringstream os_content;
+
+ void characters(std::string_view val, bool /*transient*/)
+ {
+ os_content << val;
+ }
+ };
+
+ for (const std::string& test_content : test_contents)
+ {
+ xmlns_repository repo;
+ std::ostringstream os;
+
+ {
+ xml_writer writer(repo, os);
+ auto scope_root = writer.push_element_scope({nullptr, "root"});
+ writer.add_content(test_content);
+ }
+
+ std::string stream = os.str();
+
+ _handler hdl;
+
+ sax_parser<_handler> parser(stream, hdl);
+ parser.parse();
+
+ std::string content_read = hdl.os_content.str();
+ assert(test_content == content_read);
+ }
+}
+
+void test_move()
+{
+ xmlns_repository repo;
+
+ {
+ std::ostringstream os;
+ xml_writer writer(repo, os);
+
+ writer.push_element({nullptr, "foo"});
+
+ {
+ xml_writer moved(std::move(writer)); // move constructor
+ moved.add_content("stuff");
+ }
+
+ std::string stream = os.str();
+ assert(stream == "<?xml version=\"1.0\"?><foo>stuff</foo>");
+ }
+
+ {
+ std::ostringstream os;
+ xml_writer writer(repo, os);
+
+ writer.push_element({nullptr, "foo2"});
+
+ {
+ std::ostringstream os2;
+ xml_writer moved(repo, os2);
+
+ moved = std::move(writer); // move assignment.
+ moved.add_content("stuff2");
+ }
+
+ std::string stream = os.str();
+ assert(stream == "<?xml version=\"1.0\"?><foo2>stuff2</foo2>");
+ }
+}
+
+int main()
+{
+ test_encoded_content();
+ test_move();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/yaml_parser_base.cpp b/src/parser/yaml_parser_base.cpp
new file mode 100644
index 0000000..df4db23
--- /dev/null
+++ b/src/parser/yaml_parser_base.cpp
@@ -0,0 +1,512 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/yaml_parser_base.hpp>
+#include <orcus/cell_buffer.hpp>
+#include <orcus/parser_global.hpp>
+
+#include <mdds/sorted_string_map.hpp>
+
+#include <limits>
+#include <vector>
+#include <deque>
+#include <sstream>
+#include <algorithm>
+
+namespace orcus { namespace yaml {
+
+struct scope
+{
+ size_t width;
+ detail::scope_t type;
+
+ scope(size_t _width) : width(_width), type(detail::scope_t::unset) {}
+};
+
+struct parser_base::impl
+{
+ cell_buffer m_buffer;
+ std::vector<scope> m_scopes;
+ std::deque<std::string_view> m_line_buffer;
+ const char* m_document;
+
+ size_t m_comment_length;
+
+ bool m_in_literal_block;
+ bool m_parsed_to_end_of_line;
+
+ detail::parse_token_t m_last_token;
+
+ impl() :
+ m_document(nullptr),
+ m_comment_length(0),
+ m_in_literal_block(false),
+ m_parsed_to_end_of_line(false),
+ m_last_token(detail::parse_token_t::unknown) {}
+};
+
+const size_t parser_base::parse_indent_blank_line = std::numeric_limits<size_t>::max();
+const size_t parser_base::parse_indent_end_of_stream = std::numeric_limits<size_t>::max() - 1;
+const size_t parser_base::scope_empty = std::numeric_limits<size_t>::max() - 2;
+
+parser_base::parser_base(std::string_view content) :
+ orcus::parser_base(content.data(), content.size()), mp_impl(std::make_unique<impl>()) {}
+
+parser_base::~parser_base() = default;
+
+void parser_base::push_parse_token(detail::parse_token_t t)
+{
+ mp_impl->m_last_token = t;
+}
+
+detail::parse_token_t parser_base::get_last_parse_token() const
+{
+ return mp_impl->m_last_token;
+}
+
+size_t parser_base::offset_last_char_of_line() const
+{
+ // The current parser position should be on the linefeed char after
+ // calling parse_to_end_of_line().
+ assert(mp_impl->m_parsed_to_end_of_line);
+
+ size_t pos = offset(); // character past the '\n'.
+ pos -= 1; // move back to the '\n'.
+
+ if (mp_impl->m_comment_length)
+ {
+ assert(mp_impl->m_comment_length < pos);
+ pos -= mp_impl->m_comment_length; // should be on the '#' character.
+ }
+
+ pos -= 1;
+
+ // Ignore any trailing whitespaces.
+ const char* p = mp_begin + pos;
+ for (; mp_begin < p && *p == ' '; --p, --pos)
+ ;
+
+ return pos;
+}
+
+size_t parser_base::parse_indent()
+{
+ for (size_t indent = 0; has_char(); next(), ++indent)
+ {
+ char c = cur_char();
+ switch (c)
+ {
+ case '#':
+ skip_comment();
+ return parse_indent_blank_line;
+ case '\n':
+ next();
+ return parse_indent_blank_line;
+ case ' ':
+ continue;
+ default:
+ return indent;
+ }
+ }
+
+ return parse_indent_end_of_stream;
+}
+
+std::string_view parser_base::parse_to_end_of_line()
+{
+ const char* p = mp_char;
+ size_t len = 0;
+ for (; has_char(); next(), ++len)
+ {
+ switch (cur_char())
+ {
+ case '#':
+ skip_comment();
+ break;
+ case '\'':
+ {
+ const char* p_open_quote = mp_char;
+
+ // character immediately after the closing quote.
+ const char* p_end =
+ parse_to_closing_single_quote(mp_char, remaining_size());
+
+ if (!p_end)
+ throw parse_error("parse_to_end_of_line: closing single quote was expected but not found.", offset());
+
+ size_t diff = p_end - p_open_quote - 1;
+
+ // Move the cursor to the closing quote.
+ next(diff);
+ len += diff;
+ assert(cur_char() == '\'');
+ continue;
+ }
+ break;
+ case '"':
+ {
+ const char* p_open_quote = mp_char;
+
+ // character immediately after the closing quote.
+ const char* p_end =
+ parse_to_closing_double_quote(mp_char, remaining_size());
+
+ if (!p_end)
+ throw parse_error("parse_to_end_of_line: closing double quote was expected but not found.", offset());
+
+ size_t diff = p_end - p_open_quote - 1;
+
+ // Move the cursor to the closing quote.
+ next(diff);
+ len += diff;
+ assert(cur_char() == '"');
+ continue;
+ }
+ break;
+ case '\n':
+ next();
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ std::string_view ret(p, len);
+ mp_impl->m_parsed_to_end_of_line = true;
+ return ret;
+}
+
+void parser_base::skip_comment()
+{
+ assert(cur_char() == '#');
+
+ size_t n = 1;
+
+ for (; has_char(); next(), ++n)
+ {
+ if (cur_char() == '\n')
+ {
+ next();
+ break;
+ }
+ }
+
+ mp_impl->m_comment_length = n;
+}
+
+void parser_base::reset_on_new_line()
+{
+ mp_impl->m_comment_length = 0;
+ mp_impl->m_parsed_to_end_of_line = false;
+}
+
+size_t parser_base::get_scope() const
+{
+ return (mp_impl->m_scopes.empty()) ? scope_empty : mp_impl->m_scopes.back().width;
+}
+
+void parser_base::push_scope(size_t scope_width)
+{
+ mp_impl->m_scopes.emplace_back(scope_width);
+}
+
+void parser_base::clear_scopes()
+{
+ mp_impl->m_scopes.clear();
+}
+
+detail::scope_t parser_base::get_scope_type() const
+{
+ assert(!mp_impl->m_scopes.empty());
+ return mp_impl->m_scopes.back().type;
+}
+
+void parser_base::set_scope_type(detail::scope_t type)
+{
+ assert(!mp_impl->m_scopes.empty());
+ mp_impl->m_scopes.back().type = type;
+}
+
+size_t parser_base::pop_scope()
+{
+ assert(!mp_impl->m_scopes.empty());
+ mp_impl->m_scopes.pop_back();
+ return get_scope();
+}
+
+void parser_base::push_line_back(const char* p, size_t n)
+{
+ mp_impl->m_line_buffer.emplace_back(p, n);
+}
+
+std::string_view parser_base::pop_line_front()
+{
+ assert(!mp_impl->m_line_buffer.empty());
+
+ std::string_view ret = mp_impl->m_line_buffer.front();
+ mp_impl->m_line_buffer.pop_front();
+ return ret;
+}
+
+bool parser_base::has_line_buffer() const
+{
+ return !mp_impl->m_line_buffer.empty();
+}
+
+size_t parser_base::get_line_buffer_count() const
+{
+ return mp_impl->m_line_buffer.size();
+}
+
+std::string_view parser_base::merge_line_buffer()
+{
+ assert(!mp_impl->m_line_buffer.empty());
+
+ char sep = mp_impl->m_in_literal_block ? '\n' : ' ';
+
+ cell_buffer& buf = mp_impl->m_buffer;
+ buf.reset();
+
+ auto it = mp_impl->m_line_buffer.begin();
+ buf.append(it->data(), it->size());
+ ++it;
+
+ std::for_each(it, mp_impl->m_line_buffer.end(),
+ [&](std::string_view line)
+ {
+ buf.append(&sep, 1);
+ buf.append(line.data(), line.size());
+ }
+ );
+
+ mp_impl->m_line_buffer.clear();
+ mp_impl->m_in_literal_block = false;
+
+ return buf.str();
+}
+
+const char* parser_base::get_doc_hash() const
+{
+ return mp_impl->m_document;
+}
+
+void parser_base::set_doc_hash(const char* hash)
+{
+ mp_impl->m_document = hash;
+}
+
+namespace {
+
+namespace keyword {
+
+using map_type = mdds::sorted_string_map<detail::keyword_t, mdds::string_view_map_entry>;
+
+constexpr map_type::entry entries[] = {
+ { "FALSE", detail::keyword_t::boolean_false },
+ { "False", detail::keyword_t::boolean_false },
+ { "N", detail::keyword_t::boolean_false },
+ { "NO", detail::keyword_t::boolean_false },
+ { "NULL", detail::keyword_t::null },
+ { "No", detail::keyword_t::boolean_false },
+ { "Null", detail::keyword_t::null },
+ { "OFF", detail::keyword_t::boolean_false },
+ { "ON", detail::keyword_t::boolean_true },
+ { "Off", detail::keyword_t::boolean_false },
+ { "On", detail::keyword_t::boolean_true },
+ { "TRUE", detail::keyword_t::boolean_true },
+ { "True", detail::keyword_t::boolean_true },
+ { "Y", detail::keyword_t::boolean_true },
+ { "YES", detail::keyword_t::boolean_true },
+ { "Yes", detail::keyword_t::boolean_true },
+ { "false", detail::keyword_t::boolean_false },
+ { "n", detail::keyword_t::boolean_false },
+ { "no", detail::keyword_t::boolean_false },
+ { "null", detail::keyword_t::null },
+ { "off", detail::keyword_t::boolean_false },
+ { "on", detail::keyword_t::boolean_true },
+ { "true", detail::keyword_t::boolean_true },
+ { "y", detail::keyword_t::boolean_true },
+ { "yes", detail::keyword_t::boolean_true },
+ { "~", detail::keyword_t::null },
+};
+
+const map_type& get()
+{
+ static const map_type map(entries, std::size(entries), detail::keyword_t::unknown);
+ return map;
+}
+
+} // namespace keyword
+
+void throw_quoted_string_parse_error(
+ const char* func_name, const parse_quoted_string_state& ret, std::ptrdiff_t offset)
+{
+ std::ostringstream os;
+ os << func_name << ": failed to parse ";
+ if (ret.length == parse_quoted_string_state::error_illegal_escape_char)
+ os << "due to the presence of illegal escape character.";
+ else if (ret.length == parse_quoted_string_state::error_no_closing_quote)
+ os << "because the closing quote was not found.";
+ else
+ os << "due to unknown reason.";
+
+ throw parse_error(os.str(), offset);
+}
+
+}
+
+detail::keyword_t parser_base::parse_keyword(const char* p, size_t len)
+{
+ return keyword::get().find({p, len});
+}
+
+parser_base::key_value parser_base::parse_key_value(const char* p, size_t len)
+{
+ size_t scope = get_scope();
+ assert(scope != scope_empty);
+
+ assert(*p != ' ');
+ assert(len);
+
+ const char* p_end = p + len;
+
+ key_value kv;
+
+ char last = 0;
+ bool key_found = false;
+
+ const char* p_head = p;
+
+ for (; p != p_end; ++p)
+ {
+ if (*p == ' ')
+ {
+ if (!key_found)
+ {
+ if (last == ':')
+ {
+ // Key found.
+ std::size_t n = p - p_head - 1;
+ kv.key = trim({p_head, n});
+ key_found = true;
+ p_head = nullptr;
+ }
+ }
+ }
+ else
+ {
+ if (!p_head)
+ p_head = p;
+ }
+
+ last = *p;
+ }
+
+ assert(p_head);
+
+ if (key_found)
+ {
+ // Key has already been found and the value comes after the ':'.
+ kv.value = std::string_view(p_head, p-p_head);
+ }
+ else if (last == ':')
+ {
+ // Line only contains a key and ends with ':'.
+ std::size_t n = p - p_head - 1;
+ kv.key = trim({p_head, n});
+ }
+ else
+ {
+ // Key has not been found.
+ detail::scope_t st = get_scope_type();
+ if (st == detail::scope_t::map)
+ throw parse_error("key was expected, but not found.", offset_last_char_of_line());
+ }
+
+ return kv;
+}
+
+std::string_view parser_base::parse_single_quoted_string_value(const char*& p, size_t max_length)
+{
+ parse_quoted_string_state ret =
+ parse_single_quoted_string(p, max_length, mp_impl->m_buffer);
+
+ if (!ret.str)
+ throw_quoted_string_parse_error("parse_single_quoted_string_value", ret, offset());
+
+ return std::string_view(ret.str, ret.length);
+}
+
+std::string_view parser_base::parse_double_quoted_string_value(const char*& p, size_t max_length)
+{
+ parse_quoted_string_state ret =
+ parse_double_quoted_string(p, max_length, mp_impl->m_buffer);
+
+ if (!ret.str)
+ throw_quoted_string_parse_error("parse_double_quoted_string_value", ret, offset());
+
+ return std::string_view(ret.str, ret.length);
+}
+
+void parser_base::skip_blanks(const char*& p, size_t len)
+{
+ const char* p_end = p + len;
+ for (; p != p_end && *p == ' '; ++p)
+ ;
+}
+
+void parser_base::start_literal_block()
+{
+ mp_impl->m_in_literal_block = true;
+}
+
+bool parser_base::in_literal_block() const
+{
+ return mp_impl->m_in_literal_block;
+}
+
+void parser_base::handle_line_in_literal(size_t indent)
+{
+ size_t cur_scope = get_scope();
+
+ if (!has_line_buffer())
+ {
+ // Start a new multi-line string scope.
+
+ if (indent == cur_scope)
+ throw parse_error("parse: first line of a literal block must be indented.", offset());
+
+ push_scope(indent);
+ set_scope_type(yaml::detail::scope_t::multi_line_string);
+ }
+ else
+ {
+ // The current scope is already a multi-line scope.
+ assert(get_scope_type() == yaml::detail::scope_t::multi_line_string);
+ size_t leading_indent = indent - cur_scope;
+ prev(leading_indent);
+ }
+
+ std::string_view line = parse_to_end_of_line();
+ push_line_back(line.data(), line.size());
+}
+
+void parser_base::handle_line_in_multi_line_string()
+{
+ if (get_scope_type() != yaml::detail::scope_t::multi_line_string)
+ set_scope_type(yaml::detail::scope_t::multi_line_string);
+
+ std::string_view line = parse_to_end_of_line();
+ line = trim(line);
+ assert(!line.empty());
+ push_line_back(line.data(), line.size());
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/yaml_parser_test.cpp b/src/parser/yaml_parser_test.cpp
new file mode 100644
index 0000000..88103db
--- /dev/null
+++ b/src/parser/yaml_parser_test.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/yaml_parser.hpp>
+
+#include <string>
+
+void test_handler()
+{
+ constexpr std::string_view test_code =
+ "section-one:\n"
+ " - item 1\n"
+ " - item 2\n"
+ "\n";
+
+ orcus::yaml_handler hdl;
+ orcus::yaml_parser<orcus::yaml_handler> parser(test_code, hdl);
+ parser.parse();
+}
+
+int main()
+{
+ test_handler();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/zip_archive.cpp b/src/parser/zip_archive.cpp
new file mode 100644
index 0000000..50d5da5
--- /dev/null
+++ b/src/parser/zip_archive.cpp
@@ -0,0 +1,601 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcus/zip_archive.hpp>
+#include <orcus/zip_archive_stream.hpp>
+#include <orcus/string_pool.hpp>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <unordered_map>
+#include <sstream>
+#include <string_view>
+#include <iomanip>
+
+#include <zlib.h>
+#include <zconf.h>
+
+#define ORCUS_DEBUG_ZIP_ARCHIVE 0
+
+namespace orcus {
+
+namespace {
+
+struct zip_file_param
+{
+ enum compress_method_type { stored = 0, deflated = 8 };
+
+ std::string_view filename;
+ compress_method_type compress_method;
+ std::size_t offset_file_header;
+ std::size_t size_compressed;
+ std::size_t size_uncompressed;
+
+ uint16_t version_made_by;
+ uint16_t minimum_version_needed;
+ uint16_t flags;
+ uint16_t last_modified_time;
+ uint16_t last_modified_date;
+
+ uint16_t filename_length;
+ uint16_t extra_field_length;
+ uint16_t comment_length;
+
+ uint16_t disk_id_where_file_starts;
+ uint16_t file_attributes_internal;
+ uint32_t file_attributes_external;
+
+ uint32_t crc32;
+};
+
+class zip_inflater
+{
+ z_stream m_zlib_cxt;
+
+ zip_inflater(); // disabled
+public:
+ zip_inflater(std::vector<unsigned char>& raw_buf, std::vector<unsigned char>& dest_buf, const zip_file_param& param)
+ {
+ memset(&m_zlib_cxt, 0, sizeof(m_zlib_cxt));
+ m_zlib_cxt.next_in = static_cast<Bytef*>(&raw_buf[0]);
+ m_zlib_cxt.avail_in = param.size_compressed;
+
+ m_zlib_cxt.next_out = static_cast<Bytef*>(&dest_buf[0]);
+ m_zlib_cxt.avail_out = param.size_uncompressed;
+ }
+
+ ~zip_inflater()
+ {
+ inflateEnd(&m_zlib_cxt);
+ }
+
+ bool init()
+ {
+ int err = inflateInit2(&m_zlib_cxt, -MAX_WBITS);
+ return err == Z_OK;
+ }
+
+ bool inflate()
+ {
+ int err = ::inflate(&m_zlib_cxt, Z_SYNC_FLUSH);
+ if (err >= 0 && m_zlib_cxt.msg)
+ return false;
+
+ return true;
+ }
+};
+
+/**
+ * Stream doesn't know its size; only its starting offset position within
+ * the file stream.
+ */
+class zip_stream_parser
+{
+ zip_archive_stream* m_stream;
+ size_t m_pos;
+ size_t m_pos_internal;
+
+ void read_string_to_buffer(size_t n, std::vector<unsigned char>& buf)
+ {
+ if (!n)
+ throw zip_error("attempt to read string of zero size.");
+
+ m_stream->seek(m_pos+m_pos_internal);
+ m_stream->read(&buf[0], n);
+ m_pos_internal += n;
+ }
+
+public:
+ zip_stream_parser() : m_stream(nullptr), m_pos(0), m_pos_internal(0) {}
+ zip_stream_parser(zip_archive_stream* stream, size_t pos) : m_stream(stream), m_pos(pos), m_pos_internal(0) {}
+
+ std::string read_string(size_t n)
+ {
+ std::vector<unsigned char> buf(n+1, '\0');
+ read_string_to_buffer(n, buf);
+ return std::string(reinterpret_cast<const char*>(&buf[0]));
+ }
+
+ std::vector<uint8_t> read_bytes(std::size_t n)
+ {
+ if (!n)
+ throw zip_error("attempt to read string of zero size.");
+
+ std::vector<uint8_t> buf;
+ m_stream->seek(m_pos+m_pos_internal);
+ m_stream->read(buf.data(), n);
+ m_pos_internal += n;
+ return buf;
+ }
+
+ std::string_view read_string(size_t n, string_pool& pool)
+ {
+ std::vector<unsigned char> buf(n+1, '\0');
+ read_string_to_buffer(n, buf);
+ return pool.intern({reinterpret_cast<const char*>(buf.data()), n}).first;
+ }
+
+ void skip_bytes(size_t n)
+ {
+ m_pos_internal += n;
+ }
+
+ uint32_t read_4bytes()
+ {
+ m_stream->seek(m_pos+m_pos_internal);
+ unsigned char buf[4];
+ m_stream->read(&buf[0], 4);
+ m_pos_internal += 4;
+
+ uint32_t ret = buf[0];
+ ret |= (buf[1] << 8);
+ ret |= (buf[2] << 16);
+ ret |= (buf[3] << 24);
+
+ return ret;
+ }
+
+ uint16_t read_2bytes()
+ {
+ m_stream->seek(m_pos+m_pos_internal);
+ unsigned char buf[2];
+ m_stream->read(&buf[0], 2);
+ m_pos_internal += 2;
+
+ uint16_t ret = buf[0];
+ ret |= (buf[1] << 8);
+
+ return ret;
+ }
+
+ size_t tell() const
+ {
+ return m_pos + m_pos_internal;
+ }
+};
+
+/**
+ * Content of the end part of the central directory.
+ */
+struct central_dir_end
+{
+ uint32_t magic_number;
+ uint16_t this_disk_id;
+ uint16_t central_dir_disk_id;
+ uint16_t num_central_dir_records_local;
+ uint16_t num_celtral_dir_records_total;
+ uint32_t size_central_dir;
+ size_t central_dir_pos;
+ uint16_t comment_length;
+};
+
+} // anonymous namespace
+
+
+zip_file_entry_header::zip_file_entry_header() = default;
+zip_file_entry_header::zip_file_entry_header(const zip_file_entry_header& other) = default;
+zip_file_entry_header::zip_file_entry_header(zip_file_entry_header&& other) = default;
+zip_file_entry_header::~zip_file_entry_header() = default;
+
+zip_file_entry_header& zip_file_entry_header::operator=(const zip_file_entry_header& other) = default;
+zip_file_entry_header& zip_file_entry_header::operator=(zip_file_entry_header&& other) = default;
+
+std::ostream& operator<<(std::ostream& os, const zip_file_entry_header& header)
+{
+ os << "header signature: 0x" << std::hex << std::setfill('0') << std::setw(8) << header.header_signature << "\n"
+ << "version needed to extract: " << header.required_version << "\n"
+ << "general purpose bit flag: 0x" << std::hex << std::setfill('0') << std::setw(4) << header.flag << "\n"
+ << "compression method: " << header.compression_method << "\n"
+ << "last modified time: " << header.last_modified_time << "\n"
+ << "last modified date: " << header.last_modified_date << "\n"
+ << "crc32: 0x" << std::hex << std::setfill('0') << std::setw(8) << header.crc32 << "\n"
+ << "compressed size: " << header.compressed_size << "\n"
+ << "uncompressed size: " << header.uncompressed_size << "\n"
+ << "filename: " << header.filename << "\n"
+ << "extra field length: " << header.extra_field.size();
+
+ return os;
+}
+
+class zip_archive::impl
+{
+ typedef std::vector<zip_file_param> file_params_type;
+ typedef std::unordered_map<std::string_view, std::size_t> filename_map_type;
+
+ string_pool m_pool;
+ zip_archive_stream* m_stream;
+ off_t m_stream_size;
+ size_t m_central_dir_pos;
+
+ zip_stream_parser m_central_dir_end;
+
+ file_params_type m_file_params;
+ filename_map_type m_filenames;
+
+public:
+ impl(zip_archive_stream* stream);
+
+ void load();
+ zip_file_entry_header get_file_entry_header(std::size_t index) const;
+ zip_file_entry_header get_file_entry_header(std::string_view name) const;
+ std::string_view get_file_entry_name(size_t pos) const;
+
+ size_t get_file_entry_count() const
+ {
+ return m_file_params.size();
+ }
+
+ std::vector<unsigned char> read_file_entry(std::string_view entry_name) const;
+
+private:
+
+ /**
+ * Find the central directory of a zip file, located toward the end before
+ * the global comment, and starts with the byte sequence of 0x504b0506.
+ */
+ size_t seek_central_dir();
+
+ void read_central_dir_end();
+ void read_file_entries();
+};
+
+zip_archive::impl::impl(zip_archive_stream* stream) :
+ m_stream(stream), m_stream_size(0), m_central_dir_pos(0)
+{
+ if (!m_stream)
+ throw zip_error("null stream is not allowed.");
+
+ m_stream_size = m_stream->size();
+}
+
+void zip_archive::impl::load()
+{
+ size_t central_dir_end_pos = seek_central_dir();
+ if (!central_dir_end_pos)
+ throw zip_error("failed to seek the end position of the central directory");
+
+ m_central_dir_end = zip_stream_parser(m_stream, central_dir_end_pos);
+
+ // Read the end part of the central directory.
+ read_central_dir_end();
+
+ // Read file entries that are in the front part of the central directory.
+ read_file_entries();
+}
+
+zip_file_entry_header zip_archive::impl::get_file_entry_header(std::size_t index) const
+{
+ if (index >= m_file_params.size())
+ throw zip_error("invalid file entry index.");
+
+ const zip_file_param& param = m_file_params[index];
+ zip_stream_parser file_header(m_stream, param.offset_file_header);
+
+ zip_file_entry_header header;
+
+ header.header_signature = file_header.read_4bytes();
+ header.required_version = file_header.read_2bytes();
+ header.flag = file_header.read_2bytes();
+ header.compression_method = file_header.read_2bytes();
+ header.last_modified_time = file_header.read_2bytes();
+ header.last_modified_date = file_header.read_2bytes();
+ header.crc32 = file_header.read_4bytes();
+ header.compressed_size = file_header.read_4bytes();
+ header.uncompressed_size = file_header.read_4bytes();
+ uint16_t filename_len = file_header.read_2bytes();
+ uint16_t extra_field_len = file_header.read_2bytes();
+
+ if (filename_len)
+ header.filename = file_header.read_string(filename_len);
+
+ if (extra_field_len)
+ header.extra_field = file_header.read_bytes(extra_field_len);
+
+ return header;
+}
+
+zip_file_entry_header zip_archive::impl::get_file_entry_header(std::string_view name) const
+{
+ auto it = m_filenames.find(name);
+ if (it == m_filenames.end())
+ {
+ std::ostringstream os;
+ os << "file entry named '" << name << "' not found";
+ throw zip_error(os.str());
+ }
+
+ return get_file_entry_header(it->second);
+}
+
+void zip_archive::impl::read_file_entries()
+{
+ m_file_params.clear();
+
+ zip_stream_parser central_dir(m_stream, m_central_dir_pos);
+ uint32_t magic_num = central_dir.read_4bytes();
+
+ while (magic_num == 0x02014b50)
+ {
+ zip_file_param param;
+
+ param.version_made_by = central_dir.read_2bytes();
+ param.minimum_version_needed = central_dir.read_2bytes();
+ param.flags = central_dir.read_2bytes();
+ param.compress_method =
+ static_cast<zip_file_param::compress_method_type>(central_dir.read_2bytes());
+
+ param.last_modified_time = central_dir.read_2bytes();
+ param.last_modified_date = central_dir.read_2bytes();
+ param.crc32 = central_dir.read_4bytes();
+ param.size_compressed = central_dir.read_4bytes();
+ param.size_uncompressed = central_dir.read_4bytes();
+ param.filename_length = central_dir.read_2bytes();
+ param.extra_field_length = central_dir.read_2bytes();
+ param.comment_length = central_dir.read_2bytes();
+ param.disk_id_where_file_starts = central_dir.read_2bytes();
+ param.file_attributes_internal = central_dir.read_2bytes();
+ param.file_attributes_external = central_dir.read_4bytes();
+ param.offset_file_header = central_dir.read_4bytes();
+
+ if (param.filename_length)
+ param.filename = central_dir.read_string(param.filename_length, m_pool);
+
+ if (param.extra_field_length)
+ // Ignore extra field for now.
+ central_dir.skip_bytes(param.extra_field_length);
+
+ if (param.comment_length)
+ // Ignore file comment for now.
+ central_dir.skip_bytes(param.comment_length);
+
+ magic_num = central_dir.read_4bytes(); // magic number for the next entry.
+
+ m_file_params.push_back(param);
+ m_filenames.insert(filename_map_type::value_type(param.filename, m_file_params.size()-1));
+
+#if ORCUS_DEBUG_ZIP_ARCHIVE
+ std::cout << "-- file entries" << std::endl;
+ printf( " magic number: 0x%8.8x\n", magic_num);
+ std::cout << " version made by: " << param.version_made_by << std::endl;
+ std::cout << " minimum version needed to extract: " << param.minimum_version_needed << std::endl;
+ printf( " general purpose bit flag: 0x%4.4x\n", param.flags);
+ std::cout << " compression method: " << param.compress_method << " (0=stored, 8=deflated)" << std::endl;
+ std::cout << " file last modified time: " << param.last_modified_time << std::endl;
+ std::cout << " file last modified date: " << param.last_modified_date << std::endl;
+ printf( " crc32: 0x%8.8x\n", param.crc32);
+ std::cout << " compressed size: " << param.size_compressed << std::endl;
+ std::cout << " uncompressed size: " << param.size_uncompressed << std::endl;
+ std::cout << " file name length: " << param.filename_length << std::endl;
+ std::cout << " extra field length: " << param.extra_field_length << std::endl;
+ std::cout << " file comment length: " << param.comment_length << std::endl;
+ std::cout << " disk number where file starts: " << param.disk_id_where_file_starts << std::endl;
+ printf( " internal file attributes: 0x%4.4x\n", param.file_attributes_internal);
+ printf( " external file attributes: 0x%8.8x\n", param.file_attributes_external);
+ std::cout << " relative offset of local file header: " << param.offset_file_header << std::endl;
+
+ if (param.filename_length)
+ std::cout << " filename: '" << param.filename << "'" << std::endl;
+
+ std::cout << "--" << std::endl;
+#endif
+ }
+}
+
+std::string_view zip_archive::impl::get_file_entry_name(std::size_t pos) const
+{
+ if (pos >= m_file_params.size())
+ return std::string_view{};
+
+ return m_file_params[pos].filename;
+}
+
+std::vector<unsigned char> zip_archive::impl::read_file_entry(std::string_view entry_name) const
+{
+ filename_map_type::const_iterator it = m_filenames.find(entry_name);
+ if (it == m_filenames.end())
+ {
+ std::ostringstream os;
+ os << "entry named '" << entry_name << "' not found";
+ throw zip_error(os.str());
+ }
+
+
+ size_t index = it->second;
+ if (index >= m_file_params.size())
+ throw zip_error("entry index is out-of-bound");
+
+ const zip_file_param& param = m_file_params[index];
+
+ // Skip the file header section.
+ zip_stream_parser file_header(m_stream, param.offset_file_header);
+ file_header.skip_bytes(4);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(2);
+ file_header.skip_bytes(4);
+ file_header.skip_bytes(4);
+ file_header.skip_bytes(4);
+ uint16_t filename_len = file_header.read_2bytes();
+ uint16_t extra_field_len = file_header.read_2bytes();
+ file_header.skip_bytes(filename_len);
+ file_header.skip_bytes(extra_field_len);
+
+ // Data section is immediately followed by the header section.
+ m_stream->seek(file_header.tell());
+
+ std::vector<unsigned char> raw_buf(param.size_compressed+1, 0);
+ m_stream->read(raw_buf.data(), param.size_compressed);
+
+ switch (param.compress_method)
+ {
+ case zip_file_param::stored:
+ {
+ // Not compressed at all.
+ return raw_buf;
+ }
+ case zip_file_param::deflated:
+ {
+ // deflate compression
+ std::vector<unsigned char> zip_buf(param.size_uncompressed+1, 0); // null-terminated
+ zip_inflater inflater(raw_buf, zip_buf, param);
+ if (!inflater.init())
+ throw zip_error("error during initialization of inflater");
+
+ if (!inflater.inflate())
+ throw zip_error("error during inflate.");
+
+ return zip_buf;
+ }
+ }
+
+ throw std::logic_error("compress method can be either 'stored' or 'deflated', but neither has happened");
+}
+
+size_t zip_archive::impl::seek_central_dir()
+{
+ // Search for the position of 0x06054b50 (read in little endian order - so
+ // it's 0x50, 0x4b, 0x05, 0x06 in this order) somewhere near the end of
+ // the stream.
+
+ unsigned char magic[] = { 0x06, 0x05, 0x4b, 0x50 };
+ size_t n_magic = 4;
+
+ off_t max_comment_size = 0xffff;
+
+ size_t buf_size = 22 + max_comment_size; // central directory size is 22 + n (n maxing at 0xffff).
+ std::vector<unsigned char> buf(buf_size);
+
+ // Read stream backward and try to find the magic number.
+
+ size_t read_end_pos = m_stream_size;
+ while (read_end_pos)
+ {
+ if (read_end_pos < buf.size())
+ // Last segment to read.
+ buf.resize(read_end_pos);
+
+ size_t read_pos = read_end_pos - buf.size();
+ m_stream->seek(read_pos);
+ m_stream->read(&buf[0], buf.size());
+
+ // Search this byte segment for the magic number.
+ std::vector<unsigned char>::reverse_iterator i = buf.rbegin(), ie = buf.rend();
+ size_t magic_pos = 0;
+ for (; i != ie; ++i)
+ {
+ // 06 05 4b 50
+ if (*i == magic[magic_pos])
+ {
+ ++magic_pos;
+ if (magic_pos == n_magic)
+ {
+ // magic number is found.
+ size_t dist = distance(buf.rbegin(), i) + 1;
+ size_t pos = read_end_pos - dist;
+ return pos;
+ }
+ }
+ else
+ magic_pos = 0;
+ }
+
+ read_end_pos -= buf.size();
+ }
+
+ return 0;
+}
+
+void zip_archive::impl::read_central_dir_end()
+{
+ central_dir_end content;
+ content.magic_number = m_central_dir_end.read_4bytes();
+ content.this_disk_id = m_central_dir_end.read_2bytes();
+ content.central_dir_disk_id = m_central_dir_end.read_2bytes();
+ content.num_central_dir_records_local = m_central_dir_end.read_2bytes();
+ content.num_celtral_dir_records_total = m_central_dir_end.read_2bytes();
+ content.size_central_dir = m_central_dir_end.read_4bytes();
+ content.central_dir_pos = m_central_dir_end.read_4bytes();
+ m_central_dir_pos = content.central_dir_pos;
+
+ content.comment_length = m_central_dir_end.read_2bytes();
+
+#if ORCUS_DEBUG_ZIP_ARCHIVE
+ std::cout << "-- central directory content" << std::endl;
+ printf(" magic number: 0x%8.8x\n", content.magic_number);
+ std::cout << " number of this disk: " << content.this_disk_id << std::endl;
+ std::cout << " disk where central directory starts: " << content.central_dir_disk_id << std::endl;
+ std::cout << " number of central directory records on this disk: " << content.num_central_dir_records_local << std::endl;
+ std::cout << " total number of central directory records: " << content.num_celtral_dir_records_total << std::endl;
+ std::cout << " size of central directory: " << content.size_central_dir << std::endl;
+ std::cout << " offset of start of central directory, relative to start of archive: " << content.central_dir_pos << std::endl;
+ std::cout << " comment length: " << content.comment_length << std::endl;
+ std::cout << "--" << std::endl;
+#endif
+}
+
+zip_archive::zip_archive(zip_archive_stream* stream) : mp_impl(std::make_unique<impl>(stream))
+{
+}
+
+zip_archive::~zip_archive() = default;
+
+void zip_archive::load()
+{
+ mp_impl->load();
+}
+
+zip_file_entry_header zip_archive::get_file_entry_header(std::size_t index) const
+{
+ return mp_impl->get_file_entry_header(index);
+}
+
+zip_file_entry_header zip_archive::get_file_entry_header(std::string_view name) const
+{
+ return mp_impl->get_file_entry_header(name);
+}
+
+std::string_view zip_archive::get_file_entry_name(std::size_t index) const
+{
+ return mp_impl->get_file_entry_name(index);
+}
+
+size_t zip_archive::get_file_entry_count() const
+{
+ return mp_impl->get_file_entry_count();
+}
+
+std::vector<unsigned char> zip_archive::read_file_entry(std::string_view entry_name) const
+{
+ return mp_impl->read_file_entry(entry_name);
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/zip_archive_stream.cpp b/src/parser/zip_archive_stream.cpp
new file mode 100644
index 0000000..776ac14
--- /dev/null
+++ b/src/parser/zip_archive_stream.cpp
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "orcus/zip_archive_stream.hpp"
+#include "orcus/zip_archive.hpp"
+
+#include <sstream>
+#include <cstring>
+
+#ifdef _MSC_VER
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#endif
+
+using namespace std;
+
+namespace orcus {
+
+zip_archive_stream::~zip_archive_stream() {}
+
+zip_archive_stream_fd::zip_archive_stream_fd(const char* filepath) :
+ m_stream(fopen(filepath, "rb"))
+{
+ if (!m_stream)
+ {
+ // Fail early at instantiation time.
+ ostringstream os;
+ os << "failed to open " << filepath << " for reading";
+ throw zip_error(os.str());
+ }
+}
+
+zip_archive_stream_fd::~zip_archive_stream_fd()
+{
+ if (m_stream)
+ fclose(m_stream);
+}
+
+size_t zip_archive_stream_fd::size() const
+{
+ if (fseeko(m_stream, 0, SEEK_END))
+ throw zip_error("failed to set seek position to the end of stream.");
+
+ return ftello(m_stream);
+}
+
+size_t zip_archive_stream_fd::tell() const
+{
+ return ftello(m_stream);
+}
+
+void zip_archive_stream_fd::read(unsigned char* buffer, size_t length) const
+{
+ size_t size_read = fread(buffer, 1, length, m_stream);
+ if (size_read != length)
+ throw zip_error("actual size read doesn't match what was expected.");
+}
+
+void zip_archive_stream_fd::seek(size_t pos)
+{
+ if (fseeko(m_stream, pos, SEEK_SET))
+ {
+ ostringstream os;
+ os << "failed to set seek position to " << pos << ".";
+ throw zip_error(os.str());
+ }
+}
+
+
+zip_archive_stream_blob::zip_archive_stream_blob(const uint8_t* blob, std::size_t size) :
+ m_blob(blob), m_cur(blob), m_size(size) {}
+
+zip_archive_stream_blob::~zip_archive_stream_blob() {}
+
+size_t zip_archive_stream_blob::size() const
+{
+ return m_size;
+}
+
+size_t zip_archive_stream_blob::tell() const
+{
+ return std::distance(m_blob, m_cur);
+}
+
+void zip_archive_stream_blob::seek(size_t pos)
+{
+ if (pos > m_size)
+ {
+ ostringstream os;
+ os << "failed to seek position to " << pos << ".";
+ throw zip_error(os.str());
+ }
+ m_cur = m_blob + pos;
+}
+
+void zip_archive_stream_blob::read(unsigned char* buffer, size_t length) const
+{
+ if (!length)
+ return;
+ // First, make sure we have enough blob to satisfy the requested stream length.
+ const size_t length_available = m_size - tell();
+ if (length_available < length)
+ throw zip_error("There is not enough stream left to fill requested length.");
+
+ memcpy(buffer, m_cur, length);
+}
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/parser/zip_archive_test.cpp b/src/parser/zip_archive_test.cpp
new file mode 100644
index 0000000..bbaa597
--- /dev/null
+++ b/src/parser/zip_archive_test.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "test_global.hpp"
+#include <algorithm>
+#include <cstdlib>
+#include <vector>
+
+#include <orcus/zip_archive_stream.hpp>
+#include <orcus/zip_archive.hpp>
+
+#include "filesystem_env.hpp"
+
+#define ASSERT_THROW(expr) \
+try \
+{ \
+ expr; \
+ assert(0); \
+} \
+catch (...) \
+{ \
+}
+
+using namespace orcus;
+
+void test_zip_archive_stream(zip_archive_stream* const strm, const unsigned char* const data, std::size_t const length)
+{
+ assert(strm->size() == length);
+ assert(strm->tell() == 0);
+
+ std::vector<unsigned char> buffer(length, 0);
+ unsigned char* buf = buffer.data();
+
+ strm->read(buf, 2);
+ assert(std::equal(data, data + 2, buf));
+ assert(strm->tell() == 0);
+ strm->read(buf, length);
+ assert(std::equal(data, data + length, buf));
+ ASSERT_THROW(strm->read(buf, length + 1));
+ strm->read(buf, 0);
+
+ strm->seek(2);
+ assert(strm->tell() == 2);
+ strm->read(buf, 2);
+ assert(std::equal(data + 2, data + 4, buf));
+ strm->seek(length);
+ assert(strm->tell() == length);
+ ASSERT_THROW(strm->seek(length + 1));
+ assert(strm->tell() == length);
+}
+
+void test_zip_archive_stream_blob()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ const unsigned char data[] = "My hovercraft is full of eels.";
+ zip_archive_stream_blob strm(data, sizeof(data));
+ test_zip_archive_stream(&strm, data, sizeof(data));
+}
+
+void test_zip_archive_file_entry_header()
+{
+ ORCUS_TEST_FUNC_SCOPE;
+
+ fs::path filepath{SRCDIR"/test/ods/raw-values-1/input.ods"};
+ assert(fs::is_regular_file(filepath));
+
+ zip_archive_stream_fd strm(filepath.string().c_str());
+
+ zip_archive archive(&strm);
+ archive.load();
+ std::size_t n_entries = archive.get_file_entry_count();
+ for (std::size_t i = 0; i < n_entries; ++i)
+ {
+ std::string_view name = archive.get_file_entry_name(i);
+ std::cout << "* entry name: " << name << std::endl;
+ zip_file_entry_header header = archive.get_file_entry_header(i);
+ assert(header.filename == name);
+ assert(header.header_signature == 0x04034b50);
+
+ // 0 = none; 8 = deflate
+ assert(header.compression_method == 0 || header.compression_method == 8);
+ }
+}
+
+int main()
+{
+ test_zip_archive_stream_blob();
+ test_zip_archive_file_entry_header();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */