poedit-2.3/0000775000372000037200000000000013616053246007651 500000000000000poedit-2.3/docs/0000775000372000037200000000000013616053245010600 500000000000000poedit-2.3/docs/Makefile.am0000664000372000037200000000015013616053171012546 00000000000000 dist_man_MANS = poedit.1 EXTRA_DIST = generate-docs.make man_asciidoc.conf man_fix.xsl poedit_man.txt poedit-2.3/docs/man_fix.xsl0000664000372000037200000000134013616053171012665 00000000000000 poedit-2.3/docs/poedit.10000664000372000037200000000411313616053171012063 00000000000000'\" t .\" Title: poedit .\" Author: Vaclav Slavik .\" Generator: DocBook XSL Stylesheets v1.79.1 .\" Date: 06/11/2018 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" .TH "POEDIT" "1" "06/11/2018" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" poedit \- gettext catalogs editor .SH "SYNOPSIS" .HP \w'\fBpoedit\fR\ 'u \fBpoedit\fR [\fB\-h\fR] [\fB\-\-verbose\fR] [\fIFILE\fR...] .SH "DESCRIPTION" .sp Poedit is GUI editor for GNU gettext translation files\&. .sp When launched with one or more files as argument, it loads and opens them for editing\&. .SH "OPTIONS" .PP \fB\-h\fR, \fB\-\-help\fR .RS 4 Display usage information and exit\&. .RE .PP \fB\-\-verbose\fR .RS 4 Print verbose logging information\&. .RE .SH "AUTHOR" .sp Written by Vaclav Slavik <\m[blue]\fBvaclav@slavik\&.io\fR\m[]\&\s-2\u[1]\d\s+2> .SH "RESOURCES" .sp Web site: \m[blue]\fBhttps://poedit\&.net/\fR\m[] .SH "COPYRIGHT" .sp Copyright (C) 2008\-2020 Vaclav Slavik\&. .sp Free use of this software is granted under the terms of the MIT license\&. .SH "AUTHOR" .PP \fBVaclav Slavik\fR <\&vaclav@slavik\&.io\&> .RS 4 Author. .RE .SH "NOTES" .IP " 1." 4 vaclav@slavik.io .RS 4 \%mailto:vaclav@slavik.io .RE poedit-2.3/docs/Makefile.in0000664000372000037200000003706413616053217012576 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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 = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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@ subdir = docs DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(dist_man_MANS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/admin/ax_boost_base.m4 \ $(top_srcdir)/admin/ax_boost_iostreams.m4 \ $(top_srcdir)/admin/ax_boost_regex.m4 \ $(top_srcdir)/admin/ax_boost_system.m4 \ $(top_srcdir)/admin/ax_boost_thread.m4 \ $(top_srcdir)/admin/ax_cxx_check_flag.m4 \ $(top_srcdir)/admin/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/admin/wxwin.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac 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; }; \ } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" NROFF = nroff MANS = $(dist_man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ BOOST_IOSTREAMS_LIB = @BOOST_IOSTREAMS_LIB@ BOOST_LDFLAGS = @BOOST_LDFLAGS@ BOOST_REGEX_LIB = @BOOST_REGEX_LIB@ BOOST_SYSTEM_LIB = @BOOST_SYSTEM_LIB@ BOOST_THREAD_LIB = @BOOST_THREAD_LIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CLD2_LIBS = @CLD2_LIBS@ CPPFLAGS = @CPPFLAGS@ CPPREST_LIBS = @CPPREST_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ GTKSPELL_CFLAGS = @GTKSPELL_CFLAGS@ GTKSPELL_LIBS = @GTKSPELL_LIBS@ HAVE_CXX14 = @HAVE_CXX14@ ICU_CFLAGS = @ICU_CFLAGS@ ICU_LIBS = @ICU_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBSECRET_CFLAGS = @LIBSECRET_CFLAGS@ LIBSECRET_LIBS = @LIBSECRET_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUCENE_CFLAGS = @LUCENE_CFLAGS@ LUCENE_LIBS = @LUCENE_LIBS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PUGIXML_CFLAGS = @PUGIXML_CFLAGS@ PUGIXML_LIBS = @PUGIXML_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WXRC = @WXRC@ WX_CFLAGS = @WX_CFLAGS@ WX_CFLAGS_ONLY = @WX_CFLAGS_ONLY@ WX_CONFIG_PATH = @WX_CONFIG_PATH@ WX_CONFIG_WITH_ARGS = @WX_CONFIG_WITH_ARGS@ WX_CPPFLAGS = @WX_CPPFLAGS@ WX_CXXFLAGS = @WX_CXXFLAGS@ WX_CXXFLAGS_ONLY = @WX_CXXFLAGS_ONLY@ WX_LIBS = @WX_LIBS@ WX_LIBS_STATIC = @WX_LIBS_STATIC@ WX_RESCOMP = @WX_RESCOMP@ WX_VERSION = @WX_VERSION@ WX_VERSION_MAJOR = @WX_VERSION_MAJOR@ WX_VERSION_MICRO = @WX_VERSION_MICRO@ WX_VERSION_MINOR = @WX_VERSION_MINOR@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ 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@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ 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@ dist_man_MANS = poedit.1 EXTRA_DIST = generate-docs.make man_asciidoc.conf man_fix.xsl poedit_man.txt all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(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 docs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign docs/Makefile .PRECIOUS: 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__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-man1: $(dist_man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(dist_man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(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 check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man1dir)"; 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: 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." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic 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-man install-man1 install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am uninstall-man \ uninstall-man1 # 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: poedit-2.3/docs/man_asciidoc.conf0000664000372000037200000000064013616053171013776 00000000000000[replacements] # interpret --foo and -f as options: (^|[\s]+|\[)(-|—|--)([\w]+)=\1 # repeatable, optional placeholder ("[FILE...]") \[([A-Z]+)(\.\.\.|…)\]=\1 # [-f] indicates optional choice: \[([^]]+)\]=\1 # $poedit$ means command "poedit": \$(.+)\$=\1 poedit-2.3/docs/generate-docs.make0000664000372000037200000000047613616053171014104 00000000000000 ASCIIDOC = asciidoc XSLTPROC = xsltproc XMLTO = xmlto all: poedit.1 clean: rm -f poedit.1 poedit.1: poedit_man.txt man_asciidoc.conf man_fix.xsl $(ASCIIDOC) -d manpage -f man_asciidoc.conf -b docbook -o - poedit_man.txt \ | $(XSLTPROC) -o poedit.1.xml man_fix.xsl - $(XMLTO) man poedit.1.xml rm poedit.1.xml poedit-2.3/docs/poedit_man.txt0000664000372000037200000000127013616053171013376 00000000000000POEDIT(1) ========= Vaclav Slavik NAME ---- poedit - gettext catalogs editor SYNOPSIS -------- $poedit$ [-h] [--verbose] [FILE...] DESCRIPTION ----------- Poedit is GUI editor for GNU gettext translation files. When launched with one or more files as argument, it loads and opens them for editing. OPTIONS ------- -h, --help:: Display usage information and exit. --verbose:: Print verbose logging information. AUTHOR ------ Written by Vaclav Slavik RESOURCES --------- Web site: https://poedit.net/ COPYRIGHT --------- Copyright \(C) 2008-2020 Vaclav Slavik. Free use of this software is granted under the terms of the MIT license. poedit-2.3/aclocal.m40000664000372000037200000014061213616053216011432 00000000000000# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.14' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.14.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.14.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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 macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file 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. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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. # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless 'enable' is passed literally. # For symmetry, 'disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], am_maintainer_other[ make rules and dependencies not useful (and sometimes confusing) to the casual installer])], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file 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. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file 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. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file 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. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([admin/ax_boost_base.m4]) m4_include([admin/ax_boost_iostreams.m4]) m4_include([admin/ax_boost_regex.m4]) m4_include([admin/ax_boost_system.m4]) m4_include([admin/ax_boost_thread.m4]) m4_include([admin/ax_cxx_check_flag.m4]) m4_include([admin/ax_cxx_compile_stdcxx.m4]) m4_include([admin/wxwin.m4]) poedit-2.3/Makefile.am0000664000372000037200000000074313616053165011631 00000000000000 ACLOCAL_AMFLAGS = -I admin SUBDIRS = src docs locales artwork desktopdir=$(datadir)/applications dist_desktop_DATA = net.poedit.Poedit.desktop net.poedit.PoeditURI.desktop metainfodir=$(datadir)/metainfo dist_metainfo_DATA = net.poedit.Poedit.appdata.xml EXTRA_DIST = \ deps/json/LICENSE.MIT \ deps/json/single_include/nlohmann/json.hpp \ deps/pugixml/LICENSE.md \ deps/pugixml/src/pugiconfig.hpp \ deps/pugixml/src/pugixml.cpp \ deps/pugixml/src/pugixml.hpp \ bootstrap poedit-2.3/net.poedit.PoeditURI.desktop0000664000372000037200000000024713616053171015040 00000000000000[Desktop Entry] Name=Poedit Type=Application Terminal=false NoDisplay=true MimeType=x-scheme-handler/poedit; Exec=poedit --handle-poedit-uri %u Icon=net.poedit.Poedit poedit-2.3/NEWS0000664000372000037200000010232213616053165010270 00000000000000 Version 2.3 ------------- - Improved pre-translation performance. - Added support for XLIFF 1.0. - Improved handling of punctuation in QA checks. - Improved macOS 10.15 Catalina compatiblity. Version 2.2.4 ------------- - XLIFF improvements: handling of initial states, non-translatable items and better visual representation of placeholders. - Upgraded bundled GNU gettext version to 0.20.1; in particular, this adds support for ES6 template literals to the JavaScript extractor. - If a file has warnings or errors, show them immediately upon opening instead of waiting for the user to explicitly validate the file. - Misc. small fixes and visual improvements. Version 2.2.3 ------------- - Fixed asserts when compiled against wxGTK 3.0. - [Windows] Fixed issue where custom font wasn't respected in some cases. Version 2.2.2 ------------- - [Windows] Fix problem with some MSIE proxy configurations not being imported. - [Windows] Performance improvements. - Assorted bugfixes. Version 2.2.1 ------------- - Improved highlighting of HTML and placeholders. - File references are now supported in XLIFF. - [Linux] Compatibility fixes for Wayland, wxGTK 3.0 and dark themes. Version 2.2 ----------- - Support for editing XLIFF (both 1.2 and 2) files. - Fixes for correct handling of dark themes, including on macOS Mojave. - [Linux] Improved appearance with GTK+ 3. - [Linux] Updated AppData and desktop files to use reverse DNS naming. Version 2.1.1 ------------- - Fixed breakage of some localizations on macOS. Version 2.1 ----------- - Added import and export of translation memory as TMX files. - Added ability to delete bad translations from the TM. - TM now has limited support for plural forms (only nplurals<=2). - Improved handling plural form rules. CLDR is now used as the data source and expressions are checked for equivalence before warning about unusual forms. Version 2.0.9 ------------- - Improved dark theme supports (still not perfect). - Fix broken list rendering of RTL text on Windows. Version 2.0.8 ------------- - Add CakePHP support. - QA warnings and RTL fixes. - Make TM reset work when the index is corrupted. Version 2.0.7 ------------- - Fix mangled non-English gettext error messages. - Add inline explanation of custom extractors syntax. Version 2.0.6 ------------- - Fix hanging with certain rare (non-UTF8, non-ASCII msgids) PO files. Version 2.0.5 ------------- - [macOS] Fixed crashing bug on macOS. - [Windows] Improved HiDPI support. - Assorted bugfixes. Version 2.0.4 ------------- - Added support for Crowdin branches. - Poedit now remembers your pre-translation settings. Version 2.0.3 ------------- - Much faster loading and saving of large PO files. - Fixed frequent false positives in QA warnings for German, Japanese, Arabic and translations with reordered brackets. - Fixed issues with suggestions not showing up in the sidebar if the user had an unusually tall editing area set up. - Fixed assert when opening a PO file on Linux. Version 2.0.2 ------------- - Unusual whitespace (2+ spaces) in the middle of strings is now highlighted. - Strings with warnings are now put at the top together with errors. - Fixed crash when clicking on an item with plurals in a POT file. - Added --line command line argument to open a file at specified item. Version 2.0.1 ------------- - Restored compatibility with Zend Framework and its .phtml extension. - Fixed keyboard navigation between plurals. - Fixed false positives in punctuation warnings (quotes, Chinese). - [Linux] Mostly fixed compatibility with wxGTK 3.0.2. - [macOS] Fixed crash with Vietnamese input method. - [Windows] Fixed disappearing menu with HiDPI >200% zoom. - [Windows] Fixed settings-related crash. - [Windows] Fixed Ctrl+A handling. IMPORTANT NOTE TO DISTRIBUTION MAINTAINERS: Poedit is affected by a bug in wxGTK 3.0.2 that cannot be worked around in user code, requiring this patch to wxGTK to be applied: https://github.com/wxWidgets/wxWidgets/commit/ed88188be7e97a0503f3471f7b0452740b732902 Version 2.0 ----------- - Revamped user interface. - Syntax highlighting for markup and special characters. - Warnings are now shown for common translation mistakes. - More robust pre-translation (previous "Fill missing translations from TM"). - "Fuzzy" was renamed "Needs work" thorough to be more accessible to gettext non-experts. - xgettext invocation can now be customized on per-file basis. - Files opened from Crowdin now auto-sync on save. - New Linux icon. - Many small improvements all over. Version 1.8.12 -------------- - Fixed previous msgid display. - Fixed Find to correctly highlight text with "whole words only" enabled. - [Windows] Fixed to accelerators and suggestions interaction with selection. - Poedit now passes --previous to msgmerge. Version 1.8.11 -------------- - [macOS] Fixed opening files by double-clicking them in Finder. - Fixed handling of sr_RS locale. Version 1.8.10 -------------- - Added support for X-Source-Language header. - [macOS] Improved macOS Sierra compatibility. - [Windows] Fixed Open in Editor button that didn't work in some cases. - [UNIX] Added AppData file. Version 1.8.9 ------------- - [Windows] Use IE proxy settings. - Start searches from the current position, not beginning of the file. - Updated bundled gettext to 0.19.8.1. - More fixes for right-to-left languages. Version 1.8.8 ------------- - Greatly reduced UI flicker on Windows plus other visual improvements on Windows 10. - Multiple fixes to Poedit’s interface in right-to-left languages. - Don't leave directional marks in translated text if there's a LTR/RTL mismatch. - Assorted small fixes. Version 1.8.7 ------------- - Added Copy From Singular operation and Next/Prev Plural Form navigation shortcuts. - Translation errors are now properly translated. - Fixed default Turkish plural form. - Fixed a bug where a perfect match wouldn't be found in the TM in some rare cases. - Updated bundled gettext to 0.19.7 (added appdata.xml and ITS support). - Assorted bugfixes. Version 1.8.6 ------------- - Fix properties window on OS X 10.9 and older. - Fix visual flicker when quickly scrolling through a file with arrow keys. - [OS X] Fix rare exception when pasting text. - Fix file width autodetection when long comments were present. - Disable Find next/prev menu items properly. Version 1.8.5 ------------- - Improved setting and handling of source paths. - Implement gzip support in Crowdin API client. - Assorted fixes. Version 1.8.4 ------------- - Fixed bug in handling POTs with plural forms introduced in 1.8.3. Version 1.8.3 ------------- - Fixed Last-Translator error when creating a new translation from existing POT. - Fixed bogus "Sources not available" error for single files setups. - Fixed TM error reporting to prevent rendering the entire UI mostly unusable. Version 1.8.2 ------------- - text editor now ensures that trailing newlines are present only if they also exist in the source text - fix HTML export error on Windows - automatically fix some bad paths settings in PO files - improved source language detection - fix incorrect timezone of PO-Revision-Date in some cases - use the user's default browser for Crowdin authentication on all platforms (wxWebView no longer required as a dependency when building on Linux) Version 1.8.1 ------------- - fix TM-related crash under heavy concurrency - [OS X] fix crash when a concurrent task throws Version 1.8 ----------- - integration with the Crowdin localization management platform - search & replace - support for directly handling POT files - improved interface for configuring source code paths - Poedit now automatically fixes certain broken files produced by certain broken tools (e.g. WPML) - modernized HTML export - [OS X] Quick Look preview - support for non-English source languages (auto-detected) - [Windows] opening multiple Poedit windows now works correctly Version 1.7.7 ------------- - strip whitespace in extractor definitions resulting from copy & paste Version 1.7.6 ------------- - fix handling of multiple displays - [Windows] fix "file couldn't be formatted nicely" problems with files in directories with (some) Unicode names Version 1.7.5 ------------- - fix scrolling to the top when saving a file; focus should be preserved now - fix disabling of extractors in preferences (oops) - [Windows, OS X] improve resilience of the TM to power loss Version 1.7.4 ------------- - size of the bottom editing part is now remembered correctly again - [GTK+] fix broken Edit->Copy/Cut/Paste - [OS X] fix stray BOM marks appearing on suggestions in some cases - [OS X] fix Brazilian Portuguese localization not being used - [OS X] fix sandbox permission window with unusual source paths setting - [Windows] HiDPI support Version 1.7.3 ------------- - it is now possible to disable unwanted extractors in preferences - source paths in catalog properties can now include individual files - exclusion paths in catalog properties can now use wildcards (e.g. *.js, now default for WordPress) - "Consult TM when updating from sources" now includes only "good" matches (with at least 75% score) - fix losing of the editing position when saving a file - fix Preferences layout in Japanese and Chinese translations - Windows: fix custom font setting after using a suggestion or copying from source text (there was no version 1.7.2) Version 1.7.1 ------------- - fix menu shortcuts problem in Polish localization Version 1.7 ----------- - reworked preferences - support for extraction from JavaScript (and more) sources - suggestions and other relevant information (comments etc.) are now much easier to access in a unified sidebar - syntax highlighting of special characters in translations - added Group by Context sorting option - implemented multiple selection - formatting of PO files can now be customized - added support for msgmerge --no-fuzzy-matching Version 1.6.10 -------------- - multiple fixes to parsing of the Language header - fix handling of broken POTs with duplicate headers - improved robustness of the Lucene TM database - misc small fixes - translations updates and fixes Version 1.6.9 ------------- - fixes to handling of RTL translations - fix editing-related crashes under wxGTK - translations updates Version 1.6.8 ------------- - fix parsing of obsolete entries in PO files - improved spellchecker handling on OS X and Windows - misc fixes - translations updates Version 1.6.7 ------------- - better handle "fatal" (but not really) msgfmt errors - OS X: fix OS X 10.7 compatibility - OS X/Win: update bundled Gettext to 0.19.2 - translations updates Version 1.6.6 ------------- - added exclusion paths support to updating from sources - spellchecking is now supported on Windows 8+ - STL version of wxWidgets is no longer required to build on Unix - update Windows and OS X builds to GNU gettext 0.19 - misc fixes - translations updates Version 1.6.5 ------------- - assorted small bugfixes Version 1.6.4 ------------- - translation memory tuning - Unix: restore compatibility with GTK+ 2 - misc fixes - minor UI improvements (better wording etc.) - OS X: misc fixes for Mavericks compatibility - OS X/Win: update bundled Gettext to 0.18.3.2 - translations updates Version 1.6.3 ------------- - fix invocation of external parser tools that need PATH - Unix: use XDG_CONFIG_HOME for dotfile location - OS X: fix conflict with Smart Quotes on Mavericks - translations updates Version 1.6.2 ------------- - fix TM failures with non-ASCII paths on Windows - add support for Zend Framework's .phtml - and support for WordPress' translators: comments - translations updates Version 1.6.1 ------------- - fixes to TM migration code - OS X: fixes for Retina displays Version 1.6 ----------- - improved languages handling (entering, sorting, plural forms expressions) - completely new translation memory implementation - assorted UI improvements - better build systems on OS X and Windows - OS X: minimum required version is 10.7; PPC builds are no longer supported Version 1.5.7 ------------- - fix incorrect --add-comments flag introduced in 1.5.6 Version 1.5.6 ------------- - fix several problems with the file viewer: better lookup of files, fix display of UTF-8 files, better detection of DOS-style paths - fix Find window's text field focus on OS X - add --add-comments=TRANSLATORS to xgettext call in default parsers - fix parsing of obsolete entries to recognize "#~|" - fix incorrect update stats when using msg contexts - translations updates Version 1.5.5 ------------- - fix crash when auto-updating translations with some TMs - fix file corruption when the catalog's charset was set to one that couldn't represent all of the text - translations updates Version 1.5.4 ------------- - fix display of source code (#472) - fix bug when saving file fails on permissions (#491) - fix Unix makefiles to install all icons (#493) - translations updates Version 1.5.3 ------------- - fixes to parsing of msgfmt errors - misc UI fixes - OS X: fixed crash when closing a document and opening another - fixed compatibility with OS X 10.5 Leopard - fixed problems with TM migration after upgrade - reverted removal of line numbers in 1.5.2 - reverted: the default is to compile MO files on save again - translations updates Version 1.5.2 ------------- - fixed crash when clearing the translation (#428, #468) - removed no longer needed line numbers from the UI - OS X: improved attention bar looks - translations updates Version 1.5.1 ------------- - Windows: fix missing libstdc++-6.dll - updated several translations Version 1.5 ----------- - show translation errors inline with the entries they relate to, instead of a confusing errors log when saving - implement full support for message contexts - replaced popups when Poedit is started for the first time with unobtrusive Firefox-style notifications - selecting suggested translation from right-click popup menu now correctly removes fuzzy flag from the translation - warn the user if Plural-Forms header is inconsistent with the number of plural translations in the catalog or if has syntax errors - correctly deduce catalog's language from filenames in the form of foo.LANG.po, as used by several large Open Source projects (#267) - Boost library is now required when compiling from sources - fixed the Find window so that it can be closed using the Esc key (#187) - positions of translation fields are now remembered correctly when Poedit window is maximized (#194) - added Edit->Clear translation command (Marcin Floryan) - removed View->Fullscreen view, it doesn't make sense in this kind of app - better application and document icons - removed the "Shaded translations list" option, it's now always enabled - misc minor UI improvements - fixed possible transaction memory database corruption (#337, #352) - added instructions on how to install additional spellchecker dictionaries - added sorting by different criteria (#256, #239) - improved source files viewer (#346) - included outdated documentation was replaced with online wiki docs (#343) - more keyboard navigation shortcuts - saving PO files no longer reformats source code references (#323); moreover, they are always formatted according to the default style used by GNU gettext tools (#348) - don't restore remembered window positions if they are outside currently available screens (#318) - changed Alt+ shortcuts to non-conflicting Ctrl+ ones: "Copy From Source Text" now uses Ctrl+B and "Translation Is Fuzzy" Ctrl+U - various UI improvements - added more translations: Bosnian translation (Kenan Dervisevic) Tajik (Victor Ibragimov) Kurdish Sorani (Asos Ap) Version 1.4.6 ------------- - OS X: fixed TM configuration tab to show languages list - fixed bug introduced in 1.4.3 that caused "Update from POT file" to clear metadata in catalog header (#355) - added Kazakh translation (Baurzhan Muftakhidinov) Version 1.4.5 ------------- - OS X: fixed Find to actually show hits in text control - OS X: fixed "Check for updates" preference broken by 1.4.4 Version 1.4.4 ------------- - sort catalogs in the manager alphabetically (#245) - fixed escaping of quotes in catalog headers (#290) - fixed reformatting of obsolete entries in catalogs (#329) - fixed list selection visibility on Windows 7 (#336) - Windows: automatically check for available updates Version 1.4.3 ------------- - Unix: fixed crash with Zemberek spell-checker backend installed (#276) - fixed parsing of catalogs produced with xgettext --indent (#189) - fixed TM updating broken in 1.3.5 (#294) - support GNOME's xml2po file references (#314) - fixed handling of "%" in filenames (#143) - added more translations: Vietnamese (Trần Ngọc Quân) Uzbek (Oybek Djuraev) Version 1.4.2 ------------- - Unix: fixed Ctrl+Up/Down/PgUp/PgDn shortcuts when NumLock is on (#2006843) - OS X: fixed running Gettext tools when Poedit is in directory with spaces in its name (#2025823) - added Uyghur translation (Abduqadir Abliz) Version 1.4.1 ------------- - fixed HTML export to properly escape the text (#1739062) - remember last used search phrase in Find window (#1909847) - Windows: fixed text entry using AltGr on many European keyboards Version 1.4 ----------- - wxWidgets >= 2.8 is now required when compiling from sources - don't show comments windows by default to avoid confusion - OS X: fixed conflict with 10.5's Spaces - Command-arrows can now be used to navigate in the list control in addition to Ctrl-arrows - Windows, OS X: significantly faster updating of catalogs on multi-core machines (on Linux, some distributions included multi-threaded gettext, some don't) - fixed remaining problems with list selection - use more standard way of differentiating between different kinds of entries in the list (translated, fuzzy, new) by using font variants instead of different background colors (#1863332) - don't update PO-Revision-Date header if it's unused (#1900298) - Windows: common shortcuts like Ctrl-A or Ctrl-backspace now work - added Belarusian latin translation (Alaksandar Navicki) Version 1.3.9 ------------- - OS X: fixed corruption of first entry when opening catalog from manager Version 1.3.8 ------------- - OS X: fixed startup on computers that didn't have Poedit installed before - fixed translation status color indicator to work correctly in case of plural entries - changed the official spelling from "poEdit" to "Poedit" - preserve old msgid records (#| msgid "...") when saving - preserve deleted records when updating catalogs - preserve msgctxt entries in catalogs (#1680554) - OS X: Sparkle is now used for automatic updates - OS X: fixed spell checker to use catalog's language - fixed View->Display quotes setting broken in 1.3.7 - Windows: fixed crash when catalog update removes translations - added more translations: Irish (Seanán Ó Coistín) Version 1.3.7 ------------- - Windows: Windows 95/98 is no longer supported by the official binary - OS X: Poedit is now built as Universal binary - fixed the Preferences menu entry in catalogs manager - fixed to handle file references with Windows paths on Unix - fixed the "failed to convert to unicode" bug when saving (#1589744) - OS X: fixed clicking on PO files in Finder (#1583967) - fixed opening source files in external editor if the path contains spaces (#1743172) - Windows: fixed keyboard navigation in Find dialog (#1697743) - added more translations: Urdu (Muhammad Shakir Aziz) Version 1.3.6 ------------- - fixed failure to load correct catalogs without error message - fixed loading of X-Poedit-Language header (#1567018) - fixed loading of files in charsets other than UTF-8 (#1562780) - fixed shortcuts on Mac OS X to not use Alt+something Version 1.3.5 ------------- - fixed Content-Type header parsing (bug #1346495) - Unicode build of wxWidgets 2.6 is now required - fixed bug with entering numbers when using German translation (#1325590) - fixed broken layout on startup when showing comments window (#1313612) - initial Mac OS X port - fixed crash when loading some invalid PO files (#1495970) - fixed the Find window to not be on top of other apps' windows - install .desktop files and icons according to freedesktop.org standards - changed the icons to a combination of Tango Desktop Project and Silk icons - removed on-the-fly checking of catalog items, it's too buggy - added more translations: Macedonian (Jovan Kostovski) Arabic (Mohammed al zaid) Thai (Pun) Malay (Mahrazi Mohd Kamal) Version 1.3.4 ------------- - fixed crash when closing the application - fixed searching in catalogs (bug #1230857) - fixed restoring window size when maximized - fixed reading of files with trailing whitespace on lines - use standard accelerators for Close command - fixed "Copy original to translation field" to work on singular form entries in catalogs that contain plural forms - added Tatarish translation (Albert Fazli) Version 1.3.3 ------------- - added ability to create bookmarks (Olivier Sannier) - improved status icons (Olivier Sannier) - more robust parsing of catalog headers - saving into read-only file now fails as expected - fixed saving of gettext keywords with commas in them - added more translations: Galician (Leandro Regueiro) Indonesian (Bayu Artanto) Friulian (Andrea Decorte) Finnish (Keikki Suopanki) Version 1.3.2 ------------- - fixed bogus warnings when updating from a POT file - added "New catalog from POT file" feature - added ability to display automatic comments in the UI (Olivier Sannier) - translations manager now searches subdirectories as well (David Fraser) - the Find tool can now optionally search from current position instead of from the beginning of the catalog (Olivier Sannier) - fixed TM to not crash on catalogs with non-ASCII msgid values - fixed catalog parser to correctly preserve automatic comments with duplicate lines and to not ignore every second automatic comment (Olivier Sannier) - added ability to search comments (Olivier Sannier) - Poedit now preserves obsolete translations (Olivier Sannier) - added checking of input files' correctness - fixed parsing of "\\n" substrings in catalog headers - fixed compilation with wxWidgets >= 2.5.3 - fixed Find to search in all plural forms instead of only the first one - added "whole words only" option to Find tool (Olivier Sannier) - added default parsers for more programming languages supported by xgettext - Windows: fixed list control corruption when updated catalog had fewer items than before the update - added more translations: Korean (Hojin Choi) Hebrew (Nir Lavi) Kyrgyz (Ilyas Bakirov) Ukrainian (Cawko Xakep) Puerto Rico Spanish (Fernando Ortiz) Asturian (Softastur) Version 1.3.1 ------------- - fixed assertion failure when viewing source files in the builtin viewer - fixed wrong escaping of backslashes in X-Poedit-* headers - fixed parsing of references to filenames containing spaces (Shane Harper) - fixed crash with catalogs that have plural forms but no Plural-Forms header - fixed parsing of the line following last msgstr[i] entry (bug #1025211) - fixed controls layout when compiled against wxWidgets 2.4 Version 1.3.0 ------------- - plural forms support (based on patch by Christophe Hermier and Guido Flohr) - fixed catalog I/O to correctly handle automatic comments (Tim Dijkstra) - Windows: visual improvements to main window (Tim Kosse) - usability improvements - fixed storing of non-ASCII catalog headers - Poedit now preserves non-standard entries in PO file header - Poedit now respects c-format and no-c-format when checking tokens correctness - position in translations list is no longer lost when saving the file - configure now correctly detects libdb4 with versioned symbols - "Find" tool now selects matches in text controls (Sergio Talens-Oliag) - use msgfmt for tokens validation - double-clicking on invalid entry now pops up error description - Unix: use GNOME theme icons if they are installed on the system - Unix: use GtkSpell for spell checking (GTK+ 2 only) - Poedit no longer saves .po.poedit file, the headers were moved into custom X-Poedit-* fields in .po file header - added more translations: Punjabi (Amanpreet Singh Alam) Albanian (Besnik Bleta) Amharic (Tegegne Tefera) Hindi (Dhananjaya Sharma) Esperanto (Tim Morley) Belarusian (Siarhei) Breton (Korvigellou an Drouizig) Walloon (Pablo Saratxaga) Bangla (Omi Azad) Basque (3ARRANO Euskalgintza Taldea) Version 1.2.5 ------------- - added catalog export to HTML (Christophe Hermier) - fixed bug in displaying list entries in ANSI build introduced in 1.2.4 - fixed opening of source files specified using absolute path - Poedit now preserves fuzzy status if set after partially editing an entry - many fixes to comment window (Olivier Sannier) - comment window is now (optionally) editable (Olivier Sannier) - fixed preferences dialog if translation memory is not used (Olivier Sannier) - added printf() tokens validation (Frederic Giudicelli) (requires wxWidgets >= 2.5.1 in Unicode build) - added ability to specify source code charset other than US-ASCII (based on patch by Stefan Kowski) - added Mongolian translation (Mendbayar Bayar, Khurelbaatar Lkhagvasuren) Version 1.2.4 ------------- - added optional comment window to the bottom of main screen (based on patch by Olivier Sannier, still not fully functional) - added "Automatically translate using TM" operation to the Catalog menu - Windows: upgraded bundled gettext to 0.12.1 - fixed .po files parser to read files created by xgettext -i - added ability to customize fonts - Windows: added support for Delphi via dxgettext (http://dybdahl.dk/dxgettext/) - translation memory wizard fixes for multiple languages case - comments and msgid strings are stored using catalog's charset and are not limited to US-ASCII anymore (based on patch by Stefan Kowski) Version 1.2.3 ------------- - fixed compilation with Berkeley DB 4.1.25 - fixed disappearing catalog status information - fixed bug in redrawing overview list on startup - added more translations: Serbian (Bojan Suzic) Portuguese (Lazarus Long) Hungarian (Szilard Vizi) Lithuanian (Mantas Kriauciunas, Liudas Dmitrijevas, Kestutis Snieska, Ramunas Lukasevicius) Farsi (Abbas Izad) Afrikaans (Petri Jooste) Slovenian (Luka Marinko) Version 1.2.2 ------------- - Poedit now correctly differentiates between Traditional and Simplified Chinese - optimizations for better handling of catalogs with very large entries - Mac: compilation fixes for buggy gcc 3.1 snapshot used by MacOS X - added country metadata into catalog settings dialog - Windows: it is now possible to change UI language directly in Poedit - added catalog updating from POT files - more intuitive UI for translation memory creation - added more translations: partial Greek translation (Simos Xenitellis) Japanese (Masapon) Simplified Chinese (Leo Liaw) Russian (Pavel Maryanov) Norwegian Bokmål (Hans Fr. Nordhaug) Icelandic (Samúel Jón Gunnarsson) Brazilian Portuguese (Leonardo Peixoto) Spanish (Javier Bravo) Danish (Lars Dybdahl) Version 1.2.1 ------------- - Windows: Poedit window now accepts files dropped on it via drag'n'drop - added more translations: Georgian (Aiet Kolkhi) Romanian (Ovidiu Constantin) Catalan (Pau Bosch i Crespo) - reworked Traditional Chinese translation (Leo Liaw) - fixed bug when empty error text was shown if msgfmt reported error - moved "Shaded translations list" from preferences into the View menu - Windows: allow coexistence of multiple Poedit versions on same system Version 1.2.0 ------------- - fixed bug in catalog updater: didn't use default keywords if none specified - added a warning if no files were found during catalog update - fixed "Copy original to translation field" to do exact copy - added more translations: Tamil (Prabu Anand) Bulgarian (Dimitar Boyn) Swedish (Simon Bohlin) Slovak (Pavol Cvengros) - fixed Turkish translation (wrong catalog included by mistake) - Linux: RPMs are no longer provided in Mandrake and RedHat flavors, they were unified into single RPM (mdk menu support was _not_ lost by this) - fixed data loss when updating catalog with invalid entries - Windows: fixed toolbars look on Windows XP - Windows: the installer no longer requires Administrator privileges Version 1.1.10 -------------- - fix to "fixes to catalog charset handling" from 1.1.9 - Unix: configure now checks for db4 in addition to db and db3 - Windows: fixed launching Poedit via associations when long filenames were involved - added more translations: Polish (Arkadiusz Lipiec) Norwegian Nynorsk (Karl Ove Hufthammer) Turkish (Hakki Dogusan) Latvian (Artis Trops) Italian (Pino Toscano) Version 1.1.9 ------------- - fixes to catalog charset handling - Linux: added Mandrake RPM packages - added translations to more languages: Estonian (Joosep-Georg Jarvemaa) Dutch (Patrick Hubers) German (Bernd Böckmann) French (Lionel Allorge) Croatian (Mladen Mintakovic) Version 1.1.8 ------------- - fixes to editable list control Version 1.1.7 ------------- - fixed a bug that prevented direct opening of files in editor from working - fixed Find dialog (didn't select found entries in the list) - Poedit 1.1.6 package contained out-of-date resources.zip by mistake, this is fixed now - added an option to disable list rows shading - minor UI tweaks - added Chinese (zh_TW) translation (Ying-Chieh Liao) - several fixes related to handling of directory names with spaces - fixed launching Poedit with filename as the argument Version 1.1.6 ------------- - support for Windows XP native look & feel - Win32 version is now Unicode-enabled - fixes to the way multiline entries are stored in .po file - i18n support in the app itself (finally!) (so far only Czech translation is available, translators welcome!) - added an option to display .po file line numbers for catalog entries - fixed crash when browsing certain source files - added ability to open referred source files directly in the editor of choice instead of in built-in files viewer - Windows: fixed wrong placement of progress indicator in the status bar - Unix: man page is now installed - Unix: Poedit now links with libdb-3.x for x > 1, too - Linux: RPM package now comes in two favors: poedit and poedit-semistatic (the latter is statically linked against wxGTK and libdb) Version 1.1.5 ------------- - upgraded to link against any of libdb-3.{1,2,3} - Windows: fixed bug when editing entries in editable listbox control - updated ISO 639-1 table - visually improved listbox - Win32 binary package is now cross-compiled with Mingw32 - fixed Unix makefile to not attempt to install KDE and/or GNOME entries if you doesn't have necessary write permissions Version 1.1.4 ------------- - fixed bug in Search when looking for strings with non-ASCII characters in them - charset combobox in catalog settings now remember values Version 1.1.3 ------------- - added ability to edit comments - nicer icons by Dean S. Jones - new source code references browser - new keyboard navigation - various UI improvements and bugfixes - added catalogs manager for easier access to translator's files - updated documentation Version 1.1.2 ------------- - fixed incorrect update of TM database path setting from preferences dialog - fixed assertion failures with empty catalog files when right-clicking the list control - changed default TM DB path to something more sane under Windows - Windows: fixed directories traversal during TM update under Windows Version 1.1.1 ------------- - added support for semi-automatic translations using translation memory concept. Translation memory is an indexed database of all string-translation pairs found in the system, plus algorithm to retrieve similar strings from the database. Poedit can dig translations from PO, MO and RPM files. - implemented search - Poedit source code is now documented with Doxygen - Windows: HTML Help documentation now uses CSS and looks much better - better keyboard navigation Version 1.1.0 ------------- - support for UTF-8 - changes to make Poedit work correctly with gettext 0.10.37 - fixed default ISO charset names to be iso-8859-n instead of iso8859-n - new ability to save catalogs in all common CR/LF formats, plus an option to preserve file's format (default values: Unix and preserve) - added fullscreen mode Version 1.0.3 ------------- - fixed comments parsing bug (reported by Mattias Dahlberg) - Windows: fixed ugly blinking when resizing Poedit window Version 1.0.2 ------------- - Unix: fixed problem with localized versions of gettext - fixed Content-Transfer-Encoding header (was "8-bit" instead of "8bit") - fixed POT-Creation-Date and PO-Revision-Date date writing - better handling of \n: strings with \n in them are now both displayed and saved to .po file as multiline records - saving catalog now preserves comments - Unix: fixed dist makefile target Version 1.0.1 ------------- - fixed loading of catalogs with multiline msgid records - fixed assertion failure in parsers info saving if ~/.poedit did not exist [harmless, in debug builds only] - right-clicking list control now selects the item under cursor - Unix: fixed docs/Makefile.am to cd correctly - Unix: configure change: better check for wxWidgets - Linux: fixed RPM spec file - Unix: added integration with KDE and GNOME desktops Version 1.0.0 ------------- - initial release poedit-2.3/COPYING0000664000372000037200000000204613616053165010626 00000000000000Copyright (c) 1999-2020 Vaclav Slavik 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. poedit-2.3/Makefile.in0000664000372000037200000007137313616053217011647 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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 = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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@ subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(dist_desktop_DATA) $(dist_metainfo_DATA) AUTHORS COPYING \ NEWS README admin/compile admin/config.guess admin/config.sub \ admin/install-sh admin/missing $(top_srcdir)/admin/compile \ $(top_srcdir)/admin/config.guess \ $(top_srcdir)/admin/config.sub $(top_srcdir)/admin/install-sh \ $(top_srcdir)/admin/missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/admin/ax_boost_base.m4 \ $(top_srcdir)/admin/ax_boost_iostreams.m4 \ $(top_srcdir)/admin/ax_boost_regex.m4 \ $(top_srcdir)/admin/ax_boost_system.m4 \ $(top_srcdir)/admin/ax_boost_thread.m4 \ $(top_srcdir)/admin/ax_cxx_check_flag.m4 \ $(top_srcdir)/admin/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/admin/wxwin.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac 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)$(desktopdir)" "$(DESTDIR)$(metainfodir)" DATA = $(dist_desktop_DATA) $(dist_metainfo_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck 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)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BOOST_CPPFLAGS = @BOOST_CPPFLAGS@ BOOST_IOSTREAMS_LIB = @BOOST_IOSTREAMS_LIB@ BOOST_LDFLAGS = @BOOST_LDFLAGS@ BOOST_REGEX_LIB = @BOOST_REGEX_LIB@ BOOST_SYSTEM_LIB = @BOOST_SYSTEM_LIB@ BOOST_THREAD_LIB = @BOOST_THREAD_LIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CLD2_LIBS = @CLD2_LIBS@ CPPFLAGS = @CPPFLAGS@ CPPREST_LIBS = @CPPREST_LIBS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ GTKSPELL_CFLAGS = @GTKSPELL_CFLAGS@ GTKSPELL_LIBS = @GTKSPELL_LIBS@ HAVE_CXX14 = @HAVE_CXX14@ ICU_CFLAGS = @ICU_CFLAGS@ ICU_LIBS = @ICU_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBSECRET_CFLAGS = @LIBSECRET_CFLAGS@ LIBSECRET_LIBS = @LIBSECRET_LIBS@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LUCENE_CFLAGS = @LUCENE_CFLAGS@ LUCENE_LIBS = @LUCENE_LIBS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PUGIXML_CFLAGS = @PUGIXML_CFLAGS@ PUGIXML_LIBS = @PUGIXML_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ WXRC = @WXRC@ WX_CFLAGS = @WX_CFLAGS@ WX_CFLAGS_ONLY = @WX_CFLAGS_ONLY@ WX_CONFIG_PATH = @WX_CONFIG_PATH@ WX_CONFIG_WITH_ARGS = @WX_CONFIG_WITH_ARGS@ WX_CPPFLAGS = @WX_CPPFLAGS@ WX_CXXFLAGS = @WX_CXXFLAGS@ WX_CXXFLAGS_ONLY = @WX_CXXFLAGS_ONLY@ WX_LIBS = @WX_LIBS@ WX_LIBS_STATIC = @WX_LIBS_STATIC@ WX_RESCOMP = @WX_RESCOMP@ WX_VERSION = @WX_VERSION@ WX_VERSION_MAJOR = @WX_VERSION_MAJOR@ WX_VERSION_MICRO = @WX_VERSION_MICRO@ WX_VERSION_MINOR = @WX_VERSION_MINOR@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ 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@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ 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@ ACLOCAL_AMFLAGS = -I admin SUBDIRS = src docs locales artwork desktopdir = $(datadir)/applications dist_desktop_DATA = net.poedit.Poedit.desktop net.poedit.PoeditURI.desktop metainfodir = $(datadir)/metainfo dist_metainfo_DATA = net.poedit.Poedit.appdata.xml EXTRA_DIST = \ deps/json/LICENSE.MIT \ deps/json/single_include/nlohmann/json.hpp \ deps/pugixml/LICENSE.md \ deps/pugixml/src/pugiconfig.hpp \ deps/pugixml/src/pugixml.cpp \ deps/pugixml/src/pugixml.hpp \ bootstrap all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): install-dist_desktopDATA: $(dist_desktop_DATA) @$(NORMAL_INSTALL) @list='$(dist_desktop_DATA)'; test -n "$(desktopdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(desktopdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(desktopdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(desktopdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(desktopdir)" || exit $$?; \ done uninstall-dist_desktopDATA: @$(NORMAL_UNINSTALL) @list='$(dist_desktop_DATA)'; test -n "$(desktopdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(desktopdir)'; $(am__uninstall_files_from_dir) install-dist_metainfoDATA: $(dist_metainfo_DATA) @$(NORMAL_INSTALL) @list='$(dist_metainfo_DATA)'; test -n "$(metainfodir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(metainfodir)'"; \ $(MKDIR_P) "$(DESTDIR)$(metainfodir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(metainfodir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(metainfodir)" || exit $$?; \ done uninstall-dist_metainfoDATA: @$(NORMAL_UNINSTALL) @list='$(dist_metainfo_DATA)'; test -n "$(metainfodir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(metainfodir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(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-recursive 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" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive 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 -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(metainfodir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: 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." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_desktopDATA install-dist_metainfoDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_desktopDATA uninstall-dist_metainfoDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-tags \ distcleancheck distdir distuninstallcheck dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_desktopDATA \ install-dist_metainfoDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-dist_desktopDATA \ uninstall-dist_metainfoDATA # 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: poedit-2.3/deps/0000775000372000037200000000000013616053245010603 500000000000000poedit-2.3/deps/pugixml/0000775000372000037200000000000013616053245012270 500000000000000poedit-2.3/deps/pugixml/LICENSE.md0000664000372000037200000000206713616053215013616 00000000000000MIT License Copyright (c) 2006-2019 Arseny Kapoulkine 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. poedit-2.3/deps/pugixml/src/0000775000372000037200000000000013616053245013057 500000000000000poedit-2.3/deps/pugixml/src/pugixml.hpp0000664000372000037200000014720213616053215015200 00000000000000/** * pugixml parser - version 1.10 * -------------------------------------------------------- * Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef PUGIXML_VERSION // Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons // Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits # define PUGIXML_VERSION 1100 #endif // Include user configuration file (this can define various configuration macros) #include "pugiconfig.hpp" #ifndef HEADER_PUGIXML_HPP #define HEADER_PUGIXML_HPP // Include stddef.h for size_t and ptrdiff_t #include // Include exception header for XPath #if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) # include #endif // Include STL headers #ifndef PUGIXML_NO_STL # include # include # include #endif // Macro for deprecated features #ifndef PUGIXML_DEPRECATED # if defined(__GNUC__) # define PUGIXML_DEPRECATED __attribute__((deprecated)) # elif defined(_MSC_VER) && _MSC_VER >= 1300 # define PUGIXML_DEPRECATED __declspec(deprecated) # else # define PUGIXML_DEPRECATED # endif #endif // If no API is defined, assume default #ifndef PUGIXML_API # define PUGIXML_API #endif // If no API for classes is defined, assume default #ifndef PUGIXML_CLASS # define PUGIXML_CLASS PUGIXML_API #endif // If no API for functions is defined, assume default #ifndef PUGIXML_FUNCTION # define PUGIXML_FUNCTION PUGIXML_API #endif // If the platform is known to have long long support, enable long long functions #ifndef PUGIXML_HAS_LONG_LONG # if __cplusplus >= 201103 # define PUGIXML_HAS_LONG_LONG # elif defined(_MSC_VER) && _MSC_VER >= 1400 # define PUGIXML_HAS_LONG_LONG # endif #endif // If the platform is known to have move semantics support, compile move ctor/operator implementation #ifndef PUGIXML_HAS_MOVE # if __cplusplus >= 201103 # define PUGIXML_HAS_MOVE # elif defined(_MSC_VER) && _MSC_VER >= 1600 # define PUGIXML_HAS_MOVE # endif #endif // If C++ is 2011 or higher, add 'noexcept' specifiers #ifndef PUGIXML_NOEXCEPT # if __cplusplus >= 201103 # define PUGIXML_NOEXCEPT noexcept # elif defined(_MSC_VER) && _MSC_VER >= 1900 # define PUGIXML_NOEXCEPT noexcept # else # define PUGIXML_NOEXCEPT # endif #endif // Some functions can not be noexcept in compact mode #ifdef PUGIXML_COMPACT # define PUGIXML_NOEXCEPT_IF_NOT_COMPACT #else # define PUGIXML_NOEXCEPT_IF_NOT_COMPACT PUGIXML_NOEXCEPT #endif // If C++ is 2011 or higher, add 'override' qualifiers #ifndef PUGIXML_OVERRIDE # if __cplusplus >= 201103 # define PUGIXML_OVERRIDE override # elif defined(_MSC_VER) && _MSC_VER >= 1700 # define PUGIXML_OVERRIDE override # else # define PUGIXML_OVERRIDE # endif #endif // Character interface macros #ifdef PUGIXML_WCHAR_MODE # define PUGIXML_TEXT(t) L ## t # define PUGIXML_CHAR wchar_t #else # define PUGIXML_TEXT(t) t # define PUGIXML_CHAR char #endif namespace pugi { // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE typedef PUGIXML_CHAR char_t; #ifndef PUGIXML_NO_STL // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE typedef std::basic_string, std::allocator > string_t; #endif } // The PugiXML namespace namespace pugi { // Tree node types enum xml_node_type { node_null, // Empty (null) node handle node_document, // A document tree's absolute root node_element, // Element tag, i.e. '' node_pcdata, // Plain character data, i.e. 'text' node_cdata, // Character data, i.e. '' node_comment, // Comment tag, i.e. '' node_pi, // Processing instruction, i.e. '' node_declaration, // Document declaration, i.e. '' node_doctype // Document type declaration, i.e. '' }; // Parsing options // Minimal parsing mode (equivalent to turning all other flags off). // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. const unsigned int parse_minimal = 0x0000; // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. const unsigned int parse_pi = 0x0001; // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. const unsigned int parse_comments = 0x0002; // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. const unsigned int parse_cdata = 0x0004; // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. const unsigned int parse_ws_pcdata = 0x0008; // This flag determines if character and entity references are expanded during parsing. This flag is on by default. const unsigned int parse_escapes = 0x0010; // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. const unsigned int parse_eol = 0x0020; // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. const unsigned int parse_wconv_attribute = 0x0040; // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. const unsigned int parse_wnorm_attribute = 0x0080; // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. const unsigned int parse_declaration = 0x0100; // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. const unsigned int parse_doctype = 0x0200; // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only // of whitespace is added to the DOM tree. // This flag is off by default; turning it on may result in slower parsing and more memory consumption. const unsigned int parse_ws_pcdata_single = 0x0400; // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default. const unsigned int parse_trim_pcdata = 0x0800; // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document // is a valid document. This flag is off by default. const unsigned int parse_fragment = 0x1000; // This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of // the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments. // This flag is off by default. const unsigned int parse_embed_pcdata = 0x2000; // The default parsing mode. // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; // The full parsing mode. // Nodes of all types are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; // These flags determine the encoding of input data for XML document enum xml_encoding { encoding_auto, // Auto-detect input encoding using BOM or < / class xml_object_range { public: typedef It const_iterator; typedef It iterator; xml_object_range(It b, It e): _begin(b), _end(e) { } It begin() const { return _begin; } It end() const { return _end; } private: It _begin, _end; }; // Writer interface for node printing (see xml_node::print) class PUGIXML_CLASS xml_writer { public: virtual ~xml_writer() {} // Write memory chunk into stream/file/whatever virtual void write(const void* data, size_t size) = 0; }; // xml_writer implementation for FILE* class PUGIXML_CLASS xml_writer_file: public xml_writer { public: // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio xml_writer_file(void* file); virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: void* file; }; #ifndef PUGIXML_NO_STL // xml_writer implementation for streams class PUGIXML_CLASS xml_writer_stream: public xml_writer { public: // Construct writer from an output stream object xml_writer_stream(std::basic_ostream >& stream); xml_writer_stream(std::basic_ostream >& stream); virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: std::basic_ostream >* narrow_stream; std::basic_ostream >* wide_stream; }; #endif // A light-weight handle for manipulating attributes in DOM tree class PUGIXML_CLASS xml_attribute { friend class xml_attribute_iterator; friend class xml_node; private: xml_attribute_struct* _attr; typedef void (*unspecified_bool_type)(xml_attribute***); public: // Default constructor. Constructs an empty attribute. xml_attribute(); // Constructs attribute from internal pointer explicit xml_attribute(xml_attribute_struct* attr); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators (compares wrapped attribute pointers) bool operator==(const xml_attribute& r) const; bool operator!=(const xml_attribute& r) const; bool operator<(const xml_attribute& r) const; bool operator>(const xml_attribute& r) const; bool operator<=(const xml_attribute& r) const; bool operator>=(const xml_attribute& r) const; // Check if attribute is empty bool empty() const; // Get attribute name/value, or "" if attribute is empty const char_t* name() const; const char_t* value() const; // Get attribute value, or the default value if attribute is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty int as_int(int def = 0) const; unsigned int as_uint(unsigned int def = 0) const; double as_double(double def = 0) const; float as_float(float def = 0) const; #ifdef PUGIXML_HAS_LONG_LONG long long as_llong(long long def = 0) const; unsigned long long as_ullong(unsigned long long def = 0) const; #endif // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty bool as_bool(bool def = false) const; // Set attribute name/value (returns false if attribute is empty or there is not enough memory) bool set_name(const char_t* rhs); bool set_value(const char_t* rhs); // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); bool set_value(unsigned int rhs); bool set_value(long rhs); bool set_value(unsigned long rhs); bool set_value(double rhs); bool set_value(float rhs); bool set_value(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set_value(long long rhs); bool set_value(unsigned long long rhs); #endif // Set attribute value (equivalent to set_value without error checking) xml_attribute& operator=(const char_t* rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); xml_attribute& operator=(long rhs); xml_attribute& operator=(unsigned long rhs); xml_attribute& operator=(double rhs); xml_attribute& operator=(float rhs); xml_attribute& operator=(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_attribute& operator=(long long rhs); xml_attribute& operator=(unsigned long long rhs); #endif // Get next/previous attribute in the attribute list of the parent node xml_attribute next_attribute() const; xml_attribute previous_attribute() const; // Get hash value (unique for handles to the same object) size_t hash_value() const; // Get internal pointer xml_attribute_struct* internal_object() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); #endif // A light-weight handle for manipulating nodes in DOM tree class PUGIXML_CLASS xml_node { friend class xml_attribute_iterator; friend class xml_node_iterator; friend class xml_named_node_iterator; protected: xml_node_struct* _root; typedef void (*unspecified_bool_type)(xml_node***); public: // Default constructor. Constructs an empty node. xml_node(); // Constructs node from internal pointer explicit xml_node(xml_node_struct* p); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators (compares wrapped node pointers) bool operator==(const xml_node& r) const; bool operator!=(const xml_node& r) const; bool operator<(const xml_node& r) const; bool operator>(const xml_node& r) const; bool operator<=(const xml_node& r) const; bool operator>=(const xml_node& r) const; // Check if node is empty. bool empty() const; // Get node type xml_node_type type() const; // Get node name, or "" if node is empty or it has no name const char_t* name() const; // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. const char_t* value() const; // Get attribute list xml_attribute first_attribute() const; xml_attribute last_attribute() const; // Get children list xml_node first_child() const; xml_node last_child() const; // Get next/previous sibling in the children list of the parent node xml_node next_sibling() const; xml_node previous_sibling() const; // Get parent node xml_node parent() const; // Get root of DOM tree this node belongs to xml_node root() const; // Get text object for the current node xml_text text() const; // Get child, attribute or next/previous sibling with the specified name xml_node child(const char_t* name) const; xml_attribute attribute(const char_t* name) const; xml_node next_sibling(const char_t* name) const; xml_node previous_sibling(const char_t* name) const; // Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast) xml_attribute attribute(const char_t* name, xml_attribute& hint) const; // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA const char_t* child_value() const; // Get child value of child with specified name. Equivalent to child(name).child_value(). const char_t* child_value(const char_t* name) const; // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) bool set_name(const char_t* rhs); bool set_value(const char_t* rhs); // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(const char_t* name); xml_attribute prepend_attribute(const char_t* name); xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); xml_attribute prepend_copy(const xml_attribute& proto); xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); // Add child node with specified type. Returns added node, or empty node on errors. xml_node append_child(xml_node_type type = node_element); xml_node prepend_child(xml_node_type type = node_element); xml_node insert_child_after(xml_node_type type, const xml_node& node); xml_node insert_child_before(xml_node_type type, const xml_node& node); // Add child element with specified name. Returns added node, or empty node on errors. xml_node append_child(const char_t* name); xml_node prepend_child(const char_t* name); xml_node insert_child_after(const char_t* name, const xml_node& node); xml_node insert_child_before(const char_t* name, const xml_node& node); // Add a copy of the specified node as a child. Returns added node, or empty node on errors. xml_node append_copy(const xml_node& proto); xml_node prepend_copy(const xml_node& proto); xml_node insert_copy_after(const xml_node& proto, const xml_node& node); xml_node insert_copy_before(const xml_node& proto, const xml_node& node); // Move the specified node to become a child of this node. Returns moved node, or empty node on errors. xml_node append_move(const xml_node& moved); xml_node prepend_move(const xml_node& moved); xml_node insert_move_after(const xml_node& moved, const xml_node& node); xml_node insert_move_before(const xml_node& moved, const xml_node& node); // Remove specified attribute bool remove_attribute(const xml_attribute& a); bool remove_attribute(const char_t* name); // Remove specified child bool remove_child(const xml_node& n); bool remove_child(const char_t* name); // Parses buffer as an XML document fragment and appends all nodes as children of the current node. // Copies/converts the buffer, so it may be deleted or changed after the function returns. // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory. xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Find attribute using predicate. Returns first attribute for which predicate returned true. template xml_attribute find_attribute(Predicate pred) const { if (!_root) return xml_attribute(); for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) if (pred(attrib)) return attrib; return xml_attribute(); } // Find child node using predicate. Returns first child for which predicate returned true. template xml_node find_child(Predicate pred) const { if (!_root) return xml_node(); for (xml_node node = first_child(); node; node = node.next_sibling()) if (pred(node)) return node; return xml_node(); } // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. template xml_node find_node(Predicate pred) const { if (!_root) return xml_node(); xml_node cur = first_child(); while (cur._root && cur._root != _root) { if (pred(cur)) return cur; if (cur.first_child()) cur = cur.first_child(); else if (cur.next_sibling()) cur = cur.next_sibling(); else { while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); if (cur._root != _root) cur = cur.next_sibling(); } } return xml_node(); } // Find child node by attribute name/value xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; #ifndef PUGIXML_NO_STL // Get the absolute node path from root as a text string. string_t path(char_t delimiter = '/') const; #endif // Search for a node by path consisting of node names and . or .. elements. xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; // Recursively traverse subtree with xml_tree_walker bool traverse(xml_tree_walker& walker); #ifndef PUGIXML_NO_XPATH // Select single node by evaluating XPath query. Returns first node from the resulting node set. xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const; xpath_node select_node(const xpath_query& query) const; // Select node set by evaluating XPath query xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; xpath_node_set select_nodes(const xpath_query& query) const; // (deprecated: use select_node instead) Select single node by evaluating XPath query. PUGIXML_DEPRECATED xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; PUGIXML_DEPRECATED xpath_node select_single_node(const xpath_query& query) const; #endif // Print subtree using a writer object void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; #ifndef PUGIXML_NO_STL // Print subtree to stream void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; #endif // Child nodes iterators typedef xml_node_iterator iterator; iterator begin() const; iterator end() const; // Attribute iterators typedef xml_attribute_iterator attribute_iterator; attribute_iterator attributes_begin() const; attribute_iterator attributes_end() const; // Range-based for support xml_object_range children() const; xml_object_range children(const char_t* name) const; xml_object_range attributes() const; // Get node offset in parsed file/string (in char_t units) for debugging purposes ptrdiff_t offset_debug() const; // Get hash value (unique for handles to the same object) size_t hash_value() const; // Get internal pointer xml_node_struct* internal_object() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); #endif // A helper for working with text inside PCDATA nodes class PUGIXML_CLASS xml_text { friend class xml_node; xml_node_struct* _root; typedef void (*unspecified_bool_type)(xml_text***); explicit xml_text(xml_node_struct* root); xml_node_struct* _data_new(); xml_node_struct* _data() const; public: // Default constructor. Constructs an empty object. xml_text(); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Check if text object is empty bool empty() const; // Get text, or "" if object is empty const char_t* get() const; // Get text, or the default value if object is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; // Get text as a number, or the default value if conversion did not succeed or object is empty int as_int(int def = 0) const; unsigned int as_uint(unsigned int def = 0) const; double as_double(double def = 0) const; float as_float(float def = 0) const; #ifdef PUGIXML_HAS_LONG_LONG long long as_llong(long long def = 0) const; unsigned long long as_ullong(unsigned long long def = 0) const; #endif // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) bool set(const char_t* rhs); // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); bool set(unsigned int rhs); bool set(long rhs); bool set(unsigned long rhs); bool set(double rhs); bool set(float rhs); bool set(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set(long long rhs); bool set(unsigned long long rhs); #endif // Set text (equivalent to set without error checking) xml_text& operator=(const char_t* rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); xml_text& operator=(long rhs); xml_text& operator=(unsigned long rhs); xml_text& operator=(double rhs); xml_text& operator=(float rhs); xml_text& operator=(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_text& operator=(long long rhs); xml_text& operator=(unsigned long long rhs); #endif // Get the data node (node_pcdata or node_cdata) for this object xml_node data() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs); #endif // Child node iterator (a bidirectional iterator over a collection of xml_node) class PUGIXML_CLASS xml_node_iterator { friend class xml_node; private: mutable xml_node _wrap; xml_node _parent; xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_node value_type; typedef xml_node* pointer; typedef xml_node& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_node_iterator(); // Construct an iterator which points to the specified node xml_node_iterator(const xml_node& node); // Iterator operators bool operator==(const xml_node_iterator& rhs) const; bool operator!=(const xml_node_iterator& rhs) const; xml_node& operator*() const; xml_node* operator->() const; const xml_node_iterator& operator++(); xml_node_iterator operator++(int); const xml_node_iterator& operator--(); xml_node_iterator operator--(int); }; // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) class PUGIXML_CLASS xml_attribute_iterator { friend class xml_node; private: mutable xml_attribute _wrap; xml_node _parent; xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_attribute value_type; typedef xml_attribute* pointer; typedef xml_attribute& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_attribute_iterator(); // Construct an iterator which points to the specified attribute xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); // Iterator operators bool operator==(const xml_attribute_iterator& rhs) const; bool operator!=(const xml_attribute_iterator& rhs) const; xml_attribute& operator*() const; xml_attribute* operator->() const; const xml_attribute_iterator& operator++(); xml_attribute_iterator operator++(int); const xml_attribute_iterator& operator--(); xml_attribute_iterator operator--(int); }; // Named node range helper class PUGIXML_CLASS xml_named_node_iterator { friend class xml_node; public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_node value_type; typedef xml_node* pointer; typedef xml_node& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_named_node_iterator(); // Construct an iterator which points to the specified node xml_named_node_iterator(const xml_node& node, const char_t* name); // Iterator operators bool operator==(const xml_named_node_iterator& rhs) const; bool operator!=(const xml_named_node_iterator& rhs) const; xml_node& operator*() const; xml_node* operator->() const; const xml_named_node_iterator& operator++(); xml_named_node_iterator operator++(int); const xml_named_node_iterator& operator--(); xml_named_node_iterator operator--(int); private: mutable xml_node _wrap; xml_node _parent; const char_t* _name; xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name); }; // Abstract tree walker class (see xml_node::traverse) class PUGIXML_CLASS xml_tree_walker { friend class xml_node; private: int _depth; protected: // Get current traversal depth int depth() const; public: xml_tree_walker(); virtual ~xml_tree_walker(); // Callback that is called when traversal begins virtual bool begin(xml_node& node); // Callback that is called for each node traversed virtual bool for_each(xml_node& node) = 0; // Callback that is called when traversal ends virtual bool end(xml_node& node); }; // Parsing status, returned as part of xml_parse_result object enum xml_parse_status { status_ok = 0, // No error status_file_not_found, // File was not found during load_file() status_io_error, // Error reading from file/stream status_out_of_memory, // Could not allocate memory status_internal_error, // Internal error occurred status_unrecognized_tag, // Parser could not determine tag type status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction status_bad_comment, // Parsing error occurred while parsing comment status_bad_cdata, // Parsing error occurred while parsing CDATA section status_bad_doctype, // Parsing error occurred while parsing document type declaration status_bad_pcdata, // Parsing error occurred while parsing PCDATA section status_bad_start_element, // Parsing error occurred while parsing start element tag status_bad_attribute, // Parsing error occurred while parsing element attribute status_bad_end_element, // Parsing error occurred while parsing end element tag status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) status_append_invalid_root, // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer) status_no_document_element // Parsing resulted in a document without element nodes }; // Parsing result struct PUGIXML_CLASS xml_parse_result { // Parsing status (see xml_parse_status) xml_parse_status status; // Last parsed offset (in char_t units from start of input data) ptrdiff_t offset; // Source document encoding xml_encoding encoding; // Default constructor, initializes object to failed state xml_parse_result(); // Cast to bool operator operator bool() const; // Get error description const char* description() const; }; // Document class (DOM tree root) class PUGIXML_CLASS xml_document: public xml_node { private: char_t* _buffer; char _memory[192]; // Non-copyable semantics xml_document(const xml_document&); xml_document& operator=(const xml_document&); void _create(); void _destroy(); void _move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; public: // Default constructor, makes empty document xml_document(); // Destructor, invalidates all node/attribute handles to this document ~xml_document(); #ifdef PUGIXML_HAS_MOVE // Move semantics support xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; xml_document& operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT; #endif // Removes all nodes, leaving the empty document void reset(); // Removes all nodes, then copies the entire contents of the specified document void reset(const xml_document& proto); #ifndef PUGIXML_NO_STL // Load document from stream. xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); #endif // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. PUGIXML_DEPRECATED xml_parse_result load(const char_t* contents, unsigned int options = parse_default); // Load document from zero-terminated string. No encoding conversions are applied. xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); // Load document from file xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; #ifndef PUGIXML_NO_STL // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; #endif // Save XML to file bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; // Get document element xml_node document_element() const; }; #ifndef PUGIXML_NO_XPATH // XPath query return type enum xpath_value_type { xpath_type_none, // Unknown type (query failed to compile) xpath_type_node_set, // Node set (xpath_node_set) xpath_type_number, // Number xpath_type_string, // String xpath_type_boolean // Boolean }; // XPath parsing result struct PUGIXML_CLASS xpath_parse_result { // Error message (0 if no error) const char* error; // Last parsed offset (in char_t units from string start) ptrdiff_t offset; // Default constructor, initializes object to failed state xpath_parse_result(); // Cast to bool operator operator bool() const; // Get error description const char* description() const; }; // A single XPath variable class PUGIXML_CLASS xpath_variable { friend class xpath_variable_set; protected: xpath_value_type _type; xpath_variable* _next; xpath_variable(xpath_value_type type); // Non-copyable semantics xpath_variable(const xpath_variable&); xpath_variable& operator=(const xpath_variable&); public: // Get variable name const char_t* name() const; // Get variable type xpath_value_type type() const; // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error bool get_boolean() const; double get_number() const; const char_t* get_string() const; const xpath_node_set& get_node_set() const; // Set variable value; no type conversion is performed, false is returned on type mismatch error bool set(bool value); bool set(double value); bool set(const char_t* value); bool set(const xpath_node_set& value); }; // A set of XPath variables class PUGIXML_CLASS xpath_variable_set { private: xpath_variable* _data[64]; void _assign(const xpath_variable_set& rhs); void _swap(xpath_variable_set& rhs); xpath_variable* _find(const char_t* name) const; static bool _clone(xpath_variable* var, xpath_variable** out_result); static void _destroy(xpath_variable* var); public: // Default constructor/destructor xpath_variable_set(); ~xpath_variable_set(); // Copy constructor/assignment operator xpath_variable_set(const xpath_variable_set& rhs); xpath_variable_set& operator=(const xpath_variable_set& rhs); #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; xpath_variable_set& operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT; #endif // Add a new variable or get the existing one, if the types match xpath_variable* add(const char_t* name, xpath_value_type type); // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch bool set(const char_t* name, bool value); bool set(const char_t* name, double value); bool set(const char_t* name, const char_t* value); bool set(const char_t* name, const xpath_node_set& value); // Get existing variable by name xpath_variable* get(const char_t* name); const xpath_variable* get(const char_t* name) const; }; // A compiled XPath query object class PUGIXML_CLASS xpath_query { private: void* _impl; xpath_parse_result _result; typedef void (*unspecified_bool_type)(xpath_query***); // Non-copyable semantics xpath_query(const xpath_query&); xpath_query& operator=(const xpath_query&); public: // Construct a compiled object from XPath expression. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); // Constructor xpath_query(); // Destructor ~xpath_query(); #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT; xpath_query& operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT; #endif // Get query expression return type xpath_value_type return_type() const; // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. bool evaluate_boolean(const xpath_node& n) const; // Evaluate expression as double value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. double evaluate_number(const xpath_node& n) const; #ifndef PUGIXML_NO_STL // Evaluate expression as string value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. string_t evaluate_string(const xpath_node& n) const; #endif // Evaluate expression as string value in the specified context; performs type conversion if necessary. // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; // Evaluate expression as node set in the specified context. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. xpath_node_set evaluate_node_set(const xpath_node& n) const; // Evaluate expression as node set in the specified context. // Return first node in document order, or empty node if node set is empty. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead. xpath_node evaluate_node(const xpath_node& n) const; // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) const xpath_parse_result& result() const; // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; }; #ifndef PUGIXML_NO_EXCEPTIONS #if defined(_MSC_VER) // C4275 can be ignored in Visual C++ if you are deriving // from a type in the Standard C++ Library #pragma warning(push) #pragma warning(disable: 4275) #endif // XPath exception class class PUGIXML_CLASS xpath_exception: public std::exception { private: xpath_parse_result _result; public: // Construct exception from parse result explicit xpath_exception(const xpath_parse_result& result); // Get error message virtual const char* what() const throw() PUGIXML_OVERRIDE; // Get parse result const xpath_parse_result& result() const; }; #if defined(_MSC_VER) #pragma warning(pop) #endif #endif // XPath node class (either xml_node or xml_attribute) class PUGIXML_CLASS xpath_node { private: xml_node _node; xml_attribute _attribute; typedef void (*unspecified_bool_type)(xpath_node***); public: // Default constructor; constructs empty XPath node xpath_node(); // Construct XPath node from XML node/attribute xpath_node(const xml_node& node); xpath_node(const xml_attribute& attribute, const xml_node& parent); // Get node/attribute, if any xml_node node() const; xml_attribute attribute() const; // Get parent of contained node/attribute xml_node parent() const; // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators bool operator==(const xpath_node& n) const; bool operator!=(const xpath_node& n) const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); #endif // A fixed-size collection of XPath nodes class PUGIXML_CLASS xpath_node_set { public: // Collection type enum type_t { type_unsorted, // Not ordered type_sorted, // Sorted by document order (ascending) type_sorted_reverse // Sorted by document order (descending) }; // Constant iterator type typedef const xpath_node* const_iterator; // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work typedef const xpath_node* iterator; // Default constructor. Constructs empty set. xpath_node_set(); // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); // Destructor ~xpath_node_set(); // Copy constructor/assignment operator xpath_node_set(const xpath_node_set& ns); xpath_node_set& operator=(const xpath_node_set& ns); #ifdef PUGIXML_HAS_MOVE // Move semantics support xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; xpath_node_set& operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT; #endif // Get collection type type_t type() const; // Get collection size size_t size() const; // Indexing operator const xpath_node& operator[](size_t index) const; // Collection iterators const_iterator begin() const; const_iterator end() const; // Sort the collection in ascending/descending order by document order void sort(bool reverse = false); // Get first node in the collection by document order xpath_node first() const; // Check if collection is empty bool empty() const; private: type_t _type; xpath_node _storage[1]; xpath_node* _begin; xpath_node* _end; void _assign(const_iterator begin, const_iterator end, type_t type); void _move(xpath_node_set& rhs) PUGIXML_NOEXCEPT; }; #endif #ifndef PUGIXML_NO_STL // Convert wide string to UTF8 std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); // Convert UTF8 to wide string std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); #endif // Memory allocation function interface; returns pointer to allocated memory or NULL on failure typedef void* (*allocation_function)(size_t size); // Memory deallocation function interface typedef void (*deallocation_function)(void* ptr); // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); // Get current memory management functions allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); } #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) namespace std { // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&); } #endif #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) namespace std { // Workarounds for (non-standard) iterator category detection std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&); } #endif #endif // Make sure implementation is included in header-only mode // Use macro expansion in #include to work around QMake (QTBUG-11923) #if defined(PUGIXML_HEADER_ONLY) && !defined(PUGIXML_SOURCE) # define PUGIXML_SOURCE "pugixml.cpp" # include PUGIXML_SOURCE #endif /** * Copyright (c) 2006-2019 Arseny Kapoulkine * * 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. */ poedit-2.3/deps/pugixml/src/pugiconfig.hpp0000664000372000037200000000534713616053215015650 00000000000000/** * pugixml parser - version 1.10 * -------------------------------------------------------- * Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef HEADER_PUGICONFIG_HPP #define HEADER_PUGICONFIG_HPP // Uncomment this to enable wchar_t mode // #define PUGIXML_WCHAR_MODE // Uncomment this to enable compact mode // #define PUGIXML_COMPACT // Uncomment this to disable XPath // #define PUGIXML_NO_XPATH // Uncomment this to disable STL // #define PUGIXML_NO_STL // Uncomment this to disable exceptions // #define PUGIXML_NO_EXCEPTIONS // Set this to control attributes for public classes/functions, i.e.: // #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL // #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL // #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead // Tune these constants to adjust memory-related behavior // #define PUGIXML_MEMORY_PAGE_SIZE 32768 // #define PUGIXML_MEMORY_OUTPUT_STACK 10240 // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 // Uncomment this to switch to header-only version // #define PUGIXML_HEADER_ONLY // Uncomment this to enable long long support // #define PUGIXML_HAS_LONG_LONG #endif /** * Copyright (c) 2006-2019 Arseny Kapoulkine * * 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. */ poedit-2.3/deps/pugixml/src/pugixml.cpp0000664000372000037200000121257113616053215015176 00000000000000/** * pugixml parser - version 1.10 * -------------------------------------------------------- * Copyright (C) 2006-2019, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef SOURCE_PUGIXML_CPP #define SOURCE_PUGIXML_CPP #include "pugixml.hpp" #include #include #include #include #include #ifdef PUGIXML_WCHAR_MODE # include #endif #ifndef PUGIXML_NO_XPATH # include # include #endif #ifndef PUGIXML_NO_STL # include # include # include #endif // For placement new #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4324) // structure was padded due to __declspec(align()) # pragma warning(disable: 4702) // unreachable code # pragma warning(disable: 4996) // this function or variable may be unsafe #endif #if defined(_MSC_VER) && defined(__c2__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated" // this function or variable may be unsafe #endif #ifdef __INTEL_COMPILER # pragma warning(disable: 177) // function was declared but never referenced # pragma warning(disable: 279) // controlling expression is constant # pragma warning(disable: 1478 1786) // function was declared "deprecated" # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type #endif #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY) # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away #endif #ifdef __BORLANDC__ # pragma option push # pragma warn -8008 // condition is always false # pragma warn -8066 // unreachable code #endif #ifdef __SNC__ // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug # pragma diag_suppress=178 // function was declared but never referenced # pragma diag_suppress=237 // controlling expression is constant #endif #ifdef __TI_COMPILER_VERSION__ # pragma diag_suppress 179 // function was declared but never referenced #endif // Inlining controls #if defined(_MSC_VER) && _MSC_VER >= 1300 # define PUGI__NO_INLINE __declspec(noinline) #elif defined(__GNUC__) # define PUGI__NO_INLINE __attribute__((noinline)) #else # define PUGI__NO_INLINE #endif // Branch weight controls #if defined(__GNUC__) && !defined(__c2__) # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) #else # define PUGI__UNLIKELY(cond) (cond) #endif // Simple static assertion #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } // Digital Mars C++ bug workaround for passing char loaded from memory via stack #ifdef __DMC__ # define PUGI__DMC_VOLATILE volatile #else # define PUGI__DMC_VOLATILE #endif // Integer sanitizer workaround; we only apply this for clang since gcc8 has no_sanitize but not unsigned-integer-overflow and produces "attribute directive ignored" warnings #if defined(__clang__) && defined(__has_attribute) # if __has_attribute(no_sanitize) # define PUGI__UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow"))) # else # define PUGI__UNSIGNED_OVERFLOW # endif #else # define PUGI__UNSIGNED_OVERFLOW #endif // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) using std::memcpy; using std::memmove; using std::memset; #endif // Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations #if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX) # define LLONG_MIN (-LLONG_MAX - 1LL) # define LLONG_MAX __LONG_LONG_MAX__ # define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) #endif // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features #if defined(_MSC_VER) && !defined(__S3E__) # define PUGI__MSVC_CRT_VERSION _MSC_VER #endif // Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size. #if __cplusplus >= 201103 # define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) #elif defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 # define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__) #else # define PUGI__SNPRINTF sprintf #endif // We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat. #ifdef PUGIXML_HEADER_ONLY # define PUGI__NS_BEGIN namespace pugi { namespace impl { # define PUGI__NS_END } } # define PUGI__FN inline # define PUGI__FN_NO_INLINE inline #else # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces # define PUGI__NS_BEGIN namespace pugi { namespace impl { # define PUGI__NS_END } } # else # define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace { # define PUGI__NS_END } } } # endif # define PUGI__FN # define PUGI__FN_NO_INLINE PUGI__NO_INLINE #endif // uintptr_t #if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561) namespace pugi { # ifndef _UINTPTR_T_DEFINED typedef size_t uintptr_t; # endif typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; } #else # include #endif // Memory allocation PUGI__NS_BEGIN PUGI__FN void* default_allocate(size_t size) { return malloc(size); } PUGI__FN void default_deallocate(void* ptr) { free(ptr); } template struct xml_memory_management_function_storage { static allocation_function allocate; static deallocation_function deallocate; }; // Global allocation functions are stored in class statics so that in header mode linker deduplicates them // Without a template<> we'll get multiple definitions of the same static template allocation_function xml_memory_management_function_storage::allocate = default_allocate; template deallocation_function xml_memory_management_function_storage::deallocate = default_deallocate; typedef xml_memory_management_function_storage xml_memory; PUGI__NS_END // String utilities PUGI__NS_BEGIN // Get string length PUGI__FN size_t strlength(const char_t* s) { assert(s); #ifdef PUGIXML_WCHAR_MODE return wcslen(s); #else return strlen(s); #endif } // Compare two strings PUGI__FN bool strequal(const char_t* src, const char_t* dst) { assert(src && dst); #ifdef PUGIXML_WCHAR_MODE return wcscmp(src, dst) == 0; #else return strcmp(src, dst) == 0; #endif } // Compare lhs with [rhs_begin, rhs_end) PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) { for (size_t i = 0; i < count; ++i) if (lhs[i] != rhs[i]) return false; return lhs[count] == 0; } // Get length of wide string, even if CRT lacks wide character support PUGI__FN size_t strlength_wide(const wchar_t* s) { assert(s); #ifdef PUGIXML_WCHAR_MODE return wcslen(s); #else const wchar_t* end = s; while (*end) end++; return static_cast(end - s); #endif } PUGI__NS_END // auto_ptr-like object for exception recovery PUGI__NS_BEGIN template struct auto_deleter { typedef void (*D)(T*); T* data; D deleter; auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_) { } ~auto_deleter() { if (data) deleter(data); } T* release() { T* result = data; data = 0; return result; } }; PUGI__NS_END #ifdef PUGIXML_COMPACT PUGI__NS_BEGIN class compact_hash_table { public: compact_hash_table(): _items(0), _capacity(0), _count(0) { } void clear() { if (_items) { xml_memory::deallocate(_items); _items = 0; _capacity = 0; _count = 0; } } void* find(const void* key) { if (_capacity == 0) return 0; item_t* item = get_item(key); assert(item); assert(item->key == key || (item->key == 0 && item->value == 0)); return item->value; } void insert(const void* key, void* value) { assert(_capacity != 0 && _count < _capacity - _capacity / 4); item_t* item = get_item(key); assert(item); if (item->key == 0) { _count++; item->key = key; } item->value = value; } bool reserve(size_t extra = 16) { if (_count + extra >= _capacity - _capacity / 4) return rehash(_count + extra); return true; } private: struct item_t { const void* key; void* value; }; item_t* _items; size_t _capacity; size_t _count; bool rehash(size_t count); item_t* get_item(const void* key) { assert(key); assert(_capacity > 0); size_t hashmod = _capacity - 1; size_t bucket = hash(key) & hashmod; for (size_t probe = 0; probe <= hashmod; ++probe) { item_t& probe_item = _items[bucket]; if (probe_item.key == key || probe_item.key == 0) return &probe_item; // hash collision, quadratic probing bucket = (bucket + probe + 1) & hashmod; } assert(false && "Hash table is full"); // unreachable return 0; } static PUGI__UNSIGNED_OVERFLOW unsigned int hash(const void* key) { unsigned int h = static_cast(reinterpret_cast(key)); // MurmurHash3 32-bit finalizer h ^= h >> 16; h *= 0x85ebca6bu; h ^= h >> 13; h *= 0xc2b2ae35u; h ^= h >> 16; return h; } }; PUGI__FN_NO_INLINE bool compact_hash_table::rehash(size_t count) { size_t capacity = 32; while (count >= capacity - capacity / 4) capacity *= 2; compact_hash_table rt; rt._capacity = capacity; rt._items = static_cast(xml_memory::allocate(sizeof(item_t) * capacity)); if (!rt._items) return false; memset(rt._items, 0, sizeof(item_t) * capacity); for (size_t i = 0; i < _capacity; ++i) if (_items[i].key) rt.insert(_items[i].key, _items[i].value); if (_items) xml_memory::deallocate(_items); _capacity = capacity; _items = rt._items; assert(_count == rt._count); return true; } PUGI__NS_END #endif PUGI__NS_BEGIN #ifdef PUGIXML_COMPACT static const uintptr_t xml_memory_block_alignment = 4; #else static const uintptr_t xml_memory_block_alignment = sizeof(void*); #endif // extra metadata bits static const uintptr_t xml_memory_page_contents_shared_mask = 64; static const uintptr_t xml_memory_page_name_allocated_mask = 32; static const uintptr_t xml_memory_page_value_allocated_mask = 16; static const uintptr_t xml_memory_page_type_mask = 15; // combined masks for string uniqueness static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; #ifdef PUGIXML_COMPACT #define PUGI__GETHEADER_IMPL(object, page, flags) // unused #define PUGI__GETPAGE_IMPL(header) (header).get_page() #else #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast(object) - reinterpret_cast(page)) << 8) | (flags)) // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings #define PUGI__GETPAGE_IMPL(header) static_cast(const_cast(static_cast(reinterpret_cast(&header) - (header >> 8)))) #endif #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header) #define PUGI__NODETYPE(n) static_cast((n)->header & impl::xml_memory_page_type_mask) struct xml_allocator; struct xml_memory_page { static xml_memory_page* construct(void* memory) { xml_memory_page* result = static_cast(memory); result->allocator = 0; result->prev = 0; result->next = 0; result->busy_size = 0; result->freed_size = 0; #ifdef PUGIXML_COMPACT result->compact_string_base = 0; result->compact_shared_parent = 0; result->compact_page_marker = 0; #endif return result; } xml_allocator* allocator; xml_memory_page* prev; xml_memory_page* next; size_t busy_size; size_t freed_size; #ifdef PUGIXML_COMPACT char_t* compact_string_base; void* compact_shared_parent; uint32_t* compact_page_marker; #endif }; static const size_t xml_memory_page_size = #ifdef PUGIXML_MEMORY_PAGE_SIZE (PUGIXML_MEMORY_PAGE_SIZE) #else 32768 #endif - sizeof(xml_memory_page); struct xml_memory_string_header { uint16_t page_offset; // offset from page->data uint16_t full_size; // 0 if string occupies whole page }; struct xml_allocator { xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) { #ifdef PUGIXML_COMPACT _hash = 0; #endif } xml_memory_page* allocate_page(size_t data_size) { size_t size = sizeof(xml_memory_page) + data_size; // allocate block with some alignment, leaving memory for worst-case padding void* memory = xml_memory::allocate(size); if (!memory) return 0; // prepare page structure xml_memory_page* page = xml_memory_page::construct(memory); assert(page); page->allocator = _root->allocator; return page; } static void deallocate_page(xml_memory_page* page) { xml_memory::deallocate(page); } void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); void* allocate_memory(size_t size, xml_memory_page*& out_page) { if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size)) return allocate_memory_oob(size, out_page); void* buf = reinterpret_cast(_root) + sizeof(xml_memory_page) + _busy_size; _busy_size += size; out_page = _root; return buf; } #ifdef PUGIXML_COMPACT void* allocate_object(size_t size, xml_memory_page*& out_page) { void* result = allocate_memory(size + sizeof(uint32_t), out_page); if (!result) return 0; // adjust for marker ptrdiff_t offset = static_cast(result) - reinterpret_cast(out_page->compact_page_marker); if (PUGI__UNLIKELY(static_cast(offset) >= 256 * xml_memory_block_alignment)) { // insert new marker uint32_t* marker = static_cast(result); *marker = static_cast(reinterpret_cast(marker) - reinterpret_cast(out_page)); out_page->compact_page_marker = marker; // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block // this will make sure deallocate_memory correctly tracks the size out_page->freed_size += sizeof(uint32_t); return marker + 1; } else { // roll back uint32_t part _busy_size -= sizeof(uint32_t); return result; } } #else void* allocate_object(size_t size, xml_memory_page*& out_page) { return allocate_memory(size, out_page); } #endif void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) { if (page == _root) page->busy_size = _busy_size; assert(ptr >= reinterpret_cast(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast(page) + sizeof(xml_memory_page) + page->busy_size); (void)!ptr; page->freed_size += size; assert(page->freed_size <= page->busy_size); if (page->freed_size == page->busy_size) { if (page->next == 0) { assert(_root == page); // top page freed, just reset sizes page->busy_size = 0; page->freed_size = 0; #ifdef PUGIXML_COMPACT // reset compact state to maximize efficiency page->compact_string_base = 0; page->compact_shared_parent = 0; page->compact_page_marker = 0; #endif _busy_size = 0; } else { assert(_root != page); assert(page->prev); // remove from the list page->prev->next = page->next; page->next->prev = page->prev; // deallocate deallocate_page(page); } } } char_t* allocate_string(size_t length) { static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment; PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); // allocate memory for string and header block size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); // round size up to block alignment boundary size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1); xml_memory_page* page; xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); if (!header) return 0; // setup header ptrdiff_t page_offset = reinterpret_cast(header) - reinterpret_cast(page) - sizeof(xml_memory_page); assert(page_offset % xml_memory_block_alignment == 0); assert(page_offset >= 0 && static_cast(page_offset) < max_encoded_offset); header->page_offset = static_cast(static_cast(page_offset) / xml_memory_block_alignment); // full_size == 0 for large strings that occupy the whole page assert(full_size % xml_memory_block_alignment == 0); assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0)); header->full_size = static_cast(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0); // round-trip through void* to avoid 'cast increases required alignment of target type' warning // header is guaranteed a pointer-sized alignment, which should be enough for char_t return static_cast(static_cast(header + 1)); } void deallocate_string(char_t* string) { // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string // get header xml_memory_string_header* header = static_cast(static_cast(string)) - 1; assert(header); // deallocate size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment; xml_memory_page* page = reinterpret_cast(static_cast(reinterpret_cast(header) - page_offset)); // if full_size == 0 then this string occupies the whole page size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment; deallocate_memory(header, full_size, page); } bool reserve() { #ifdef PUGIXML_COMPACT return _hash->reserve(); #else return true; #endif } xml_memory_page* _root; size_t _busy_size; #ifdef PUGIXML_COMPACT compact_hash_table* _hash; #endif }; PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) { const size_t large_allocation_threshold = xml_memory_page_size / 4; xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); out_page = page; if (!page) return 0; if (size <= large_allocation_threshold) { _root->busy_size = _busy_size; // insert page at the end of linked list page->prev = _root; _root->next = page; _root = page; _busy_size = size; } else { // insert page before the end of linked list, so that it is deleted as soon as possible // the last page is not deleted even if it's empty (see deallocate_memory) assert(_root->prev); page->prev = _root->prev; page->next = _root; _root->prev->next = page; _root->prev = page; page->busy_size = size; } return reinterpret_cast(page) + sizeof(xml_memory_page); } PUGI__NS_END #ifdef PUGIXML_COMPACT PUGI__NS_BEGIN static const uintptr_t compact_alignment_log2 = 2; static const uintptr_t compact_alignment = 1 << compact_alignment_log2; class compact_header { public: compact_header(xml_memory_page* page, unsigned int flags) { PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment); ptrdiff_t offset = (reinterpret_cast(this) - reinterpret_cast(page->compact_page_marker)); assert(offset % compact_alignment == 0 && static_cast(offset) < 256 * compact_alignment); _page = static_cast(offset >> compact_alignment_log2); _flags = static_cast(flags); } void operator&=(uintptr_t mod) { _flags &= static_cast(mod); } void operator|=(uintptr_t mod) { _flags |= static_cast(mod); } uintptr_t operator&(uintptr_t mod) const { return _flags & mod; } xml_memory_page* get_page() const { // round-trip through void* to silence 'cast increases required alignment of target type' warnings const char* page_marker = reinterpret_cast(this) - (_page << compact_alignment_log2); const char* page = page_marker - *reinterpret_cast(static_cast(page_marker)); return const_cast(reinterpret_cast(static_cast(page))); } private: unsigned char _page; unsigned char _flags; }; PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset) { const compact_header* header = reinterpret_cast(static_cast(object) - header_offset); return header->get_page(); } template PUGI__FN_NO_INLINE T* compact_get_value(const void* object) { return static_cast(compact_get_page(object, header_offset)->allocator->_hash->find(object)); } template PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value) { compact_get_page(object, header_offset)->allocator->_hash->insert(object, value); } template class compact_pointer { public: compact_pointer(): _data(0) { } void operator=(const compact_pointer& rhs) { *this = rhs + 0; } void operator=(T* value) { if (value) { // value is guaranteed to be compact-aligned; 'this' is not // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*) // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to // compensate for arithmetic shift rounding for negative values ptrdiff_t diff = reinterpret_cast(value) - reinterpret_cast(this); ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start; if (static_cast(offset) <= 253) _data = static_cast(offset + 1); else { compact_set_value(this, value); _data = 255; } } else _data = 0; } operator T*() const { if (_data) { if (_data < 255) { uintptr_t base = reinterpret_cast(this) & ~(compact_alignment - 1); return reinterpret_cast(base + (_data - 1 + start) * compact_alignment); } else return compact_get_value(this); } else return 0; } T* operator->() const { return *this; } private: unsigned char _data; }; template class compact_pointer_parent { public: compact_pointer_parent(): _data(0) { } void operator=(const compact_pointer_parent& rhs) { *this = rhs + 0; } void operator=(T* value) { if (value) { // value is guaranteed to be compact-aligned; 'this' is not // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*) // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to // compensate for arithmetic shift behavior for negative values ptrdiff_t diff = reinterpret_cast(value) - reinterpret_cast(this); ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533; if (static_cast(offset) <= 65533) { _data = static_cast(offset + 1); } else { xml_memory_page* page = compact_get_page(this, header_offset); if (PUGI__UNLIKELY(page->compact_shared_parent == 0)) page->compact_shared_parent = value; if (page->compact_shared_parent == value) { _data = 65534; } else { compact_set_value(this, value); _data = 65535; } } } else { _data = 0; } } operator T*() const { if (_data) { if (_data < 65534) { uintptr_t base = reinterpret_cast(this) & ~(compact_alignment - 1); return reinterpret_cast(base + (_data - 1 - 65533) * compact_alignment); } else if (_data == 65534) return static_cast(compact_get_page(this, header_offset)->compact_shared_parent); else return compact_get_value(this); } else return 0; } T* operator->() const { return *this; } private: uint16_t _data; }; template class compact_string { public: compact_string(): _data(0) { } void operator=(const compact_string& rhs) { *this = rhs + 0; } void operator=(char_t* value) { if (value) { xml_memory_page* page = compact_get_page(this, header_offset); if (PUGI__UNLIKELY(page->compact_string_base == 0)) page->compact_string_base = value; ptrdiff_t offset = value - page->compact_string_base; if (static_cast(offset) < (65535 << 7)) { // round-trip through void* to silence 'cast increases required alignment of target type' warnings uint16_t* base = reinterpret_cast(static_cast(reinterpret_cast(this) - base_offset)); if (*base == 0) { *base = static_cast((offset >> 7) + 1); _data = static_cast((offset & 127) + 1); } else { ptrdiff_t remainder = offset - ((*base - 1) << 7); if (static_cast(remainder) <= 253) { _data = static_cast(remainder + 1); } else { compact_set_value(this, value); _data = 255; } } } else { compact_set_value(this, value); _data = 255; } } else { _data = 0; } } operator char_t*() const { if (_data) { if (_data < 255) { xml_memory_page* page = compact_get_page(this, header_offset); // round-trip through void* to silence 'cast increases required alignment of target type' warnings const uint16_t* base = reinterpret_cast(static_cast(reinterpret_cast(this) - base_offset)); assert(*base); ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1); return page->compact_string_base + offset; } else { return compact_get_value(this); } } else return 0; } private: unsigned char _data; }; PUGI__NS_END #endif #ifdef PUGIXML_COMPACT namespace pugi { struct xml_attribute_struct { xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0) { PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8); } impl::compact_header header; uint16_t namevalue_base; impl::compact_string<4, 2> name; impl::compact_string<5, 3> value; impl::compact_pointer prev_attribute_c; impl::compact_pointer next_attribute; }; struct xml_node_struct { xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) { PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); } impl::compact_header header; uint16_t namevalue_base; impl::compact_string<4, 2> name; impl::compact_string<5, 3> value; impl::compact_pointer_parent parent; impl::compact_pointer first_child; impl::compact_pointer prev_sibling_c; impl::compact_pointer next_sibling; impl::compact_pointer first_attribute; }; } #else namespace pugi { struct xml_attribute_struct { xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0) { header = PUGI__GETHEADER_IMPL(this, page, 0); } uintptr_t header; char_t* name; char_t* value; xml_attribute_struct* prev_attribute_c; xml_attribute_struct* next_attribute; }; struct xml_node_struct { xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) { header = PUGI__GETHEADER_IMPL(this, page, type); } uintptr_t header; char_t* name; char_t* value; xml_node_struct* parent; xml_node_struct* first_child; xml_node_struct* prev_sibling_c; xml_node_struct* next_sibling; xml_attribute_struct* first_attribute; }; } #endif PUGI__NS_BEGIN struct xml_extra_buffer { char_t* buffer; xml_extra_buffer* next; }; struct xml_document_struct: public xml_node_struct, public xml_allocator { xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) { } const char_t* buffer; xml_extra_buffer* extra_buffers; #ifdef PUGIXML_COMPACT compact_hash_table hash; #endif }; template inline xml_allocator& get_allocator(const Object* object) { assert(object); return *PUGI__GETPAGE(object)->allocator; } template inline xml_document_struct& get_document(const Object* object) { assert(object); return *static_cast(PUGI__GETPAGE(object)->allocator); } PUGI__NS_END // Low-level DOM operations PUGI__NS_BEGIN inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) { xml_memory_page* page; void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page); if (!memory) return 0; return new (memory) xml_attribute_struct(page); } inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) { xml_memory_page* page; void* memory = alloc.allocate_object(sizeof(xml_node_struct), page); if (!memory) return 0; return new (memory) xml_node_struct(page, type); } inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) { if (a->header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); if (a->header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a)); } inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) { if (n->header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); if (n->header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); for (xml_attribute_struct* attr = n->first_attribute; attr; ) { xml_attribute_struct* next = attr->next_attribute; destroy_attribute(attr, alloc); attr = next; } for (xml_node_struct* child = n->first_child; child; ) { xml_node_struct* next = child->next_sibling; destroy_node(child, alloc); child = next; } alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n)); } inline void append_node(xml_node_struct* child, xml_node_struct* node) { child->parent = node; xml_node_struct* head = node->first_child; if (head) { xml_node_struct* tail = head->prev_sibling_c; tail->next_sibling = child; child->prev_sibling_c = tail; head->prev_sibling_c = child; } else { node->first_child = child; child->prev_sibling_c = child; } } inline void prepend_node(xml_node_struct* child, xml_node_struct* node) { child->parent = node; xml_node_struct* head = node->first_child; if (head) { child->prev_sibling_c = head->prev_sibling_c; head->prev_sibling_c = child; } else child->prev_sibling_c = child; child->next_sibling = head; node->first_child = child; } inline void insert_node_after(xml_node_struct* child, xml_node_struct* node) { xml_node_struct* parent = node->parent; child->parent = parent; if (node->next_sibling) node->next_sibling->prev_sibling_c = child; else parent->first_child->prev_sibling_c = child; child->next_sibling = node->next_sibling; child->prev_sibling_c = node; node->next_sibling = child; } inline void insert_node_before(xml_node_struct* child, xml_node_struct* node) { xml_node_struct* parent = node->parent; child->parent = parent; if (node->prev_sibling_c->next_sibling) node->prev_sibling_c->next_sibling = child; else parent->first_child = child; child->prev_sibling_c = node->prev_sibling_c; child->next_sibling = node; node->prev_sibling_c = child; } inline void remove_node(xml_node_struct* node) { xml_node_struct* parent = node->parent; if (node->next_sibling) node->next_sibling->prev_sibling_c = node->prev_sibling_c; else parent->first_child->prev_sibling_c = node->prev_sibling_c; if (node->prev_sibling_c->next_sibling) node->prev_sibling_c->next_sibling = node->next_sibling; else parent->first_child = node->next_sibling; node->parent = 0; node->prev_sibling_c = 0; node->next_sibling = 0; } inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node) { xml_attribute_struct* head = node->first_attribute; if (head) { xml_attribute_struct* tail = head->prev_attribute_c; tail->next_attribute = attr; attr->prev_attribute_c = tail; head->prev_attribute_c = attr; } else { node->first_attribute = attr; attr->prev_attribute_c = attr; } } inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node) { xml_attribute_struct* head = node->first_attribute; if (head) { attr->prev_attribute_c = head->prev_attribute_c; head->prev_attribute_c = attr; } else attr->prev_attribute_c = attr; attr->next_attribute = head; node->first_attribute = attr; } inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { if (place->next_attribute) place->next_attribute->prev_attribute_c = attr; else node->first_attribute->prev_attribute_c = attr; attr->next_attribute = place->next_attribute; attr->prev_attribute_c = place; place->next_attribute = attr; } inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { if (place->prev_attribute_c->next_attribute) place->prev_attribute_c->next_attribute = attr; else node->first_attribute = attr; attr->prev_attribute_c = place->prev_attribute_c; attr->next_attribute = place; place->prev_attribute_c = attr; } inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node) { if (attr->next_attribute) attr->next_attribute->prev_attribute_c = attr->prev_attribute_c; else node->first_attribute->prev_attribute_c = attr->prev_attribute_c; if (attr->prev_attribute_c->next_attribute) attr->prev_attribute_c->next_attribute = attr->next_attribute; else node->first_attribute = attr->next_attribute; attr->prev_attribute_c = 0; attr->next_attribute = 0; } PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) { if (!alloc.reserve()) return 0; xml_node_struct* child = allocate_node(alloc, type); if (!child) return 0; append_node(child, node); return child; } PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc) { if (!alloc.reserve()) return 0; xml_attribute_struct* attr = allocate_attribute(alloc); if (!attr) return 0; append_attribute(attr, node); return attr; } PUGI__NS_END // Helper classes for code generation PUGI__NS_BEGIN struct opt_false { enum { value = 0 }; }; struct opt_true { enum { value = 1 }; }; PUGI__NS_END // Unicode utilities PUGI__NS_BEGIN inline uint16_t endian_swap(uint16_t value) { return static_cast(((value & 0xff) << 8) | (value >> 8)); } inline uint32_t endian_swap(uint32_t value) { return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); } struct utf8_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t ch) { // U+0000..U+007F if (ch < 0x80) return result + 1; // U+0080..U+07FF else if (ch < 0x800) return result + 2; // U+0800..U+FFFF else return result + 3; } static value_type high(value_type result, uint32_t) { // U+10000..U+10FFFF return result + 4; } }; struct utf8_writer { typedef uint8_t* value_type; static value_type low(value_type result, uint32_t ch) { // U+0000..U+007F if (ch < 0x80) { *result = static_cast(ch); return result + 1; } // U+0080..U+07FF else if (ch < 0x800) { result[0] = static_cast(0xC0 | (ch >> 6)); result[1] = static_cast(0x80 | (ch & 0x3F)); return result + 2; } // U+0800..U+FFFF else { result[0] = static_cast(0xE0 | (ch >> 12)); result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); result[2] = static_cast(0x80 | (ch & 0x3F)); return result + 3; } } static value_type high(value_type result, uint32_t ch) { // U+10000..U+10FFFF result[0] = static_cast(0xF0 | (ch >> 18)); result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); result[3] = static_cast(0x80 | (ch & 0x3F)); return result + 4; } static value_type any(value_type result, uint32_t ch) { return (ch < 0x10000) ? low(result, ch) : high(result, ch); } }; struct utf16_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t) { return result + 1; } static value_type high(value_type result, uint32_t) { return result + 2; } }; struct utf16_writer { typedef uint16_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = static_cast(ch); return result + 1; } static value_type high(value_type result, uint32_t ch) { uint32_t msh = static_cast(ch - 0x10000) >> 10; uint32_t lsh = static_cast(ch - 0x10000) & 0x3ff; result[0] = static_cast(0xD800 + msh); result[1] = static_cast(0xDC00 + lsh); return result + 2; } static value_type any(value_type result, uint32_t ch) { return (ch < 0x10000) ? low(result, ch) : high(result, ch); } }; struct utf32_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t) { return result + 1; } static value_type high(value_type result, uint32_t) { return result + 1; } }; struct utf32_writer { typedef uint32_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = ch; return result + 1; } static value_type high(value_type result, uint32_t ch) { *result = ch; return result + 1; } static value_type any(value_type result, uint32_t ch) { *result = ch; return result + 1; } }; struct latin1_writer { typedef uint8_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = static_cast(ch > 255 ? '?' : ch); return result + 1; } static value_type high(value_type result, uint32_t ch) { (void)ch; *result = '?'; return result + 1; } }; struct utf8_decoder { typedef uint8_t type; template static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) { const uint8_t utf8_byte_mask = 0x3f; while (size) { uint8_t lead = *data; // 0xxxxxxx -> U+0000..U+007F if (lead < 0x80) { result = Traits::low(result, lead); data += 1; size -= 1; // process aligned single-byte (ascii) blocks if ((reinterpret_cast(data) & 3) == 0) { // round-trip through void* to silence 'cast increases required alignment of target type' warnings while (size >= 4 && (*static_cast(static_cast(data)) & 0x80808080) == 0) { result = Traits::low(result, data[0]); result = Traits::low(result, data[1]); result = Traits::low(result, data[2]); result = Traits::low(result, data[3]); data += 4; size -= 4; } } } // 110xxxxx -> U+0080..U+07FF else if (static_cast(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) { result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); data += 2; size -= 2; } // 1110xxxx -> U+0800-U+FFFF else if (static_cast(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) { result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); data += 3; size -= 3; } // 11110xxx -> U+10000..U+10FFFF else if (static_cast(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) { result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); data += 4; size -= 4; } // 10xxxxxx or 11111xxx -> invalid else { data += 1; size -= 1; } } return result; } }; template struct utf16_decoder { typedef uint16_t type; template static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits) { while (size) { uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; // U+0000..U+D7FF if (lead < 0xD800) { result = Traits::low(result, lead); data += 1; size -= 1; } // U+E000..U+FFFF else if (static_cast(lead - 0xE000) < 0x2000) { result = Traits::low(result, lead); data += 1; size -= 1; } // surrogate pair lead else if (static_cast(lead - 0xD800) < 0x400 && size >= 2) { uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; if (static_cast(next - 0xDC00) < 0x400) { result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); data += 2; size -= 2; } else { data += 1; size -= 1; } } else { data += 1; size -= 1; } } return result; } }; template struct utf32_decoder { typedef uint32_t type; template static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits) { while (size) { uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; // U+0000..U+FFFF if (lead < 0x10000) { result = Traits::low(result, lead); data += 1; size -= 1; } // U+10000..U+10FFFF else { result = Traits::high(result, lead); data += 1; size -= 1; } } return result; } }; struct latin1_decoder { typedef uint8_t type; template static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) { while (size) { result = Traits::low(result, *data); data += 1; size -= 1; } return result; } }; template struct wchar_selector; template <> struct wchar_selector<2> { typedef uint16_t type; typedef utf16_counter counter; typedef utf16_writer writer; typedef utf16_decoder decoder; }; template <> struct wchar_selector<4> { typedef uint32_t type; typedef utf32_counter counter; typedef utf32_writer writer; typedef utf32_decoder decoder; }; typedef wchar_selector::counter wchar_counter; typedef wchar_selector::writer wchar_writer; struct wchar_decoder { typedef wchar_t type; template static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits) { typedef wchar_selector::decoder decoder; return decoder::process(reinterpret_cast(data), size, result, traits); } }; #ifdef PUGIXML_WCHAR_MODE PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) { for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); } #endif PUGI__NS_END PUGI__NS_BEGIN enum chartype_t { ct_parse_pcdata = 1, // \0, &, \r, < ct_parse_attr = 2, // \0, &, \r, ', " ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab ct_space = 8, // \r, \n, space, tab ct_parse_cdata = 16, // \0, ], >, \r ct_parse_comment = 32, // \0, -, >, \r ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : }; static const unsigned char chartype_table[256] = { 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 }; enum chartypex_t { ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > ctx_special_attr = 2, // Any symbol >= 0 and < 32, &, <, ", ' ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ ctx_digit = 8, // 0-9 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . }; static const unsigned char chartypex_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, // 0-15 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 0, 0, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 1, 0, // 48-63 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; #ifdef PUGIXML_WCHAR_MODE #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) #else #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) #endif #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table) #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table) PUGI__FN bool is_little_endian() { unsigned int ui = 1; return *reinterpret_cast(&ui) == 1; } PUGI__FN xml_encoding get_wchar_encoding() { PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); if (sizeof(wchar_t) == 2) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; else return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; } PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) { #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; } // check if we have a non-empty XML declaration if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space))) return false; // scan XML declaration until the encoding field for (size_t i = 6; i + 1 < size; ++i) { // declaration can not contain ? in quoted values if (data[i] == '?') return false; if (data[i] == 'e' && data[i + 1] == 'n') { size_t offset = i; // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o'); PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g'); // S? = S? PUGI__SCANCHARTYPE(ct_space); PUGI__SCANCHAR('='); PUGI__SCANCHARTYPE(ct_space); // the only two valid delimiters are ' and " uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\''; PUGI__SCANCHAR(delimiter); size_t start = offset; out_encoding = data + offset; PUGI__SCANCHARTYPE(ct_symbol); out_length = offset - start; PUGI__SCANCHAR(delimiter); return true; } } return false; #undef PUGI__SCANCHAR #undef PUGI__SCANCHARTYPE } PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) { // skip encoding autodetection if input buffer is too small if (size < 4) return encoding_utf8; uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; // look for BOM in first few bytes if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; // look for <, (contents); return guess_buffer_encoding(data, size); } PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { size_t length = size / sizeof(char_t); if (is_mutable) { out_buffer = static_cast(const_cast(contents)); out_length = length; } else { char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; if (contents) memcpy(buffer, contents, length * sizeof(char_t)); else assert(length == 0); buffer[length] = 0; out_buffer = buffer; out_length = length + 1; } return true; } #ifdef PUGIXML_WCHAR_MODE PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) { return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); } PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const char_t* data = static_cast(contents); size_t length = size / sizeof(char_t); if (is_mutable) { char_t* buffer = const_cast(data); convert_wchar_endian_swap(buffer, data, length); out_buffer = buffer; out_length = length; } else { char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; convert_wchar_endian_swap(buffer, data, length); buffer[length] = 0; out_buffer = buffer; out_length = length + 1; } return true; } template PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { const typename D::type* data = static_cast(contents); size_t data_length = size / sizeof(typename D::type); // first pass: get length in wchar_t units size_t length = D::process(data, data_length, 0, wchar_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf16 input to wchar_t wchar_writer::value_type obegin = reinterpret_cast(buffer); wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer()); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // get native encoding xml_encoding wchar_encoding = get_wchar_encoding(); // fast path: no conversion required if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // only endian-swapping is required if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf8 if (encoding == encoding_utf8) return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder()); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()); } // source encoding is utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()); } // source encoding is latin1 if (encoding == encoding_latin1) return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); assert(false && "Invalid encoding"); // unreachable return false; } #else template PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { const typename D::type* data = static_cast(contents); size_t data_length = size / sizeof(typename D::type); // first pass: get length in utf8 units size_t length = D::process(data, data_length, 0, utf8_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf16 input to utf8 uint8_t* obegin = reinterpret_cast(buffer); uint8_t* oend = D::process(data, data_length, obegin, utf8_writer()); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) { for (size_t i = 0; i < size; ++i) if (data[i] > 127) return i; return size; } PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const uint8_t* data = static_cast(contents); size_t data_length = size; // get size of prefix that does not need utf8 conversion size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length); assert(prefix_length <= data_length); const uint8_t* postfix = data + prefix_length; size_t postfix_length = data_length - prefix_length; // if no conversion is needed, just return the original buffer if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // first pass: get length in utf8 units size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter()); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert latin1 input to utf8 memcpy(buffer, data, prefix_length); uint8_t* obegin = reinterpret_cast(buffer); uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer()); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // fast path: no conversion required if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder()); } // source encoding is utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()) : convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder()); } // source encoding is latin1 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); assert(false && "Invalid encoding"); // unreachable return false; } #endif PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) { // get length in utf8 characters return wchar_decoder::process(str, length, 0, utf8_counter()); } PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) { // convert to utf8 uint8_t* begin = reinterpret_cast(buffer); uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer()); assert(begin + size == end); (void)!end; (void)!size; } #ifndef PUGIXML_NO_STL PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) { // first pass: get length in utf8 characters size_t size = as_utf8_begin(str, length); // allocate resulting string std::string result; result.resize(size); // second pass: convert to utf8 if (size > 0) as_utf8_end(&result[0], size, str, length); return result; } PUGI__FN std::basic_string as_wide_impl(const char* str, size_t size) { const uint8_t* data = reinterpret_cast(str); // first pass: get length in wchar_t units size_t length = utf8_decoder::process(data, size, 0, wchar_counter()); // allocate resulting string std::basic_string result; result.resize(length); // second pass: convert to wchar_t if (length > 0) { wchar_writer::value_type begin = reinterpret_cast(&result[0]); wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer()); assert(begin + length == end); (void)!end; } return result; } #endif template inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target) { // never reuse shared memory if (header & xml_memory_page_contents_shared_mask) return false; size_t target_length = strlength(target); // always reuse document buffer memory if possible if ((header & header_mask) == 0) return target_length >= length; // reuse heap memory if waste is not too great const size_t reuse_threshold = 32; return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); } template PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) { if (source_length == 0) { // empty string and null pointer are equivalent, so just deallocate old memory xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated dest = 0; header &= ~header_mask; return true; } else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) { // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, source_length * sizeof(char_t)); dest[source_length] = 0; return true; } else { xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; if (!alloc->reserve()) return false; // allocate new buffer char_t* buf = alloc->allocate_string(source_length + 1); if (!buf) return false; // copy the string (including zero terminator) memcpy(buf, source, source_length * sizeof(char_t)); buf[source_length] = 0; // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); // the string is now allocated, so set the flag dest = buf; header |= header_mask; return true; } } struct gap { char_t* end; size_t size; gap(): end(0), size(0) { } // Push new gap, move s count bytes further (skipping the gap). // Collapse previous gap. void push(char_t*& s, size_t count) { if (end) // there was a gap already; collapse it { // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) assert(s >= end); memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); } s += count; // end of current gap // "merge" two gaps end = s; size += count; } // Collapse all gaps, return past-the-end pointer char_t* flush(char_t* s) { if (end) { // Move [old_gap_end, current_pos) to [old_gap_start, ...) assert(s >= end); memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); return s - size; } else return s; } }; PUGI__FN char_t* strconv_escape(char_t* s, gap& g) { char_t* stre = s + 1; switch (*stre) { case '#': // &#... { unsigned int ucsc = 0; if (stre[1] == 'x') // &#x... (hex code) { stre += 2; char_t ch = *stre; if (ch == ';') return stre; for (;;) { if (static_cast(ch - '0') <= 9) ucsc = 16 * ucsc + (ch - '0'); else if (static_cast((ch | ' ') - 'a') <= 5) ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); else if (ch == ';') break; else // cancel return stre; ch = *++stre; } ++stre; } else // &#... (dec code) { char_t ch = *++stre; if (ch == ';') return stre; for (;;) { if (static_cast(ch - '0') <= 9) ucsc = 10 * ucsc + (ch - '0'); else if (ch == ';') break; else // cancel return stre; ch = *++stre; } ++stre; } #ifdef PUGIXML_WCHAR_MODE s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); #else s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); #endif g.push(s, stre - s); return stre; } case 'a': // &a { ++stre; if (*stre == 'm') // &am { if (*++stre == 'p' && *++stre == ';') // & { *s++ = '&'; ++stre; g.push(s, stre - s); return stre; } } else if (*stre == 'p') // &ap { if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' { *s++ = '\''; ++stre; g.push(s, stre - s); return stre; } } break; } case 'g': // &g { if (*++stre == 't' && *++stre == ';') // > { *s++ = '>'; ++stre; g.push(s, stre - s); return stre; } break; } case 'l': // &l { if (*++stre == 't' && *++stre == ';') // < { *s++ = '<'; ++stre; g.push(s, stre - s); return stre; } break; } case 'q': // &q { if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " { *s++ = '"'; ++stre; g.push(s, stre - s); return stre; } break; } default: break; } return stre; } // Parser utilities #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } #define PUGI__POPNODE() { cursor = cursor->parent; } #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } #define PUGI__SCANWHILE(X) { while (X) ++s; } #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here { *g.flush(s) = 0; return s + (s[2] == '>' ? 3 : 2); } else if (*s == 0) { return 0; } else ++s; } } PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here { *g.flush(s) = 0; return s + 1; } else if (*s == 0) { return 0; } else ++s; } } typedef char_t* (*strconv_pcdata_t)(char_t*); template struct strconv_pcdata_impl { static char_t* parse(char_t* s) { gap g; char_t* begin = s; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata)); if (*s == '<') // PCDATA ends here { char_t* end = g.flush(s); if (opt_trim::value) while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; return s + 1; } else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (*s == 0) { char_t* end = g.flush(s); if (opt_trim::value) while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; return s; } else ++s; } } }; PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above { case 0: return strconv_pcdata_impl::parse; case 1: return strconv_pcdata_impl::parse; case 2: return strconv_pcdata_impl::parse; case 3: return strconv_pcdata_impl::parse; case 4: return strconv_pcdata_impl::parse; case 5: return strconv_pcdata_impl::parse; case 6: return strconv_pcdata_impl::parse; case 7: return strconv_pcdata_impl::parse; default: assert(false); return 0; // unreachable } } typedef char_t* (*strconv_attribute_t)(char_t*, char_t); template struct strconv_attribute_impl { static char_t* parse_wnorm(char_t* s, char_t end_quote) { gap g; // trim leading whitespaces if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s; do ++str; while (PUGI__IS_CHARTYPE(*str, ct_space)); g.push(s, str - s); } while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); if (*s == end_quote) { char_t* str = g.flush(s); do *str-- = 0; while (PUGI__IS_CHARTYPE(*str, ct_space)); return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) { *s++ = ' '; if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s + 1; while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; g.push(s, str - s); } } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } static char_t* parse_wconv(char_t* s, char_t end_quote) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) { if (*s == '\r') { *s++ = ' '; if (*s == '\n') g.push(s, 1); } else *s++ = ' '; } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } static char_t* parse_eol(char_t* s, char_t end_quote) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (*s == '\r') { *s++ = '\n'; if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } static char_t* parse_simple(char_t* s, char_t end_quote) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } }; PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); switch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above { case 0: return strconv_attribute_impl::parse_simple; case 1: return strconv_attribute_impl::parse_simple; case 2: return strconv_attribute_impl::parse_eol; case 3: return strconv_attribute_impl::parse_eol; case 4: return strconv_attribute_impl::parse_wconv; case 5: return strconv_attribute_impl::parse_wconv; case 6: return strconv_attribute_impl::parse_wconv; case 7: return strconv_attribute_impl::parse_wconv; case 8: return strconv_attribute_impl::parse_wnorm; case 9: return strconv_attribute_impl::parse_wnorm; case 10: return strconv_attribute_impl::parse_wnorm; case 11: return strconv_attribute_impl::parse_wnorm; case 12: return strconv_attribute_impl::parse_wnorm; case 13: return strconv_attribute_impl::parse_wnorm; case 14: return strconv_attribute_impl::parse_wnorm; case 15: return strconv_attribute_impl::parse_wnorm; default: assert(false); return 0; // unreachable } } inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) { xml_parse_result result; result.status = status; result.offset = offset; return result; } struct xml_parser { xml_allocator* alloc; char_t* error_offset; xml_parse_status error_status; xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) { } // DOCTYPE consists of nested sections of the following possible types: // , , "...", '...' // // // First group can not contain nested groups // Second group can contain nested groups of the same type // Third group can contain all other groups char_t* parse_doctype_primitive(char_t* s) { if (*s == '"' || *s == '\'') { // quoted string char_t ch = *s++; PUGI__SCANFOR(*s == ch); if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); s++; } else if (s[0] == '<' && s[1] == '?') { // s += 2; PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); s += 2; } else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') { s += 4; PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); s += 3; } else PUGI__THROW_ERROR(status_bad_doctype, s); return s; } char_t* parse_doctype_ignore(char_t* s) { size_t depth = 0; assert(s[0] == '<' && s[1] == '!' && s[2] == '['); s += 3; while (*s) { if (s[0] == '<' && s[1] == '!' && s[2] == '[') { // nested ignore section s += 3; depth++; } else if (s[0] == ']' && s[1] == ']' && s[2] == '>') { // ignore section end s += 3; if (depth == 0) return s; depth--; } else s++; } PUGI__THROW_ERROR(status_bad_doctype, s); } char_t* parse_doctype_group(char_t* s, char_t endch) { size_t depth = 0; assert((s[0] == '<' || s[0] == 0) && s[1] == '!'); s += 2; while (*s) { if (s[0] == '<' && s[1] == '!' && s[2] != '-') { if (s[2] == '[') { // ignore s = parse_doctype_ignore(s); if (!s) return s; } else { // some control group s += 2; depth++; } } else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') { // unknown tag (forbidden), or some primitive group s = parse_doctype_primitive(s); if (!s) return s; } else if (*s == '>') { if (depth == 0) return s; depth--; s++; } else s++; } if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s); return s; } char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) { // parse node contents, starting with exclamation mark ++s; if (*s == '-') // 'value = s; // Save the offset. } if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) { s = strconv_comment(s, endch); if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); } else { // Scan for terminating '-->'. PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_comment, s); if (PUGI__OPTSET(parse_comments)) *s = 0; // Zero-terminate this segment at the first terminating '-'. s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. } } else PUGI__THROW_ERROR(status_bad_comment, s); } else if (*s == '[') { // 'value = s; // Save the offset. if (PUGI__OPTSET(parse_eol)) { s = strconv_cdata(s, endch); if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); } else { // Scan for terminating ']]>'. PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_cdata, s); *s++ = 0; // Zero-terminate this segment. } } else // Flagged for discard, but we still have to scan for the terminator. { // Scan for terminating ']]>'. PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_cdata, s); ++s; } s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. } else PUGI__THROW_ERROR(status_bad_cdata, s); } else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E')) { s -= 2; if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s); char_t* mark = s + 9; s = parse_doctype_group(s, endch); if (!s) return s; assert((*s == 0 && endch == '>') || *s == '>'); if (*s) *s++ = 0; if (PUGI__OPTSET(parse_doctype)) { while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark; PUGI__PUSHNODE(node_doctype); cursor->value = mark; } } else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s); else PUGI__THROW_ERROR(status_unrecognized_tag, s); return s; } char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) { // load into registers xml_node_struct* cursor = ref_cursor; char_t ch = 0; // parse node contents, starting with question mark ++s; // read PI target char_t* target = s; if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s); PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); PUGI__CHECK_ERROR(status_bad_pi, s); // determine node type; stricmp / strcasecmp is not portable bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi)) { if (declaration) { // disallow non top-level declarations if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s); PUGI__PUSHNODE(node_declaration); } else { PUGI__PUSHNODE(node_pi); } cursor->name = target; PUGI__ENDSEG(); // parse value/attributes if (ch == '?') { // empty node if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s); s += (*s == '>'); PUGI__POPNODE(); } else if (PUGI__IS_CHARTYPE(ch, ct_space)) { PUGI__SKIPWS(); // scan for tag end char_t* value = s; PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); PUGI__CHECK_ERROR(status_bad_pi, s); if (declaration) { // replace ending ? with / so that 'element' terminates properly *s = '/'; // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES s = value; } else { // store value and step over > cursor->value = value; PUGI__POPNODE(); PUGI__ENDSEG(); s += (*s == '>'); } } else PUGI__THROW_ERROR(status_bad_pi, s); } else { // scan for tag end PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); PUGI__CHECK_ERROR(status_bad_pi, s); s += (s[1] == '>' ? 2 : 1); } // store from registers ref_cursor = cursor; return s; } char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch) { strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); char_t ch = 0; xml_node_struct* cursor = root; char_t* mark = s; while (*s != 0) { if (*s == '<') { ++s; LOC_TAG: if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' { PUGI__PUSHNODE(node_element); // Append a new node to the tree. cursor->name = s; PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. if (ch == '>') { // end of tag } else if (PUGI__IS_CHARTYPE(ch, ct_space)) { LOC_ATTRIBUTES: while (true) { PUGI__SKIPWS(); // Eat any whitespace. if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... { xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute. if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); a->name = s; // Save the offset. PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. if (PUGI__IS_CHARTYPE(ch, ct_space)) { PUGI__SKIPWS(); // Eat any whitespace. ch = *s; ++s; } if (ch == '=') // '<... #=...' { PUGI__SKIPWS(); // Eat any whitespace. if (*s == '"' || *s == '\'') // '<... #="...' { ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. ++s; // Step over the quote. a->value = s; // Save the offset. s = strconv_attribute(s, ch); if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); // After this line the loop continues from the start; // Whitespaces, / and > are ok, symbols and EOF are wrong, // everything else will be detected if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s); } else PUGI__THROW_ERROR(status_bad_attribute, s); } else PUGI__THROW_ERROR(status_bad_attribute, s); } else if (*s == '/') { ++s; if (*s == '>') { PUGI__POPNODE(); s++; break; } else if (*s == 0 && endch == '>') { PUGI__POPNODE(); break; } else PUGI__THROW_ERROR(status_bad_start_element, s); } else if (*s == '>') { ++s; break; } else if (*s == 0 && endch == '>') { break; } else PUGI__THROW_ERROR(status_bad_start_element, s); } // !!! } else if (ch == '/') // '<#.../' { if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s); PUGI__POPNODE(); // Pop. s += (*s == '>'); } else if (ch == 0) { // we stepped over null terminator, backtrack & handle closing tag --s; if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); } else PUGI__THROW_ERROR(status_bad_start_element, s); } else if (*s == '/') { ++s; mark = s; char_t* name = cursor->name; if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark); while (PUGI__IS_CHARTYPE(*s, ct_symbol)) { if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark); } if (*name) { if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); else PUGI__THROW_ERROR(status_end_element_mismatch, mark); } PUGI__POPNODE(); // Pop. PUGI__SKIPWS(); if (*s == 0) { if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s); } else { if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s); ++s; } } else if (*s == '?') // 'first_child) continue; } } if (!PUGI__OPTSET(parse_trim_pcdata)) s = mark; if (cursor->parent || PUGI__OPTSET(parse_fragment)) { if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) { cursor->value = s; // Save the offset. } else { PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. cursor->value = s; // Save the offset. PUGI__POPNODE(); // Pop since this is a standalone. } s = strconv_pcdata(s); if (!*s) break; } else { PUGI__SCANFOR(*s == '<'); // '...<' if (!*s) break; ++s; } // We're after '<' goto LOC_TAG; } } // check that last tag is closed if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s); return s; } #ifdef PUGIXML_WCHAR_MODE static char_t* parse_skip_bom(char_t* s) { unsigned int bom = 0xfeff; return (s[0] == static_cast(bom)) ? s + 1 : s; } #else static char_t* parse_skip_bom(char_t* s) { return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s; } #endif static bool has_element_node_siblings(xml_node_struct* node) { while (node) { if (PUGI__NODETYPE(node) == node_element) return true; node = node->next_sibling; } return false; } static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk) { // early-out for empty documents if (length == 0) return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); // get last child of the root before parsing xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0; // create parser on stack xml_parser parser(static_cast(xmldoc)); // save last character and make buffer zero-terminated (speeds up parsing) char_t endch = buffer[length - 1]; buffer[length - 1] = 0; // skip BOM to make sure it does not end up as part of parse output char_t* buffer_data = parse_skip_bom(buffer); // perform actual parsing parser.parse_tree(buffer_data, root, optmsk, endch); xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); assert(result.offset >= 0 && static_cast(result.offset) <= length); if (result) { // since we removed last character, we have to handle the only possible false positive (stray <) if (endch == '<') return make_parse_result(status_unrecognized_tag, length - 1); // check if there are any element nodes parsed xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0; if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) return make_parse_result(status_no_document_element, length - 1); } else { // roll back offset if it occurs on a null terminator in the source buffer if (result.offset > 0 && static_cast(result.offset) == length - 1 && endch == 0) result.offset--; } return result; } }; // Output facilities PUGI__FN xml_encoding get_write_native_encoding() { #ifdef PUGIXML_WCHAR_MODE return get_wchar_encoding(); #else return encoding_utf8; #endif } PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) { // replace wchar encoding with utf implementation if (encoding == encoding_wchar) return get_wchar_encoding(); // replace utf16 encoding with utf16 with specific endianness if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; // replace utf32 encoding with utf32 with specific endianness if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; // only do autodetection if no explicit encoding is requested if (encoding != encoding_auto) return encoding; // assume utf8 encoding return encoding_utf8; } template PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T) { PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); return static_cast(end - dest) * sizeof(*dest); } template PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap) { PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); if (opt_swap) { for (typename T::value_type i = dest; i != end; ++i) *i = endian_swap(*i); } return static_cast(end - dest) * sizeof(*dest); } #ifdef PUGIXML_WCHAR_MODE PUGI__FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 1) return 0; // discard last character if it's the lead of a surrogate pair return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; } PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { // only endian-swapping is required if (need_endian_swap_utf(encoding, get_wchar_encoding())) { convert_wchar_endian_swap(r_char, data, length); return length * sizeof(char_t); } // convert to utf8 if (encoding == encoding_utf8) return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer()); // convert to utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding); } // convert to utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding); } // convert to latin1 if (encoding == encoding_latin1) return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); assert(false && "Invalid encoding"); // unreachable return 0; } #else PUGI__FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 5) return 0; for (size_t i = 1; i <= 4; ++i) { uint8_t ch = static_cast(data[length - i]); // either a standalone character or a leading one if ((ch & 0xc0) != 0x80) return length - i; } // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk return length; } PUGI__FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding); } if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding); } if (encoding == encoding_latin1) return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); assert(false && "Invalid encoding"); // unreachable return 0; } #endif class xml_buffered_writer { xml_buffered_writer(const xml_buffered_writer&); xml_buffered_writer& operator=(const xml_buffered_writer&); public: xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) { PUGI__STATIC_ASSERT(bufcapacity >= 8); } size_t flush() { flush(buffer, bufsize); bufsize = 0; return 0; } void flush(const char_t* data, size_t size) { if (size == 0) return; // fast path, just write data if (encoding == get_write_native_encoding()) writer.write(data, size * sizeof(char_t)); else { // convert chunk size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding); assert(result <= sizeof(scratch)); // write data writer.write(scratch.data_u8, result); } } void write_direct(const char_t* data, size_t length) { // flush the remaining buffer contents flush(); // handle large chunks if (length > bufcapacity) { if (encoding == get_write_native_encoding()) { // fast path, can just write data chunk writer.write(data, length * sizeof(char_t)); return; } // need to convert in suitable chunks while (length > bufcapacity) { // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) size_t chunk_size = get_valid_length(data, bufcapacity); assert(chunk_size); // convert chunk and write flush(data, chunk_size); // iterate data += chunk_size; length -= chunk_size; } // small tail is copied below bufsize = 0; } memcpy(buffer + bufsize, data, length * sizeof(char_t)); bufsize += length; } void write_buffer(const char_t* data, size_t length) { size_t offset = bufsize; if (offset + length <= bufcapacity) { memcpy(buffer + offset, data, length * sizeof(char_t)); bufsize = offset + length; } else { write_direct(data, length); } } void write_string(const char_t* data) { // write the part of the string that fits in the buffer size_t offset = bufsize; while (*data && offset < bufcapacity) buffer[offset++] = *data++; // write the rest if (offset < bufcapacity) { bufsize = offset; } else { // backtrack a bit if we have split the codepoint size_t length = offset - bufsize; size_t extra = length - get_valid_length(data - length, length); bufsize = offset - extra; write_direct(data - extra, strlength(data) + extra); } } void write(char_t d0) { size_t offset = bufsize; if (offset > bufcapacity - 1) offset = flush(); buffer[offset + 0] = d0; bufsize = offset + 1; } void write(char_t d0, char_t d1) { size_t offset = bufsize; if (offset > bufcapacity - 2) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; bufsize = offset + 2; } void write(char_t d0, char_t d1, char_t d2) { size_t offset = bufsize; if (offset > bufcapacity - 3) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; bufsize = offset + 3; } void write(char_t d0, char_t d1, char_t d2, char_t d3) { size_t offset = bufsize; if (offset > bufcapacity - 4) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; bufsize = offset + 4; } void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) { size_t offset = bufsize; if (offset > bufcapacity - 5) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; buffer[offset + 4] = d4; bufsize = offset + 5; } void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) { size_t offset = bufsize; if (offset > bufcapacity - 6) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; buffer[offset + 4] = d4; buffer[offset + 5] = d5; bufsize = offset + 6; } // utf8 maximum expansion: x4 (-> utf32) // utf16 maximum expansion: x2 (-> utf32) // utf32 maximum expansion: x1 enum { bufcapacitybytes = #ifdef PUGIXML_MEMORY_OUTPUT_STACK PUGIXML_MEMORY_OUTPUT_STACK #else 10240 #endif , bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4) }; char_t buffer[bufcapacity]; union { uint8_t data_u8[4 * bufcapacity]; uint16_t data_u16[2 * bufcapacity]; uint32_t data_u32[bufcapacity]; char_t data_char[bufcapacity]; } scratch; xml_writer& writer; size_t bufsize; xml_encoding encoding; }; PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) { while (*s) { const char_t* prev = s; // While *s is a usual symbol PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); writer.write_buffer(prev, static_cast(s - prev)); switch (*s) { case 0: break; case '&': writer.write('&', 'a', 'm', 'p', ';'); ++s; break; case '<': writer.write('&', 'l', 't', ';'); ++s; break; case '>': writer.write('&', 'g', 't', ';'); ++s; break; case '"': if (flags & format_attribute_single_quote) writer.write('"'); else writer.write('&', 'q', 'u', 'o', 't', ';'); ++s; break; case '\'': if (flags & format_attribute_single_quote) writer.write('&', 'a', 'p', 'o', 's', ';'); else writer.write('\''); ++s; break; default: // s is not a usual symbol { unsigned int ch = static_cast(*s++); assert(ch < 32); if (!(flags & format_skip_control_chars)) writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); } } } } PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) { if (flags & format_no_escapes) writer.write_string(s); else text_output_escaped(writer, s, type, flags); } PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) { do { writer.write('<', '!', '[', 'C', 'D'); writer.write('A', 'T', 'A', '['); const char_t* prev = s; // look for ]]> sequence - we can't output it as is since it terminates CDATA while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; // skip ]] if we stopped at ]]>, > will go to the next CDATA section if (*s) s += 2; writer.write_buffer(prev, static_cast(s - prev)); writer.write(']', ']', '>'); } while (*s); } PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth) { switch (indent_length) { case 1: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0]); break; } case 2: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1]); break; } case 3: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1], indent[2]); break; } case 4: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1], indent[2], indent[3]); break; } default: { for (unsigned int i = 0; i < depth; ++i) writer.write_buffer(indent, indent_length); } } } PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s) { writer.write('<', '!', '-', '-'); while (*s) { const char_t* prev = s; // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s; writer.write_buffer(prev, static_cast(s - prev)); if (*s) { assert(*s == '-'); writer.write('-', ' '); ++s; } } writer.write('-', '-', '>'); } PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s) { while (*s) { const char_t* prev = s; // look for ?> sequence - we can't output it since ?> terminates PI while (*s && !(s[0] == '?' && s[1] == '>')) ++s; writer.write_buffer(prev, static_cast(s - prev)); if (*s) { assert(s[0] == '?' && s[1] == '>'); writer.write('?', ' ', '>'); s += 2; } } } PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t enquotation_char = (flags & format_attribute_single_quote) ? '\'' : '"'; for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) { if ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes) { writer.write('\n'); text_output_indent(writer, indent, indent_length, depth + 1); } else { writer.write(' '); } writer.write_string(a->name ? a->name + 0 : default_name); writer.write('=', enquotation_char); if (a->value) text_output(writer, a->value, ctx_special_attr, flags); writer.write(enquotation_char); } } PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name + 0 : default_name; writer.write('<'); writer.write_string(name); if (node->first_attribute) node_output_attributes(writer, node, indent, indent_length, flags, depth); // element nodes can have value if parse_embed_pcdata was used if (!node->value) { if (!node->first_child) { if (flags & format_no_empty_element_tags) { writer.write('>', '<', '/'); writer.write_string(name); writer.write('>'); return false; } else { if ((flags & format_raw) == 0) writer.write(' '); writer.write('/', '>'); return false; } } else { writer.write('>'); return true; } } else { writer.write('>'); text_output(writer, node->value, ctx_special_pcdata, flags); if (!node->first_child) { writer.write('<', '/'); writer.write_string(name); writer.write('>'); return false; } else { return true; } } } PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name + 0 : default_name; writer.write('<', '/'); writer.write_string(name); writer.write('>'); } PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); switch (PUGI__NODETYPE(node)) { case node_pcdata: text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags); break; case node_cdata: text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT("")); break; case node_comment: node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT("")); break; case node_pi: writer.write('<', '?'); writer.write_string(node->name ? node->name + 0 : default_name); if (node->value) { writer.write(' '); node_output_pi_value(writer, node->value); } writer.write('?', '>'); break; case node_declaration: writer.write('<', '?'); writer.write_string(node->name ? node->name + 0 : default_name); node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0); writer.write('?', '>'); break; case node_doctype: writer.write('<', '!', 'D', 'O', 'C'); writer.write('T', 'Y', 'P', 'E'); if (node->value) { writer.write(' '); writer.write_string(node->value); } writer.write('>'); break; default: assert(false && "Invalid node type"); // unreachable } } enum indent_flags_t { indent_newline = 1, indent_indent = 2 }; PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth) { size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0; unsigned int indent_flags = indent_indent; xml_node_struct* node = root; do { assert(node); // begin writing current node if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata) { node_output_simple(writer, node, flags); indent_flags = 0; } else { if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); if ((indent_flags & indent_indent) && indent_length) text_output_indent(writer, indent, indent_length, depth); if (PUGI__NODETYPE(node) == node_element) { indent_flags = indent_newline | indent_indent; if (node_output_start(writer, node, indent, indent_length, flags, depth)) { // element nodes can have value if parse_embed_pcdata was used if (node->value) indent_flags = 0; node = node->first_child; depth++; continue; } } else if (PUGI__NODETYPE(node) == node_document) { indent_flags = indent_indent; if (node->first_child) { node = node->first_child; continue; } } else { node_output_simple(writer, node, flags); indent_flags = indent_newline | indent_indent; } } // continue to the next node while (node != root) { if (node->next_sibling) { node = node->next_sibling; break; } node = node->parent; // write closing node if (PUGI__NODETYPE(node) == node_element) { depth--; if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); if ((indent_flags & indent_indent) && indent_length) text_output_indent(writer, indent, indent_length, depth); node_output_end(writer, node); indent_flags = indent_newline | indent_indent; } } } while (node != root); if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); } PUGI__FN bool has_declaration(xml_node_struct* node) { for (xml_node_struct* child = node->first_child; child; child = child->next_sibling) { xml_node_type type = PUGI__NODETYPE(child); if (type == node_declaration) return true; if (type == node_element) return false; } return false; } PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node) { for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) if (a == attr) return true; return false; } PUGI__FN bool allow_insert_attribute(xml_node_type parent) { return parent == node_element || parent == node_declaration; } PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child) { if (parent != node_document && parent != node_element) return false; if (child == node_document || child == node_null) return false; if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; return true; } PUGI__FN bool allow_move(xml_node parent, xml_node child) { // check that child can be a child of parent if (!allow_insert_child(parent.type(), child.type())) return false; // check that node is not moved between documents if (parent.root() != child.root()) return false; // check that new parent is not in the child subtree xml_node cur = parent; while (cur) { if (cur == child) return false; cur = cur.parent(); } return true; } template PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) { assert(!dest && (header & header_mask) == 0); if (source) { if (alloc && (source_header & header_mask) == 0) { dest = source; // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared header |= xml_memory_page_contents_shared_mask; source_header |= xml_memory_page_contents_shared_mask; } else strcpy_insitu(dest, header, header_mask, source, strlength(source)); } } PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) { node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) { xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn)); if (da) { node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); } } } PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) { xml_allocator& alloc = get_allocator(dn); xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0; node_copy_contents(dn, sn, shared_alloc); xml_node_struct* dit = dn; xml_node_struct* sit = sn->first_child; while (sit && sit != sn) { // when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop if (sit != dn) { xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit)); if (copy) { node_copy_contents(copy, sit, shared_alloc); if (sit->first_child) { dit = copy; sit = sit->first_child; continue; } } } // continue to the next node do { if (sit->next_sibling) { sit = sit->next_sibling; break; } sit = sit->parent; dit = dit->parent; } while (sit != sn); } } PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa) { xml_allocator& alloc = get_allocator(da); xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0; node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); } inline bool is_text_node(xml_node_struct* node) { xml_node_type type = PUGI__NODETYPE(node); return type == node_pcdata || type == node_cdata; } // get value with conversion functions template PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv) { U result = 0; const char_t* s = value; while (PUGI__IS_CHARTYPE(*s, ct_space)) s++; bool negative = (*s == '-'); s += (*s == '+' || *s == '-'); bool overflow = false; if (s[0] == '0' && (s[1] | ' ') == 'x') { s += 2; // since overflow detection relies on length of the sequence skip leading zeros while (*s == '0') s++; const char_t* start = s; for (;;) { if (static_cast(*s - '0') < 10) result = result * 16 + (*s - '0'); else if (static_cast((*s | ' ') - 'a') < 6) result = result * 16 + ((*s | ' ') - 'a' + 10); else break; s++; } size_t digits = static_cast(s - start); overflow = digits > sizeof(U) * 2; } else { // since overflow detection relies on length of the sequence skip leading zeros while (*s == '0') s++; const char_t* start = s; for (;;) { if (static_cast(*s - '0') < 10) result = result * 10 + (*s - '0'); else break; s++; } size_t digits = static_cast(s - start); PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2); const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5; const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6'; const size_t high_bit = sizeof(U) * 8 - 1; overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit))); } if (negative) { // Workaround for crayc++ CC-3059: Expected no overflow in routine. #ifdef _CRAYC return (overflow || result > ~minv + 1) ? minv : ~result + 1; #else return (overflow || result > 0 - minv) ? minv : 0 - result; #endif } else return (overflow || result > maxv) ? maxv : result; } PUGI__FN int get_value_int(const char_t* value) { return string_to_integer(value, static_cast(INT_MIN), INT_MAX); } PUGI__FN unsigned int get_value_uint(const char_t* value) { return string_to_integer(value, 0, UINT_MAX); } PUGI__FN double get_value_double(const char_t* value) { #ifdef PUGIXML_WCHAR_MODE return wcstod(value, 0); #else return strtod(value, 0); #endif } PUGI__FN float get_value_float(const char_t* value) { #ifdef PUGIXML_WCHAR_MODE return static_cast(wcstod(value, 0)); #else return static_cast(strtod(value, 0)); #endif } PUGI__FN bool get_value_bool(const char_t* value) { // only look at first char char_t first = *value; // 1*, t* (true), T* (True), y* (yes), Y* (YES) return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long get_value_llong(const char_t* value) { return string_to_integer(value, static_cast(LLONG_MIN), LLONG_MAX); } PUGI__FN unsigned long long get_value_ullong(const char_t* value) { return string_to_integer(value, 0, ULLONG_MAX); } #endif template PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) { char_t* result = end - 1; U rest = negative ? 0 - value : value; do { *result-- = static_cast('0' + (rest % 10)); rest /= 10; } while (rest); assert(result >= begin); (void)begin; *result = '-'; return result + !negative; } // set value with conversion functions template PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) { #ifdef PUGIXML_WCHAR_MODE char_t wbuf[128]; assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0])); size_t offset = 0; for (; buf[offset]; ++offset) wbuf[offset] = buf[offset]; return strcpy_insitu(dest, header, header_mask, wbuf, offset); #else return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); #endif } template PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) { char_t buf[64]; char_t* end = buf + sizeof(buf) / sizeof(buf[0]); char_t* begin = integer_to_string(buf, end, value, negative); return strcpy_insitu(dest, header, header_mask, begin, end - begin); } template PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value) { char buf[128]; PUGI__SNPRINTF(buf, "%.9g", double(value)); return set_value_ascii(dest, header, header_mask, buf); } template PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value) { char buf[128]; PUGI__SNPRINTF(buf, "%.17g", value); return set_value_ascii(dest, header, header_mask, buf); } template PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) { return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); } PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) { // check input buffer if (!contents && size) return make_parse_result(status_io_error); // get actual encoding xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); // get private buffer char_t* buffer = 0; size_t length = 0; // coverity[var_deref_model] if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); // delete original buffer if we performed a conversion if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself if (own || buffer != contents) *out_buffer = buffer; // store buffer for offset_debug doc->buffer = buffer; // parse xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options); // remember encoding res.encoding = buffer_encoding; return res; } // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) { #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) // there are 64-bit versions of fseek/ftell, let's use them typedef __int64 length_type; _fseeki64(file, 0, SEEK_END); length_type length = _ftelli64(file); _fseeki64(file, 0, SEEK_SET); #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)) // there are 64-bit versions of fseek/ftell, let's use them typedef off64_t length_type; fseeko64(file, 0, SEEK_END); length_type length = ftello64(file); fseeko64(file, 0, SEEK_SET); #else // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. typedef long length_type; fseek(file, 0, SEEK_END); length_type length = ftell(file); fseek(file, 0, SEEK_SET); #endif // check for I/O errors if (length < 0) return status_io_error; // check for overflow size_t result = static_cast(length); if (static_cast(result) != length) return status_out_of_memory; // finalize out_result = result; return status_ok; } // This function assumes that buffer has extra sizeof(char_t) writable bytes after size PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) { // We only need to zero-terminate if encoding conversion does not do it for us #ifdef PUGIXML_WCHAR_MODE xml_encoding wchar_encoding = get_wchar_encoding(); if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding)) { size_t length = size / sizeof(char_t); static_cast(buffer)[length] = 0; return (length + 1) * sizeof(char_t); } #else if (encoding == encoding_utf8) { static_cast(buffer)[size] = 0; return size + 1; } #endif return size; } PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer) { if (!file) return make_parse_result(status_file_not_found); // get file size (can result in I/O errors) size_t size = 0; xml_parse_status size_status = get_file_size(file, size); if (size_status != status_ok) return make_parse_result(size_status); size_t max_suffix_size = sizeof(char_t); // allocate buffer for the whole file char* contents = static_cast(xml_memory::allocate(size + max_suffix_size)); if (!contents) return make_parse_result(status_out_of_memory); // read file in memory size_t read_size = fread(contents, 1, size, file); if (read_size != size) { xml_memory::deallocate(contents); return make_parse_result(status_io_error); } xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); } PUGI__FN void close_file(FILE* file) { fclose(file); } #ifndef PUGIXML_NO_STL template struct xml_stream_chunk { static xml_stream_chunk* create() { void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); if (!memory) return 0; return new (memory) xml_stream_chunk(); } static void destroy(xml_stream_chunk* chunk) { // free chunk chain while (chunk) { xml_stream_chunk* next_ = chunk->next; xml_memory::deallocate(chunk); chunk = next_; } } xml_stream_chunk(): next(0), size(0) { } xml_stream_chunk* next; size_t size; T data[xml_memory_page_size / sizeof(T)]; }; template PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { auto_deleter > chunks(0, xml_stream_chunk::destroy); // read file to a chunk list size_t total = 0; xml_stream_chunk* last = 0; while (!stream.eof()) { // allocate new chunk xml_stream_chunk* chunk = xml_stream_chunk::create(); if (!chunk) return status_out_of_memory; // append chunk to list if (last) last = last->next = chunk; else chunks.data = last = chunk; // read data to chunk stream.read(chunk->data, static_cast(sizeof(chunk->data) / sizeof(T))); chunk->size = static_cast(stream.gcount()) * sizeof(T); // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; // guard against huge files (chunk size is small enough to make this overflow check work) if (total + chunk->size < total) return status_out_of_memory; total += chunk->size; } size_t max_suffix_size = sizeof(char_t); // copy chunk list to a contiguous buffer char* buffer = static_cast(xml_memory::allocate(total + max_suffix_size)); if (!buffer) return status_out_of_memory; char* write = buffer; for (xml_stream_chunk* chunk = chunks.data; chunk; chunk = chunk->next) { assert(write + chunk->size <= buffer + total); memcpy(write, chunk->data, chunk->size); write += chunk->size; } assert(write == buffer + total); // return buffer *out_buffer = buffer; *out_size = total; return status_ok; } template PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { // get length of remaining data in stream typename std::basic_istream::pos_type pos = stream.tellg(); stream.seekg(0, std::ios::end); std::streamoff length = stream.tellg() - pos; stream.seekg(pos); if (stream.fail() || pos < 0) return status_io_error; // guard against huge files size_t read_length = static_cast(length); if (static_cast(read_length) != length || length < 0) return status_out_of_memory; size_t max_suffix_size = sizeof(char_t); // read stream data into memory (guard against stream exceptions with buffer holder) auto_deleter buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate); if (!buffer.data) return status_out_of_memory; stream.read(static_cast(buffer.data), static_cast(read_length)); // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; // return buffer size_t actual_length = static_cast(stream.gcount()); assert(actual_length <= read_length); *out_buffer = buffer.release(); *out_size = actual_length * sizeof(T); return status_ok; } template PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer) { void* buffer = 0; size_t size = 0; xml_parse_status status = status_ok; // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits) if (stream.fail()) return make_parse_result(status_io_error); // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory) if (stream.tellg() < 0) { stream.clear(); // clear error flags that could be set by a failing tellg status = load_stream_data_noseek(stream, &buffer, &size); } else status = load_stream_data_seek(stream, &buffer, &size); if (status != status_ok) return make_parse_result(status); xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer); } #endif #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { return _wfopen(path, mode); } #else PUGI__FN char* convert_path_heap(const wchar_t* str) { assert(str); // first pass: get length in utf8 characters size_t length = strlength_wide(str); size_t size = as_utf8_begin(str, length); // allocate resulting string char* result = static_cast(xml_memory::allocate(size + 1)); if (!result) return 0; // second pass: convert to utf8 as_utf8_end(result, size, str, length); // zero-terminate result[size] = 0; return result; } PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { // there is no standard function to open wide paths, so our best bet is to try utf8 path char* path_utf8 = convert_path_heap(path); if (!path_utf8) return 0; // convert mode to ASCII (we mirror _wfopen interface) char mode_ascii[4] = {0}; for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); // try to open the utf8 path FILE* result = fopen(path_utf8, mode_ascii); // free dummy buffer xml_memory::deallocate(path_utf8); return result; } #endif PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) { if (!file) return false; xml_writer_file writer(file); doc.save(writer, indent, flags, encoding); return ferror(file) == 0; } struct name_null_sentry { xml_node_struct* node; char_t* name; name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name) { node->name = 0; } ~name_null_sentry() { node->name = name; } }; PUGI__NS_END namespace pugi { PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_) { } PUGI__FN void xml_writer_file::write(const void* data, size_t size) { size_t result = fwrite(data, 1, size, static_cast(file)); (void)!result; // unfortunately we can't do proper error handling here } #ifndef PUGIXML_NO_STL PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) { } PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) { } PUGI__FN void xml_writer_stream::write(const void* data, size_t size) { if (narrow_stream) { assert(!wide_stream); narrow_stream->write(reinterpret_cast(data), static_cast(size)); } else { assert(wide_stream); assert(size % sizeof(wchar_t) == 0); wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); } } #endif PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) { } PUGI__FN xml_tree_walker::~xml_tree_walker() { } PUGI__FN int xml_tree_walker::depth() const { return _depth; } PUGI__FN bool xml_tree_walker::begin(xml_node&) { return true; } PUGI__FN bool xml_tree_walker::end(xml_node&) { return true; } PUGI__FN xml_attribute::xml_attribute(): _attr(0) { } PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) { } PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***) { } PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const { return _attr ? unspecified_bool_xml_attribute : 0; } PUGI__FN bool xml_attribute::operator!() const { return !_attr; } PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const { return (_attr == r._attr); } PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const { return (_attr != r._attr); } PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const { return (_attr < r._attr); } PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const { return (_attr > r._attr); } PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const { return (_attr <= r._attr); } PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const { return (_attr >= r._attr); } PUGI__FN xml_attribute xml_attribute::next_attribute() const { return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); } PUGI__FN xml_attribute xml_attribute::previous_attribute() const { return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); } PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const { return (_attr && _attr->value) ? _attr->value + 0 : def; } PUGI__FN int xml_attribute::as_int(int def) const { return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def; } PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const { return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def; } PUGI__FN double xml_attribute::as_double(double def) const { return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def; } PUGI__FN float xml_attribute::as_float(float def) const { return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def; } PUGI__FN bool xml_attribute::as_bool(bool def) const { return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long xml_attribute::as_llong(long long def) const { return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def; } PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const { return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def; } #endif PUGI__FN bool xml_attribute::empty() const { return !_attr; } PUGI__FN const char_t* xml_attribute::name() const { return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_attribute::value() const { return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT(""); } PUGI__FN size_t xml_attribute::hash_value() const { return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); } PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const { return _attr; } PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(long rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) { set_value(rhs); return *this; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs) { set_value(rhs); return *this; } #endif PUGI__FN bool xml_attribute::set_name(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } PUGI__FN bool xml_attribute::set_value(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } PUGI__FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(double rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(bool rhs) { if (!_attr) return false; return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN bool xml_attribute::set_value(long long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } #endif #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN xml_node::xml_node(): _root(0) { } PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) { } PUGI__FN static void unspecified_bool_xml_node(xml_node***) { } PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const { return _root ? unspecified_bool_xml_node : 0; } PUGI__FN bool xml_node::operator!() const { return !_root; } PUGI__FN xml_node::iterator xml_node::begin() const { return iterator(_root ? _root->first_child + 0 : 0, _root); } PUGI__FN xml_node::iterator xml_node::end() const { return iterator(0, _root); } PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const { return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root); } PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const { return attribute_iterator(0, _root); } PUGI__FN xml_object_range xml_node::children() const { return xml_object_range(begin(), end()); } PUGI__FN xml_object_range xml_node::children(const char_t* name_) const { return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_)); } PUGI__FN xml_object_range xml_node::attributes() const { return xml_object_range(attributes_begin(), attributes_end()); } PUGI__FN bool xml_node::operator==(const xml_node& r) const { return (_root == r._root); } PUGI__FN bool xml_node::operator!=(const xml_node& r) const { return (_root != r._root); } PUGI__FN bool xml_node::operator<(const xml_node& r) const { return (_root < r._root); } PUGI__FN bool xml_node::operator>(const xml_node& r) const { return (_root > r._root); } PUGI__FN bool xml_node::operator<=(const xml_node& r) const { return (_root <= r._root); } PUGI__FN bool xml_node::operator>=(const xml_node& r) const { return (_root >= r._root); } PUGI__FN bool xml_node::empty() const { return !_root; } PUGI__FN const char_t* xml_node::name() const { return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); } PUGI__FN xml_node_type xml_node::type() const { return _root ? PUGI__NODETYPE(_root) : node_null; } PUGI__FN const char_t* xml_node::value() const { return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); } PUGI__FN xml_node xml_node::child(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); return xml_node(); } PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const { if (!_root) return xml_attribute(); for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) if (i->name && impl::strequal(name_, i->name)) return xml_attribute(i); return xml_attribute(); } PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); return xml_node(); } PUGI__FN xml_node xml_node::next_sibling() const { return _root ? xml_node(_root->next_sibling) : xml_node(); } PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); return xml_node(); } PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const { xml_attribute_struct* hint = hint_._attr; // if hint is not an attribute of node, behavior is not defined assert(!hint || (_root && impl::is_attribute_of(hint, _root))); if (!_root) return xml_attribute(); // optimistically search from hint up until the end for (xml_attribute_struct* i = hint; i; i = i->next_attribute) if (i->name && impl::strequal(name_, i->name)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = i->next_attribute; return xml_attribute(i); } // wrap around and search from the first attribute until the hint // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) if (j->name && impl::strequal(name_, j->name)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = j->next_attribute; return xml_attribute(j); } return xml_attribute(); } PUGI__FN xml_node xml_node::previous_sibling() const { if (!_root) return xml_node(); if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); else return xml_node(); } PUGI__FN xml_node xml_node::parent() const { return _root ? xml_node(_root->parent) : xml_node(); } PUGI__FN xml_node xml_node::root() const { return _root ? xml_node(&impl::get_document(_root)) : xml_node(); } PUGI__FN xml_text xml_node::text() const { return xml_text(_root); } PUGI__FN const char_t* xml_node::child_value() const { if (!_root) return PUGIXML_TEXT(""); // element nodes can have value if parse_embed_pcdata was used if (PUGI__NODETYPE(_root) == node_element && _root->value) return _root->value; for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (impl::is_text_node(i) && i->value) return i->value; return PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const { return child(name_).child_value(); } PUGI__FN xml_attribute xml_node::first_attribute() const { return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); } PUGI__FN xml_attribute xml_node::last_attribute() const { return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); } PUGI__FN xml_node xml_node::first_child() const { return _root ? xml_node(_root->first_child) : xml_node(); } PUGI__FN xml_node xml_node::last_child() const { return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); } PUGI__FN bool xml_node::set_name(const char_t* rhs) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } PUGI__FN bool xml_node::set_value(const char_t* rhs) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) return false; return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::append_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::prepend_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_after(a._attr, attr._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_before(a._attr, attr._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::append_attribute(a._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::prepend_attribute(a._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_after(a._attr, attr._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_attribute(); xml_attribute a(impl::allocate_attribute(alloc)); if (!a) return xml_attribute(); impl::insert_attribute_before(a._attr, attr._attr, _root); impl::node_copy_attribute(a._attr, proto._attr); return a; } PUGI__FN xml_node xml_node::append_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::append_node(n._root, _root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_before(n._root, node._root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_after(n._root, node._root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::append_child(const char_t* name_) { xml_node result = append_child(node_element); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) { xml_node result = prepend_child(node_element); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) { xml_node result = insert_child_after(node_element, node); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) { xml_node result = insert_child_before(node_element, node); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::append_node(n._root, _root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_after(n._root, node._root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); xml_node n(impl::allocate_node(alloc, type_)); if (!n) return xml_node(); impl::insert_node_before(n._root, node._root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::append_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::append_node(moved._root, _root); return moved; } PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::prepend_node(moved._root, _root); return moved; } PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); if (moved._root == node._root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::insert_node_after(moved._root, node._root); return moved; } PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); if (moved._root == node._root) return xml_node(); impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::insert_node_before(moved._root, node._root); return moved; } PUGI__FN bool xml_node::remove_attribute(const char_t* name_) { return remove_attribute(attribute(name_)); } PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a) { if (!_root || !a._attr) return false; if (!impl::is_attribute_of(a._attr, _root)) return false; impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return false; impl::remove_attribute(a._attr, _root); impl::destroy_attribute(a._attr, alloc); return true; } PUGI__FN bool xml_node::remove_child(const char_t* name_) { return remove_child(child(name_)); } PUGI__FN bool xml_node::remove_child(const xml_node& n) { if (!_root || !n._root || n._root->parent != _root) return false; impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return false; impl::remove_node(n._root); impl::destroy_node(n._root, alloc); return true; } PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { // append_buffer is only valid for elements/documents if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root); // get document node impl::xml_document_struct* doc = &impl::get_document(_root); // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense doc->header |= impl::xml_memory_page_contents_shared_mask; // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) impl::xml_memory_page* page = 0; impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer) + sizeof(void*), page)); (void)page; if (!extra) return impl::make_parse_result(status_out_of_memory); #ifdef PUGIXML_COMPACT // align the memory block to a pointer boundary; this is required for compact mode where memory allocations are only 4b aligned // note that this requires up to sizeof(void*)-1 additional memory, which the allocation above takes into account extra = reinterpret_cast((reinterpret_cast(extra) + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1)); #endif // add extra buffer to the list extra->buffer = 0; extra->next = doc->extra_buffers; doc->extra_buffers = extra; // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level impl::name_null_sentry sentry(_root); return impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &extra->buffer); } PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) { for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) return xml_node(i); } return xml_node(); } PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) return xml_node(i); return xml_node(); } #ifndef PUGIXML_NO_STL PUGI__FN string_t xml_node::path(char_t delimiter) const { if (!_root) return string_t(); size_t offset = 0; for (xml_node_struct* i = _root; i; i = i->parent) { offset += (i != _root); offset += i->name ? impl::strlength(i->name) : 0; } string_t result; result.resize(offset); for (xml_node_struct* j = _root; j; j = j->parent) { if (j != _root) result[--offset] = delimiter; if (j->name) { size_t length = impl::strlength(j->name); offset -= length; memcpy(&result[offset], j->name, length * sizeof(char_t)); } } assert(offset == 0); return result; } #endif PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const { xml_node found = *this; // Current search context. if (!_root || !path_[0]) return found; if (path_[0] == delimiter) { // Absolute path; e.g. '/foo/bar' found = found.root(); ++path_; } const char_t* path_segment = path_; while (*path_segment == delimiter) ++path_segment; const char_t* path_segment_end = path_segment; while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; if (path_segment == path_segment_end) return found; const char_t* next_segment = path_segment_end; while (*next_segment == delimiter) ++next_segment; if (*path_segment == '.' && path_segment + 1 == path_segment_end) return found.first_element_by_path(next_segment, delimiter); else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) return found.parent().first_element_by_path(next_segment, delimiter); else { for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) { if (j->name && impl::strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) { xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); if (subsearch) return subsearch; } } return xml_node(); } } PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) { walker._depth = -1; xml_node arg_begin(_root); if (!walker.begin(arg_begin)) return false; xml_node_struct* cur = _root ? _root->first_child + 0 : 0; if (cur) { ++walker._depth; do { xml_node arg_for_each(cur); if (!walker.for_each(arg_for_each)) return false; if (cur->first_child) { ++walker._depth; cur = cur->first_child; } else if (cur->next_sibling) cur = cur->next_sibling; else { while (!cur->next_sibling && cur != _root && cur->parent) { --walker._depth; cur = cur->parent; } if (cur != _root) cur = cur->next_sibling; } } while (cur && cur != _root); } assert(walker._depth == -1); xml_node arg_end(_root); return walker.end(arg_end); } PUGI__FN size_t xml_node::hash_value() const { return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); } PUGI__FN xml_node_struct* xml_node::internal_object() const { return _root; } PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { if (!_root) return; impl::xml_buffered_writer buffered_writer(writer, encoding); impl::node_output(buffered_writer, _root, indent, flags, depth); buffered_writer.flush(); } #ifndef PUGIXML_NO_STL PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { xml_writer_stream writer(stream); print(writer, indent, flags, encoding, depth); } PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const { xml_writer_stream writer(stream); print(writer, indent, flags, encoding_wchar, depth); } #endif PUGI__FN ptrdiff_t xml_node::offset_debug() const { if (!_root) return -1; impl::xml_document_struct& doc = impl::get_document(_root); // we can determine the offset reliably only if there is exactly once parse buffer if (!doc.buffer || doc.extra_buffers) return -1; switch (type()) { case node_document: return 0; case node_element: case node_declaration: case node_pi: return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1; case node_pcdata: case node_cdata: case node_comment: case node_doctype: return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1; default: assert(false && "Invalid node type"); // unreachable return -1; } } #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xml_node& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xml_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root) { } PUGI__FN xml_node_struct* xml_text::_data() const { if (!_root || impl::is_text_node(_root)) return _root; // element nodes can have value if parse_embed_pcdata was used if (PUGI__NODETYPE(_root) == node_element && _root->value) return _root; for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) if (impl::is_text_node(node)) return node; return 0; } PUGI__FN xml_node_struct* xml_text::_data_new() { xml_node_struct* d = _data(); if (d) return d; return xml_node(_root).append_child(node_pcdata).internal_object(); } PUGI__FN xml_text::xml_text(): _root(0) { } PUGI__FN static void unspecified_bool_xml_text(xml_text***) { } PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const { return _data() ? unspecified_bool_xml_text : 0; } PUGI__FN bool xml_text::operator!() const { return !_data(); } PUGI__FN bool xml_text::empty() const { return _data() == 0; } PUGI__FN const char_t* xml_text::get() const { xml_node_struct* d = _data(); return (d && d->value) ? d->value + 0 : PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_text::as_string(const char_t* def) const { xml_node_struct* d = _data(); return (d && d->value) ? d->value + 0 : def; } PUGI__FN int xml_text::as_int(int def) const { xml_node_struct* d = _data(); return (d && d->value) ? impl::get_value_int(d->value) : def; } PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const { xml_node_struct* d = _data(); return (d && d->value) ? impl::get_value_uint(d->value) : def; } PUGI__FN double xml_text::as_double(double def) const { xml_node_struct* d = _data(); return (d && d->value) ? impl::get_value_double(d->value) : def; } PUGI__FN float xml_text::as_float(float def) const { xml_node_struct* d = _data(); return (d && d->value) ? impl::get_value_float(d->value) : def; } PUGI__FN bool xml_text::as_bool(bool def) const { xml_node_struct* d = _data(); return (d && d->value) ? impl::get_value_bool(d->value) : def; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long xml_text::as_llong(long long def) const { xml_node_struct* d = _data(); return (d && d->value) ? impl::get_value_llong(d->value) : def; } PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const { xml_node_struct* d = _data(); return (d && d->value) ? impl::get_value_ullong(d->value) : def; } #endif PUGI__FN bool xml_text::set(const char_t* rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; } PUGI__FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(float rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(double rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(bool rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN bool xml_text::set(long long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } #endif PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(int rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(unsigned int rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(long rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(unsigned long rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(double rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(float rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(bool rhs) { set(rhs); return *this; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN xml_text& xml_text::operator=(long long rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs) { set(rhs); return *this; } #endif PUGI__FN xml_node xml_text::data() const { return xml_node(_data()); } #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xml_text& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xml_text& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN xml_node_iterator::xml_node_iterator() { } PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) { } PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } PUGI__FN xml_node& xml_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } PUGI__FN xml_node* xml_node_iterator::operator->() const { assert(_wrap._root); return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() { assert(_wrap._root); _wrap._root = _wrap._root->next_sibling; return *this; } PUGI__FN xml_node_iterator xml_node_iterator::operator++(int) { xml_node_iterator temp = *this; ++*this; return temp; } PUGI__FN const xml_node_iterator& xml_node_iterator::operator--() { _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); return *this; } PUGI__FN xml_node_iterator xml_node_iterator::operator--(int) { xml_node_iterator temp = *this; --*this; return temp; } PUGI__FN xml_attribute_iterator::xml_attribute_iterator() { } PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) { } PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const { return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; } PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const { return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; } PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const { assert(_wrap._attr); return _wrap; } PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const { assert(_wrap._attr); return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() { assert(_wrap._attr); _wrap._attr = _wrap._attr->next_attribute; return *this; } PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int) { xml_attribute_iterator temp = *this; ++*this; return temp; } PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--() { _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); return *this; } PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int) { xml_attribute_iterator temp = *this; --*this; return temp; } PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) { } PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) { } PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) { } PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } PUGI__FN xml_node& xml_named_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } PUGI__FN xml_node* xml_named_node_iterator::operator->() const { assert(_wrap._root); return const_cast(&_wrap); // BCC5 workaround } PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() { assert(_wrap._root); _wrap = _wrap.next_sibling(_name); return *this; } PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int) { xml_named_node_iterator temp = *this; ++*this; return temp; } PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator--() { if (_wrap._root) _wrap = _wrap.previous_sibling(_name); else { _wrap = _parent.last_child(); if (!impl::strequal(_wrap.name(), _name)) _wrap = _wrap.previous_sibling(_name); } return *this; } PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int) { xml_named_node_iterator temp = *this; --*this; return temp; } PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) { } PUGI__FN xml_parse_result::operator bool() const { return status == status_ok; } PUGI__FN const char* xml_parse_result::description() const { switch (status) { case status_ok: return "No error"; case status_file_not_found: return "File was not found"; case status_io_error: return "Error reading from file/stream"; case status_out_of_memory: return "Could not allocate memory"; case status_internal_error: return "Internal error occurred"; case status_unrecognized_tag: return "Could not determine tag type"; case status_bad_pi: return "Error parsing document declaration/processing instruction"; case status_bad_comment: return "Error parsing comment"; case status_bad_cdata: return "Error parsing CDATA section"; case status_bad_doctype: return "Error parsing document type declaration"; case status_bad_pcdata: return "Error parsing PCDATA section"; case status_bad_start_element: return "Error parsing start element tag"; case status_bad_attribute: return "Error parsing element attribute"; case status_bad_end_element: return "Error parsing end element tag"; case status_end_element_mismatch: return "Start-end tags mismatch"; case status_append_invalid_root: return "Unable to append nodes: root is not an element or document"; case status_no_document_element: return "No document element found"; default: return "Unknown error"; } } PUGI__FN xml_document::xml_document(): _buffer(0) { _create(); } PUGI__FN xml_document::~xml_document() { _destroy(); } #ifdef PUGIXML_HAS_MOVE PUGI__FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(0) { _create(); _move(rhs); } PUGI__FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT { if (this == &rhs) return *this; _destroy(); _create(); _move(rhs); return *this; } #endif PUGI__FN void xml_document::reset() { _destroy(); _create(); } PUGI__FN void xml_document::reset(const xml_document& proto) { reset(); for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) append_copy(cur); } PUGI__FN void xml_document::_create() { assert(!_root); #ifdef PUGIXML_COMPACT // space for page marker for the first page (uint32_t), rounded up to pointer size; assumes pointers are at least 32-bit const size_t page_offset = sizeof(void*); #else const size_t page_offset = 0; #endif // initialize sentinel page PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); // prepare page structure impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory); assert(page); page->busy_size = impl::xml_memory_page_size; // setup first page marker #ifdef PUGIXML_COMPACT // round-trip through void* to avoid 'cast increases required alignment of target type' warning page->compact_page_marker = reinterpret_cast(static_cast(reinterpret_cast(page) + sizeof(impl::xml_memory_page))); *page->compact_page_marker = sizeof(impl::xml_memory_page); #endif // allocate new root _root = new (reinterpret_cast(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page); _root->prev_sibling_c = _root; // setup sentinel page page->allocator = static_cast(_root); // setup hash table pointer in allocator #ifdef PUGIXML_COMPACT page->allocator->_hash = &static_cast(_root)->hash; #endif // verify the document allocation assert(reinterpret_cast(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); } PUGI__FN void xml_document::_destroy() { assert(_root); // destroy static storage if (_buffer) { impl::xml_memory::deallocate(_buffer); _buffer = 0; } // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator) for (impl::xml_extra_buffer* extra = static_cast(_root)->extra_buffers; extra; extra = extra->next) { if (extra->buffer) impl::xml_memory::deallocate(extra->buffer); } // destroy dynamic storage, leave sentinel page (it's in static memory) impl::xml_memory_page* root_page = PUGI__GETPAGE(_root); assert(root_page && !root_page->prev); assert(reinterpret_cast(root_page) >= _memory && reinterpret_cast(root_page) < _memory + sizeof(_memory)); for (impl::xml_memory_page* page = root_page->next; page; ) { impl::xml_memory_page* next = page->next; impl::xml_allocator::deallocate_page(page); page = next; } #ifdef PUGIXML_COMPACT // destroy hash table static_cast(_root)->hash.clear(); #endif _root = 0; } #ifdef PUGIXML_HAS_MOVE PUGI__FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT { impl::xml_document_struct* doc = static_cast(_root); impl::xml_document_struct* other = static_cast(rhs._root); // save first child pointer for later; this needs hash access xml_node_struct* other_first_child = other->first_child; #ifdef PUGIXML_COMPACT // reserve space for the hash table up front; this is the only operation that can fail // if it does, we have no choice but to throw (if we have exceptions) if (other_first_child) { size_t other_children = 0; for (xml_node_struct* node = other_first_child; node; node = node->next_sibling) other_children++; // in compact mode, each pointer assignment could result in a hash table request // during move, we have to relocate document first_child and parents of all children // normally there's just one child and its parent has a pointerless encoding but // we assume the worst here if (!other->_hash->reserve(other_children + 1)) { #ifdef PUGIXML_NO_EXCEPTIONS return; #else throw std::bad_alloc(); #endif } } #endif // move allocation state doc->_root = other->_root; doc->_busy_size = other->_busy_size; // move buffer state doc->buffer = other->buffer; doc->extra_buffers = other->extra_buffers; _buffer = rhs._buffer; #ifdef PUGIXML_COMPACT // move compact hash; note that the hash table can have pointers to other but they will be "inactive", similarly to nodes removed with remove_child doc->hash = other->hash; doc->_hash = &doc->hash; // make sure we don't access other hash up until the end when we reinitialize other document other->_hash = 0; #endif // move page structure impl::xml_memory_page* doc_page = PUGI__GETPAGE(doc); assert(doc_page && !doc_page->prev && !doc_page->next); impl::xml_memory_page* other_page = PUGI__GETPAGE(other); assert(other_page && !other_page->prev); // relink pages since root page is embedded into xml_document if (impl::xml_memory_page* page = other_page->next) { assert(page->prev == other_page); page->prev = doc_page; doc_page->next = page; other_page->next = 0; } // make sure pages point to the correct document state for (impl::xml_memory_page* page = doc_page->next; page; page = page->next) { assert(page->allocator == other); page->allocator = doc; #ifdef PUGIXML_COMPACT // this automatically migrates most children between documents and prevents ->parent assignment from allocating if (page->compact_shared_parent == other) page->compact_shared_parent = doc; #endif } // move tree structure assert(!doc->first_child); doc->first_child = other_first_child; for (xml_node_struct* node = other_first_child; node; node = node->next_sibling) { #ifdef PUGIXML_COMPACT // most children will have migrated when we reassigned compact_shared_parent assert(node->parent == other || node->parent == doc); node->parent = doc; #else assert(node->parent == other); node->parent = doc; #endif } // reset other document new (other) impl::xml_document_struct(PUGI__GETPAGE(other)); rhs._buffer = 0; } #endif #ifndef PUGIXML_NO_STL PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) { reset(); return impl::load_stream_impl(static_cast(_root), stream, options, encoding, &_buffer); } PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) { reset(); return impl::load_stream_impl(static_cast(_root), stream, options, encoding_wchar, &_buffer); } #endif PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) { // Force native encoding (skip autodetection) #ifdef PUGIXML_WCHAR_MODE xml_encoding encoding = encoding_wchar; #else xml_encoding encoding = encoding_utf8; #endif return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); } PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) { return load_string(contents, options); } PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) { reset(); using impl::auto_deleter; // MSVC7 workaround auto_deleter file(fopen(path_, "rb"), impl::close_file); return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) { reset(); using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file_wide(path_, L"rb"), impl::close_file); return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, const_cast(contents), size, options, encoding, false, false, &_buffer); } PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, false, &_buffer); } PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, true, &_buffer); } PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const { impl::xml_buffered_writer buffered_writer(writer, encoding); if ((flags & format_write_bom) && encoding != encoding_latin1) { // BOM always represents the codepoint U+FEFF, so just write it in native encoding #ifdef PUGIXML_WCHAR_MODE unsigned int bom = 0xfeff; buffered_writer.write(static_cast(bom)); #else buffered_writer.write('\xef', '\xbb', '\xbf'); #endif } if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) { buffered_writer.write_string(PUGIXML_TEXT("'); if (!(flags & format_raw)) buffered_writer.write('\n'); } impl::node_output(buffered_writer, _root, indent, flags, 0); buffered_writer.flush(); } #ifndef PUGIXML_NO_STL PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const { xml_writer_stream writer(stream); save(writer, indent, flags, encoding); } PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const { xml_writer_stream writer(stream); save(writer, indent, flags, encoding_wchar); } #endif PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround auto_deleter file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding); } PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); return impl::save_file_impl(*this, file.data, indent, flags, encoding); } PUGI__FN xml_node xml_document::document_element() const { assert(_root); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (PUGI__NODETYPE(i) == node_element) return xml_node(i); return xml_node(); } #ifndef PUGIXML_NO_STL PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) { assert(str); return impl::as_utf8_impl(str, impl::strlength_wide(str)); } PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) { return impl::as_utf8_impl(str.c_str(), str.size()); } PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) { assert(str); return impl::as_wide_impl(str, strlen(str)); } PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) { return impl::as_wide_impl(str.c_str(), str.size()); } #endif PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) { impl::xml_memory::allocate = allocate; impl::xml_memory::deallocate = deallocate; } PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() { return impl::xml_memory::allocate; } PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() { return impl::xml_memory::deallocate; } } #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) namespace std { // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } } #endif #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) namespace std { // Workarounds for (non-standard) iterator category detection PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } } #endif #ifndef PUGIXML_NO_XPATH // STL replacements PUGI__NS_BEGIN struct equal_to { template bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } }; struct not_equal_to { template bool operator()(const T& lhs, const T& rhs) const { return lhs != rhs; } }; struct less { template bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } }; struct less_equal { template bool operator()(const T& lhs, const T& rhs) const { return lhs <= rhs; } }; template inline void swap(T& lhs, T& rhs) { T temp = lhs; lhs = rhs; rhs = temp; } template PUGI__FN I min_element(I begin, I end, const Pred& pred) { I result = begin; for (I it = begin + 1; it != end; ++it) if (pred(*it, *result)) result = it; return result; } template PUGI__FN void reverse(I begin, I end) { while (end - begin > 1) swap(*begin++, *--end); } template PUGI__FN I unique(I begin, I end) { // fast skip head while (end - begin > 1 && *begin != *(begin + 1)) begin++; if (begin == end) return begin; // last written element I write = begin++; // merge unique elements while (begin != end) { if (*begin != *write) *++write = *begin++; else begin++; } // past-the-end (write points to live element) return write + 1; } template PUGI__FN void insertion_sort(T* begin, T* end, const Pred& pred) { if (begin == end) return; for (T* it = begin + 1; it != end; ++it) { T val = *it; T* hole = it; // move hole backwards while (hole > begin && pred(val, *(hole - 1))) { *hole = *(hole - 1); hole--; } // fill hole with element *hole = val; } } template inline I median3(I first, I middle, I last, const Pred& pred) { if (pred(*middle, *first)) swap(middle, first); if (pred(*last, *middle)) swap(last, middle); if (pred(*middle, *first)) swap(middle, first); return middle; } template PUGI__FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend) { // invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups) T* eq = begin; T* lt = begin; T* gt = end; while (lt < gt) { if (pred(*lt, pivot)) lt++; else if (*lt == pivot) swap(*eq++, *lt++); else swap(*lt, *--gt); } // we now have just 4 groups: = < >; move equal elements to the middle T* eqbeg = gt; for (T* it = begin; it != eq; ++it) swap(*it, *--eqbeg); *out_eqbeg = eqbeg; *out_eqend = gt; } template PUGI__FN void sort(I begin, I end, const Pred& pred) { // sort large chunks while (end - begin > 16) { // find median element I middle = begin + (end - begin) / 2; I median = median3(begin, middle, end - 1, pred); // partition in three chunks (< = >) I eqbeg, eqend; partition3(begin, end, *median, pred, &eqbeg, &eqend); // loop on larger half if (eqbeg - begin > end - eqend) { sort(eqend, end, pred); end = eqbeg; } else { sort(begin, eqbeg, pred); begin = eqend; } } // insertion sort small chunk insertion_sort(begin, end, pred); } PUGI__FN bool hash_insert(const void** table, size_t size, const void* key) { assert(key); unsigned int h = static_cast(reinterpret_cast(key)); // MurmurHash3 32-bit finalizer h ^= h >> 16; h *= 0x85ebca6bu; h ^= h >> 13; h *= 0xc2b2ae35u; h ^= h >> 16; size_t hashmod = size - 1; size_t bucket = h & hashmod; for (size_t probe = 0; probe <= hashmod; ++probe) { if (table[bucket] == 0) { table[bucket] = key; return true; } if (table[bucket] == key) return false; // hash collision, quadratic probing bucket = (bucket + probe + 1) & hashmod; } assert(false && "Hash table is full"); // unreachable return false; } PUGI__NS_END // Allocator used for AST and evaluation stacks PUGI__NS_BEGIN static const size_t xpath_memory_page_size = #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE PUGIXML_MEMORY_XPATH_PAGE_SIZE #else 4096 #endif ; static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); struct xpath_memory_block { xpath_memory_block* next; size_t capacity; union { char data[xpath_memory_page_size]; double alignment; }; }; struct xpath_allocator { xpath_memory_block* _root; size_t _root_size; bool* _error; xpath_allocator(xpath_memory_block* root, bool* error = 0): _root(root), _root_size(0), _error(error) { } void* allocate(size_t size) { // round size up to block alignment boundary size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); if (_root_size + size <= _root->capacity) { void* buf = &_root->data[0] + _root_size; _root_size += size; return buf; } else { // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests size_t block_capacity_base = sizeof(_root->data); size_t block_capacity_req = size + block_capacity_base / 4; size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req; size_t block_size = block_capacity + offsetof(xpath_memory_block, data); xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); if (!block) { if (_error) *_error = true; return 0; } block->next = _root; block->capacity = block_capacity; _root = block; _root_size = size; return block->data; } } void* reallocate(void* ptr, size_t old_size, size_t new_size) { // round size up to block alignment boundary old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); // we can only reallocate the last object assert(ptr == 0 || static_cast(ptr) + old_size == &_root->data[0] + _root_size); // try to reallocate the object inplace if (ptr && _root_size - old_size + new_size <= _root->capacity) { _root_size = _root_size - old_size + new_size; return ptr; } // allocate a new block void* result = allocate(new_size); if (!result) return 0; // we have a new block if (ptr) { // copy old data (we only support growing) assert(new_size >= old_size); memcpy(result, ptr, old_size); // free the previous page if it had no other objects assert(_root->data == result); assert(_root->next); if (_root->next->data == ptr) { // deallocate the whole page, unless it was the first one xpath_memory_block* next = _root->next->next; if (next) { xml_memory::deallocate(_root->next); _root->next = next; } } } return result; } void revert(const xpath_allocator& state) { // free all new pages xpath_memory_block* cur = _root; while (cur != state._root) { xpath_memory_block* next = cur->next; xml_memory::deallocate(cur); cur = next; } // restore state _root = state._root; _root_size = state._root_size; } void release() { xpath_memory_block* cur = _root; assert(cur); while (cur->next) { xpath_memory_block* next = cur->next; xml_memory::deallocate(cur); cur = next; } } }; struct xpath_allocator_capture { xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) { } ~xpath_allocator_capture() { _target->revert(_state); } xpath_allocator* _target; xpath_allocator _state; }; struct xpath_stack { xpath_allocator* result; xpath_allocator* temp; }; struct xpath_stack_data { xpath_memory_block blocks[2]; xpath_allocator result; xpath_allocator temp; xpath_stack stack; bool oom; xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false) { blocks[0].next = blocks[1].next = 0; blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data); stack.result = &result; stack.temp = &temp; } ~xpath_stack_data() { result.release(); temp.release(); } }; PUGI__NS_END // String class PUGI__NS_BEGIN class xpath_string { const char_t* _buffer; bool _uses_heap; size_t _length_heap; static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) { char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); if (!result) return 0; memcpy(result, string, length * sizeof(char_t)); result[length] = 0; return result; } xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap) { } public: static xpath_string from_const(const char_t* str) { return xpath_string(str, false, 0); } static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end) { assert(begin <= end && *end == 0); return xpath_string(begin, true, static_cast(end - begin)); } static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc) { assert(begin <= end); if (begin == end) return xpath_string(); size_t length = static_cast(end - begin); const char_t* data = duplicate_string(begin, length, alloc); return data ? xpath_string(data, true, length) : xpath_string(); } xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0) { } void append(const xpath_string& o, xpath_allocator* alloc) { // skip empty sources if (!*o._buffer) return; // fast append for constant empty target and constant source if (!*_buffer && !_uses_heap && !o._uses_heap) { _buffer = o._buffer; } else { // need to make heap copy size_t target_length = length(); size_t source_length = o.length(); size_t result_length = target_length + source_length; // allocate new buffer char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); if (!result) return; // append first string to the new buffer in case there was no reallocation if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); // append second string to the new buffer memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); result[result_length] = 0; // finalize _buffer = result; _uses_heap = true; _length_heap = result_length; } } const char_t* c_str() const { return _buffer; } size_t length() const { return _uses_heap ? _length_heap : strlength(_buffer); } char_t* data(xpath_allocator* alloc) { // make private heap copy if (!_uses_heap) { size_t length_ = strlength(_buffer); const char_t* data_ = duplicate_string(_buffer, length_, alloc); if (!data_) return 0; _buffer = data_; _uses_heap = true; _length_heap = length_; } return const_cast(_buffer); } bool empty() const { return *_buffer == 0; } bool operator==(const xpath_string& o) const { return strequal(_buffer, o._buffer); } bool operator!=(const xpath_string& o) const { return !strequal(_buffer, o._buffer); } bool uses_heap() const { return _uses_heap; } }; PUGI__NS_END PUGI__NS_BEGIN PUGI__FN bool starts_with(const char_t* string, const char_t* pattern) { while (*pattern && *string == *pattern) { string++; pattern++; } return *pattern == 0; } PUGI__FN const char_t* find_char(const char_t* s, char_t c) { #ifdef PUGIXML_WCHAR_MODE return wcschr(s, c); #else return strchr(s, c); #endif } PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p) { #ifdef PUGIXML_WCHAR_MODE // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) return (*p == 0) ? s : wcsstr(s, p); #else return strstr(s, p); #endif } // Converts symbol to lower case, if it is an ASCII one PUGI__FN char_t tolower_ascii(char_t ch) { return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; } PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) { if (na.attribute()) return xpath_string::from_const(na.attribute().value()); else { xml_node n = na.node(); switch (n.type()) { case node_pcdata: case node_cdata: case node_comment: case node_pi: return xpath_string::from_const(n.value()); case node_document: case node_element: { xpath_string result; // element nodes can have value if parse_embed_pcdata was used if (n.value()[0]) result.append(xpath_string::from_const(n.value()), alloc); xml_node cur = n.first_child(); while (cur && cur != n) { if (cur.type() == node_pcdata || cur.type() == node_cdata) result.append(xpath_string::from_const(cur.value()), alloc); if (cur.first_child()) cur = cur.first_child(); else if (cur.next_sibling()) cur = cur.next_sibling(); else { while (!cur.next_sibling() && cur != n) cur = cur.parent(); if (cur != n) cur = cur.next_sibling(); } } return result; } default: return xpath_string(); } } } PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) { assert(ln->parent == rn->parent); // there is no common ancestor (the shared parent is null), nodes are from different documents if (!ln->parent) return ln < rn; // determine sibling order xml_node_struct* ls = ln; xml_node_struct* rs = rn; while (ls && rs) { if (ls == rn) return true; if (rs == ln) return false; ls = ls->next_sibling; rs = rs->next_sibling; } // if rn sibling chain ended ln must be before rn return !rs; } PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) { // find common ancestor at the same depth, if any xml_node_struct* lp = ln; xml_node_struct* rp = rn; while (lp && rp && lp->parent != rp->parent) { lp = lp->parent; rp = rp->parent; } // parents are the same! if (lp && rp) return node_is_before_sibling(lp, rp); // nodes are at different depths, need to normalize heights bool left_higher = !lp; while (lp) { lp = lp->parent; ln = ln->parent; } while (rp) { rp = rp->parent; rn = rn->parent; } // one node is the ancestor of the other if (ln == rn) return left_higher; // find common ancestor... again while (ln->parent != rn->parent) { ln = ln->parent; rn = rn->parent; } return node_is_before_sibling(ln, rn); } PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) { while (node && node != parent) node = node->parent; return parent && node == parent; } PUGI__FN const void* document_buffer_order(const xpath_node& xnode) { xml_node_struct* node = xnode.node().internal_object(); if (node) { if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0) { if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name; if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value; } return 0; } xml_attribute_struct* attr = xnode.attribute().internal_object(); if (attr) { if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0) { if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name; if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value; } return 0; } return 0; } struct document_order_comparator { bool operator()(const xpath_node& lhs, const xpath_node& rhs) const { // optimized document order based check const void* lo = document_buffer_order(lhs); const void* ro = document_buffer_order(rhs); if (lo && ro) return lo < ro; // slow comparison xml_node ln = lhs.node(), rn = rhs.node(); // compare attributes if (lhs.attribute() && rhs.attribute()) { // shared parent if (lhs.parent() == rhs.parent()) { // determine sibling order for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) if (a == rhs.attribute()) return true; return false; } // compare attribute parents ln = lhs.parent(); rn = rhs.parent(); } else if (lhs.attribute()) { // attributes go after the parent element if (lhs.parent() == rhs.node()) return false; ln = lhs.parent(); } else if (rhs.attribute()) { // attributes go after the parent element if (rhs.parent() == lhs.node()) return true; rn = rhs.parent(); } if (ln == rn) return false; if (!ln || !rn) return ln < rn; return node_is_before(ln.internal_object(), rn.internal_object()); } }; PUGI__FN double gen_nan() { #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); typedef uint32_t UI; // BCC5 workaround union { float f; UI i; } u; u.i = 0x7fc00000; return double(u.f); #else // fallback const volatile double zero = 0.0; return zero / zero; #endif } PUGI__FN bool is_nan(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) return !!_isnan(value); #elif defined(fpclassify) && defined(FP_NAN) return fpclassify(value) == FP_NAN; #else // fallback const volatile double v = value; return v != v; #endif } PUGI__FN const char_t* convert_number_to_string_special(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; if (_isnan(value)) return PUGIXML_TEXT("NaN"); return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) switch (fpclassify(value)) { case FP_NAN: return PUGIXML_TEXT("NaN"); case FP_INFINITE: return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); case FP_ZERO: return PUGIXML_TEXT("0"); default: return 0; } #else // fallback const volatile double v = value; if (v == 0) return PUGIXML_TEXT("0"); if (v != v) return PUGIXML_TEXT("NaN"); if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); return 0; #endif } PUGI__FN bool convert_number_to_boolean(double value) { return (value != 0 && !is_nan(value)); } PUGI__FN void truncate_zeros(char* begin, char* end) { while (begin != end && end[-1] == '0') end--; *end = 0; } // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get base values int sign, exponent; _ecvt_s(buffer, sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign); // truncate redundant zeros truncate_zeros(buffer, buffer + strlen(buffer)); // fill results *out_mantissa = buffer; *out_exponent = exponent; } #else PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get a scientific notation value with IEEE DBL_DIG decimals PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value); // get the exponent (possibly negative) char* exponent_string = strchr(buffer, 'e'); assert(exponent_string); int exponent = atoi(exponent_string + 1); // extract mantissa string: skip sign char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; assert(mantissa[0] != '0' && mantissa[1] == '.'); // divide mantissa by 10 to eliminate integer part mantissa[1] = mantissa[0]; mantissa++; exponent++; // remove extra mantissa digits and zero-terminate mantissa truncate_zeros(mantissa, exponent_string); // fill results *out_mantissa = mantissa; *out_exponent = exponent; } #endif PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) { // try special number conversion const char_t* special = convert_number_to_string_special(value); if (special) return xpath_string::from_const(special); // get mantissa + exponent form char mantissa_buffer[32]; char* mantissa; int exponent; convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent); // allocate a buffer of suitable length for the number size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4; char_t* result = static_cast(alloc->allocate(sizeof(char_t) * result_size)); if (!result) return xpath_string(); // make the number! char_t* s = result; // sign if (value < 0) *s++ = '-'; // integer part if (exponent <= 0) { *s++ = '0'; } else { while (exponent > 0) { assert(*mantissa == 0 || static_cast(*mantissa - '0') <= 9); *s++ = *mantissa ? *mantissa++ : '0'; exponent--; } } // fractional part if (*mantissa) { // decimal point *s++ = '.'; // extra zeroes from negative exponent while (exponent < 0) { *s++ = '0'; exponent++; } // extra mantissa digits while (*mantissa) { assert(static_cast(*mantissa - '0') <= 9); *s++ = *mantissa++; } } // zero-terminate assert(s < result + result_size); *s = 0; return xpath_string::from_heap_preallocated(result, s); } PUGI__FN bool check_string_to_number_format(const char_t* string) { // parse leading whitespace while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; // parse sign if (*string == '-') ++string; if (!*string) return false; // if there is no integer part, there should be a decimal part with at least one digit if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false; // parse integer part while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; // parse decimal part if (*string == '.') { ++string; while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; } // parse trailing whitespace while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; return *string == 0; } PUGI__FN double convert_string_to_number(const char_t* string) { // check string format if (!check_string_to_number_format(string)) return gen_nan(); // parse string #ifdef PUGIXML_WCHAR_MODE return wcstod(string, 0); #else return strtod(string, 0); #endif } PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result) { size_t length = static_cast(end - begin); char_t* scratch = buffer; if (length >= sizeof(buffer) / sizeof(buffer[0])) { // need to make dummy on-heap copy scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!scratch) return false; } // copy string to zero-terminated buffer and perform conversion memcpy(scratch, begin, length * sizeof(char_t)); scratch[length] = 0; *out_result = convert_string_to_number(scratch); // free dummy buffer if (scratch != buffer) xml_memory::deallocate(scratch); return true; } PUGI__FN double round_nearest(double value) { return floor(value + 0.5); } PUGI__FN double round_nearest_nzero(double value) { // same as round_nearest, but returns -0 for [-0.5, -0] // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); } PUGI__FN const char_t* qualified_name(const xpath_node& node) { return node.attribute() ? node.attribute().name() : node.node().name(); } PUGI__FN const char_t* local_name(const xpath_node& node) { const char_t* name = qualified_name(node); const char_t* p = find_char(name, ':'); return p ? p + 1 : name; } struct namespace_uri_predicate { const char_t* prefix; size_t prefix_length; namespace_uri_predicate(const char_t* name) { const char_t* pos = find_char(name, ':'); prefix = pos ? name : 0; prefix_length = pos ? static_cast(pos - name) : 0; } bool operator()(xml_attribute a) const { const char_t* name = a.name(); if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; } }; PUGI__FN const char_t* namespace_uri(xml_node node) { namespace_uri_predicate pred = node.name(); xml_node p = node; while (p) { xml_attribute a = p.find_attribute(pred); if (a) return a.value(); p = p.parent(); } return PUGIXML_TEXT(""); } PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { namespace_uri_predicate pred = attr.name(); // Default namespace does not apply to attributes if (!pred.prefix) return PUGIXML_TEXT(""); xml_node p = parent; while (p) { xml_attribute a = p.find_attribute(pred); if (a) return a.value(); p = p.parent(); } return PUGIXML_TEXT(""); } PUGI__FN const char_t* namespace_uri(const xpath_node& node) { return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); } PUGI__FN char_t* normalize_space(char_t* buffer) { char_t* write = buffer; for (char_t* it = buffer; *it; ) { char_t ch = *it++; if (PUGI__IS_CHARTYPE(ch, ct_space)) { // replace whitespace sequence with single space while (PUGI__IS_CHARTYPE(*it, ct_space)) it++; // avoid leading spaces if (write != buffer) *write++ = ' '; } else *write++ = ch; } // remove trailing space if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--; // zero-terminate *write = 0; return write; } PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length) { char_t* write = buffer; while (*buffer) { PUGI__DMC_VOLATILE char_t ch = *buffer++; const char_t* pos = find_char(from, ch); if (!pos) *write++ = ch; // do not process else if (static_cast(pos - from) < to_length) *write++ = to[pos - from]; // replace } // zero-terminate *write = 0; return write; } PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to) { unsigned char table[128] = {0}; while (*from) { unsigned int fc = static_cast(*from); unsigned int tc = static_cast(*to); if (fc >= 128 || tc >= 128) return 0; // code=128 means "skip character" if (!table[fc]) table[fc] = static_cast(tc ? tc : 128); from++; if (tc) to++; } for (int i = 0; i < 128; ++i) if (!table[i]) table[i] = static_cast(i); void* result = alloc->allocate(sizeof(table)); if (!result) return 0; memcpy(result, table, sizeof(table)); return static_cast(result); } PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table) { char_t* write = buffer; while (*buffer) { char_t ch = *buffer++; unsigned int index = static_cast(ch); if (index < 128) { unsigned char code = table[index]; // code=128 means "skip character" (table size is 128 so 128 can be a special value) // this code skips these characters without extra branches *write = static_cast(code); write += 1 - (code >> 7); } else { *write++ = ch; } } // zero-terminate *write = 0; return write; } inline bool is_xpath_attribute(const char_t* name) { return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')); } struct xpath_variable_boolean: xpath_variable { xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false) { } bool value; char_t name[1]; }; struct xpath_variable_number: xpath_variable { xpath_variable_number(): xpath_variable(xpath_type_number), value(0) { } double value; char_t name[1]; }; struct xpath_variable_string: xpath_variable { xpath_variable_string(): xpath_variable(xpath_type_string), value(0) { } ~xpath_variable_string() { if (value) xml_memory::deallocate(value); } char_t* value; char_t name[1]; }; struct xpath_variable_node_set: xpath_variable { xpath_variable_node_set(): xpath_variable(xpath_type_node_set) { } xpath_node_set value; char_t name[1]; }; static const xpath_node_set dummy_node_set; PUGI__FN PUGI__UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str) { // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) unsigned int result = 0; while (*str) { result += static_cast(*str++); result += result << 10; result ^= result >> 6; } result += result << 3; result ^= result >> 11; result += result << 15; return result; } template PUGI__FN T* new_xpath_variable(const char_t* name) { size_t length = strlength(name); if (length == 0) return 0; // empty variable names are invalid // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); if (!memory) return 0; T* result = new (memory) T(); memcpy(result->name, name, (length + 1) * sizeof(char_t)); return result; } PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) { switch (type) { case xpath_type_node_set: return new_xpath_variable(name); case xpath_type_number: return new_xpath_variable(name); case xpath_type_string: return new_xpath_variable(name); case xpath_type_boolean: return new_xpath_variable(name); default: return 0; } } template PUGI__FN void delete_xpath_variable(T* var) { var->~T(); xml_memory::deallocate(var); } PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) { switch (type) { case xpath_type_node_set: delete_xpath_variable(static_cast(var)); break; case xpath_type_number: delete_xpath_variable(static_cast(var)); break; case xpath_type_string: delete_xpath_variable(static_cast(var)); break; case xpath_type_boolean: delete_xpath_variable(static_cast(var)); break; default: assert(false && "Invalid variable type"); // unreachable } } PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs) { switch (rhs->type()) { case xpath_type_node_set: return lhs->set(static_cast(rhs)->value); case xpath_type_number: return lhs->set(static_cast(rhs)->value); case xpath_type_string: return lhs->set(static_cast(rhs)->value); case xpath_type_boolean: return lhs->set(static_cast(rhs)->value); default: assert(false && "Invalid variable type"); // unreachable return false; } } PUGI__FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result) { size_t length = static_cast(end - begin); char_t* scratch = buffer; if (length >= sizeof(buffer) / sizeof(buffer[0])) { // need to make dummy on-heap copy scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!scratch) return false; } // copy string to zero-terminated buffer and perform lookup memcpy(scratch, begin, length * sizeof(char_t)); scratch[length] = 0; *out_result = set->get(scratch); // free dummy buffer if (scratch != buffer) xml_memory::deallocate(scratch); return true; } PUGI__NS_END // Internal node set class PUGI__NS_BEGIN PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end) { if (end - begin < 2) return xpath_node_set::type_sorted; document_order_comparator cmp; bool first = cmp(begin[0], begin[1]); for (const xpath_node* it = begin + 1; it + 1 < end; ++it) if (cmp(it[0], it[1]) != first) return xpath_node_set::type_unsorted; return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse; } PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) { xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; if (type == xpath_node_set::type_unsorted) { xpath_node_set::type_t sorted = xpath_get_order(begin, end); if (sorted == xpath_node_set::type_unsorted) { sort(begin, end, document_order_comparator()); type = xpath_node_set::type_sorted; } else type = sorted; } if (type != order) reverse(begin, end); return order; } PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) { if (begin == end) return xpath_node(); switch (type) { case xpath_node_set::type_sorted: return *begin; case xpath_node_set::type_sorted_reverse: return *(end - 1); case xpath_node_set::type_unsorted: return *min_element(begin, end, document_order_comparator()); default: assert(false && "Invalid node set type"); // unreachable return xpath_node(); } } class xpath_node_set_raw { xpath_node_set::type_t _type; xpath_node* _begin; xpath_node* _end; xpath_node* _eos; public: xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) { } xpath_node* begin() const { return _begin; } xpath_node* end() const { return _end; } bool empty() const { return _begin == _end; } size_t size() const { return static_cast(_end - _begin); } xpath_node first() const { return xpath_first(_begin, _end, _type); } void push_back_grow(const xpath_node& node, xpath_allocator* alloc); void push_back(const xpath_node& node, xpath_allocator* alloc) { if (_end != _eos) *_end++ = node; else push_back_grow(node, alloc); } void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc) { if (begin_ == end_) return; size_t size_ = static_cast(_end - _begin); size_t capacity = static_cast(_eos - _begin); size_t count = static_cast(end_ - begin_); if (size_ + count > capacity) { // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); if (!data) return; // finalize _begin = data; _end = data + size_; _eos = data + size_ + count; } memcpy(_end, begin_, count * sizeof(xpath_node)); _end += count; } void sort_do() { _type = xpath_sort(_begin, _end, _type, false); } void truncate(xpath_node* pos) { assert(_begin <= pos && pos <= _end); _end = pos; } void remove_duplicates(xpath_allocator* alloc) { if (_type == xpath_node_set::type_unsorted && _end - _begin > 2) { xpath_allocator_capture cr(alloc); size_t size_ = static_cast(_end - _begin); size_t hash_size = 1; while (hash_size < size_ + size_ / 2) hash_size *= 2; const void** hash_data = static_cast(alloc->allocate(hash_size * sizeof(void**))); if (!hash_data) return; memset(hash_data, 0, hash_size * sizeof(const void**)); xpath_node* write = _begin; for (xpath_node* it = _begin; it != _end; ++it) { const void* attr = it->attribute().internal_object(); const void* node = it->node().internal_object(); const void* key = attr ? attr : node; if (key && hash_insert(hash_data, hash_size, key)) { *write++ = *it; } } _end = write; } else { _end = unique(_begin, _end); } } xpath_node_set::type_t type() const { return _type; } void set_type(xpath_node_set::type_t value) { _type = value; } }; PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc) { size_t capacity = static_cast(_eos - _begin); // get new capacity (1.5x rule) size_t new_capacity = capacity + capacity / 2 + 1; // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); if (!data) return; // finalize _begin = data; _end = data + capacity; _eos = data + new_capacity; // push *_end++ = node; } PUGI__NS_END PUGI__NS_BEGIN struct xpath_context { xpath_node n; size_t position, size; xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_) { } }; enum lexeme_t { lex_none = 0, lex_equal, lex_not_equal, lex_less, lex_greater, lex_less_or_equal, lex_greater_or_equal, lex_plus, lex_minus, lex_multiply, lex_union, lex_var_ref, lex_open_brace, lex_close_brace, lex_quoted_string, lex_number, lex_slash, lex_double_slash, lex_open_square_brace, lex_close_square_brace, lex_string, lex_comma, lex_axis_attribute, lex_dot, lex_double_dot, lex_double_colon, lex_eof }; struct xpath_lexer_string { const char_t* begin; const char_t* end; xpath_lexer_string(): begin(0), end(0) { } bool operator==(const char_t* other) const { size_t length = static_cast(end - begin); return strequalrange(other, begin, length); } }; class xpath_lexer { const char_t* _cur; const char_t* _cur_lexeme_pos; xpath_lexer_string _cur_lexeme_contents; lexeme_t _cur_lexeme; public: explicit xpath_lexer(const char_t* query): _cur(query) { next(); } const char_t* state() const { return _cur; } void next() { const char_t* cur = _cur; while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; // save lexeme position for error reporting _cur_lexeme_pos = cur; switch (*cur) { case 0: _cur_lexeme = lex_eof; break; case '>': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_greater_or_equal; } else { cur += 1; _cur_lexeme = lex_greater; } break; case '<': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_less_or_equal; } else { cur += 1; _cur_lexeme = lex_less; } break; case '!': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_not_equal; } else { _cur_lexeme = lex_none; } break; case '=': cur += 1; _cur_lexeme = lex_equal; break; case '+': cur += 1; _cur_lexeme = lex_plus; break; case '-': cur += 1; _cur_lexeme = lex_minus; break; case '*': cur += 1; _cur_lexeme = lex_multiply; break; case '|': cur += 1; _cur_lexeme = lex_union; break; case '$': cur += 1; if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname { cur++; // : while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_var_ref; } else { _cur_lexeme = lex_none; } break; case '(': cur += 1; _cur_lexeme = lex_open_brace; break; case ')': cur += 1; _cur_lexeme = lex_close_brace; break; case '[': cur += 1; _cur_lexeme = lex_open_square_brace; break; case ']': cur += 1; _cur_lexeme = lex_close_square_brace; break; case ',': cur += 1; _cur_lexeme = lex_comma; break; case '/': if (*(cur+1) == '/') { cur += 2; _cur_lexeme = lex_double_slash; } else { cur += 1; _cur_lexeme = lex_slash; } break; case '.': if (*(cur+1) == '.') { cur += 2; _cur_lexeme = lex_double_dot; } else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit)) { _cur_lexeme_contents.begin = cur; // . ++cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; _cur_lexeme_contents.end = cur; _cur_lexeme = lex_number; } else { cur += 1; _cur_lexeme = lex_dot; } break; case '@': cur += 1; _cur_lexeme = lex_axis_attribute; break; case '"': case '\'': { char_t terminator = *cur; ++cur; _cur_lexeme_contents.begin = cur; while (*cur && *cur != terminator) cur++; _cur_lexeme_contents.end = cur; if (!*cur) _cur_lexeme = lex_none; else { cur += 1; _cur_lexeme = lex_quoted_string; } break; } case ':': if (*(cur+1) == ':') { cur += 2; _cur_lexeme = lex_double_colon; } else { _cur_lexeme = lex_none; } break; default: if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) { _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; if (*cur == '.') { cur++; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_number; } else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; if (cur[0] == ':') { if (cur[1] == '*') // namespace test ncname:* { cur += 2; // :* } else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname { cur++; // : while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_string; } else { _cur_lexeme = lex_none; } } _cur = cur; } lexeme_t current() const { return _cur_lexeme; } const char_t* current_pos() const { return _cur_lexeme_pos; } const xpath_lexer_string& contents() const { assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); return _cur_lexeme_contents; } }; enum ast_type_t { ast_unknown, ast_op_or, // left or right ast_op_and, // left and right ast_op_equal, // left = right ast_op_not_equal, // left != right ast_op_less, // left < right ast_op_greater, // left > right ast_op_less_or_equal, // left <= right ast_op_greater_or_equal, // left >= right ast_op_add, // left + right ast_op_subtract, // left - right ast_op_multiply, // left * right ast_op_divide, // left / right ast_op_mod, // left % right ast_op_negate, // left - right ast_op_union, // left | right ast_predicate, // apply predicate to set; next points to next predicate ast_filter, // select * from left where right ast_string_constant, // string constant ast_number_constant, // number constant ast_variable, // variable ast_func_last, // last() ast_func_position, // position() ast_func_count, // count(left) ast_func_id, // id(left) ast_func_local_name_0, // local-name() ast_func_local_name_1, // local-name(left) ast_func_namespace_uri_0, // namespace-uri() ast_func_namespace_uri_1, // namespace-uri(left) ast_func_name_0, // name() ast_func_name_1, // name(left) ast_func_string_0, // string() ast_func_string_1, // string(left) ast_func_concat, // concat(left, right, siblings) ast_func_starts_with, // starts_with(left, right) ast_func_contains, // contains(left, right) ast_func_substring_before, // substring-before(left, right) ast_func_substring_after, // substring-after(left, right) ast_func_substring_2, // substring(left, right) ast_func_substring_3, // substring(left, right, third) ast_func_string_length_0, // string-length() ast_func_string_length_1, // string-length(left) ast_func_normalize_space_0, // normalize-space() ast_func_normalize_space_1, // normalize-space(left) ast_func_translate, // translate(left, right, third) ast_func_boolean, // boolean(left) ast_func_not, // not(left) ast_func_true, // true() ast_func_false, // false() ast_func_lang, // lang(left) ast_func_number_0, // number() ast_func_number_1, // number(left) ast_func_sum, // sum(left) ast_func_floor, // floor(left) ast_func_ceiling, // ceiling(left) ast_func_round, // round(left) ast_step, // process set left with step ast_step_root, // select root node ast_opt_translate_table, // translate(left, right, third) where right/third are constants ast_opt_compare_attribute // @name = 'string' }; enum axis_t { axis_ancestor, axis_ancestor_or_self, axis_attribute, axis_child, axis_descendant, axis_descendant_or_self, axis_following, axis_following_sibling, axis_namespace, axis_parent, axis_preceding, axis_preceding_sibling, axis_self }; enum nodetest_t { nodetest_none, nodetest_name, nodetest_type_node, nodetest_type_comment, nodetest_type_pi, nodetest_type_text, nodetest_pi, nodetest_all, nodetest_all_in_namespace }; enum predicate_t { predicate_default, predicate_posinv, predicate_constant, predicate_constant_one }; enum nodeset_eval_t { nodeset_eval_all, nodeset_eval_any, nodeset_eval_first }; template struct axis_to_type { static const axis_t axis; }; template const axis_t axis_to_type::axis = N; class xpath_ast_node { private: // node type char _type; char _rettype; // for ast_step char _axis; // for ast_step/ast_predicate/ast_filter char _test; // tree node structure xpath_ast_node* _left; xpath_ast_node* _right; xpath_ast_node* _next; union { // value for ast_string_constant const char_t* string; // value for ast_number_constant double number; // variable for ast_variable xpath_variable* variable; // node test for ast_step (node name/namespace/node type/pi target) const char_t* nodetest; // table for ast_opt_translate_table const unsigned char* table; } _data; xpath_ast_node(const xpath_ast_node&); xpath_ast_node& operator=(const xpath_ast_node&); template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) { xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); if (lt != xpath_type_node_set && rt != xpath_type_node_set) { if (lt == xpath_type_boolean || rt == xpath_type_boolean) return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); else if (lt == xpath_type_number || rt == xpath_type_number) return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); else if (lt == xpath_type_string || rt == xpath_type_string) { xpath_allocator_capture cr(stack.result); xpath_string ls = lhs->eval_string(c, stack); xpath_string rs = rhs->eval_string(c, stack); return comp(ls, rs); } } else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) return true; } return false; } else { if (lt == xpath_type_node_set) { swap(lhs, rhs); swap(lt, rt); } if (lt == xpath_type_boolean) return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); else if (lt == xpath_type_number) { xpath_allocator_capture cr(stack.result); double l = lhs->eval_number(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } return false; } else if (lt == xpath_type_string) { xpath_allocator_capture cr(stack.result); xpath_string l = lhs->eval_string(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, string_value(*ri, stack.result))) return true; } return false; } } assert(false && "Wrong types"); // unreachable return false; } static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) { return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any; } template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) { xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); if (lt != xpath_type_node_set && rt != xpath_type_node_set) return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { xpath_allocator_capture cri(stack.result); double l = convert_string_to_number(string_value(*li, stack.result).c_str()); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture crii(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } } return false; } else if (lt != xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); double l = lhs->eval_number(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } return false; } else if (lt == xpath_type_node_set && rt != xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); double r = rhs->eval_number(c, stack); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { xpath_allocator_capture cri(stack.result); if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) return true; } return false; } else { assert(false && "Wrong types"); // unreachable return false; } } static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) { assert(ns.size() >= first); assert(expr->rettype() != xpath_type_number); size_t i = 1; size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; // remove_if... or well, sort of for (xpath_node* it = last; it != ns.end(); ++it, ++i) { xpath_context c(*it, i, size); if (expr->eval_boolean(c, stack)) { *last++ = *it; if (once) break; } } ns.truncate(last); } static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) { assert(ns.size() >= first); assert(expr->rettype() == xpath_type_number); size_t i = 1; size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; // remove_if... or well, sort of for (xpath_node* it = last; it != ns.end(); ++it, ++i) { xpath_context c(*it, i, size); if (expr->eval_number(c, stack) == i) { *last++ = *it; if (once) break; } } ns.truncate(last); } static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) { assert(ns.size() >= first); assert(expr->rettype() == xpath_type_number); size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; xpath_context c(xpath_node(), 1, size); double er = expr->eval_number(c, stack); if (er >= 1.0 && er <= size) { size_t eri = static_cast(er); if (er == eri) { xpath_node r = last[eri - 1]; *last++ = r; } } ns.truncate(last); } void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once) { if (ns.size() == first) return; assert(_type == ast_filter || _type == ast_predicate); if (_test == predicate_constant || _test == predicate_constant_one) apply_predicate_number_const(ns, first, _right, stack); else if (_right->rettype() == xpath_type_number) apply_predicate_number(ns, first, _right, stack, once); else apply_predicate_boolean(ns, first, _right, stack, once); } void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval) { if (ns.size() == first) return; bool last_once = eval_once(ns.type(), eval); for (xpath_ast_node* pred = _right; pred; pred = pred->_next) pred->apply_predicate(ns, first, stack, !pred->_next && last_once); } bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc) { assert(a); const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT(""); switch (_test) { case nodetest_name: if (strequal(name, _data.nodetest) && is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; case nodetest_type_node: case nodetest_all: if (is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; case nodetest_all_in_namespace: if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; default: ; } return false; } bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) { assert(n); xml_node_type type = PUGI__NODETYPE(n); switch (_test) { case nodetest_name: if (type == node_element && n->name && strequal(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_node: ns.push_back(xml_node(n), alloc); return true; case nodetest_type_comment: if (type == node_comment) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_text: if (type == node_pcdata || type == node_cdata) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_pi: if (type == node_pi) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_pi: if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_all: if (type == node_element) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_all_in_namespace: if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; default: assert(false && "Unknown axis"); // unreachable } return false; } template void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T) { const axis_t axis = T::axis; switch (axis) { case axis_attribute: { for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) if (step_push(ns, a, n, alloc) & once) return; break; } case axis_child: { for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; break; } case axis_descendant: case axis_descendant_or_self: { if (axis == axis_descendant_or_self) if (step_push(ns, n, alloc) & once) return; xml_node_struct* cur = n->first_child; while (cur) { if (step_push(ns, cur, alloc) & once) return; if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (cur == n) return; } cur = cur->next_sibling; } } break; } case axis_following_sibling: { for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; break; } case axis_preceding_sibling: { for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) if (step_push(ns, c, alloc) & once) return; break; } case axis_following: { xml_node_struct* cur = n; // exit from this node so that we don't include descendants while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; while (cur) { if (step_push(ns, cur, alloc) & once) return; if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; } } break; } case axis_preceding: { xml_node_struct* cur = n; // exit from this node so that we don't include descendants while (!cur->prev_sibling_c->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->prev_sibling_c; while (cur) { if (cur->first_child) cur = cur->first_child->prev_sibling_c; else { // leaf node, can't be ancestor if (step_push(ns, cur, alloc) & once) return; while (!cur->prev_sibling_c->next_sibling) { cur = cur->parent; if (!cur) return; if (!node_is_ancestor(cur, n)) if (step_push(ns, cur, alloc) & once) return; } cur = cur->prev_sibling_c; } } break; } case axis_ancestor: case axis_ancestor_or_self: { if (axis == axis_ancestor_or_self) if (step_push(ns, n, alloc) & once) return; xml_node_struct* cur = n->parent; while (cur) { if (step_push(ns, cur, alloc) & once) return; cur = cur->parent; } break; } case axis_self: { step_push(ns, n, alloc); break; } case axis_parent: { if (n->parent) step_push(ns, n->parent, alloc); break; } default: assert(false && "Unimplemented axis"); // unreachable } } template void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; switch (axis) { case axis_ancestor: case axis_ancestor_or_self: { if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test if (step_push(ns, a, p, alloc) & once) return; xml_node_struct* cur = p; while (cur) { if (step_push(ns, cur, alloc) & once) return; cur = cur->parent; } break; } case axis_descendant_or_self: case axis_self: { if (_test == nodetest_type_node) // reject attributes based on principal node type test step_push(ns, a, p, alloc); break; } case axis_following: { xml_node_struct* cur = p; while (cur) { if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; } if (step_push(ns, cur, alloc) & once) return; } break; } case axis_parent: { step_push(ns, p, alloc); break; } case axis_preceding: { // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding step_fill(ns, p, alloc, once, v); break; } default: assert(false && "Unimplemented axis"); // unreachable } } template void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); if (xn.node()) step_fill(ns, xn.node().internal_object(), alloc, once, v); else if (axis_has_attributes && xn.attribute() && xn.parent()) step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v); } template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) { const axis_t axis = T::axis; const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling); const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; bool once = (axis == axis_attribute && _test == nodetest_name) || (!_right && eval_once(axis_type, eval)) || // coverity[mixed_enums] (_right && !_right->_next && _right->_test == predicate_constant_one); xpath_node_set_raw ns; ns.set_type(axis_type); if (_left) { xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all); // self axis preserves the original order if (axis == axis_self) ns.set_type(s.type()); for (const xpath_node* it = s.begin(); it != s.end(); ++it) { size_t size = ns.size(); // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); step_fill(ns, *it, stack.result, once, v); if (_right) apply_predicates(ns, size, stack, eval); } } else { step_fill(ns, c.n, stack.result, once, v); if (_right) apply_predicates(ns, 0, stack, eval); } // child, attribute and self axes always generate unique set of nodes // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) ns.remove_duplicates(stack.temp); return ns; } public: xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_string_constant); _data.string = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_number_constant); _data.number = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_variable); _data.variable = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) { } xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(0), _next(0) { assert(type == ast_step); _data.nodetest = contents; } xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test): _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast(test)), _left(left), _right(right), _next(0) { assert(type == ast_filter || type == ast_predicate); } void set_next(xpath_ast_node* value) { _next = value; } void set_right(xpath_ast_node* value) { _right = value; } bool eval_boolean(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_op_or: return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); case ast_op_and: return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); case ast_op_equal: return compare_eq(_left, _right, c, stack, equal_to()); case ast_op_not_equal: return compare_eq(_left, _right, c, stack, not_equal_to()); case ast_op_less: return compare_rel(_left, _right, c, stack, less()); case ast_op_greater: return compare_rel(_right, _left, c, stack, less()); case ast_op_less_or_equal: return compare_rel(_left, _right, c, stack, less_equal()); case ast_op_greater_or_equal: return compare_rel(_right, _left, c, stack, less_equal()); case ast_func_starts_with: { xpath_allocator_capture cr(stack.result); xpath_string lr = _left->eval_string(c, stack); xpath_string rr = _right->eval_string(c, stack); return starts_with(lr.c_str(), rr.c_str()); } case ast_func_contains: { xpath_allocator_capture cr(stack.result); xpath_string lr = _left->eval_string(c, stack); xpath_string rr = _right->eval_string(c, stack); return find_substring(lr.c_str(), rr.c_str()) != 0; } case ast_func_boolean: return _left->eval_boolean(c, stack); case ast_func_not: return !_left->eval_boolean(c, stack); case ast_func_true: return true; case ast_func_false: return false; case ast_func_lang: { if (c.n.attribute()) return false; xpath_allocator_capture cr(stack.result); xpath_string lang = _left->eval_string(c, stack); for (xml_node n = c.n.node(); n; n = n.parent()) { xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); if (a) { const char_t* value = a.value(); // strnicmp / strncasecmp is not portable for (const char_t* lit = lang.c_str(); *lit; ++lit) { if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; ++value; } return *value == 0 || *value == '-'; } } return false; } case ast_opt_compare_attribute: { const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string(); xml_attribute attr = c.n.node().attribute(_left->_data.nodetest); return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name()); } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_boolean) return _data.variable->get_boolean(); } // fallthrough default: { switch (_rettype) { case xpath_type_number: return convert_number_to_boolean(eval_number(c, stack)); case xpath_type_string: { xpath_allocator_capture cr(stack.result); return !eval_string(c, stack).empty(); } case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return !eval_node_set(c, stack, nodeset_eval_any).empty(); } default: assert(false && "Wrong expression for return type boolean"); // unreachable return false; } } } } double eval_number(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_op_add: return _left->eval_number(c, stack) + _right->eval_number(c, stack); case ast_op_subtract: return _left->eval_number(c, stack) - _right->eval_number(c, stack); case ast_op_multiply: return _left->eval_number(c, stack) * _right->eval_number(c, stack); case ast_op_divide: return _left->eval_number(c, stack) / _right->eval_number(c, stack); case ast_op_mod: return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); case ast_op_negate: return -_left->eval_number(c, stack); case ast_number_constant: return _data.number; case ast_func_last: return static_cast(c.size); case ast_func_position: return static_cast(c.position); case ast_func_count: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_node_set(c, stack, nodeset_eval_all).size()); } case ast_func_string_length_0: { xpath_allocator_capture cr(stack.result); return static_cast(string_value(c.n, stack.result).length()); } case ast_func_string_length_1: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_string(c, stack).length()); } case ast_func_number_0: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(string_value(c.n, stack.result).c_str()); } case ast_func_number_1: return _left->eval_number(c, stack); case ast_func_sum: { xpath_allocator_capture cr(stack.result); double r = 0; xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) { xpath_allocator_capture cri(stack.result); r += convert_string_to_number(string_value(*it, stack.result).c_str()); } return r; } case ast_func_floor: { double r = _left->eval_number(c, stack); return r == r ? floor(r) : r; } case ast_func_ceiling: { double r = _left->eval_number(c, stack); return r == r ? ceil(r) : r; } case ast_func_round: return round_nearest_nzero(_left->eval_number(c, stack)); case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_number) return _data.variable->get_number(); } // fallthrough default: { switch (_rettype) { case xpath_type_boolean: return eval_boolean(c, stack) ? 1 : 0; case xpath_type_string: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } default: assert(false && "Wrong expression for return type number"); // unreachable return 0; } } } } xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) { assert(_type == ast_func_concat); xpath_allocator_capture ct(stack.temp); // count the string number size_t count = 1; for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; // allocate a buffer for temporary string objects xpath_string* buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); if (!buffer) return xpath_string(); // evaluate all strings to temporary stack xpath_stack swapped_stack = {stack.temp, stack.result}; buffer[0] = _left->eval_string(c, swapped_stack); size_t pos = 1; for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); assert(pos == count); // get total length size_t length = 0; for (size_t i = 0; i < count; ++i) length += buffer[i].length(); // create final string char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); if (!result) return xpath_string(); char_t* ri = result; for (size_t j = 0; j < count; ++j) for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) *ri++ = *bi; *ri = 0; return xpath_string::from_heap_preallocated(result, ri); } xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_string_constant: return xpath_string::from_const(_data.string); case ast_func_local_name_0: { xpath_node na = c.n; return xpath_string::from_const(local_name(na)); } case ast_func_local_name_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(local_name(na)); } case ast_func_name_0: { xpath_node na = c.n; return xpath_string::from_const(qualified_name(na)); } case ast_func_name_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(qualified_name(na)); } case ast_func_namespace_uri_0: { xpath_node na = c.n; return xpath_string::from_const(namespace_uri(na)); } case ast_func_namespace_uri_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(namespace_uri(na)); } case ast_func_string_0: return string_value(c.n, stack.result); case ast_func_string_1: return _left->eval_string(c, stack); case ast_func_concat: return eval_string_concat(c, stack); case ast_func_substring_before: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); } case ast_func_substring_after: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); if (!pos) return xpath_string(); const char_t* rbegin = pos + p.length(); const char_t* rend = s.c_str() + s.length(); return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_2: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); if (is_nan(first)) return xpath_string(); // NaN else if (first >= s_length + 1) return xpath_string(); size_t pos = first < 1 ? 1 : static_cast(first); assert(1 <= pos && pos <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + s.length(); return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_3: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); double last = first + round_nearest(_right->_next->eval_number(c, stack)); if (is_nan(first) || is_nan(last)) return xpath_string(); else if (first >= s_length + 1) return xpath_string(); else if (first >= last) return xpath_string(); else if (last < 1) return xpath_string(); size_t pos = first < 1 ? 1 : static_cast(first); size_t end = last >= s_length + 1 ? s_length + 1 : static_cast(last); assert(1 <= pos && pos <= end && end <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + (end - 1); return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result); } case ast_func_normalize_space_0: { xpath_string s = string_value(c.n, stack.result); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = normalize_space(begin); return xpath_string::from_heap_preallocated(begin, end); } case ast_func_normalize_space_1: { xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = normalize_space(begin); return xpath_string::from_heap_preallocated(begin, end); } case ast_func_translate: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, stack); xpath_string from = _right->eval_string(c, swapped_stack); xpath_string to = _right->_next->eval_string(c, swapped_stack); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = translate(begin, from.c_str(), to.c_str(), to.length()); return xpath_string::from_heap_preallocated(begin, end); } case ast_opt_translate_table: { xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); if (!begin) return xpath_string(); char_t* end = translate_table(begin, _data.table); return xpath_string::from_heap_preallocated(begin, end); } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_string) return xpath_string::from_const(_data.variable->get_string()); } // fallthrough default: { switch (_rettype) { case xpath_type_boolean: return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); case xpath_type_number: return convert_number_to_string(eval_number(c, stack), stack.result); case xpath_type_node_set: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); } default: assert(false && "Wrong expression for return type string"); // unreachable return xpath_string(); } } } } xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval) { switch (_type) { case ast_op_union: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_node_set_raw ls = _left->eval_node_set(c, stack, eval); xpath_node_set_raw rs = _right->eval_node_set(c, swapped_stack, eval); // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother ls.set_type(xpath_node_set::type_unsorted); ls.append(rs.begin(), rs.end(), stack.result); ls.remove_duplicates(stack.temp); return ls; } case ast_filter: { xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all); // either expression is a number or it contains position() call; sort by document order if (_test != predicate_posinv) set.sort_do(); bool once = eval_once(set.type(), eval); apply_predicate(set, 0, stack, once); return set; } case ast_func_id: return xpath_node_set_raw(); case ast_step: { switch (_axis) { case axis_ancestor: return step_do(c, stack, eval, axis_to_type()); case axis_ancestor_or_self: return step_do(c, stack, eval, axis_to_type()); case axis_attribute: return step_do(c, stack, eval, axis_to_type()); case axis_child: return step_do(c, stack, eval, axis_to_type()); case axis_descendant: return step_do(c, stack, eval, axis_to_type()); case axis_descendant_or_self: return step_do(c, stack, eval, axis_to_type()); case axis_following: return step_do(c, stack, eval, axis_to_type()); case axis_following_sibling: return step_do(c, stack, eval, axis_to_type()); case axis_namespace: // namespaced axis is not supported return xpath_node_set_raw(); case axis_parent: return step_do(c, stack, eval, axis_to_type()); case axis_preceding: return step_do(c, stack, eval, axis_to_type()); case axis_preceding_sibling: return step_do(c, stack, eval, axis_to_type()); case axis_self: return step_do(c, stack, eval, axis_to_type()); default: assert(false && "Unknown axis"); // unreachable return xpath_node_set_raw(); } } case ast_step_root: { assert(!_right); // root step can't have any predicates xpath_node_set_raw ns; ns.set_type(xpath_node_set::type_sorted); if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); return ns; } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_node_set) { const xpath_node_set& s = _data.variable->get_node_set(); xpath_node_set_raw ns; ns.set_type(s.type()); ns.append(s.begin(), s.end(), stack.result); return ns; } } // fallthrough default: assert(false && "Wrong expression for return type node set"); // unreachable return xpath_node_set_raw(); } } void optimize(xpath_allocator* alloc) { if (_left) _left->optimize(alloc); if (_right) _right->optimize(alloc); if (_next) _next->optimize(alloc); // coverity[var_deref_model] optimize_self(alloc); } void optimize_self(xpath_allocator* alloc) { // Rewrite [position()=expr] with [expr] // Note that this step has to go before classification to recognize [position()=1] if ((_type == ast_filter || _type == ast_predicate) && _right && // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate) _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number) { _right = _right->_right; } // Classify filter/predicate ops to perform various optimizations during evaluation if ((_type == ast_filter || _type == ast_predicate) && _right) // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate) { assert(_test == predicate_default); if (_right->_type == ast_number_constant && _right->_data.number == 1.0) _test = predicate_constant_one; else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last)) _test = predicate_constant; else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr()) _test = predicate_posinv; } // Rewrite descendant-or-self::node()/child::foo with descendant::foo // The former is a full form of //foo, the latter is much faster since it executes the node test immediately // Do a similar kind of rewrite for self/descendant/descendant-or-self axes // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1]) if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) && _left && _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right && is_posinv_step()) { if (_axis == axis_child || _axis == axis_descendant) _axis = axis_descendant; else _axis = axis_descendant_or_self; _left = _left->_left; } // Use optimized lookup table implementation for translate() with constant arguments if (_type == ast_func_translate && _right && // workaround for clang static analyzer (_right is never null for ast_func_translate) _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant) { unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string); if (table) { _type = ast_opt_translate_table; _data.table = table; } } // Use optimized path for @attr = 'value' or @attr = $value if (_type == ast_op_equal && _left && _right && // workaround for clang static analyzer and Coverity (_left and _right are never null for ast_op_equal) // coverity[mixed_enums] _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right && (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string))) { _type = ast_opt_compare_attribute; } } bool is_posinv_expr() const { switch (_type) { case ast_func_position: case ast_func_last: return false; case ast_string_constant: case ast_number_constant: case ast_variable: return true; case ast_step: case ast_step_root: return true; case ast_predicate: case ast_filter: return true; default: if (_left && !_left->is_posinv_expr()) return false; for (xpath_ast_node* n = _right; n; n = n->_next) if (!n->is_posinv_expr()) return false; return true; } } bool is_posinv_step() const { assert(_type == ast_step); for (xpath_ast_node* n = _right; n; n = n->_next) { assert(n->_type == ast_predicate); if (n->_test != predicate_posinv) return false; } return true; } xpath_value_type rettype() const { return static_cast(_rettype); } }; struct xpath_parser { xpath_allocator* _alloc; xpath_lexer _lexer; const char_t* _query; xpath_variable_set* _variables; xpath_parse_result* _result; char_t _scratch[32]; xpath_ast_node* error(const char* message) { _result->error = message; _result->offset = _lexer.current_pos() - _query; return 0; } xpath_ast_node* error_oom() { assert(_alloc->_error); *_alloc->_error = true; return 0; } void* alloc_node() { return _alloc->allocate(sizeof(xpath_ast_node)); } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, const char_t* value) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, double value) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : 0; } xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : 0; } xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test) { void* memory = alloc_node(); return memory ? new (memory) xpath_ast_node(type, left, right, test) : 0; } const char_t* alloc_string(const xpath_lexer_string& value) { if (!value.begin) return PUGIXML_TEXT(""); size_t length = static_cast(value.end - value.begin); char_t* c = static_cast(_alloc->allocate((length + 1) * sizeof(char_t))); if (!c) return 0; memcpy(c, value.begin, length * sizeof(char_t)); c[length] = 0; return c; } xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) { switch (name.begin[0]) { case 'b': if (name == PUGIXML_TEXT("boolean") && argc == 1) return alloc_node(ast_func_boolean, xpath_type_boolean, args[0]); break; case 'c': if (name == PUGIXML_TEXT("count") && argc == 1) { if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(ast_func_count, xpath_type_number, args[0]); } else if (name == PUGIXML_TEXT("contains") && argc == 2) return alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); else if (name == PUGIXML_TEXT("concat") && argc >= 2) return alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("ceiling") && argc == 1) return alloc_node(ast_func_ceiling, xpath_type_number, args[0]); break; case 'f': if (name == PUGIXML_TEXT("false") && argc == 0) return alloc_node(ast_func_false, xpath_type_boolean); else if (name == PUGIXML_TEXT("floor") && argc == 1) return alloc_node(ast_func_floor, xpath_type_number, args[0]); break; case 'i': if (name == PUGIXML_TEXT("id") && argc == 1) return alloc_node(ast_func_id, xpath_type_node_set, args[0]); break; case 'l': if (name == PUGIXML_TEXT("last") && argc == 0) return alloc_node(ast_func_last, xpath_type_number); else if (name == PUGIXML_TEXT("lang") && argc == 1) return alloc_node(ast_func_lang, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("local-name") && argc <= 1) { if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(argc == 0 ? ast_func_local_name_0 : ast_func_local_name_1, xpath_type_string, args[0]); } break; case 'n': if (name == PUGIXML_TEXT("name") && argc <= 1) { if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]); } else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) { if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(argc == 0 ? ast_func_namespace_uri_0 : ast_func_namespace_uri_1, xpath_type_string, args[0]); } else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) return alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("not") && argc == 1) return alloc_node(ast_func_not, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("number") && argc <= 1) return alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); break; case 'p': if (name == PUGIXML_TEXT("position") && argc == 0) return alloc_node(ast_func_position, xpath_type_number); break; case 'r': if (name == PUGIXML_TEXT("round") && argc == 1) return alloc_node(ast_func_round, xpath_type_number, args[0]); break; case 's': if (name == PUGIXML_TEXT("string") && argc <= 1) return alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); else if (name == PUGIXML_TEXT("string-length") && argc <= 1) return alloc_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); else if (name == PUGIXML_TEXT("starts-with") && argc == 2) return alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); else if (name == PUGIXML_TEXT("substring-before") && argc == 2) return alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("substring-after") && argc == 2) return alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) return alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("sum") && argc == 1) { if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set"); return alloc_node(ast_func_sum, xpath_type_number, args[0]); } break; case 't': if (name == PUGIXML_TEXT("translate") && argc == 3) return alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("true") && argc == 0) return alloc_node(ast_func_true, xpath_type_boolean); break; default: break; } return error("Unrecognized function or wrong parameter count"); } axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) { specified = true; switch (name.begin[0]) { case 'a': if (name == PUGIXML_TEXT("ancestor")) return axis_ancestor; else if (name == PUGIXML_TEXT("ancestor-or-self")) return axis_ancestor_or_self; else if (name == PUGIXML_TEXT("attribute")) return axis_attribute; break; case 'c': if (name == PUGIXML_TEXT("child")) return axis_child; break; case 'd': if (name == PUGIXML_TEXT("descendant")) return axis_descendant; else if (name == PUGIXML_TEXT("descendant-or-self")) return axis_descendant_or_self; break; case 'f': if (name == PUGIXML_TEXT("following")) return axis_following; else if (name == PUGIXML_TEXT("following-sibling")) return axis_following_sibling; break; case 'n': if (name == PUGIXML_TEXT("namespace")) return axis_namespace; break; case 'p': if (name == PUGIXML_TEXT("parent")) return axis_parent; else if (name == PUGIXML_TEXT("preceding")) return axis_preceding; else if (name == PUGIXML_TEXT("preceding-sibling")) return axis_preceding_sibling; break; case 's': if (name == PUGIXML_TEXT("self")) return axis_self; break; default: break; } specified = false; return axis_child; } nodetest_t parse_node_test_type(const xpath_lexer_string& name) { switch (name.begin[0]) { case 'c': if (name == PUGIXML_TEXT("comment")) return nodetest_type_comment; break; case 'n': if (name == PUGIXML_TEXT("node")) return nodetest_type_node; break; case 'p': if (name == PUGIXML_TEXT("processing-instruction")) return nodetest_type_pi; break; case 't': if (name == PUGIXML_TEXT("text")) return nodetest_type_text; break; default: break; } return nodetest_none; } // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall xpath_ast_node* parse_primary_expression() { switch (_lexer.current()) { case lex_var_ref: { xpath_lexer_string name = _lexer.contents(); if (!_variables) return error("Unknown variable: variable set is not provided"); xpath_variable* var = 0; if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var)) return error_oom(); if (!var) return error("Unknown variable: variable set does not contain the given name"); _lexer.next(); return alloc_node(ast_variable, var->type(), var); } case lex_open_brace: { _lexer.next(); xpath_ast_node* n = parse_expression(); if (!n) return 0; if (_lexer.current() != lex_close_brace) return error("Expected ')' to match an opening '('"); _lexer.next(); return n; } case lex_quoted_string: { const char_t* value = alloc_string(_lexer.contents()); if (!value) return 0; _lexer.next(); return alloc_node(ast_string_constant, xpath_type_string, value); } case lex_number: { double value = 0; if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value)) return error_oom(); _lexer.next(); return alloc_node(ast_number_constant, xpath_type_number, value); } case lex_string: { xpath_ast_node* args[2] = {0}; size_t argc = 0; xpath_lexer_string function = _lexer.contents(); _lexer.next(); xpath_ast_node* last_arg = 0; if (_lexer.current() != lex_open_brace) return error("Unrecognized function call"); _lexer.next(); while (_lexer.current() != lex_close_brace) { if (argc > 0) { if (_lexer.current() != lex_comma) return error("No comma between function arguments"); _lexer.next(); } xpath_ast_node* n = parse_expression(); if (!n) return 0; if (argc < 2) args[argc] = n; else last_arg->set_next(n); argc++; last_arg = n; } _lexer.next(); return parse_function(function, argc, args); } default: return error("Unrecognizable primary expression"); } } // FilterExpr ::= PrimaryExpr | FilterExpr Predicate // Predicate ::= '[' PredicateExpr ']' // PredicateExpr ::= Expr xpath_ast_node* parse_filter_expression() { xpath_ast_node* n = parse_primary_expression(); if (!n) return 0; while (_lexer.current() == lex_open_square_brace) { _lexer.next(); if (n->rettype() != xpath_type_node_set) return error("Predicate has to be applied to node set"); xpath_ast_node* expr = parse_expression(); if (!expr) return 0; n = alloc_node(ast_filter, n, expr, predicate_default); if (!n) return 0; if (_lexer.current() != lex_close_square_brace) return error("Expected ']' to match an opening '['"); _lexer.next(); } return n; } // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep // AxisSpecifier ::= AxisName '::' | '@'? // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' // NameTest ::= '*' | NCName ':' '*' | QName // AbbreviatedStep ::= '.' | '..' xpath_ast_node* parse_step(xpath_ast_node* set) { if (set && set->rettype() != xpath_type_node_set) return error("Step has to be applied to node set"); bool axis_specified = false; axis_t axis = axis_child; // implied child axis if (_lexer.current() == lex_axis_attribute) { axis = axis_attribute; axis_specified = true; _lexer.next(); } else if (_lexer.current() == lex_dot) { _lexer.next(); if (_lexer.current() == lex_open_square_brace) return error("Predicates are not allowed after an abbreviated step"); return alloc_node(ast_step, set, axis_self, nodetest_type_node, 0); } else if (_lexer.current() == lex_double_dot) { _lexer.next(); if (_lexer.current() == lex_open_square_brace) return error("Predicates are not allowed after an abbreviated step"); return alloc_node(ast_step, set, axis_parent, nodetest_type_node, 0); } nodetest_t nt_type = nodetest_none; xpath_lexer_string nt_name; if (_lexer.current() == lex_string) { // node name test nt_name = _lexer.contents(); _lexer.next(); // was it an axis name? if (_lexer.current() == lex_double_colon) { // parse axis name if (axis_specified) return error("Two axis specifiers in one step"); axis = parse_axis_name(nt_name, axis_specified); if (!axis_specified) return error("Unknown axis"); // read actual node test _lexer.next(); if (_lexer.current() == lex_multiply) { nt_type = nodetest_all; nt_name = xpath_lexer_string(); _lexer.next(); } else if (_lexer.current() == lex_string) { nt_name = _lexer.contents(); _lexer.next(); } else { return error("Unrecognized node test"); } } if (nt_type == nodetest_none) { // node type test or processing-instruction if (_lexer.current() == lex_open_brace) { _lexer.next(); if (_lexer.current() == lex_close_brace) { _lexer.next(); nt_type = parse_node_test_type(nt_name); if (nt_type == nodetest_none) return error("Unrecognized node type"); nt_name = xpath_lexer_string(); } else if (nt_name == PUGIXML_TEXT("processing-instruction")) { if (_lexer.current() != lex_quoted_string) return error("Only literals are allowed as arguments to processing-instruction()"); nt_type = nodetest_pi; nt_name = _lexer.contents(); _lexer.next(); if (_lexer.current() != lex_close_brace) return error("Unmatched brace near processing-instruction()"); _lexer.next(); } else { return error("Unmatched brace near node type test"); } } // QName or NCName:* else { if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* { nt_name.end--; // erase * nt_type = nodetest_all_in_namespace; } else { nt_type = nodetest_name; } } } } else if (_lexer.current() == lex_multiply) { nt_type = nodetest_all; _lexer.next(); } else { return error("Unrecognized node test"); } const char_t* nt_name_copy = alloc_string(nt_name); if (!nt_name_copy) return 0; xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy); if (!n) return 0; xpath_ast_node* last = 0; while (_lexer.current() == lex_open_square_brace) { _lexer.next(); xpath_ast_node* expr = parse_expression(); if (!expr) return 0; xpath_ast_node* pred = alloc_node(ast_predicate, 0, expr, predicate_default); if (!pred) return 0; if (_lexer.current() != lex_close_square_brace) return error("Expected ']' to match an opening '['"); _lexer.next(); if (last) last->set_next(pred); else n->set_right(pred); last = pred; } return n; } // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) { xpath_ast_node* n = parse_step(set); if (!n) return 0; while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); if (l == lex_double_slash) { n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); if (!n) return 0; } n = parse_step(n); if (!n) return 0; } return n; } // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath xpath_ast_node* parse_location_path() { if (_lexer.current() == lex_slash) { _lexer.next(); xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); if (!n) return 0; // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path lexeme_t l = _lexer.current(); if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) return parse_relative_location_path(n); else return n; } else if (_lexer.current() == lex_double_slash) { _lexer.next(); xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); if (!n) return 0; n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); if (!n) return 0; return parse_relative_location_path(n); } // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 return parse_relative_location_path(0); } // PathExpr ::= LocationPath // | FilterExpr // | FilterExpr '/' RelativeLocationPath // | FilterExpr '//' RelativeLocationPath // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr // UnaryExpr ::= UnionExpr | '-' UnaryExpr xpath_ast_node* parse_path_or_unary_expression() { // Clarification. // PathExpr begins with either LocationPath or FilterExpr. // FilterExpr begins with PrimaryExpr // PrimaryExpr begins with '$' in case of it being a variable reference, // '(' in case of it being an expression, string literal, number constant or // function call. if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || _lexer.current() == lex_string) { if (_lexer.current() == lex_string) { // This is either a function call, or not - if not, we shall proceed with location path const char_t* state = _lexer.state(); while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; if (*state != '(') return parse_location_path(); // This looks like a function call; however this still can be a node-test. Check it. if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); } xpath_ast_node* n = parse_filter_expression(); if (!n) return 0; if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); if (l == lex_double_slash) { if (n->rettype() != xpath_type_node_set) return error("Step has to be applied to node set"); n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); if (!n) return 0; } // select from location path return parse_relative_location_path(n); } return n; } else if (_lexer.current() == lex_minus) { _lexer.next(); // precedence 7+ - only parses union expressions xpath_ast_node* n = parse_expression(7); if (!n) return 0; return alloc_node(ast_op_negate, xpath_type_number, n); } else { return parse_location_path(); } } struct binary_op_t { ast_type_t asttype; xpath_value_type rettype; int precedence; binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0) { } binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_) { } static binary_op_t parse(xpath_lexer& lexer) { switch (lexer.current()) { case lex_string: if (lexer.contents() == PUGIXML_TEXT("or")) return binary_op_t(ast_op_or, xpath_type_boolean, 1); else if (lexer.contents() == PUGIXML_TEXT("and")) return binary_op_t(ast_op_and, xpath_type_boolean, 2); else if (lexer.contents() == PUGIXML_TEXT("div")) return binary_op_t(ast_op_divide, xpath_type_number, 6); else if (lexer.contents() == PUGIXML_TEXT("mod")) return binary_op_t(ast_op_mod, xpath_type_number, 6); else return binary_op_t(); case lex_equal: return binary_op_t(ast_op_equal, xpath_type_boolean, 3); case lex_not_equal: return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3); case lex_less: return binary_op_t(ast_op_less, xpath_type_boolean, 4); case lex_greater: return binary_op_t(ast_op_greater, xpath_type_boolean, 4); case lex_less_or_equal: return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4); case lex_greater_or_equal: return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4); case lex_plus: return binary_op_t(ast_op_add, xpath_type_number, 5); case lex_minus: return binary_op_t(ast_op_subtract, xpath_type_number, 5); case lex_multiply: return binary_op_t(ast_op_multiply, xpath_type_number, 6); case lex_union: return binary_op_t(ast_op_union, xpath_type_node_set, 7); default: return binary_op_t(); } } }; xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit) { binary_op_t op = binary_op_t::parse(_lexer); while (op.asttype != ast_unknown && op.precedence >= limit) { _lexer.next(); xpath_ast_node* rhs = parse_path_or_unary_expression(); if (!rhs) return 0; binary_op_t nextop = binary_op_t::parse(_lexer); while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence) { rhs = parse_expression_rec(rhs, nextop.precedence); if (!rhs) return 0; nextop = binary_op_t::parse(_lexer); } if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set)) return error("Union operator has to be applied to node sets"); lhs = alloc_node(op.asttype, op.rettype, lhs, rhs); if (!lhs) return 0; op = binary_op_t::parse(_lexer); } return lhs; } // Expr ::= OrExpr // OrExpr ::= AndExpr | OrExpr 'or' AndExpr // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr // EqualityExpr ::= RelationalExpr // | EqualityExpr '=' RelationalExpr // | EqualityExpr '!=' RelationalExpr // RelationalExpr ::= AdditiveExpr // | RelationalExpr '<' AdditiveExpr // | RelationalExpr '>' AdditiveExpr // | RelationalExpr '<=' AdditiveExpr // | RelationalExpr '>=' AdditiveExpr // AdditiveExpr ::= MultiplicativeExpr // | AdditiveExpr '+' MultiplicativeExpr // | AdditiveExpr '-' MultiplicativeExpr // MultiplicativeExpr ::= UnaryExpr // | MultiplicativeExpr '*' UnaryExpr // | MultiplicativeExpr 'div' UnaryExpr // | MultiplicativeExpr 'mod' UnaryExpr xpath_ast_node* parse_expression(int limit = 0) { xpath_ast_node* n = parse_path_or_unary_expression(); if (!n) return 0; return parse_expression_rec(n, limit); } xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) { } xpath_ast_node* parse() { xpath_ast_node* n = parse_expression(); if (!n) return 0; // check if there are unparsed tokens left if (_lexer.current() != lex_eof) return error("Incorrect query"); return n; } static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) { xpath_parser parser(query, variables, alloc, result); return parser.parse(); } }; struct xpath_query_impl { static xpath_query_impl* create() { void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); if (!memory) return 0; return new (memory) xpath_query_impl(); } static void destroy(xpath_query_impl* impl) { // free all allocated pages impl->alloc.release(); // free allocator memory (with the first page) xml_memory::deallocate(impl); } xpath_query_impl(): root(0), alloc(&block, &oom), oom(false) { block.next = 0; block.capacity = sizeof(block.data); } xpath_ast_node* root; xpath_allocator alloc; xpath_memory_block block; bool oom; }; PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) { if (!impl) return 0; if (impl->root->rettype() != xpath_type_node_set) { #ifdef PUGIXML_NO_EXCEPTIONS return 0; #else xpath_parse_result res; res.error = "Expression does not evaluate to node set"; throw xpath_exception(res); #endif } return impl->root; } PUGI__NS_END namespace pugi { #ifndef PUGIXML_NO_EXCEPTIONS PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) { assert(_result.error); } PUGI__FN const char* xpath_exception::what() const throw() { return _result.error; } PUGI__FN const xpath_parse_result& xpath_exception::result() const { return _result; } #endif PUGI__FN xpath_node::xpath_node() { } PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) { } PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) { } PUGI__FN xml_node xpath_node::node() const { return _attribute ? xml_node() : _node; } PUGI__FN xml_attribute xpath_node::attribute() const { return _attribute; } PUGI__FN xml_node xpath_node::parent() const { return _attribute ? _node : _node.parent(); } PUGI__FN static void unspecified_bool_xpath_node(xpath_node***) { } PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const { return (_node || _attribute) ? unspecified_bool_xpath_node : 0; } PUGI__FN bool xpath_node::operator!() const { return !(_node || _attribute); } PUGI__FN bool xpath_node::operator==(const xpath_node& n) const { return _node == n._node && _attribute == n._attribute; } PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const { return _node != n._node || _attribute != n._attribute; } #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xpath_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_) { assert(begin_ <= end_); size_t size_ = static_cast(end_ - begin_); // use internal buffer for 0 or 1 elements, heap buffer otherwise xpath_node* storage = (size_ <= 1) ? _storage : static_cast(impl::xml_memory::allocate(size_ * sizeof(xpath_node))); if (!storage) { #ifdef PUGIXML_NO_EXCEPTIONS return; #else throw std::bad_alloc(); #endif } // deallocate old buffer if (_begin != _storage) impl::xml_memory::deallocate(_begin); // size check is necessary because for begin_ = end_ = nullptr, memcpy is UB if (size_) memcpy(storage, begin_, size_ * sizeof(xpath_node)); _begin = storage; _end = storage + size_; _type = type_; } #ifdef PUGIXML_HAS_MOVE PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT { _type = rhs._type; _storage[0] = rhs._storage[0]; _begin = (rhs._begin == rhs._storage) ? _storage : rhs._begin; _end = _begin + (rhs._end - rhs._begin); rhs._type = type_unsorted; rhs._begin = rhs._storage; rhs._end = rhs._storage; } #endif PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage) { } PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage) { _assign(begin_, end_, type_); } PUGI__FN xpath_node_set::~xpath_node_set() { if (_begin != _storage) impl::xml_memory::deallocate(_begin); } PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage) { _assign(ns._begin, ns._end, ns._type); } PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) { if (this == &ns) return *this; _assign(ns._begin, ns._end, ns._type); return *this; } #ifdef PUGIXML_HAS_MOVE PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage) { _move(rhs); } PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; if (_begin != _storage) impl::xml_memory::deallocate(_begin); _move(rhs); return *this; } #endif PUGI__FN xpath_node_set::type_t xpath_node_set::type() const { return _type; } PUGI__FN size_t xpath_node_set::size() const { return _end - _begin; } PUGI__FN bool xpath_node_set::empty() const { return _begin == _end; } PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const { assert(index < size()); return _begin[index]; } PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const { return _begin; } PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const { return _end; } PUGI__FN void xpath_node_set::sort(bool reverse) { _type = impl::xpath_sort(_begin, _end, _type, reverse); } PUGI__FN xpath_node xpath_node_set::first() const { return impl::xpath_first(_begin, _end, _type); } PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) { } PUGI__FN xpath_parse_result::operator bool() const { return error == 0; } PUGI__FN const char* xpath_parse_result::description() const { return error ? error : "No error"; } PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0) { } PUGI__FN const char_t* xpath_variable::name() const { switch (_type) { case xpath_type_node_set: return static_cast(this)->name; case xpath_type_number: return static_cast(this)->name; case xpath_type_string: return static_cast(this)->name; case xpath_type_boolean: return static_cast(this)->name; default: assert(false && "Invalid variable type"); // unreachable return 0; } } PUGI__FN xpath_value_type xpath_variable::type() const { return _type; } PUGI__FN bool xpath_variable::get_boolean() const { return (_type == xpath_type_boolean) ? static_cast(this)->value : false; } PUGI__FN double xpath_variable::get_number() const { return (_type == xpath_type_number) ? static_cast(this)->value : impl::gen_nan(); } PUGI__FN const char_t* xpath_variable::get_string() const { const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; return value ? value : PUGIXML_TEXT(""); } PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const { return (_type == xpath_type_node_set) ? static_cast(this)->value : impl::dummy_node_set; } PUGI__FN bool xpath_variable::set(bool value) { if (_type != xpath_type_boolean) return false; static_cast(this)->value = value; return true; } PUGI__FN bool xpath_variable::set(double value) { if (_type != xpath_type_number) return false; static_cast(this)->value = value; return true; } PUGI__FN bool xpath_variable::set(const char_t* value) { if (_type != xpath_type_string) return false; impl::xpath_variable_string* var = static_cast(this); // duplicate string size_t size = (impl::strlength(value) + 1) * sizeof(char_t); char_t* copy = static_cast(impl::xml_memory::allocate(size)); if (!copy) return false; memcpy(copy, value, size); // replace old string if (var->value) impl::xml_memory::deallocate(var->value); var->value = copy; return true; } PUGI__FN bool xpath_variable::set(const xpath_node_set& value) { if (_type != xpath_type_node_set) return false; static_cast(this)->value = value; return true; } PUGI__FN xpath_variable_set::xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; } PUGI__FN xpath_variable_set::~xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _destroy(_data[i]); } PUGI__FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs) { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; _assign(rhs); } PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs) { if (this == &rhs) return *this; _assign(rhs); return *this; } #ifdef PUGIXML_HAS_MOVE PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { _data[i] = rhs._data[i]; rhs._data[i] = 0; } } PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { _destroy(_data[i]); _data[i] = rhs._data[i]; rhs._data[i] = 0; } return *this; } #endif PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs) { xpath_variable_set temp; for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i])) return; _swap(temp); } PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs) { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { xpath_variable* chain = _data[i]; _data[i] = rhs._data[i]; rhs._data[i] = chain; } } PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; // look for existing variable for (xpath_variable* var = _data[hash]; var; var = var->_next) if (impl::strequal(var->name(), name)) return var; return 0; } PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result) { xpath_variable* last = 0; while (var) { // allocate storage for new variable xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name()); if (!nvar) return false; // link the variable to the result immediately to handle failures gracefully if (last) last->_next = nvar; else *out_result = nvar; last = nvar; // copy the value; this can fail due to out-of-memory conditions if (!impl::copy_xpath_variable(nvar, var)) return false; var = var->_next; } return true; } PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var) { while (var) { xpath_variable* next = var->_next; impl::delete_xpath_variable(var->_type, var); var = next; } } PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; // look for existing variable for (xpath_variable* var = _data[hash]; var; var = var->_next) if (impl::strequal(var->name(), name)) return var->type() == type ? var : 0; // add new variable xpath_variable* result = impl::new_xpath_variable(type, name); if (result) { result->_next = _data[hash]; _data[hash] = result; } return result; } PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value) { xpath_variable* var = add(name, xpath_type_boolean); return var ? var->set(value) : false; } PUGI__FN bool xpath_variable_set::set(const char_t* name, double value) { xpath_variable* var = add(name, xpath_type_number); return var ? var->set(value) : false; } PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value) { xpath_variable* var = add(name, xpath_type_string); return var ? var->set(value) : false; } PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) { xpath_variable* var = add(name, xpath_type_node_set); return var ? var->set(value) : false; } PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name) { return _find(name); } PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const { return _find(name); } PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) { impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); if (!qimpl) { #ifdef PUGIXML_NO_EXCEPTIONS _result.error = "Out of memory"; #else throw std::bad_alloc(); #endif } else { using impl::auto_deleter; // MSVC7 workaround auto_deleter impl(qimpl, impl::xpath_query_impl::destroy); qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result); if (qimpl->root) { qimpl->root->optimize(&qimpl->alloc); _impl = impl.release(); _result.error = 0; } else { #ifdef PUGIXML_NO_EXCEPTIONS if (qimpl->oom) _result.error = "Out of memory"; #else if (qimpl->oom) throw std::bad_alloc(); throw xpath_exception(_result); #endif } } } PUGI__FN xpath_query::xpath_query(): _impl(0) { } PUGI__FN xpath_query::~xpath_query() { if (_impl) impl::xpath_query_impl::destroy(static_cast(_impl)); } #ifdef PUGIXML_HAS_MOVE PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT { _impl = rhs._impl; _result = rhs._result; rhs._impl = 0; rhs._result = xpath_parse_result(); } PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; if (_impl) impl::xpath_query_impl::destroy(static_cast(_impl)); _impl = rhs._impl; _result = rhs._result; rhs._impl = 0; rhs._result = xpath_parse_result(); return *this; } #endif PUGI__FN xpath_value_type xpath_query::return_type() const { if (!_impl) return xpath_type_none; return static_cast(_impl)->root->rettype(); } PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const { if (!_impl) return false; impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; bool r = static_cast(_impl)->root->eval_boolean(c, sd.stack); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return false; #else throw std::bad_alloc(); #endif } return r; } PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const { if (!_impl) return impl::gen_nan(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; double r = static_cast(_impl)->root->eval_number(c, sd.stack); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return impl::gen_nan(); #else throw std::bad_alloc(); #endif } return r; } #ifndef PUGIXML_NO_STL PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const { if (!_impl) return string_t(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_string r = static_cast(_impl)->root->eval_string(c, sd.stack); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return string_t(); #else throw std::bad_alloc(); #endif } return string_t(r.c_str(), r.length()); } #endif PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const { impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_string r = _impl ? static_cast(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string(); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS r = impl::xpath_string(); #else throw std::bad_alloc(); #endif } size_t full_size = r.length() + 1; if (capacity > 0) { size_t size = (full_size < capacity) ? full_size : capacity; assert(size > 0); memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); buffer[size - 1] = 0; } return full_size; } PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node_set(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return xpath_node_set(); #else throw std::bad_alloc(); #endif } return xpath_node_set(r.begin(), r.end(), r.type()); } PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first); if (sd.oom) { #ifdef PUGIXML_NO_EXCEPTIONS return xpath_node(); #else throw std::bad_alloc(); #endif } return r.first(); } PUGI__FN const xpath_parse_result& xpath_query::result() const { return _result; } PUGI__FN static void unspecified_bool_xpath_query(xpath_query***) { } PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const { return _impl ? unspecified_bool_xpath_query : 0; } PUGI__FN bool xpath_query::operator!() const { return !_impl; } PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node(*this); } PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const { return query.evaluate_node(*this); } PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node_set(*this); } PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const { return query.evaluate_node_set(*this); } PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node(*this); } PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const { return query.evaluate_node(*this); } } #endif #ifdef __BORLANDC__ # pragma option pop #endif // Intel C++ does not properly keep warning state for function templates, // so popping warning state at the end of translation unit leads to warnings in the middle. #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # pragma warning(pop) #endif #if defined(_MSC_VER) && defined(__c2__) # pragma clang diagnostic pop #endif // Undefine all local macros (makes sure we're not leaking macros in header-only mode) #undef PUGI__NO_INLINE #undef PUGI__UNLIKELY #undef PUGI__STATIC_ASSERT #undef PUGI__DMC_VOLATILE #undef PUGI__UNSIGNED_OVERFLOW #undef PUGI__MSVC_CRT_VERSION #undef PUGI__SNPRINTF #undef PUGI__NS_BEGIN #undef PUGI__NS_END #undef PUGI__FN #undef PUGI__FN_NO_INLINE #undef PUGI__GETHEADER_IMPL #undef PUGI__GETPAGE_IMPL #undef PUGI__GETPAGE #undef PUGI__NODETYPE #undef PUGI__IS_CHARTYPE_IMPL #undef PUGI__IS_CHARTYPE #undef PUGI__IS_CHARTYPEX #undef PUGI__ENDSWITH #undef PUGI__SKIPWS #undef PUGI__OPTSET #undef PUGI__PUSHNODE #undef PUGI__POPNODE #undef PUGI__SCANFOR #undef PUGI__SCANWHILE #undef PUGI__SCANWHILE_UNROLL #undef PUGI__ENDSEG #undef PUGI__THROW_ERROR #undef PUGI__CHECK_ERROR #endif /** * Copyright (c) 2006-2019 Arseny Kapoulkine * * 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. */ poedit-2.3/deps/json/0000775000372000037200000000000013616053245011554 500000000000000poedit-2.3/deps/json/LICENSE.MIT0000664000372000037200000000206413616053214013127 00000000000000MIT License Copyright (c) 2013-2019 Niels Lohmann 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. poedit-2.3/deps/json/single_include/0000775000372000037200000000000013616053245014540 500000000000000poedit-2.3/deps/json/single_include/nlohmann/0000775000372000037200000000000013616053245016352 500000000000000poedit-2.3/deps/json/single_include/nlohmann/json.hpp0000664000372000037200000305502113616053214017756 00000000000000/* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ | | |__ | | | | | | version 3.7.3 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . SPDX-License-Identifier: MIT Copyright (c) 2013-2019 Niels Lohmann . 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 INCLUDE_NLOHMANN_JSON_HPP_ #define INCLUDE_NLOHMANN_JSON_HPP_ #define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MINOR 7 #define NLOHMANN_JSON_VERSION_PATCH 3 #include // all_of, find, for_each #include // assert #include // and, not, or #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list #include // istream, ostream #include // random_access_iterator_tag #include // unique_ptr #include // accumulate #include // string, stoi, to_string #include // declval, forward, move, pair, swap #include // vector // #include #include // #include #include // transform #include // array #include // and, not #include // forward_list #include // inserter, front_inserter, end #include // map #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible #include // unordered_map #include // pair, declval #include // valarray // #include #include // exception #include // runtime_error #include // to_string // #include #include // size_t namespace nlohmann { namespace detail { /// struct to capture the start position of the current token struct position_t { /// the total number of characters read std::size_t chars_read_total = 0; /// the number of characters read in the current line std::size_t chars_read_current_line = 0; /// the number of lines read std::size_t lines_read = 0; /// conversion to size_t to preserve SAX interface constexpr operator size_t() const { return chars_read_total; } }; } // namespace detail } // namespace nlohmann // #include #include // pair // #include /* Hedley - https://nemequ.github.io/hedley * Created by Evan Nemerson * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to * the public domain worldwide. This software is distributed without * any warranty. * * For details, see . * SPDX-License-Identifier: CC0-1.0 */ #if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) #if defined(JSON_HEDLEY_VERSION) #undef JSON_HEDLEY_VERSION #endif #define JSON_HEDLEY_VERSION 11 #if defined(JSON_HEDLEY_STRINGIFY_EX) #undef JSON_HEDLEY_STRINGIFY_EX #endif #define JSON_HEDLEY_STRINGIFY_EX(x) #x #if defined(JSON_HEDLEY_STRINGIFY) #undef JSON_HEDLEY_STRINGIFY #endif #define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) #if defined(JSON_HEDLEY_CONCAT_EX) #undef JSON_HEDLEY_CONCAT_EX #endif #define JSON_HEDLEY_CONCAT_EX(a,b) a##b #if defined(JSON_HEDLEY_CONCAT) #undef JSON_HEDLEY_CONCAT #endif #define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) #if defined(JSON_HEDLEY_VERSION_ENCODE) #undef JSON_HEDLEY_VERSION_ENCODE #endif #define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) #if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) #undef JSON_HEDLEY_VERSION_DECODE_MAJOR #endif #define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) #if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) #undef JSON_HEDLEY_VERSION_DECODE_MINOR #endif #define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) #if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) #undef JSON_HEDLEY_VERSION_DECODE_REVISION #endif #define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) #if defined(JSON_HEDLEY_GNUC_VERSION) #undef JSON_HEDLEY_GNUC_VERSION #endif #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #elif defined(__GNUC__) #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) #endif #if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) #undef JSON_HEDLEY_GNUC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_GNUC_VERSION) #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_MSVC_VERSION) #undef JSON_HEDLEY_MSVC_VERSION #endif #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) #elif defined(_MSC_FULL_VER) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) #elif defined(_MSC_VER) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) #endif #if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) #undef JSON_HEDLEY_MSVC_VERSION_CHECK #endif #if !defined(_MSC_VER) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) #elif defined(_MSC_VER) && (_MSC_VER >= 1400) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) #elif defined(_MSC_VER) && (_MSC_VER >= 1200) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) #else #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) #endif #if defined(JSON_HEDLEY_INTEL_VERSION) #undef JSON_HEDLEY_INTEL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) #elif defined(__INTEL_COMPILER) #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif #if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) #undef JSON_HEDLEY_INTEL_VERSION_CHECK #endif #if defined(JSON_HEDLEY_INTEL_VERSION) #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_PGI_VERSION) #undef JSON_HEDLEY_PGI_VERSION #endif #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) #endif #if defined(JSON_HEDLEY_PGI_VERSION_CHECK) #undef JSON_HEDLEY_PGI_VERSION_CHECK #endif #if defined(JSON_HEDLEY_PGI_VERSION) #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION) #undef JSON_HEDLEY_SUNPRO_VERSION #endif #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) #elif defined(__SUNPRO_C) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) #elif defined(__SUNPRO_CC) #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION) #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) #undef JSON_HEDLEY_EMSCRIPTEN_VERSION #endif #if defined(__EMSCRIPTEN__) #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_ARM_VERSION) #undef JSON_HEDLEY_ARM_VERSION #endif #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) #endif #if defined(JSON_HEDLEY_ARM_VERSION_CHECK) #undef JSON_HEDLEY_ARM_VERSION_CHECK #endif #if defined(JSON_HEDLEY_ARM_VERSION) #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_IBM_VERSION) #undef JSON_HEDLEY_IBM_VERSION #endif #if defined(__ibmxl__) #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) #elif defined(__xlC__) && defined(__xlC_ver__) #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) #elif defined(__xlC__) #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) #endif #if defined(JSON_HEDLEY_IBM_VERSION_CHECK) #undef JSON_HEDLEY_IBM_VERSION_CHECK #endif #if defined(JSON_HEDLEY_IBM_VERSION) #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TI_VERSION) #undef JSON_HEDLEY_TI_VERSION #endif #if defined(__TI_COMPILER_VERSION__) #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_VERSION_CHECK) #undef JSON_HEDLEY_TI_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_VERSION) #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_CRAY_VERSION) #undef JSON_HEDLEY_CRAY_VERSION #endif #if defined(_CRAYC) #if defined(_RELEASE_PATCHLEVEL) #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) #else #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) #endif #endif #if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) #undef JSON_HEDLEY_CRAY_VERSION_CHECK #endif #if defined(JSON_HEDLEY_CRAY_VERSION) #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_IAR_VERSION) #undef JSON_HEDLEY_IAR_VERSION #endif #if defined(__IAR_SYSTEMS_ICC__) #if __VER__ > 1000 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) #else #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) #endif #endif #if defined(JSON_HEDLEY_IAR_VERSION_CHECK) #undef JSON_HEDLEY_IAR_VERSION_CHECK #endif #if defined(JSON_HEDLEY_IAR_VERSION) #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_TINYC_VERSION) #undef JSON_HEDLEY_TINYC_VERSION #endif #if defined(__TINYC__) #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) #endif #if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) #undef JSON_HEDLEY_TINYC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TINYC_VERSION) #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_DMC_VERSION) #undef JSON_HEDLEY_DMC_VERSION #endif #if defined(__DMC__) #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) #endif #if defined(JSON_HEDLEY_DMC_VERSION_CHECK) #undef JSON_HEDLEY_DMC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_DMC_VERSION) #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION) #undef JSON_HEDLEY_COMPCERT_VERSION #endif #if defined(__COMPCERT_VERSION__) #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION) #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_PELLES_VERSION) #undef JSON_HEDLEY_PELLES_VERSION #endif #if defined(__POCC__) #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) #endif #if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) #undef JSON_HEDLEY_PELLES_VERSION_CHECK #endif #if defined(JSON_HEDLEY_PELLES_VERSION) #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_GCC_VERSION) #undef JSON_HEDLEY_GCC_VERSION #endif #if \ defined(JSON_HEDLEY_GNUC_VERSION) && \ !defined(__clang__) && \ !defined(JSON_HEDLEY_INTEL_VERSION) && \ !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_ARM_VERSION) && \ !defined(JSON_HEDLEY_TI_VERSION) && \ !defined(__COMPCERT__) #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION #endif #if defined(JSON_HEDLEY_GCC_VERSION_CHECK) #undef JSON_HEDLEY_GCC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_GCC_VERSION) #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) #endif #if defined(JSON_HEDLEY_HAS_ATTRIBUTE) #undef JSON_HEDLEY_HAS_ATTRIBUTE #endif #if defined(__has_attribute) #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) #else #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) #else #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) #else #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE #endif #if \ defined(__has_cpp_attribute) && \ defined(__cplusplus) && \ (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS #endif #if !defined(__cplusplus) || !defined(__has_cpp_attribute) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) #elif \ !defined(JSON_HEDLEY_PGI_VERSION) && \ (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) #else #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) #else #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) #else #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_BUILTIN) #undef JSON_HEDLEY_HAS_BUILTIN #endif #if defined(__has_builtin) #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) #else #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) #undef JSON_HEDLEY_GNUC_HAS_BUILTIN #endif #if defined(__has_builtin) #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) #else #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) #undef JSON_HEDLEY_GCC_HAS_BUILTIN #endif #if defined(__has_builtin) #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) #else #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_FEATURE) #undef JSON_HEDLEY_HAS_FEATURE #endif #if defined(__has_feature) #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) #else #define JSON_HEDLEY_HAS_FEATURE(feature) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) #undef JSON_HEDLEY_GNUC_HAS_FEATURE #endif #if defined(__has_feature) #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) #else #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_FEATURE) #undef JSON_HEDLEY_GCC_HAS_FEATURE #endif #if defined(__has_feature) #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) #else #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_EXTENSION) #undef JSON_HEDLEY_HAS_EXTENSION #endif #if defined(__has_extension) #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) #else #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) #undef JSON_HEDLEY_GNUC_HAS_EXTENSION #endif #if defined(__has_extension) #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) #else #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) #undef JSON_HEDLEY_GCC_HAS_EXTENSION #endif #if defined(__has_extension) #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) #else #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) #else #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) #else #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) #else #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_HAS_WARNING) #undef JSON_HEDLEY_HAS_WARNING #endif #if defined(__has_warning) #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) #else #define JSON_HEDLEY_HAS_WARNING(warning) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_WARNING) #undef JSON_HEDLEY_GNUC_HAS_WARNING #endif #if defined(__has_warning) #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) #else #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_WARNING) #undef JSON_HEDLEY_GCC_HAS_WARNING #endif #if defined(__has_warning) #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) #else #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif /* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #endif #if defined(__cplusplus) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ xpr \ JSON_HEDLEY_DIAGNOSTIC_POP #else # define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x #endif #if \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ defined(__clang__) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_PRAGMA(value) __pragma(value) #else #define JSON_HEDLEY_PRAGMA(value) #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) #undef JSON_HEDLEY_DIAGNOSTIC_PUSH #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_POP) #undef JSON_HEDLEY_DIAGNOSTIC_POP #endif #if defined(__clang__) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) #elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") #elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") #else #define JSON_HEDLEY_DIAGNOSTIC_PUSH #define JSON_HEDLEY_DIAGNOSTIC_POP #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) #elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) #elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") #elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") #elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if defined(JSON_HEDLEY_DEPRECATED) #undef JSON_HEDLEY_DEPRECATED #endif #if defined(JSON_HEDLEY_DEPRECATED_FOR) #undef JSON_HEDLEY_DEPRECATED_FOR #endif #if defined(__cplusplus) && (__cplusplus >= 201402L) #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) #elif \ JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,3,0) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") #else #define JSON_HEDLEY_DEPRECATED(since) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) #endif #if defined(JSON_HEDLEY_UNAVAILABLE) #undef JSON_HEDLEY_UNAVAILABLE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) #else #define JSON_HEDLEY_UNAVAILABLE(available_since) #endif #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) #undef JSON_HEDLEY_WARN_UNUSED_RESULT #endif #if defined(__cplusplus) && (__cplusplus >= 201703L) #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) #elif defined(_Check_return_) /* SAL */ #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ #else #define JSON_HEDLEY_WARN_UNUSED_RESULT #endif #if defined(JSON_HEDLEY_SENTINEL) #undef JSON_HEDLEY_SENTINEL #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) #else #define JSON_HEDLEY_SENTINEL(position) #endif #if defined(JSON_HEDLEY_NO_RETURN) #undef JSON_HEDLEY_NO_RETURN #endif #if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_NO_RETURN __noreturn #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define JSON_HEDLEY_NO_RETURN _Noreturn #elif defined(__cplusplus) && (__cplusplus >= 201103L) #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) #else #define JSON_HEDLEY_NO_RETURN #endif #if defined(JSON_HEDLEY_NO_ESCAPE) #undef JSON_HEDLEY_NO_ESCAPE #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) #else #define JSON_HEDLEY_NO_ESCAPE #endif #if defined(JSON_HEDLEY_UNREACHABLE) #undef JSON_HEDLEY_UNREACHABLE #endif #if defined(JSON_HEDLEY_UNREACHABLE_RETURN) #undef JSON_HEDLEY_UNREACHABLE_RETURN #endif #if \ (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) #define JSON_HEDLEY_UNREACHABLE() __assume(0) #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) #if defined(__cplusplus) #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) #else #define JSON_HEDLEY_UNREACHABLE() _nassert(0) #endif #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value #elif defined(EXIT_FAILURE) #define JSON_HEDLEY_UNREACHABLE() abort() #else #define JSON_HEDLEY_UNREACHABLE() #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value #endif #if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() #endif #if defined(JSON_HEDLEY_ASSUME) #undef JSON_HEDLEY_ASSUME #endif #if \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_ASSUME(expr) __assume(expr) #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) #if defined(__cplusplus) #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) #else #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) #endif #elif \ (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) #else #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) #endif JSON_HEDLEY_DIAGNOSTIC_PUSH #if JSON_HEDLEY_HAS_WARNING("-Wpedantic") #pragma clang diagnostic ignored "-Wpedantic" #endif #if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" #endif #if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) #if defined(__clang__) #pragma clang diagnostic ignored "-Wvariadic-macros" #elif defined(JSON_HEDLEY_GCC_VERSION) #pragma GCC diagnostic ignored "-Wvariadic-macros" #endif #endif #if defined(JSON_HEDLEY_NON_NULL) #undef JSON_HEDLEY_NON_NULL #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #else #define JSON_HEDLEY_NON_NULL(...) #endif JSON_HEDLEY_DIAGNOSTIC_POP #if defined(JSON_HEDLEY_PRINTF_FORMAT) #undef JSON_HEDLEY_PRINTF_FORMAT #endif #if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) #elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) #else #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) #endif #if defined(JSON_HEDLEY_CONSTEXPR) #undef JSON_HEDLEY_CONSTEXPR #endif #if defined(__cplusplus) #if __cplusplus >= 201103L #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) #endif #endif #if !defined(JSON_HEDLEY_CONSTEXPR) #define JSON_HEDLEY_CONSTEXPR #endif #if defined(JSON_HEDLEY_PREDICT) #undef JSON_HEDLEY_PREDICT #endif #if defined(JSON_HEDLEY_LIKELY) #undef JSON_HEDLEY_LIKELY #endif #if defined(JSON_HEDLEY_UNLIKELY) #undef JSON_HEDLEY_UNLIKELY #endif #if defined(JSON_HEDLEY_UNPREDICTABLE) #undef JSON_HEDLEY_UNPREDICTABLE #endif #if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) #endif #if \ JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) # define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) #endif #elif \ JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) # define JSON_HEDLEY_PREDICT(expr, expected, probability) \ (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ (__extension__ ({ \ JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ })) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ (__extension__ ({ \ JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ })) # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else # define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) # define JSON_HEDLEY_LIKELY(expr) (!!(expr)) # define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) #endif #if !defined(JSON_HEDLEY_UNPREDICTABLE) #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) #endif #if defined(JSON_HEDLEY_MALLOC) #undef JSON_HEDLEY_MALLOC #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) #define JSON_HEDLEY_MALLOC __declspec(restrict) #else #define JSON_HEDLEY_MALLOC #endif #if defined(JSON_HEDLEY_PURE) #undef JSON_HEDLEY_PURE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_PURE __attribute__((__pure__)) #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else #define JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_CONST) #undef JSON_HEDLEY_CONST #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) #define JSON_HEDLEY_CONST __attribute__((__const__)) #elif \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) #define JSON_HEDLEY_CONST _Pragma("no_side_effect") #else #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_RESTRICT) #undef JSON_HEDLEY_RESTRICT #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) #define JSON_HEDLEY_RESTRICT restrict #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ defined(__clang__) #define JSON_HEDLEY_RESTRICT __restrict #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) #define JSON_HEDLEY_RESTRICT _Restrict #else #define JSON_HEDLEY_RESTRICT #endif #if defined(JSON_HEDLEY_INLINE) #undef JSON_HEDLEY_INLINE #endif #if \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ (defined(__cplusplus) && (__cplusplus >= 199711L)) #define JSON_HEDLEY_INLINE inline #elif \ defined(JSON_HEDLEY_GCC_VERSION) || \ JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) #define JSON_HEDLEY_INLINE __inline__ #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_INLINE __inline #else #define JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_ALWAYS_INLINE) #undef JSON_HEDLEY_ALWAYS_INLINE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE #elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) #define JSON_HEDLEY_ALWAYS_INLINE __forceinline #elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_NEVER_INLINE) #undef JSON_HEDLEY_NEVER_INLINE #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #else #define JSON_HEDLEY_NEVER_INLINE #endif #if defined(JSON_HEDLEY_PRIVATE) #undef JSON_HEDLEY_PRIVATE #endif #if defined(JSON_HEDLEY_PUBLIC) #undef JSON_HEDLEY_PUBLIC #endif #if defined(JSON_HEDLEY_IMPORT) #undef JSON_HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) #define JSON_HEDLEY_PRIVATE #define JSON_HEDLEY_PUBLIC __declspec(dllexport) #define JSON_HEDLEY_IMPORT __declspec(dllimport) #else #if \ JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) #else #define JSON_HEDLEY_PRIVATE #define JSON_HEDLEY_PUBLIC #endif #define JSON_HEDLEY_IMPORT extern #endif #if defined(JSON_HEDLEY_NO_THROW) #undef JSON_HEDLEY_NO_THROW #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) #define JSON_HEDLEY_NO_THROW __declspec(nothrow) #else #define JSON_HEDLEY_NO_THROW #endif #if defined(JSON_HEDLEY_FALL_THROUGH) #undef JSON_HEDLEY_FALL_THROUGH #endif #if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) #elif defined(__fallthrough) /* SAL */ #define JSON_HEDLEY_FALL_THROUGH __fallthrough #else #define JSON_HEDLEY_FALL_THROUGH #endif #if defined(JSON_HEDLEY_RETURNS_NON_NULL) #undef JSON_HEDLEY_RETURNS_NON_NULL #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ #else #define JSON_HEDLEY_RETURNS_NON_NULL #endif #if defined(JSON_HEDLEY_ARRAY_PARAM) #undef JSON_HEDLEY_ARRAY_PARAM #endif #if \ defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ !defined(__STDC_NO_VLA__) && \ !defined(__cplusplus) && \ !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_TINYC_VERSION) #define JSON_HEDLEY_ARRAY_PARAM(name) (name) #else #define JSON_HEDLEY_ARRAY_PARAM(name) #endif #if defined(JSON_HEDLEY_IS_CONSTANT) #undef JSON_HEDLEY_IS_CONSTANT #endif #if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) #undef JSON_HEDLEY_REQUIRE_CONSTEXPR #endif /* JSON_HEDLEY_IS_CONSTEXPR_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_IS_CONSTEXPR_) #undef JSON_HEDLEY_IS_CONSTEXPR_ #endif #if \ JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) # if \ JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) #if defined(__INTPTR_TYPE__) #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) #else #include #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) #endif # elif \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) #if defined(__INTPTR_TYPE__) #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) #else #include #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) #endif # elif \ defined(JSON_HEDLEY_GCC_VERSION) || \ defined(JSON_HEDLEY_INTEL_VERSION) || \ defined(JSON_HEDLEY_TINYC_VERSION) || \ defined(JSON_HEDLEY_TI_VERSION) || \ defined(__clang__) # define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ sizeof(void) != \ sizeof(*( \ 1 ? \ ((void*) ((expr) * 0L) ) : \ ((struct { char v[sizeof(void) * 2]; } *) 1) \ ) \ ) \ ) # endif #endif #if defined(JSON_HEDLEY_IS_CONSTEXPR_) #if !defined(JSON_HEDLEY_IS_CONSTANT) #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) #endif #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) #else #if !defined(JSON_HEDLEY_IS_CONSTANT) #define JSON_HEDLEY_IS_CONSTANT(expr) (0) #endif #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) #endif #if defined(JSON_HEDLEY_BEGIN_C_DECLS) #undef JSON_HEDLEY_BEGIN_C_DECLS #endif #if defined(JSON_HEDLEY_END_C_DECLS) #undef JSON_HEDLEY_END_C_DECLS #endif #if defined(JSON_HEDLEY_C_DECL) #undef JSON_HEDLEY_C_DECL #endif #if defined(__cplusplus) #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { #define JSON_HEDLEY_END_C_DECLS } #define JSON_HEDLEY_C_DECL extern "C" #else #define JSON_HEDLEY_BEGIN_C_DECLS #define JSON_HEDLEY_END_C_DECLS #define JSON_HEDLEY_C_DECL #endif #if defined(JSON_HEDLEY_STATIC_ASSERT) #undef JSON_HEDLEY_STATIC_ASSERT #endif #if \ !defined(__cplusplus) && ( \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ defined(_Static_assert) \ ) # define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) #elif \ (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) # define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) #else # define JSON_HEDLEY_STATIC_ASSERT(expr, message) #endif #if defined(JSON_HEDLEY_CONST_CAST) #undef JSON_HEDLEY_CONST_CAST #endif #if defined(__cplusplus) # define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) #elif \ JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) # define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ ((T) (expr)); \ JSON_HEDLEY_DIAGNOSTIC_POP \ })) #else # define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) #endif #if defined(JSON_HEDLEY_REINTERPRET_CAST) #undef JSON_HEDLEY_REINTERPRET_CAST #endif #if defined(__cplusplus) #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) #else #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) #endif #if defined(JSON_HEDLEY_STATIC_CAST) #undef JSON_HEDLEY_STATIC_CAST #endif #if defined(__cplusplus) #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) #else #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) #endif #if defined(JSON_HEDLEY_CPP_CAST) #undef JSON_HEDLEY_CPP_CAST #endif #if defined(__cplusplus) #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) #else #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) #endif #if defined(JSON_HEDLEY_NULL) #undef JSON_HEDLEY_NULL #endif #if defined(__cplusplus) #if __cplusplus >= 201103L #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) #elif defined(NULL) #define JSON_HEDLEY_NULL NULL #else #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) #endif #elif defined(NULL) #define JSON_HEDLEY_NULL NULL #else #define JSON_HEDLEY_NULL ((void*) 0) #endif #if defined(JSON_HEDLEY_MESSAGE) #undef JSON_HEDLEY_MESSAGE #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") # define JSON_HEDLEY_MESSAGE(msg) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ JSON_HEDLEY_PRAGMA(message msg) \ JSON_HEDLEY_DIAGNOSTIC_POP #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) #elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else # define JSON_HEDLEY_MESSAGE(msg) #endif #if defined(JSON_HEDLEY_WARNING) #undef JSON_HEDLEY_WARNING #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") # define JSON_HEDLEY_WARNING(msg) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ JSON_HEDLEY_PRAGMA(clang warning msg) \ JSON_HEDLEY_DIAGNOSTIC_POP #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) #endif #if defined(JSON_HEDLEY_REQUIRE) #undef JSON_HEDLEY_REQUIRE #endif #if defined(JSON_HEDLEY_REQUIRE_MSG) #undef JSON_HEDLEY_REQUIRE_MSG #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) # if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") # define JSON_HEDLEY_REQUIRE(expr) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ __attribute__((diagnose_if(!(expr), #expr, "error"))) \ JSON_HEDLEY_DIAGNOSTIC_POP # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ __attribute__((diagnose_if(!(expr), msg, "error"))) \ JSON_HEDLEY_DIAGNOSTIC_POP # else # define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) # endif #else # define JSON_HEDLEY_REQUIRE(expr) # define JSON_HEDLEY_REQUIRE_MSG(expr,msg) #endif #if defined(JSON_HEDLEY_FLAGS) #undef JSON_HEDLEY_FLAGS #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) #endif #if defined(JSON_HEDLEY_FLAGS_CAST) #undef JSON_HEDLEY_FLAGS_CAST #endif #if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) # define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("warning(disable:188)") \ ((T) (expr)); \ JSON_HEDLEY_DIAGNOSTIC_POP \ })) #else # define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) #endif #if defined(JSON_HEDLEY_EMPTY_BASES) #undef JSON_HEDLEY_EMPTY_BASES #endif #if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) #else #define JSON_HEDLEY_EMPTY_BASES #endif /* Remaining macros are deprecated. */ #if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK #endif #if defined(__clang__) #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) #else #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif #if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE #endif #define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE #endif #define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) #undef JSON_HEDLEY_CLANG_HAS_BUILTIN #endif #define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) #if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) #undef JSON_HEDLEY_CLANG_HAS_FEATURE #endif #define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) #if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) #undef JSON_HEDLEY_CLANG_HAS_EXTENSION #endif #define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) #if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE #endif #define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_WARNING) #undef JSON_HEDLEY_CLANG_HAS_WARNING #endif #define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ // This file contains all internal macro definitions // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them // exclude unsupported compilers #if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) #if defined(__clang__) #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif #endif // C++ language standard detection #if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 #define JSON_HAS_CPP_17 #define JSON_HAS_CPP_14 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) #define JSON_HAS_CPP_14 #endif // disable float-equal warnings on GCC/clang #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" #endif // disable documentation warnings on clang #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdocumentation" #endif // allow to disable exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) #define JSON_INTERNAL_CATCH(exception) catch(exception) #else #include #define JSON_THROW(exception) std::abort() #define JSON_TRY if(true) #define JSON_CATCH(exception) if(false) #define JSON_INTERNAL_CATCH(exception) if(false) #endif // override exception macros #if defined(JSON_THROW_USER) #undef JSON_THROW #define JSON_THROW JSON_THROW_USER #endif #if defined(JSON_TRY_USER) #undef JSON_TRY #define JSON_TRY JSON_TRY_USER #endif #if defined(JSON_CATCH_USER) #undef JSON_CATCH #define JSON_CATCH JSON_CATCH_USER #undef JSON_INTERNAL_CATCH #define JSON_INTERNAL_CATCH JSON_CATCH_USER #endif #if defined(JSON_INTERNAL_CATCH_USER) #undef JSON_INTERNAL_CATCH #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif /*! @brief macro to briefly define a mapping between an enum and JSON @def NLOHMANN_JSON_SERIALIZE_ENUM @since version 3.4.0 */ #define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ template \ inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ { \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [e](const std::pair& ej_pair) -> bool \ { \ return ej_pair.first == e; \ }); \ j = ((it != std::end(m)) ? it : std::begin(m))->second; \ } \ template \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ { \ static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ static const std::pair m[] = __VA_ARGS__; \ auto it = std::find_if(std::begin(m), std::end(m), \ [&j](const std::pair& ej_pair) -> bool \ { \ return ej_pair.second == j; \ }); \ e = ((it != std::end(m)) ? it : std::begin(m))->first; \ } // Ugly macros to avoid uglier copy-paste when specializing basic_json. They // may be removed in the future once the class is split. #define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ template class ObjectType, \ template class ArrayType, \ class StringType, class BooleanType, class NumberIntegerType, \ class NumberUnsignedType, class NumberFloatType, \ template class AllocatorType, \ template class JSONSerializer> #define NLOHMANN_BASIC_JSON_TPL \ basic_json namespace nlohmann { namespace detail { //////////////// // exceptions // //////////////// /*! @brief general exception of the @ref basic_json class This class is an extension of `std::exception` objects with a member @a id for exception ids. It is used as the base class for all exceptions thrown by the @ref basic_json class. This class can hence be used as "wildcard" to catch exceptions. Subclasses: - @ref parse_error for exceptions indicating a parse error - @ref invalid_iterator for exceptions indicating errors with iterators - @ref type_error for exceptions indicating executing a member function with a wrong type - @ref out_of_range for exceptions indicating access out of the defined range - @ref other_error for exceptions indicating other library errors @internal @note To have nothrow-copy-constructible exceptions, we internally use `std::runtime_error` which can cope with arbitrary-length error messages. Intermediate strings are built with static functions and then passed to the actual constructor. @endinternal @liveexample{The following code shows how arbitrary library exceptions can be caught.,exception} @since version 3.0.0 */ class exception : public std::exception { public: /// returns the explanatory string JSON_HEDLEY_RETURNS_NON_NULL const char* what() const noexcept override { return m.what(); } /// the id of the exception const int id; protected: JSON_HEDLEY_NON_NULL(3) exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} static std::string name(const std::string& ename, int id_) { return "[json.exception." + ename + "." + std::to_string(id_) + "] "; } private: /// an exception object as storage for error messages std::runtime_error m; }; /*! @brief exception indicating a parse error This exception is thrown by the library when a parse error occurs. Parse errors can occur during the deserialization of JSON text, CBOR, MessagePack, as well as when using JSON Patch. Member @a byte holds the byte index of the last read character in the input file. Exceptions have ids 1xx. name / id | example message | description ------------------------------ | --------------- | ------------------------- json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of file. This also holds true when reading a byte vector (CBOR or MessagePack). @liveexample{The following code shows how a `parse_error` exception can be caught.,parse_error} @sa - @ref exception for the base class of the library exceptions @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class parse_error : public exception { public: /*! @brief create a parse error exception @param[in] id_ the id of the exception @param[in] pos the position where the error occurred (or with chars_read_total=0 if the position cannot be determined) @param[in] what_arg the explanatory string @return parse_error object */ static parse_error create(int id_, const position_t& pos, const std::string& what_arg) { std::string w = exception::name("parse_error", id_) + "parse error" + position_string(pos) + ": " + what_arg; return parse_error(id_, pos.chars_read_total, w.c_str()); } static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) { std::string w = exception::name("parse_error", id_) + "parse error" + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + ": " + what_arg; return parse_error(id_, byte_, w.c_str()); } /*! @brief byte index of the parse error The byte index of the last read character in the input file. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of file. This also holds true when reading a byte vector (CBOR or MessagePack). */ const std::size_t byte; private: parse_error(int id_, std::size_t byte_, const char* what_arg) : exception(id_, what_arg), byte(byte_) {} static std::string position_string(const position_t& pos) { return " at line " + std::to_string(pos.lines_read + 1) + ", column " + std::to_string(pos.chars_read_current_line); } }; /*! @brief exception indicating errors with iterators This exception is thrown if iterators passed to a library function do not match the expected semantics. Exceptions have ids 2xx. name / id | example message | description ----------------------------------- | --------------- | ------------------------- json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). @liveexample{The following code shows how an `invalid_iterator` exception can be caught.,invalid_iterator} @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class invalid_iterator : public exception { public: static invalid_iterator create(int id_, const std::string& what_arg) { std::string w = exception::name("invalid_iterator", id_) + what_arg; return invalid_iterator(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) invalid_iterator(int id_, const char* what_arg) : exception(id_, what_arg) {} }; /*! @brief exception indicating executing a member function with a wrong type This exception is thrown in case of a type error; that is, a library function is executed on a JSON value whose type does not match the expected semantics. Exceptions have ids 3xx. name / id | example message | description ----------------------------- | --------------- | ------------------------- json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | @liveexample{The following code shows how a `type_error` exception can be caught.,type_error} @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class type_error : public exception { public: static type_error create(int id_, const std::string& what_arg) { std::string w = exception::name("type_error", id_) + what_arg; return type_error(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; /*! @brief exception indicating access out of the defined range This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance in case of array indices or nonexisting object keys. Exceptions have ids 4xx. name / id | example message | description ------------------------------- | --------------- | ------------------------- json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | @liveexample{The following code shows how an `out_of_range` exception can be caught.,out_of_range} @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class out_of_range : public exception { public: static out_of_range create(int id_, const std::string& what_arg) { std::string w = exception::name("out_of_range", id_) + what_arg; return out_of_range(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} }; /*! @brief exception indicating other library errors This exception is thrown in case of errors that cannot be classified with the other exception types. Exceptions have ids 5xx. name / id | example message | description ------------------------------ | --------------- | ------------------------- json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. @sa - @ref exception for the base class of the library exceptions @sa - @ref parse_error for exceptions indicating a parse error @sa - @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref type_error for exceptions indicating executing a member function with a wrong type @sa - @ref out_of_range for exceptions indicating access out of the defined range @liveexample{The following code shows how an `other_error` exception can be caught.,other_error} @since version 3.0.0 */ class other_error : public exception { public: static other_error create(int id_, const std::string& what_arg) { std::string w = exception::name("other_error", id_) + what_arg; return other_error(id_, w.c_str()); } private: JSON_HEDLEY_NON_NULL(3) other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; } // namespace detail } // namespace nlohmann // #include // #include #include // not #include // size_t #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type namespace nlohmann { namespace detail { // alias templates to reduce boilerplate template using enable_if_t = typename std::enable_if::type; template using uncvref_t = typename std::remove_cv::type>::type; // implementation of C++14 index_sequence and affiliates // source: https://stackoverflow.com/a/32223343 template struct index_sequence { using type = index_sequence; using value_type = std::size_t; static constexpr std::size_t size() noexcept { return sizeof...(Ints); } }; template struct merge_and_renumber; template struct merge_and_renumber, index_sequence> : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; template struct make_index_sequence : merge_and_renumber < typename make_index_sequence < N / 2 >::type, typename make_index_sequence < N - N / 2 >::type > {}; template<> struct make_index_sequence<0> : index_sequence<> {}; template<> struct make_index_sequence<1> : index_sequence<0> {}; template using index_sequence_for = make_index_sequence; // dispatch utility (taken from ranges-v3) template struct priority_tag : priority_tag < N - 1 > {}; template<> struct priority_tag<0> {}; // taken from ranges-v3 template struct static_const { static constexpr T value{}; }; template constexpr T static_const::value; } // namespace detail } // namespace nlohmann // #include #include // not #include // numeric_limits #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval // #include #include // random_access_iterator_tag // #include namespace nlohmann { namespace detail { template struct make_void { using type = void; }; template using void_t = typename make_void::type; } // namespace detail } // namespace nlohmann // #include namespace nlohmann { namespace detail { template struct iterator_types {}; template struct iterator_types < It, void_t> { using difference_type = typename It::difference_type; using value_type = typename It::value_type; using pointer = typename It::pointer; using reference = typename It::reference; using iterator_category = typename It::iterator_category; }; // This is required as some compilers implement std::iterator_traits in a way that // doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. template struct iterator_traits { }; template struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> : iterator_types { }; template struct iterator_traits::value>> { using iterator_category = std::random_access_iterator_tag; using value_type = T; using difference_type = ptrdiff_t; using pointer = T*; using reference = T&; }; } // namespace detail } // namespace nlohmann // #include // #include // #include #include // #include // http://en.cppreference.com/w/cpp/experimental/is_detected namespace nlohmann { namespace detail { struct nonesuch { nonesuch() = delete; ~nonesuch() = delete; nonesuch(nonesuch const&) = delete; nonesuch(nonesuch const&&) = delete; void operator=(nonesuch const&) = delete; void operator=(nonesuch&&) = delete; }; template class Op, class... Args> struct detector { using value_t = std::false_type; using type = Default; }; template class Op, class... Args> struct detector>, Op, Args...> { using value_t = std::true_type; using type = Op; }; template