diff --git a/Makefile b/Makefile index f10dcefa..0da876d6 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ all: @if exist "$(MAKEDIR)\src\3rdparty\chardet\Makefile" cd "$(MAKEDIR)\src\3rdparty\chardet" && $(MAKE) /NOLOGO /$(MAKEFLAGS) @if exist "$(MAKEDIR)\src\3rdparty\qrencode\Makefile" cd "$(MAKEDIR)\src\3rdparty\qrencode" && $(MAKE) /NOLOGO /$(MAKEFLAGS) @if exist "$(MAKEDIR)\src\3rdparty\tinyexpr\Makefile" cd "$(MAKEDIR)\src\3rdparty\tinyexpr" && $(MAKE) /NOLOGO /$(MAKEFLAGS) + @if exist "$(MAKEDIR)\src\3rdparty\expat\Makefile" cd "$(MAKEDIR)\src\3rdparty\expat" && $(MAKE) /NOLOGO /$(MAKEFLAGS) @if exist "$(MAKEDIR)\src\3rdparty\scintilla\Makefile" cd "$(MAKEDIR)\src\3rdparty\scintilla" && $(MAKE) /NOLOGO /$(MAKEFLAGS) cd "$(MAKEDIR)\src" @$(MAKE) /NOLOGO /$(MAKEFLAGS) @@ -52,6 +53,7 @@ clean: @if exist "$(MAKEDIR)\src\3rdparty\chardet\Makefile" cd "$(MAKEDIR)\src\3rdparty\chardet" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean @if exist "$(MAKEDIR)\src\3rdparty\qrencode\Makefile" cd "$(MAKEDIR)\src\3rdparty\qrencode" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean @if exist "$(MAKEDIR)\src\3rdparty\tinyexpr\Makefile" cd "$(MAKEDIR)\src\3rdparty\tinyexpr" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean + @if exist "$(MAKEDIR)\src\3rdparty\expat\Makefile" cd "$(MAKEDIR)\src\3rdparty\expat" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean @if exist "$(MAKEDIR)\src\3rdparty\scintilla\Makefile" cd "$(MAKEDIR)\src\3rdparty\scintilla" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean @if exist "$(MAKEDIR)\plugins\pdfview\Makefile" cd "$(MAKEDIR)\plugins\pdfview" && $(MAKE) /NOLOGO /$(MAKEFLAGS) clean cd "$(MAKEDIR)\src" diff --git a/conf/conf.d/eu_accel.lua b/conf/conf.d/eu_accel.lua index 00ebe882..17247da0 100644 --- a/conf/conf.d/eu_accel.lua +++ b/conf/conf.d/eu_accel.lua @@ -157,6 +157,8 @@ function eu_accel.loadaccel() " {bit.bor(FVIRTKEY,FCONTROL,FALT), VK_F6, IDM_FORMAT_COMPRESS_JSON},\n", " {bit.bor(FVIRTKEY,FCONTROL), VK_F7, IDM_FORMAT_REFORMAT_JS},\n", " {bit.bor(FVIRTKEY,FCONTROL,FALT), VK_F7, IDM_FORMAT_COMPRESS_JS},\n", + " {bit.bor(FVIRTKEY,FCONTROL), VK_F12, IDM_FORMAT_REFORMAT_XML},\n", + " {bit.bor(FVIRTKEY,FCONTROL,FALT), VK_F12, IDM_FORMAT_COMPRESS_XML},\n", " {bit.bor(FVIRTKEY,FCONTROL), VK_F8, IDM_FORMAT_RUN_SCRIPT},\n", " {bit.bor(FVIRTKEY,FCONTROL,FALT), VK_F8, IDM_FORMAT_BYTE_CODE},\n", " {bit.bor(FVIRTKEY), VK_F10, IDM_FORMAT_WHOLE_FILE},\n", @@ -207,7 +209,8 @@ function eu_accel.loadaccel() end local m_len = tonumber(#my_code) if (m_len ~= nil) then - if (m_len < 175) then + --print("m_len = " .. m_len) + if (m_len < 178) then eu_core.euapi.eu_reset_accs_mask() end local m_accel = eu_core.ffi.new("ACCEL[?]", m_len, {}) diff --git a/conf/conf.d/eu_conf.lua b/conf/conf.d/eu_conf.lua index b67072cb..7fef957f 100644 --- a/conf/conf.d/eu_conf.lua +++ b/conf/conf.d/eu_conf.lua @@ -152,6 +152,12 @@ function eu_conf.loadconf() " margin_right = 2000,\n" .. " margin_bottom = 2000\n" .. "}\n" .. + "-- titlebar default setting\n" .. + "titlebar = {\n" .. + " icon = true,\n" .. + " name = true,\n" .. + " path = true\n" .. + "}\n" .. "-- hyperlink hotspot default setting\n" .. "hyperlink_detection = true\n" .. "-- automatically cached file (size < 200MB)\n" .. @@ -176,20 +182,8 @@ function eu_conf.loadconf() eu_code = dofile(file) end -- Add new preference - if (update_file_notify == nil) then - update_file_notify = 0 - end - if (enable_runtime_logging == nil) then - enable_runtime_logging = false - end - if (process_customized == nil) then - process_customized = {} - end - if (history_mask == nil) then - history_mask = 44711 - end - if (code_hint_show_enable == nil) then - code_hint_show_enable = true; + if (titlebar == nil) then + titlebar = {["icon"] = true, ["name"] = true, ["path"] = true} end local m_config = eu_core.ffi.new("struct eu_config", { newfile_eols, @@ -248,6 +242,7 @@ function eu_conf.loadconf() {calltip.enable, calltip.rgb}, {complete.enable, complete.characters, complete.snippet}, {printer.header, printer.footer, printer.color_mode, printer.zoom,{printer.margin_left, printer.margin_top, printer.margin_right, printer.margin_bottom}}, + {titlebar.icon, titlebar.name, titlebar.path}, hyperlink_detection, cache_limit_size, {app_upgrade.enable, app_upgrade.flags, app_upgrade.msg_id, app_upgrade.last_check, app_upgrade.url}, @@ -256,10 +251,6 @@ function eu_conf.loadconf() m_reserved_0, m_reserved_1 }) - -- Compatible with previous versions - if (m_config ~= nil and m_config.eu_complete.characters == 0) then - m_config.eu_complete.characters = 1 - end eu_conf.fill_actions(m_config) eu_conf.fill_customize(m_config) if (not eu_core.euapi.eu_config_ptr(m_config)) then diff --git a/conf/conf.d/eu_core.lua b/conf/conf.d/eu_core.lua index 4f3bab4d..68d93af8 100644 --- a/conf/conf.d/eu_core.lua +++ b/conf/conf.d/eu_core.lua @@ -29,6 +29,13 @@ typedef struct _print_set RECT rect; }print_set; +typedef struct _titlebar_set +{ + bool icon; + bool name; + bool path; +}titlebar_set; + typedef struct _caret_set { int blink; @@ -154,6 +161,7 @@ struct eu_config calltip_set eu_calltip; complete_set eu_complete; print_set eu_print; + titlebar_set eu_titlebar; bool m_hyperlink; int m_limit; upgrade_set upgrade; @@ -234,6 +242,17 @@ struct rb_root struct rb_node *rb_node; }; +struct opt_format +{ + bool no_c; + bool no_p; + bool no_f; + bool no_x; + bool no_t; + bool no_d; + bool no_a; +}; + typedef struct rb_root eutype_t; typedef int (*init_before_ptr)(void *pnode); typedef int (*init_after_ptr)(void *pnode); @@ -332,6 +351,9 @@ bool eu_theme_ptr(struct eu_theme *ptheme, bool init); bool eu_accel_ptr(ACCEL *paccel); bool eu_toolbar_ptr(eue_toolbar *pdata, int num); bool eu_exist_path(const char *path); +bool eu_xml_pretty(void *ptr, struct opt_format *opt); + +// crt 函数 char *_fullpath(char *buf, const char *path, size_t maxlen); // all doctype callbacks @@ -407,6 +429,7 @@ int on_doc_click_list_jmp(void *pnode); int on_doc_click_list_jump_sh(void *pnode); int on_doc_click_tree_sql(void *pnode); int on_doc_click_tree_json(void *pnode); +int on_doc_click_tree_xml(void *pnode); int on_doc_click_tree_redis(void *pnode); /* lua脚本接口支持, 对各类关键字着色 */ diff --git a/conf/conf.d/eu_docs.lua b/conf/conf.d/eu_docs.lua index 6c532c90..8f3f48de 100644 --- a/conf/conf.d/eu_docs.lua +++ b/conf/conf.d/eu_docs.lua @@ -61,6 +61,7 @@ if (not eu_core.file_exists(user_file)) then " DOCTYPE_LATEX = 40,\n", " DOCTYPE_VERILOG = 41,\n", " DOCTYPE_PASCAL = 42,\n", + " DOCTYPE_TCL = 43,\n", " }\n", " local ffi_null = eu_core.ffi.cast(\"void *\", nil)\n", " local docs_t = eu_core.ffi.new (\"doctype_t[?]\", i,\n", @@ -786,6 +787,26 @@ if (not eu_core.file_exists(user_file)) then " ffi_null,\n", " },\n", " {\n", + " e.DOCTYPE_TCL,\n", + " \"tcl\",\n", + " \";*.tcl;*.itcl;*.tm;\",\n", + " \"Tcl Script\",\n", + " \"tcl.snippets\",\n", + " 0,\n", + " -1,\n", + " ffi_null,\n", + " ffi_null,\n", + " ffi_null,\n", + " ffi_null,\n", + " eu_core.euapi.on_doc_keyup_general,\n", + " eu_core.euapi.on_doc_cpp_like,\n", + " ffi_null,\n", + " ffi_null,\n", + " ffi_null,\n", + " ffi_null,\n", + " ffi_null,\n", + " },\n", + " {\n", " e.DOCTYPE_TXT,\n", " ffi_null,\n", " \";*.txt;\",\n", @@ -867,13 +888,13 @@ if (not eu_core.file_exists(user_file)) then " },\n", " {\n", " e.DOCTYPE_XML,\n", - " ffi_null,\n", + " \"xml\",\n", " \";*.xml;*.xsl;*.svg;*.xul;*.xsd;*.dtd;*.xslt;*.axl;*.xrc;*.rdf;*.manifest;*.vcproj;*.vcxproj;*.filters;*.fb2;\",\n", " \"XML\",\n", " \"xml.snippets\",\n", " 0,\n", " -1,\n", - " ffi_null,\n", + " eu_core.euapi.on_doc_init_tree,\n", " eu_core.euapi.on_doc_init_after_xml,\n", " ffi_null,\n", " ffi_null,\n", @@ -881,8 +902,8 @@ if (not eu_core.file_exists(user_file)) then " eu_core.euapi.on_doc_xml_like,\n", " ffi_null,\n", " ffi_null,\n", - " ffi_null,\n", - " ffi_null,\n", + " eu_core.euapi.on_doc_reload_tree_xml,\n", + " eu_core.euapi.on_doc_click_tree_xml,\n", " ffi_null,\n", " },\n", " {\n", @@ -1074,7 +1095,8 @@ end function fill_my_docs() local my_doc_config = user_docs.get_docs() local my_size = eu_core.ffi.sizeof(my_doc_config)/eu_core.ffi.sizeof("doctype_t") - if (my_size < 43) then + --print("my_size = " .. my_size) + if (my_size < 44) then eu_core.euapi.eu_reset_docs_mask() end for i=0,my_size-1 do diff --git a/conf/conf.d/eu_example.lua b/conf/conf.d/eu_example.lua index 782b722c..ed21cf55 100644 --- a/conf/conf.d/eu_example.lua +++ b/conf/conf.d/eu_example.lua @@ -3,19 +3,19 @@ local ffi = require('ffi') local euapi = ffi.load(ffi.os == "Windows" and "euapi.dll") ffi.cdef[[ -wchar_t * __stdcall utf8_to_utf16(const char *utf8, size_t *out_len); +wchar_t* eu_utf8_utf16(const char *utf8, size_t *out_len); +int MessageBoxW(void *w, const wchar_t *txt, const wchar_t *cap, uint32_t type); void free(void *); -int MessageBoxW(void *w, const wchar_t *txt, const wchar_t *cap, int type); ]] -- UTF-8 to UTF-16 local function U16(input) - local wstr = euapi.utf8_to_utf16(input, nil) + local wstr = euapi.eu_utf8_utf16(input, nil) ffi.gc(wstr,(function(self) if wstr ~= nil then ffi.C.free(wstr) end print("call gc, goodbye!") end)) return wstr end -ffi.C.MessageBoxW(nil, U16("你好, Skylark Edit!"), U16("测试:"), 0) +ffi.C.MessageBoxW(nil, U16("你好, 世界!"), U16("Skylark Editor:"), 0) ]=] diff --git a/conf/conf.d/eu_sci.lua b/conf/conf.d/eu_sci.lua index a31d6b23..b48b4457 100644 --- a/conf/conf.d/eu_sci.lua +++ b/conf/conf.d/eu_sci.lua @@ -3449,6 +3449,8 @@ IDM_FORMAT_REFORMAT_JSON = 42250 IDM_FORMAT_COMPRESS_JSON = 42251 IDM_FORMAT_REFORMAT_JS = 42254 IDM_FORMAT_COMPRESS_JS = 42255 +IDM_FORMAT_REFORMAT_XML = 44751 +IDM_FORMAT_COMPRESS_XML = 44752 IDM_FORMAT_WHOLE_FILE = 42252 IDM_FORMAT_RANGLE_STR = 42253 IDM_FORMAT_RUN_SCRIPT = 42406 diff --git a/conf/conf.d/eu_theme.lua b/conf/conf.d/eu_theme.lua index 4ffb264a..c89dd59b 100644 --- a/conf/conf.d/eu_theme.lua +++ b/conf/conf.d/eu_theme.lua @@ -553,41 +553,6 @@ function eu_theme.load_default(name) dofile(file) tname = name end - if (xmlsection_font == nil) then - xmlsection_font = "Consola" - xmlsection_fontsize = 11 - xmlsection_color = 0xC972C9 - xmlsection_bgcolor = 0x00000000 - xmlsection_bold = 1 - end - if (results_font == nil) then - results_font = "Consola" - results_fontsize = 11 - results_color = keywords_color - results_bgcolor = number_color - results_bold = 0 - end - if (bracesection_font == nil) then - bracesection_font = "Consola" - bracesection_fontsize = 11 - bracesection_color = 0x000000FF - bracesection_bgcolor = text_bgcolor - bracesection_bold = 1 - end - if (nchistory_font == nil) then - nchistory_font = "Consola" - nchistory_fontsize = 11 - nchistory_color = 0x0080FF - nchistory_bgcolor = 0x00A000 - nchistory_bold = 0 - end - if (dochistory_font == nil) then - dochistory_font = "Consola" - dochistory_fontsize = 11 - dochistory_color = 0x0080FF - dochistory_bgcolor = 0x00A000 - dochistory_bold = 0 - end local m_file = eu_core.ffi.new('char[260]') eu_core.ffi.C._fullpath(m_file, file, 260) local m_theme = eu_core.ffi.new("struct eu_theme", {m_file, tname, diff --git a/conf/conf.d/snippets/tcl.snippets b/conf/conf.d/snippets/tcl.snippets new file mode 100644 index 00000000..1baf6c47 --- /dev/null +++ b/conf/conf.d/snippets/tcl.snippets @@ -0,0 +1,48 @@ +########################################################################### +# SKYLARK SNIPPETS # +########################################################################### +snippet for "for... (for)" b +for {${1:set i 0}} {${2:$i < $n}} {${3:incr i}} { + $4 +} +$0 +endsnippet + +snippet foreach "foreach... (foreach)" +foreach ${1:var} ${2:$list} { + $3 +} +$0 +endsnippet + +snippet if "if... (if)" b +if {${1:condition}} { + $2 +} +$0 +endsnippet + +snippet proc "proc... (proc)" b +proc ${1:name} {${2:args}} \ +{ + $3 +} +$0 +endsnippet + +snippet switch "switch... (switch)" b +switch ${1:-exact} -- ${2:$var} { + ${3:match} { + $4 + } + default {$5} +} +$0 +endsnippet + +snippet while "while... (while)" b +while {${1:condition}} { + $2 +} +$0 +endsnippet diff --git a/conf/conf.d/tcl.lua b/conf/conf.d/tcl.lua new file mode 100644 index 00000000..c2281013 --- /dev/null +++ b/conf/conf.d/tcl.lua @@ -0,0 +1,118 @@ +tcl = {} + +require("eu_sci") +require("eu_core") + +function tcl.init_after_callback(p) + local pnode = eu_core.ffi.cast("void *", p) + local res = eu_core.euapi.on_doc_init_after_scilexer(pnode, "tcl") -- enable tcl lex + if (res ~= 1) then + eu_core.euapi.on_doc_enable_foldline(pnode) -- enable fold line + end + return res +end + +function tcl.get_comments() + -- 行注释与块注释, 注释头与注释尾用&&分开 + local line_t = "# " + local block_t = "# " + return line_t, block_t +end + +function tcl.get_styles() + local style_t = { + [SCE_TCL_COMMENT] = 0xC0C0C0, + [SCE_TCL_COMMENTLINE] = 0xC0C0C0, + [SCE_TCL_BLOCK_COMMENT] = 0xC0C0C0, + -- 给关键字加上粗体 + [SCE_TCL_WORD] = 0x00B050 + SCE_BOLD_FONT, + [SCE_TCL_WORD2] = 0x00B050 + SCE_BOLD_FONT, + [SCE_TCL_WORD3] = 0xBBBB00 + SCE_BOLD_FONT, + [SCE_TCL_WORD4] = 0xBBBB00 + SCE_BOLD_FONT, + [SCE_TCL_WORD_IN_QUOTE] = 0xC080FF, + [SCE_TCL_NUMBER] = 0x00A000, + } + return style_t +end + +function tcl.get_keywords() + local keywords0_set = "after append array auto_execok auto_import auto_load auto_load_index auto_qualify beep bgerror binary break case catch cd clock close concat continue dde default echo else elseif encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent flush for foreach format gets glob global history http if incr info interp join lappend lindex linsert list llength load loadTk lrange lreplace lsearch lset lsort memory msgcat amespace open package pid pkg::create pkg_mkIndex Platform-specific proc puts pwd re_syntax read regexp registry regsub rename resource return scan seek set socket source split string subst switch tclLog tclMacPkgSearch tclPkgSetup tclPkgUnknown tell time trace unknown unset update uplevel upvar variable vwait while" + local keywords1_set = "bell bind bindtags bitmap button canvas checkbutton clipboard colors console cursors destroy entry event focus font frame grab grid image Inter-client keysyms label labelframe listbox lower menu menubutton message option options pack panedwindow photo place radiobutton raise scale scrollbar selection send spinbox text tk tk_chooseColor tk_chooseDirectory tk_dialog tk_focusNext tk_getOpenFile tk_messageBox tk_optionMenu tk_popup tk_setPalette tkerror tkvars tkwait toplevel winfo wish wm" + local keywords2_set = "@scope body class code common component configbody constructor define destructor hull import inherit itcl itk itk_component itk_initialize itk_interior itk_option iwidgets keep method private protected public" + return keywords0_set,keywords1_set,keywords2_set +end + +function tcl.get_autocomplete() + local autocomplete_set = "after append array auto_execok auto_import auto_load auto_load_index auto_qualify beep bgerror binary break case catch cd clock close concat continue dde default echo else elseif encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent flush for foreach format gets glob global history http if incr info interp join lappend lindex linsert list llength load loadTk lrange lreplace lsearch lset lsort memory msgcat amespace open package pid pkg::create pkg_mkIndex Platform-specific proc puts pwd re_syntax read regexp registry regsub rename resource return scan seek set socket source split string subst switch tclLog tclMacPkgSearch tclPkgSetup tclPkgUnknown tell time trace unknown unset update uplevel upvar variable vwait while bell bind bindtags bitmap button canvas checkbutton clipboard colors console cursors destroy entry event focus font frame grab grid image Inter-client keysyms label labelframe listbox lower menu menubutton message option options pack panedwindow photo place radiobutton raise scale scrollbar selection send spinbox text tk tk_chooseColor tk_chooseDirectory tk_dialog tk_focusNext tk_getOpenFile tk_messageBox tk_optionMenu tk_popup tk_setPalette tkerror tkvars tkwait toplevel winfo wish wm @scope body class code common component configbody constructor define destructor hull import inherit itcl itk itk_component itk_initialize itk_interior itk_option iwidgets keep method private protected public" + return autocomplete_set +end + +function tcl.get_reqular() + local symbol_reqular_exp = "[ \\t]*proc[ \\t]+([_a-zA-Z]+[_a-zA-Z0-9]*).+\\{" + return symbol_reqular_exp +end + +function tcl.create_bakup(path) + local tcl_code = { + "user_tcl = {}\n", + "\n", + "require(\"eu_sci\")\n", + "require(\"eu_core\")\n", + "\n", + "function user_tcl.init_after_callback(p)\n", + " local pnode = eu_core.ffi.cast(\"void *\", p)\n", + " local res = eu_core.euapi.on_doc_init_after_scilexer(pnode, \"tcl\") -- enable tcl lex\n", + " if (res ~= 1) then\n", + " eu_core.euapi.on_doc_enable_foldline(pnode) -- enable fold line\n", + " end\n", + " return res\n", + "end\n", + "\n", + "function user_tcl.get_comments()\n", + " -- 行注释与块注释, 注释头与注释尾用&&分开\n", + " local line_t = \"# \"\n", + " local block_t = \"# \"\n", + " return line_t, block_t\n", + "end\n", + "\n", + "function user_tcl.get_styles()\n", + " local style_t = {\n", + " [SCE_TCL_COMMENT] = 0xC0C0C0,\n", + " [SCE_TCL_COMMENTLINE] = 0xC0C0C0,\n", + " [SCE_TCL_BLOCK_COMMENT] = 0xC0C0C0,\n", + " -- 给关键字加上粗体\n", + " [SCE_TCL_WORD] = 0x00B050 + SCE_BOLD_FONT,\n", + " [SCE_TCL_WORD2] = 0x00B050 + SCE_BOLD_FONT,\n", + " [SCE_TCL_WORD3] = 0xBBBB00 + SCE_BOLD_FONT,\n", + " [SCE_TCL_WORD4] = 0xBBBB00 + SCE_BOLD_FONT,\n", + " [SCE_TCL_WORD_IN_QUOTE] = 0xC080FF,\n", + " [SCE_TCL_NUMBER] = 0x00A000,\n", + " }\n", + " return style_t\n", + "end\n", + "\n", + "function user_tcl.get_keywords()\n", + " local keywords0_set = \"after append array auto_execok auto_import auto_load auto_load_index auto_qualify beep bgerror binary break case catch cd clock close concat continue dde default echo else elseif encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent flush for foreach format gets glob global history http if incr info interp join lappend lindex linsert list llength load loadTk lrange lreplace lsearch lset lsort memory msgcat amespace open package pid pkg::create pkg_mkIndex Platform-specific proc puts pwd re_syntax read regexp registry regsub rename resource return scan seek set socket source split string subst switch tclLog tclMacPkgSearch tclPkgSetup tclPkgUnknown tell time trace unknown unset update uplevel upvar variable vwait while\"\n", + " local keywords1_set = \"bell bind bindtags bitmap button canvas checkbutton clipboard colors console cursors destroy entry event focus font frame grab grid image Inter-client keysyms label labelframe listbox lower menu menubutton message option options pack panedwindow photo place radiobutton raise scale scrollbar selection send spinbox text tk tk_chooseColor tk_chooseDirectory tk_dialog tk_focusNext tk_getOpenFile tk_messageBox tk_optionMenu tk_popup tk_setPalette tkerror tkvars tkwait toplevel winfo wish wm\"\n", + " local keywords2_set = \"@scope body class code common component configbody constructor define destructor hull import inherit itcl itk itk_component itk_initialize itk_interior itk_option iwidgets keep method private protected public\"\n", + " return keywords0_set,keywords1_set,keywords2_set\n", + "end\n", + "\n", + "function user_tcl.get_autocomplete()\n", + " local autocomplete_set = \"after append array auto_execok auto_import auto_load auto_load_index auto_qualify beep bgerror binary break case catch cd clock close concat continue dde default echo else elseif encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent flush for foreach format gets glob global history http if incr info interp join lappend lindex linsert list llength load loadTk lrange lreplace lsearch lset lsort memory msgcat amespace open package pid pkg::create pkg_mkIndex Platform-specific proc puts pwd re_syntax read regexp registry regsub rename resource return scan seek set socket source split string subst switch tclLog tclMacPkgSearch tclPkgSetup tclPkgUnknown tell time trace unknown unset update uplevel upvar variable vwait while bell bind bindtags bitmap button canvas checkbutton clipboard colors console cursors destroy entry event focus font frame grab grid image Inter-client keysyms label labelframe listbox lower menu menubutton message option options pack panedwindow photo place radiobutton raise scale scrollbar selection send spinbox text tk tk_chooseColor tk_chooseDirectory tk_dialog tk_focusNext tk_getOpenFile tk_messageBox tk_optionMenu tk_popup tk_setPalette tkerror tkvars tkwait toplevel winfo wish wm @scope body class code common component configbody constructor define destructor hull import inherit itcl itk itk_component itk_initialize itk_interior itk_option iwidgets keep method private protected public\"\n", + " return autocomplete_set\n", + "end\n", + "\n", + "function user_tcl.get_reqular()\n", + " local symbol_reqular_exp = \"[ \\\\t]*proc[ \\\\t]+([_a-zA-Z]+[_a-zA-Z0-9]*).+\\\\{\"\n", + " return symbol_reqular_exp\n", + "end\n", + "return user_tcl", + } + local shell_code = table.concat(tcl_code) + eu_core.save_file(path, shell_code) + shell_code = nil + tcl_code = nil +end + +return tcl \ No newline at end of file diff --git a/conf/conf.d/xml.lua b/conf/conf.d/xml.lua new file mode 100644 index 00000000..0d7f2c00 --- /dev/null +++ b/conf/conf.d/xml.lua @@ -0,0 +1,29 @@ +xml = {} + +function xml.get_tabattr() + -- 0, 跟随主配置 + local tab_width = 0 + -- 0, 不转换 1, 转换, -1, 跟随主配置 + local tab_convert_spaces = 1 + return tab_width,tab_convert_spaces +end + +function xml.create_bakup(path) + local xml_code = { + "user_xml = {}\n", + "function user_xml.get_tabattr()\n", + " -- 0, 跟随主配置\n", + " local tab_width = 0\n", + " -- 0, 不转换 1, 转换, -1, 跟随主配置\n", + " local tab_convert_spaces = 1\n", + " return tab_width,tab_convert_spaces\n", + "end\n", + "return user_xml", + } + local shell_code = table.concat(xml_code) + eu_core.save_file(path, shell_code) + shell_code = nil + xml_code = nil +end + +return xml \ No newline at end of file diff --git a/conf/conf.d/xmlformater.lua b/conf/conf.d/xmlformater.lua new file mode 100644 index 00000000..1cec7679 --- /dev/null +++ b/conf/conf.d/xmlformater.lua @@ -0,0 +1,32 @@ +require("eu_core") + +function run(pnode) + local opt_file = (eu_core.script_path() .. "\\skylark_pretty.conf") + if (not eu_core.file_exists(opt_file)) then + local opt_code = -- xmlformater默认配置文件 + "-- xmlformater default configuration\n" .. + "removal_comments = false\n" .. + "removal_processing_instructions = false\n" .. + "removal_cdata_sections = false\n" .. + "removal_xml_declaration = false\n" .. + "removal_doctype_declaration = false\n" .. + "removal_character_data = false\n" .. + "removal_attributes = false" + eu_core.save_file(opt_file, opt_code) + end + dofile(opt_file) + local m_opt = eu_core.ffi.new("struct opt_format", { + removal_comments, + removal_processing_instructions, + removal_cdata_sections, + removal_xml_declaration, + removal_doctype_declaration, + removal_character_data, + removal_attributes + }) + if (not eu_core.euapi.eu_xml_pretty(pnode, m_opt)) then + -- print("eu_xml_pretty return false") + do return 1 end + end + return 0 +end diff --git a/locales/src/en-us.rc b/locales/src/en-us.rc index 88ee8d8c..c9089c66 100644 --- a/locales/src/en-us.rc +++ b/locales/src/en-us.rc @@ -244,6 +244,12 @@ BEGIN MENUITEM "Show M&enubar", IDM_VIEW_MENUBAR MENUITEM "Show Stat&usbar", IDM_VIEW_STATUSBAR END + POPUP "Customize Titlebar", IDM_VIEW_TITLEBAR_GROUP + BEGIN + MENUITEM "Show App &Icon", IDM_VIEW_TITLEBAR_ICON + MENUITEM "Show App &Name", IDM_VIEW_TITLEBAR_NAME + MENUITEM "Show Document &Path", IDM_VIEW_TITLEBAR_PATH + END POPUP "Adjust Toolbar" BEGIN MENUITEM "&Hide", IDB_SIZE_0 @@ -336,6 +342,11 @@ BEGIN MENUITEM "Reformat Js", IDM_FORMAT_REFORMAT_JS MENUITEM "Compress Js", IDM_FORMAT_COMPRESS_JS END + POPUP "XML File", IDM_EDIT_PLACEHOLDE_XML + BEGIN + MENUITEM "Reformat XML", IDM_FORMAT_REFORMAT_XML + MENUITEM "Compress XML", IDM_FORMAT_COMPRESS_XML + END POPUP "Lua Scripts", IDM_EDIT_PLACEHOLDE_LUA BEGIN MENUITEM "Run This Script", IDM_FORMAT_RUN_SCRIPT @@ -445,7 +456,7 @@ BEGIN POPUP "&Help" BEGIN MENUITEM "Donate Now", IDM_DONATION - MENUITEM "Introduction &Of Eidt ...", IDM_INTRODUTION + MENUITEM "Introduction &Of Editor ...", IDM_INTRODUTION MENUITEM "Update &history ...", IDM_CHANGELOG MENUITEM "&Command Line ...", IDM_HELP_COMMAND MENUITEM "&About ...", IDM_ABOUT diff --git a/locales/src/zh-cn.rc b/locales/src/zh-cn.rc index a69cc1ef..ba918897 100644 --- a/locales/src/zh-cn.rc +++ b/locales/src/zh-cn.rc @@ -244,6 +244,12 @@ BEGIN MENUITEM "显示菜单栏", IDM_VIEW_MENUBAR MENUITEM "显示状态栏", IDM_VIEW_STATUSBAR END + POPUP "定制标题栏", IDM_VIEW_TITLEBAR_GROUP + BEGIN + MENUITEM "显示应用图标(&I)", IDM_VIEW_TITLEBAR_ICON + MENUITEM "显示应用名称(&N)", IDM_VIEW_TITLEBAR_NAME + MENUITEM "显示文档路径(&P)", IDM_VIEW_TITLEBAR_PATH + END POPUP "调整工具栏" BEGIN MENUITEM "隐藏(&H)", IDB_SIZE_0 @@ -336,6 +342,11 @@ BEGIN MENUITEM "格式化 Js", IDM_FORMAT_REFORMAT_JS MENUITEM "压缩 Js", IDM_FORMAT_COMPRESS_JS END + POPUP "XML 文件", IDM_EDIT_PLACEHOLDE_XML + BEGIN + MENUITEM "格式化 XML", IDM_FORMAT_REFORMAT_XML + MENUITEM "压缩 XML", IDM_FORMAT_COMPRESS_XML + END POPUP "Lua 脚本", IDM_EDIT_PLACEHOLDE_LUA BEGIN MENUITEM "运行当前脚本", IDM_FORMAT_RUN_SCRIPT diff --git a/share/changelog b/share/changelog index d6d28c7b..387f210b 100644 --- a/share/changelog +++ b/share/changelog @@ -1,3 +1,12 @@ +4.0.6 2023-10-13 adonais + * 新增: XML树控件支持与格式化 + * 新增: TCL脚本高亮与代码片段 + * 新增: 标题栏定制菜单项 + * 修复: 定制命令行菜单图标加载问题 + * 修复: clang-format查找配置文件路径问题 + * 修复: 文件包含GBK编码特殊符号无法打开的问题 + * 修复: 其他几个不常见的小问题 + 4.0.5 2023-09-06 adonais * 新增: 折叠框代码提示 * 变更: 重新整理了视图菜单栏 diff --git a/src/3rdparty/expat/COPYING b/src/3rdparty/expat/COPYING new file mode 100644 index 00000000..ce9e5939 --- /dev/null +++ b/src/3rdparty/expat/COPYING @@ -0,0 +1,21 @@ +Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper +Copyright (c) 2001-2022 Expat maintainers + +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. diff --git a/src/3rdparty/expat/Makefile b/src/3rdparty/expat/Makefile new file mode 100644 index 00000000..de1138c0 --- /dev/null +++ b/src/3rdparty/expat/Makefile @@ -0,0 +1,49 @@ +# The toplevel directory of the source tree. +# +ROOT = ..\..\.. +!include "$(ROOT)\system.mak" + +SRC = .\src + +# variables +# SHARED_LIB = $(BIND)\expat.dll + +STATICLIB = $(BIND)\expat.lib + +CFLAGS = -Oy -DNDEBUG=1 -I. -W3 -EHsc -Zi -I$(SRC) -D_CRT_SECURE_NO_WARNINGS \ + -D_CRT_NONSTDC_NO_DEPRECATE -D_WIN32_WINNT=0x0600 -DHAVE_CONFIG_H \ + $(RELEASE) $(CFLAGS) + +#LDFLAGS = $(DLLFLAGS) -def:src/expat.def + +OBJS = \ + $(OBJD)\xmlparse.obj \ + $(OBJD)\xmltok.obj \ + $(OBJD)\xmlrole.obj \ + +############################################################################## +## +.SUFFIXES: .c .h .obj + +{$(SRC)}.c{$(OBJD)}.obj: + $(CC) $(CFLAGS) -Fd$(BIND)\euapi.pdb -Fo$(OBJD)\ /c $< + +# targets +all: dirs $(STATICLIB) + +dirs: + @if not exist "$(BIND)" mkdir "$(BIND)" && echo. Created $(BIND) + @if not exist "$(OBJD)" mkdir "$(OBJD)" && echo. Created $(OBJD) + +#$(SHARED_LIB): $(OBJS) +# $(LD) $(LDFLAGS) -out:$@ $(OBJS) + +$(STATICLIB): $(OBJS) + $(AR) -out:$@ $(OBJS) + +$(OBJS): $(SRC)\*.c $(SRC)\*.h + +# cleanup +clean: + -del /q $(STATICLIB) 2>nul + -del /q $(OBJS) 2>nul diff --git a/src/3rdparty/expat/src/ascii.h b/src/3rdparty/expat/src/ascii.h new file mode 100644 index 00000000..1f594d2e --- /dev/null +++ b/src/3rdparty/expat/src/ascii.h @@ -0,0 +1,123 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1999-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2007 Karl Waclawek + Copyright (c) 2017 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +#define ASCII_A 0x41 +#define ASCII_B 0x42 +#define ASCII_C 0x43 +#define ASCII_D 0x44 +#define ASCII_E 0x45 +#define ASCII_F 0x46 +#define ASCII_G 0x47 +#define ASCII_H 0x48 +#define ASCII_I 0x49 +#define ASCII_J 0x4A +#define ASCII_K 0x4B +#define ASCII_L 0x4C +#define ASCII_M 0x4D +#define ASCII_N 0x4E +#define ASCII_O 0x4F +#define ASCII_P 0x50 +#define ASCII_Q 0x51 +#define ASCII_R 0x52 +#define ASCII_S 0x53 +#define ASCII_T 0x54 +#define ASCII_U 0x55 +#define ASCII_V 0x56 +#define ASCII_W 0x57 +#define ASCII_X 0x58 +#define ASCII_Y 0x59 +#define ASCII_Z 0x5A + +#define ASCII_a 0x61 +#define ASCII_b 0x62 +#define ASCII_c 0x63 +#define ASCII_d 0x64 +#define ASCII_e 0x65 +#define ASCII_f 0x66 +#define ASCII_g 0x67 +#define ASCII_h 0x68 +#define ASCII_i 0x69 +#define ASCII_j 0x6A +#define ASCII_k 0x6B +#define ASCII_l 0x6C +#define ASCII_m 0x6D +#define ASCII_n 0x6E +#define ASCII_o 0x6F +#define ASCII_p 0x70 +#define ASCII_q 0x71 +#define ASCII_r 0x72 +#define ASCII_s 0x73 +#define ASCII_t 0x74 +#define ASCII_u 0x75 +#define ASCII_v 0x76 +#define ASCII_w 0x77 +#define ASCII_x 0x78 +#define ASCII_y 0x79 +#define ASCII_z 0x7A + +#define ASCII_0 0x30 +#define ASCII_1 0x31 +#define ASCII_2 0x32 +#define ASCII_3 0x33 +#define ASCII_4 0x34 +#define ASCII_5 0x35 +#define ASCII_6 0x36 +#define ASCII_7 0x37 +#define ASCII_8 0x38 +#define ASCII_9 0x39 + +#define ASCII_TAB 0x09 +#define ASCII_SPACE 0x20 +#define ASCII_EXCL 0x21 +#define ASCII_QUOT 0x22 +#define ASCII_AMP 0x26 +#define ASCII_APOS 0x27 +#define ASCII_MINUS 0x2D +#define ASCII_PERIOD 0x2E +#define ASCII_COLON 0x3A +#define ASCII_SEMI 0x3B +#define ASCII_LT 0x3C +#define ASCII_EQUALS 0x3D +#define ASCII_GT 0x3E +#define ASCII_LSQB 0x5B +#define ASCII_RSQB 0x5D +#define ASCII_UNDERSCORE 0x5F +#define ASCII_LPAREN 0x28 +#define ASCII_RPAREN 0x29 +#define ASCII_FF 0x0C +#define ASCII_SLASH 0x2F +#define ASCII_HASH 0x23 +#define ASCII_PIPE 0x7C +#define ASCII_COMMA 0x2C diff --git a/src/3rdparty/expat/src/asciitab.h b/src/3rdparty/expat/src/asciitab.h new file mode 100644 index 00000000..af766fb2 --- /dev/null +++ b/src/3rdparty/expat/src/asciitab.h @@ -0,0 +1,66 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2017 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, + /* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, + /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, + /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, + /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, + /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, + /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, + /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, + /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, + /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, + /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, + /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, + /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, + /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, + /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, + /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, + /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, + /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/src/3rdparty/expat/src/expat.h b/src/3rdparty/expat/src/expat.h new file mode 100644 index 00000000..1c83563c --- /dev/null +++ b/src/3rdparty/expat/src/expat.h @@ -0,0 +1,1064 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2000-2005 Fred L. Drake, Jr. + Copyright (c) 2001-2002 Greg Stein + Copyright (c) 2002-2016 Karl Waclawek + Copyright (c) 2016-2022 Sebastian Pipping + Copyright (c) 2016 Cristian Rodríguez + Copyright (c) 2016 Thomas Beutlich + Copyright (c) 2017 Rhodri James + Copyright (c) 2022 Thijs Schreijer + Licensed under the MIT license: + + 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 Expat_INCLUDED +#define Expat_INCLUDED 1 + +#include +#include "expat_external.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool)1) +#define XML_FALSE ((XML_Bool)0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1, +#define XML_STATUS_OK XML_STATUS_OK + XML_STATUS_SUSPENDED = 2 +#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + /* Added in 1.95.7. */ + XML_ERROR_UNBOUND_PREFIX, + /* Added in 1.95.8. */ + XML_ERROR_UNDECLARING_PREFIX, + XML_ERROR_INCOMPLETE_PE, + XML_ERROR_XML_DECL, + XML_ERROR_TEXT_DECL, + XML_ERROR_PUBLICID, + XML_ERROR_SUSPENDED, + XML_ERROR_NOT_SUSPENDED, + XML_ERROR_ABORTED, + XML_ERROR_FINISHED, + XML_ERROR_SUSPEND_PE, + /* Added in 2.0. */ + XML_ERROR_RESERVED_PREFIX_XML, + XML_ERROR_RESERVED_PREFIX_XMLNS, + XML_ERROR_RESERVED_NAMESPACE_URI, + /* Added in 2.2.1. */ + XML_ERROR_INVALID_ARGUMENT, + /* Added in 2.3.0. */ + XML_ERROR_NO_BUFFER, + /* Added in 2.4.0. */ + XML_ERROR_AMPLIFICATION_LIMIT_BREACH +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char *name; + unsigned int numchildren; + XML_Content *children; +}; + +/* This is called for an element declaration. See above for + description of the model argument. It's the user code's responsibility + to free model when finished with it. See XML_FreeContentModel. + There is no need to free the model from the handler, it can be kept + around and freed at a later stage. +*/ +typedef void(XMLCALL *XML_ElementDeclHandler)(void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void(XMLCALL *XML_AttlistDeclHandler)( + void *userData, const XML_Char *elname, const XML_Char *attname, + const XML_Char *att_type, const XML_Char *dflt, int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void(XMLCALL *XML_XmlDeclHandler)(void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, XML_XmlDeclHandler xmldecl); + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + It is a programming error to use the separator '\0' with namespace + triplets (see XML_SetReturnNSTriplet). + If a namespace separator is chosen that can be part of a URI or + part of an XML name, splitting an expanded name back into its + 1, 2 or 3 original parts on application level in the element handler + may end up vulnerable, so these are advised against; sane choices for + a namespace separator are e.g. '\n' (line feed) and '|' (pipe). + + Note that Expat does not validate namespace URIs (beyond encoding) + against RFC 3986 today (and is not required to do so with regard to + the XML 1.0 namespaces specification) but it may start doing that + in future releases. Before that, an application using Expat must + be ready to receive namespace URIs containing non-URI characters. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionately high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void(XMLCALL *XML_StartElementHandler)(void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void(XMLCALL *XML_EndElementHandler)(void *userData, + const XML_Char *name); + +/* s is not 0 terminated. */ +typedef void(XMLCALL *XML_CharacterDataHandler)(void *userData, + const XML_Char *s, int len); + +/* target and data are 0 terminated */ +typedef void(XMLCALL *XML_ProcessingInstructionHandler)(void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void(XMLCALL *XML_CommentHandler)(void *userData, const XML_Char *data); + +typedef void(XMLCALL *XML_StartCdataSectionHandler)(void *userData); +typedef void(XMLCALL *XML_EndCdataSectionHandler)(void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void(XMLCALL *XML_DefaultHandler)(void *userData, const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void(XMLCALL *XML_StartDoctypeDeclHandler)(void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the end of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void(XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT null-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void(XMLCALL *XML_EntityDeclHandler)( + void *userData, const XML_Char *entityName, int is_parameter_entity, + const XML_Char *value, int value_length, const XML_Char *base, + const XML_Char *systemId, const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superseded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void(XMLCALL *XML_UnparsedEntityDeclHandler)( + void *userData, const XML_Char *entityName, const XML_Char *base, + const XML_Char *systemId, const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void(XMLCALL *XML_NotationDeclHandler)(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void(XMLCALL *XML_StartNamespaceDeclHandler)(void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void(XMLCALL *XML_EndNamespaceDeclHandler)(void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int(XMLCALL *XML_NotStandaloneHandler)(void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int(XMLCALL *XML_ExternalEntityRefHandler)(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void(XMLCALL *XML_SkippedEntityHandler)(void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int(XMLCALL *convert)(void *data, const char *s); + void(XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_ERROR_UNKNOWN_ENCODING error. +*/ +typedef int(XMLCALL *XML_UnknownEncodingHandler)(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser parser, XML_StartElementHandler handler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser parser, XML_EndElementHandler handler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: For the purpose of checking WFC: Entity Declared, passing + useDTD == XML_TRUE will make the parser behave as if the document + had a DTD with an external subset. + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. + Note: If parser == NULL, returns XML_ERROR_INVALID_ARGUMENT. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this corresponds to an index into the atts array passed to the + XML_StartElementHandler. Returns -1 if parser == NULL. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute or + parser == NULL. Each attribute/value pair counts as 2; thus this + corresponds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +#ifdef XML_ATTR_INFO +/* Source file byte offsets for the start and end of attribute names and values. + The value indices are exclusive of surrounding quotes; thus in a UTF-8 source + file an attribute value of "blah" will yield: + info->valueEnd - info->valueStart = 4 bytes. +*/ +typedef struct { + XML_Index nameStart; /* Offset to beginning of the attribute name. */ + XML_Index nameEnd; /* Offset after the attribute name's last byte. */ + XML_Index valueStart; /* Offset to beginning of the attribute value. */ + XML_Index valueEnd; /* Offset after the attribute value's last byte. */ +} XML_AttrInfo; + +/* Returns an array of XML_AttrInfo structures for the attribute/value pairs + passed in last call to the XML_StartElementHandler that were specified + in the start-tag rather than defaulted. Each attribute/value pair counts + as 1; thus the number of entries in the array is + XML_GetSpecifiedAttributeCount(parser) / 2. +*/ +XMLPARSEAPI(const XML_AttrInfo *) +XML_GetAttributeInfo(XML_Parser parser); +#endif + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. + Must be called from within a call-back handler, except when aborting + (resumable = 0) an already suspended parser. Some call-backs may + still follow because they would otherwise get lost. Examples: + - endElementHandler() for empty elements when stopped in + startElementHandler(), + - endNameSpaceDeclHandler() when stopped in endElementHandler(), + and possibly others. + + Can be called from most handlers, including DTD related call-backs, + except when parsing an external parameter entity and resumable != 0. + Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. + Possible error codes: + - XML_ERROR_SUSPENDED: when suspending an already suspended parser. + - XML_ERROR_FINISHED: when the parser has already finished. + - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. + + When resumable != 0 (true) then parsing is suspended, that is, + XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. + Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() + return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. + + *Note*: + This will be applied to the current parser instance only, that is, if + there is a parent parser then it will continue parsing when the + externalEntityRefHandler() returns. It is up to the implementation of + the externalEntityRefHandler() to call XML_StopParser() on the parent + parser (recursively), if one wants to stop parsing altogether. + + When suspended, parsing can be resumed by calling XML_ResumeParser(). +*/ +XMLPARSEAPI(enum XML_Status) +XML_StopParser(XML_Parser parser, XML_Bool resumable); + +/* Resumes parsing after it has been suspended with XML_StopParser(). + Must not be called from within a handler call-back. Returns same + status codes as XML_Parse() or XML_ParseBuffer(). + Additional error code XML_ERROR_NOT_SUSPENDED possible. + + *Note*: + This must be called on the most deeply nested child parser instance + first, and on its parent parser only after the child parser has finished, + to be applied recursively until the document entity's parser is restarted. + That is, the parent parser will not resume by itself and it is up to the + application to call XML_ResumeParser() on it at the appropriate moment. +*/ +XMLPARSEAPI(enum XML_Status) +XML_ResumeParser(XML_Parser parser); + +enum XML_Parsing { XML_INITIALIZED, XML_PARSING, XML_FINISHED, XML_SUSPENDED }; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; + +/* Returns status of parser with respect to being initialized, parsing, + finished, or suspended and processing the final buffer. + XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, + XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED +*/ +XMLPARSEAPI(void) +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. + Note: If parser == NULL, the function will do nothing and return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. + Note: If parser == NULL, the function will do nothing and return 0. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. + + Note: XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber + return 0 to indicate an error. + Note: XML_GetCurrentByteIndex returns -1 to indicate an error. +*/ +XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, int *offset, int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_ATTR_MALLOC +XML_ATTR_ALLOC_SIZE(2) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_ATTR_ALLOC_SIZE(3) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR, + XML_FEATURE_NS, + XML_FEATURE_LARGE_SIZE, + XML_FEATURE_ATTR_INFO, + /* Added in Expat 2.4.0. */ + XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT, + XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + +#ifdef XML_DTD +/* Added in Expat 2.4.0. */ +XMLPARSEAPI(XML_Bool) +XML_SetBillionLaughsAttackProtectionMaximumAmplification( + XML_Parser parser, float maximumAmplificationFactor); + +/* Added in Expat 2.4.0. */ +XMLPARSEAPI(XML_Bool) +XML_SetBillionLaughsAttackProtectionActivationThreshold( + XML_Parser parser, unsigned long long activationThresholdBytes); +#endif + +/* Expat follows the semantic versioning convention. + See http://semver.org. +*/ +#define XML_MAJOR_VERSION 2 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_INCLUDED */ diff --git a/src/3rdparty/expat/src/expat_config.h b/src/3rdparty/expat/src/expat_config.h new file mode 100644 index 00000000..ce774fa8 --- /dev/null +++ b/src/3rdparty/expat/src/expat_config.h @@ -0,0 +1,140 @@ +/* expat_config.h. Generated from expat_config.h.in by configure. */ +/* expat_config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef EXPAT_CONFIG_H +#define EXPAT_CONFIG_H 1 + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* 1234 = LILENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 1234 + +/* Define to 1 if you have the `arc4random' function. */ +/* #undef HAVE_ARC4RANDOM */ + +/* Define to 1 if you have the `arc4random_buf' function. */ +/* #undef HAVE_ARC4RANDOM_BUF */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `getrandom' function. */ +/* #undef HAVE_GETRANDOM */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `bsd' library (-lbsd). */ +/* #undef HAVE_LIBBSD */ + +/* Define to 1 if you have a working `mmap' system call. */ +/* #undef HAVE_MMAP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have `syscall' and `SYS_getrandom'. */ +/* #undef HAVE_SYSCALL_GETRANDOM */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "expat" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "expat-bugs@libexpat.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "expat" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "expat 2.5.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "expat" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.5.0" + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "2.5.0" + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define to allow retrieving the byte offsets for attribute names and values. + */ +#define XML_ATTR_INFO 1 + +/* Define to specify how much context to retain around the current parse + point. */ +#define XML_CONTEXT_BYTES 1024 + +/* Define to include code reading entropy from `/dev/urandom'. */ +/* #undef XML_DEV_URANDOM */ + +/* Define to make parameter entity parsing functionality available. */ +#define XML_DTD 1 + +/* Define to make XML Namespaces functionality available. */ +#define XML_NS 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +#endif // ndef EXPAT_CONFIG_H diff --git a/src/3rdparty/expat/src/expat_external.h b/src/3rdparty/expat/src/expat_external.h new file mode 100644 index 00000000..2d18decd --- /dev/null +++ b/src/3rdparty/expat/src/expat_external.h @@ -0,0 +1,165 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2000-2004 Fred L. Drake, Jr. + Copyright (c) 2001-2002 Greg Stein + Copyright (c) 2002-2006 Karl Waclawek + Copyright (c) 2016 Cristian Rodríguez + Copyright (c) 2016-2019 Sebastian Pipping + Copyright (c) 2017 Rhodri James + Copyright (c) 2018 Yury Gribov + Licensed under the MIT license: + + 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 Expat_External_INCLUDED +#define Expat_External_INCLUDED 1 + +/* External API definitions */ + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +# if defined(_MSC_VER) +# define XMLCALL __cdecl +# elif defined(__GNUC__) && defined(__i386) && ! defined(__INTEL_COMPILER) +# define XMLCALL __attribute__((cdecl)) +# else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +# define XMLCALL +# endif +#endif /* not defined XMLCALL */ + +#if ! defined(XML_STATIC) && ! defined(XMLIMPORT) +# ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +# if defined(_MSC_EXTENSIONS) && ! defined(__BEOS__) && ! defined(__CYGWIN__) +# define XMLIMPORT __declspec(dllimport) +# endif + +# endif +#endif /* not defined XML_STATIC */ + +#ifndef XML_ENABLE_VISIBILITY +# define XML_ENABLE_VISIBILITY 0 +#endif + +#if ! defined(XMLIMPORT) && XML_ENABLE_VISIBILITY +# define XMLIMPORT __attribute__((visibility("default"))) +#endif + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +# define XMLIMPORT +#endif + +#if defined(__GNUC__) \ + && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) +# define XML_ATTR_MALLOC __attribute__((__malloc__)) +#else +# define XML_ATTR_MALLOC +#endif + +#if defined(__GNUC__) \ + && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) +# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x))) +#else +# define XML_ATTR_ALLOC_SIZE(x) +#endif + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +# ifndef XML_UNICODE +# define XML_UNICODE +# endif +# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2) +# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc" +# endif +#endif + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +# ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +# else +typedef unsigned short XML_Char; +typedef char XML_LChar; +# endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ + +#if (defined _M_X64) || (defined __x86_64__) /* Use large integers for file/stream positions. */ +typedef long long XML_Index; +typedef unsigned long long XML_Size; +#else +typedef long XML_Index; +typedef unsigned long XML_Size; +#endif /* XML_LARGE_SIZE */ + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_External_INCLUDED */ diff --git a/src/3rdparty/expat/src/iasciitab.h b/src/3rdparty/expat/src/iasciitab.h new file mode 100644 index 00000000..5d8646f2 --- /dev/null +++ b/src/3rdparty/expat/src/iasciitab.h @@ -0,0 +1,67 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2017 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, + /* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, + /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, + /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, + /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, + /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, + /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, + /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, + /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, + /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, + /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, + /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, + /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, + /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, + /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, + /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, + /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, + /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/src/3rdparty/expat/src/internal.h b/src/3rdparty/expat/src/internal.h new file mode 100644 index 00000000..e09f533b --- /dev/null +++ b/src/3rdparty/expat/src/internal.h @@ -0,0 +1,165 @@ +/* internal.h + + Internal definitions used by Expat. This is not needed to compile + client code. + + The following calling convention macros are defined for frequently + called functions: + + FASTCALL - Used for those internal functions that have a simple + body and a low number of arguments and local variables. + + PTRCALL - Used for functions called though function pointers. + + PTRFASTCALL - Like PTRCALL, but for low number of arguments. + + inline - Used for selected internal functions for which inlining + may improve performance on some platforms. + + Note: Use of these macros is based on judgement, not hard rules, + and therefore subject to change. + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2002-2003 Fred L. Drake, Jr. + Copyright (c) 2002-2006 Karl Waclawek + Copyright (c) 2003 Greg Stein + Copyright (c) 2016-2022 Sebastian Pipping + Copyright (c) 2018 Yury Gribov + Copyright (c) 2019 David Loffredo + Licensed under the MIT license: + + 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. +*/ + +#if defined(__GNUC__) && defined(__i386__) && ! defined(__MINGW32__) +/* We'll use this version by default only where we know it helps. + + regparm() generates warnings on Solaris boxes. See SF bug #692878. + + Instability reported with egcs on a RedHat Linux 7.3. + Let's comment out: + #define FASTCALL __attribute__((stdcall, regparm(3))) + and let's try this: +*/ +# define FASTCALL __attribute__((regparm(3))) +# define PTRFASTCALL __attribute__((regparm(3))) +#endif + +/* Using __fastcall seems to have an unexpected negative effect under + MS VC++, especially for function pointers, so we won't use it for + now on that platform. It may be reconsidered for a future release + if it can be made more effective. + Likely reason: __fastcall on Windows is like stdcall, therefore + the compiler cannot perform stack optimizations for call clusters. +*/ + +/* Make sure all of these are defined if they aren't already. */ + +#ifndef FASTCALL +# define FASTCALL +#endif + +#ifndef PTRCALL +# define PTRCALL +#endif + +#ifndef PTRFASTCALL +# define PTRFASTCALL +#endif + +#ifndef XML_MIN_SIZE +# if ! defined(__cplusplus) && ! defined(inline) +# ifdef __GNUC__ +# define inline __inline +# endif /* __GNUC__ */ +# endif +#endif /* XML_MIN_SIZE */ + +#ifdef __cplusplus +# define inline inline +#else +# ifndef inline +# define inline +# endif +#endif + +#include // ULONG_MAX + +#if defined(_WIN32) \ + && (! defined(__USE_MINGW_ANSI_STDIO) \ + || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0)) +# define EXPAT_FMT_ULL(midpart) "%" midpart "I64u" +# if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW +# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d" +# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "I64u" +# else +# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d" +# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u" +# endif +#else +# define EXPAT_FMT_ULL(midpart) "%" midpart "llu" +# if ! defined(ULONG_MAX) +# error Compiler did not define ULONG_MAX for us +# elif ULONG_MAX == 18446744073709551615u // 2^64-1 +# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld" +# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu" +# else +# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d" +# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u" +# endif +#endif + +#ifndef UNUSED_P +# define UNUSED_P(p) (void)p +#endif + +/* NOTE BEGIN If you ever patch these defaults to greater values + for non-attack XML payload in your environment, + please file a bug report with libexpat. Thank you! +*/ +#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT \ + 100.0f +#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \ + 8388608 // 8 MiB, 2^23 +/* NOTE END */ + +#include "expat.h" // so we can use type XML_Parser below + +#ifdef __cplusplus +extern "C" { +#endif + +void _INTERNAL_trim_to_complete_utf8_characters(const char *from, + const char **fromLimRef); + +#if defined(XML_DTD) +unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser); +unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser); +const char *unsignedCharToPrintable(unsigned char c); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/3rdparty/expat/src/latin1tab.h b/src/3rdparty/expat/src/latin1tab.h new file mode 100644 index 00000000..b681d278 --- /dev/null +++ b/src/3rdparty/expat/src/latin1tab.h @@ -0,0 +1,66 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2017 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, + /* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, + /* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, + /* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, + /* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, + /* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, + /* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, + /* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff --git a/src/3rdparty/expat/src/nametab.h b/src/3rdparty/expat/src/nametab.h new file mode 100644 index 00000000..63485446 --- /dev/null +++ b/src/3rdparty/expat/src/nametab.h @@ -0,0 +1,136 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2000 Clark Cooper + Copyright (c) 2017 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +static const unsigned namingBitmap[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x04000000, + 0x87FFFFFE, 0x07FFFFFE, 0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, + 0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFE00F, 0xFC31FFFF, 0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, + 0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, 0xFFFF0003, 0xFFFFFFFF, + 0xFFFF199F, 0x033FCFFF, 0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, + 0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, 0x00000000, 0x07FFFFFE, + 0x000007FE, 0xFFFE0000, 0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, + 0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, 0xFFF99FE0, 0x03C5FDFF, + 0xB0000000, 0x00030003, 0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, + 0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, 0xFFF99FE0, 0x23CDFDFF, + 0xB0000000, 0x00000003, 0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, + 0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, 0xFFFDDFE0, 0x03EFFDFF, + 0x40000000, 0x00000003, 0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x000D7FFF, + 0x0000003F, 0x00000000, 0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, 0x0007DAED, 0x50000000, + 0x82315001, 0x002C62AB, 0x40000000, 0xF580C900, 0x00000007, 0x02010800, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0FFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0x03FFFFFF, 0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, + 0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, 0x00000000, 0x00004C40, + 0x00000000, 0x00000000, 0x00000007, 0x00000000, 0x00000000, 0x00000000, + 0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, 0x001FFFFF, 0xFFFFFFFE, + 0xFFFFFFFF, 0x07FFFFFF, 0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000F, + 0x00000000, 0x00000000, 0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, + 0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, 0x00FFFFFF, 0x00000000, + 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, 0xFFFFD7C0, 0xFFFFFFFB, + 0x547F7FFF, 0x000FFFFD, 0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, + 0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, 0x00000000, 0xFFFE0000, + 0x027FFFFF, 0xFFFFFFFE, 0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, + 0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, 0xFFFFFFFF, 0x7CFFFFFF, + 0xFFEF7FFF, 0x03FF3DFF, 0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, + 0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, 0xFFF987E4, 0xD36DFDFF, + 0x5E003987, 0x001FFFC0, 0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, + 0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, 0xD63DC7EC, 0xC3BFC718, + 0x00803DC7, 0x0000FF80, 0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, + 0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, 0xFFFDDFEC, 0xC3FFFDFF, + 0x00803DCF, 0x0000FFC3, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, 0xFEF02596, 0x3BFF6CAE, + 0x03FF3F5F, 0x00000000, 0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, + 0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, + 0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, 0x661FFFFF, 0xFFFFFFFE, + 0xFFFFFFFF, 0x77FFFFFF, +}; +static const unsigned char nmstrtPages[] = { + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char namePages[] = { + 0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, 0x00, 0x1F, 0x20, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, 0x26, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/3rdparty/expat/src/siphash.h b/src/3rdparty/expat/src/siphash.h new file mode 100644 index 00000000..303283ad --- /dev/null +++ b/src/3rdparty/expat/src/siphash.h @@ -0,0 +1,393 @@ +/* ========================================================================== + * siphash.h - SipHash-2-4 in a single header file + * -------------------------------------------------------------------------- + * Derived by William Ahern from the reference implementation[1] published[2] + * by Jean-Philippe Aumasson and Daniel J. Berstein. + * Minimal changes by Sebastian Pipping and Victor Stinner on top, see below. + * Licensed under the CC0 Public Domain Dedication license. + * + * 1. https://www.131002.net/siphash/siphash24.c + * 2. https://www.131002.net/siphash/ + * -------------------------------------------------------------------------- + * HISTORY: + * + * 2020-10-03 (Sebastian Pipping) + * - Drop support for Visual Studio 9.0/2008 and earlier + * + * 2019-08-03 (Sebastian Pipping) + * - Mark part of sip24_valid as to be excluded from clang-format + * - Re-format code using clang-format 9 + * + * 2018-07-08 (Anton Maklakov) + * - Add "fall through" markers for GCC's -Wimplicit-fallthrough + * + * 2017-11-03 (Sebastian Pipping) + * - Hide sip_tobin and sip_binof unless SIPHASH_TOBIN macro is defined + * + * 2017-07-25 (Vadim Zeitlin) + * - Fix use of SIPHASH_MAIN macro + * + * 2017-07-05 (Sebastian Pipping) + * - Use _SIP_ULL macro to not require a C++11 compiler if compiled as C++ + * - Add const qualifiers at two places + * - Ensure <=80 characters line length (assuming tab width 4) + * + * 2017-06-23 (Victor Stinner) + * - Address Win64 compile warnings + * + * 2017-06-18 (Sebastian Pipping) + * - Clarify license note in the header + * - Address C89 issues: + * - Stop using inline keyword (and let compiler decide) + * - Replace _Bool by int + * - Turn macro siphash24 into a function + * - Address invalid conversion (void pointer) by explicit cast + * - Address lack of stdint.h for Visual Studio 2003 to 2008 + * - Always expose sip24_valid (for self-tests) + * + * 2012-11-04 - Born. (William Ahern) + * -------------------------------------------------------------------------- + * USAGE: + * + * SipHash-2-4 takes as input two 64-bit words as the key, some number of + * message bytes, and outputs a 64-bit word as the message digest. This + * implementation employs two data structures: a struct sipkey for + * representing the key, and a struct siphash for representing the hash + * state. + * + * For converting a 16-byte unsigned char array to a key, use either the + * macro sip_keyof or the routine sip_tokey. The former instantiates a + * compound literal key, while the latter requires a key object as a + * parameter. + * + * unsigned char secret[16]; + * arc4random_buf(secret, sizeof secret); + * struct sipkey *key = sip_keyof(secret); + * + * For hashing a message, use either the convenience macro siphash24 or the + * routines sip24_init, sip24_update, and sip24_final. + * + * struct siphash state; + * void *msg; + * size_t len; + * uint64_t hash; + * + * sip24_init(&state, key); + * sip24_update(&state, msg, len); + * hash = sip24_final(&state); + * + * or + * + * hash = siphash24(msg, len, key); + * + * To convert the 64-bit hash value to a canonical 8-byte little-endian + * binary representation, use either the macro sip_binof or the routine + * sip_tobin. The former instantiates and returns a compound literal array, + * while the latter requires an array object as a parameter. + * -------------------------------------------------------------------------- + * NOTES: + * + * o Neither sip_keyof, sip_binof, nor siphash24 will work with compilers + * lacking compound literal support. Instead, you must use the lower-level + * interfaces which take as parameters the temporary state objects. + * + * o Uppercase macros may evaluate parameters more than once. Lowercase + * macros should not exhibit any such side effects. + * ========================================================================== + */ +#ifndef SIPHASH_H +#define SIPHASH_H + +#include /* size_t */ +#include /* uint64_t uint32_t uint8_t */ + +/* + * Workaround to not require a C++11 compiler for using ULL suffix + * if this code is included and compiled as C++; related GCC warning is: + * warning: use of C++11 long long integer constant [-Wlong-long] + */ +#define _SIP_ULL(high, low) ((((uint64_t)high) << 32) | (low)) + +#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define SIP_U32TO8_LE(p, v) \ + (p)[0] = (uint8_t)((v) >> 0); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); + +#define SIP_U64TO8_LE(p, v) \ + SIP_U32TO8_LE((p) + 0, (uint32_t)((v) >> 0)); \ + SIP_U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); + +#define SIP_U8TO64_LE(p) \ + (((uint64_t)((p)[0]) << 0) | ((uint64_t)((p)[1]) << 8) \ + | ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) \ + | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) \ + | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) + +#define SIPHASH_INITIALIZER \ + { 0, 0, 0, 0, {0}, 0, 0 } + +struct siphash { + uint64_t v0, v1, v2, v3; + + unsigned char buf[8], *p; + uint64_t c; +}; /* struct siphash */ + +#define SIP_KEYLEN 16 + +struct sipkey { + uint64_t k[2]; +}; /* struct sipkey */ + +#define sip_keyof(k) sip_tokey(&(struct sipkey){{0}}, (k)) + +static struct sipkey * +sip_tokey(struct sipkey *key, const void *src) { + key->k[0] = SIP_U8TO64_LE((const unsigned char *)src); + key->k[1] = SIP_U8TO64_LE((const unsigned char *)src + 8); + return key; +} /* sip_tokey() */ + +#ifdef SIPHASH_TOBIN + +# define sip_binof(v) sip_tobin((unsigned char[8]){0}, (v)) + +static void * +sip_tobin(void *dst, uint64_t u64) { + SIP_U64TO8_LE((unsigned char *)dst, u64); + return dst; +} /* sip_tobin() */ + +#endif /* SIPHASH_TOBIN */ + +static void +sip_round(struct siphash *H, const int rounds) { + int i; + + for (i = 0; i < rounds; i++) { + H->v0 += H->v1; + H->v1 = SIP_ROTL(H->v1, 13); + H->v1 ^= H->v0; + H->v0 = SIP_ROTL(H->v0, 32); + + H->v2 += H->v3; + H->v3 = SIP_ROTL(H->v3, 16); + H->v3 ^= H->v2; + + H->v0 += H->v3; + H->v3 = SIP_ROTL(H->v3, 21); + H->v3 ^= H->v0; + + H->v2 += H->v1; + H->v1 = SIP_ROTL(H->v1, 17); + H->v1 ^= H->v2; + H->v2 = SIP_ROTL(H->v2, 32); + } +} /* sip_round() */ + +static struct siphash * +sip24_init(struct siphash *H, const struct sipkey *key) { + H->v0 = _SIP_ULL(0x736f6d65U, 0x70736575U) ^ key->k[0]; + H->v1 = _SIP_ULL(0x646f7261U, 0x6e646f6dU) ^ key->k[1]; + H->v2 = _SIP_ULL(0x6c796765U, 0x6e657261U) ^ key->k[0]; + H->v3 = _SIP_ULL(0x74656462U, 0x79746573U) ^ key->k[1]; + + H->p = H->buf; + H->c = 0; + + return H; +} /* sip24_init() */ + +#define sip_endof(a) (&(a)[sizeof(a) / sizeof *(a)]) + +static struct siphash * +sip24_update(struct siphash *H, const void *src, size_t len) { + const unsigned char *p = (const unsigned char *)src, *pe = p + len; + uint64_t m; + + do { + while (p < pe && H->p < sip_endof(H->buf)) + *H->p++ = *p++; + + if (H->p < sip_endof(H->buf)) + break; + + m = SIP_U8TO64_LE(H->buf); + H->v3 ^= m; + sip_round(H, 2); + H->v0 ^= m; + + H->p = H->buf; + H->c += 8; + } while (p < pe); + + return H; +} /* sip24_update() */ + +static uint64_t +sip24_final(struct siphash *H) { + const char left = (char)(H->p - H->buf); + uint64_t b = (H->c + left) << 56; + + switch (left) { + case 7: + b |= (uint64_t)H->buf[6] << 48; + /* fall through */ + case 6: + b |= (uint64_t)H->buf[5] << 40; + /* fall through */ + case 5: + b |= (uint64_t)H->buf[4] << 32; + /* fall through */ + case 4: + b |= (uint64_t)H->buf[3] << 24; + /* fall through */ + case 3: + b |= (uint64_t)H->buf[2] << 16; + /* fall through */ + case 2: + b |= (uint64_t)H->buf[1] << 8; + /* fall through */ + case 1: + b |= (uint64_t)H->buf[0] << 0; + /* fall through */ + case 0: + break; + } + + H->v3 ^= b; + sip_round(H, 2); + H->v0 ^= b; + H->v2 ^= 0xff; + sip_round(H, 4); + + return H->v0 ^ H->v1 ^ H->v2 ^ H->v3; +} /* sip24_final() */ + +static uint64_t +siphash24(const void *src, size_t len, const struct sipkey *key) { + struct siphash state = SIPHASH_INITIALIZER; + return sip24_final(sip24_update(sip24_init(&state, key), src, len)); +} /* siphash24() */ + +/* + * SipHash-2-4 output with + * k = 00 01 02 ... + * and + * in = (empty string) + * in = 00 (1 byte) + * in = 00 01 (2 bytes) + * in = 00 01 02 (3 bytes) + * ... + * in = 00 01 02 ... 3e (63 bytes) + */ +static int +sip24_valid(void) { + /* clang-format off */ + static const unsigned char vectors[64][8] = { + { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, }, + { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, }, + { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, }, + { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, }, + { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, }, + { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, }, + { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, }, + { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, }, + { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, }, + { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, }, + { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, }, + { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, }, + { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, }, + { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, }, + { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, }, + { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, }, + { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, }, + { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, }, + { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, }, + { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, }, + { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, }, + { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, }, + { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, }, + { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, }, + { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, }, + { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, }, + { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, }, + { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, }, + { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, }, + { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, }, + { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, }, + { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, }, + { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, }, + { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, }, + { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, }, + { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, }, + { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, }, + { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, }, + { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, }, + { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, }, + { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, }, + { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, }, + { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, }, + { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, }, + { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, }, + { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, }, + { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, }, + { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, }, + { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, }, + { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, }, + { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, }, + { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, }, + { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, }, + { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, }, + { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, }, + { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, }, + { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, }, + { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, }, + { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, }, + { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, }, + { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, }, + { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, }, + { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, }, + { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } + }; + /* clang-format on */ + + unsigned char in[64]; + struct sipkey k; + size_t i; + + sip_tokey(&k, "\000\001\002\003\004\005\006\007\010\011" + "\012\013\014\015\016\017"); + + for (i = 0; i < sizeof in; ++i) { + in[i] = (unsigned char)i; + + if (siphash24(in, i, &k) != SIP_U8TO64_LE(vectors[i])) + return 0; + } + + return 1; +} /* sip24_valid() */ + +#ifdef SIPHASH_MAIN + +# include + +int +main(void) { + const int ok = sip24_valid(); + + if (ok) + puts("OK"); + else + puts("FAIL"); + + return ! ok; +} /* main() */ + +#endif /* SIPHASH_MAIN */ + +#endif /* SIPHASH_H */ diff --git a/src/3rdparty/expat/src/utf8tab.h b/src/3rdparty/expat/src/utf8tab.h new file mode 100644 index 00000000..88efcf91 --- /dev/null +++ b/src/3rdparty/expat/src/utf8tab.h @@ -0,0 +1,66 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2017 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, + /* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, + /* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, + /* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, + /* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, + /* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, + /* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, + /* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, + /* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff --git a/src/3rdparty/expat/src/winconfig.h b/src/3rdparty/expat/src/winconfig.h new file mode 100644 index 00000000..2ecd61b5 --- /dev/null +++ b/src/3rdparty/expat/src/winconfig.h @@ -0,0 +1,45 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Greg Stein + Copyright (c) 2005 Karl Waclawek + Copyright (c) 2017-2021 Sebastian Pipping + Licensed under the MIT license: + + 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 WINCONFIG_H +#define WINCONFIG_H + +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN + +#include +#include + +#endif /* ndef WINCONFIG_H */ diff --git a/src/3rdparty/expat/src/xmlparse.c b/src/3rdparty/expat/src/xmlparse.c new file mode 100644 index 00000000..b6c2eca9 --- /dev/null +++ b/src/3rdparty/expat/src/xmlparse.c @@ -0,0 +1,8404 @@ +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2000-2006 Fred L. Drake, Jr. + Copyright (c) 2001-2002 Greg Stein + Copyright (c) 2002-2016 Karl Waclawek + Copyright (c) 2005-2009 Steven Solie + Copyright (c) 2016 Eric Rahm + Copyright (c) 2016-2022 Sebastian Pipping + Copyright (c) 2016 Gaurav + Copyright (c) 2016 Thomas Beutlich + Copyright (c) 2016 Gustavo Grieco + Copyright (c) 2016 Pascal Cuoq + Copyright (c) 2016 Ed Schouten + Copyright (c) 2017-2022 Rhodri James + Copyright (c) 2017 Václav Slavík + Copyright (c) 2017 Viktor Szakats + Copyright (c) 2017 Chanho Park + Copyright (c) 2017 Rolf Eike Beer + Copyright (c) 2017 Hans Wennborg + Copyright (c) 2018 Anton Maklakov + Copyright (c) 2018 Benjamin Peterson + Copyright (c) 2018 Marco Maggi + Copyright (c) 2018 Mariusz Zaborski + Copyright (c) 2019 David Loffredo + Copyright (c) 2019-2020 Ben Wagner + Copyright (c) 2019 Vadim Zeitlin + Copyright (c) 2021 Dong-hee Na + Copyright (c) 2022 Samanta Navarro + Copyright (c) 2022 Jeffrey Walton + Copyright (c) 2022 Jann Horn + Licensed under the MIT license: + + 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. +*/ + +#define XML_BUILDING_EXPAT 1 + +#include + +#if ! defined(_GNU_SOURCE) +# define _GNU_SOURCE 1 /* syscall prototype */ +#endif + +#ifdef _WIN32 +/* force stdlib to define rand_s() */ +# if ! defined(_CRT_RAND_S) +# define _CRT_RAND_S +# endif +#endif + +#include +#include /* memset(), memcpy() */ +#include +#include /* UINT_MAX */ +#include /* fprintf */ +#include /* getenv, rand_s */ +#include /* uintptr_t */ +#include /* isnan */ + +#ifdef _WIN32 +# define getpid GetCurrentProcessId +#else +# include /* gettimeofday() */ +# include /* getpid() */ +# include /* getpid() */ +# include /* O_RDONLY */ +# include +#endif + +#ifdef _WIN32 +# include "winconfig.h" +#endif + +#include "ascii.h" +#include "expat.h" +#include "siphash.h" + +#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) +# if defined(HAVE_GETRANDOM) +# include /* getrandom */ +# else +# include /* syscall */ +# include /* SYS_getrandom */ +# endif +# if ! defined(GRND_NONBLOCK) +# define GRND_NONBLOCK 0x0001 +# endif /* defined(GRND_NONBLOCK) */ +#endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */ + +#if defined(HAVE_LIBBSD) \ + && (defined(HAVE_ARC4RANDOM_BUF) || defined(HAVE_ARC4RANDOM)) +# include +#endif + +#if defined(_WIN32) && ! defined(LOAD_LIBRARY_SEARCH_SYSTEM32) +# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif + +#if ! defined(HAVE_GETRANDOM) && ! defined(HAVE_SYSCALL_GETRANDOM) \ + && ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) \ + && ! defined(XML_DEV_URANDOM) && ! defined(_WIN32) \ + && ! defined(XML_POOR_ENTROPY) +# error You do not have support for any sources of high quality entropy \ + enabled. For end user security, that is probably not what you want. \ + \ + Your options include: \ + * Linux >=3.17 + glibc >=2.25 (getrandom): HAVE_GETRANDOM, \ + * Linux >=3.17 + glibc (including <2.25) (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \ + * BSD / macOS >=10.7 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \ + * BSD / macOS (including <10.7) (arc4random): HAVE_ARC4RANDOM, \ + * libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \ + * libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \ + * Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \ + * Windows >=Vista (rand_s): _WIN32. \ + \ + If insist on not using any of these, bypass this error by defining \ + XML_POOR_ENTROPY; you have been warned. \ + \ + If you have reasons to patch this detection code away or need changes \ + to the build system, please open a bug. Thank you! +#endif + +#ifdef XML_UNICODE +# define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX +# define XmlConvert XmlUtf16Convert +# define XmlGetInternalEncoding XmlGetUtf16InternalEncoding +# define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS +# define XmlEncode XmlUtf16Encode +# define MUST_CONVERT(enc, s) (! (enc)->isUtf16 || (((uintptr_t)(s)) & 1)) +typedef unsigned short ICHAR; +#else +# define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX +# define XmlConvert XmlUtf8Convert +# define XmlGetInternalEncoding XmlGetUtf8InternalEncoding +# define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS +# define XmlEncode XmlUtf8Encode +# define MUST_CONVERT(enc, s) (! (enc)->isUtf8) +typedef char ICHAR; +#endif + +#ifndef XML_NS + +# define XmlInitEncodingNS XmlInitEncoding +# define XmlInitUnknownEncodingNS XmlInitUnknownEncoding +# undef XmlGetInternalEncodingNS +# define XmlGetInternalEncodingNS XmlGetInternalEncoding +# define XmlParseXmlDeclNS XmlParseXmlDecl + +#endif + +#ifdef XML_UNICODE + +# ifdef XML_UNICODE_WCHAR_T +# define XML_T(x) (const wchar_t) x +# define XML_L(x) L##x +# else +# define XML_T(x) (const unsigned short)x +# define XML_L(x) x +# endif + +#else + +# define XML_T(x) x +# define XML_L(x) x + +#endif + +/* Round up n to be a multiple of sz, where sz is a power of 2. */ +#define ROUND_UP(n, sz) (((n) + ((sz)-1)) & ~((sz)-1)) + +/* Do safe (NULL-aware) pointer arithmetic */ +#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0) + +#include "internal.h" +#include "xmltok.h" +#include "xmlrole.h" + +typedef const XML_Char *KEY; + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + unsigned char power; + size_t size; + size_t used; + const XML_Memory_Handling_Suite *mem; +} HASH_TABLE; + +static size_t keylen(KEY s); + +static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key); + +/* For probing (after a collision) we need a step size relative prime + to the hash table size, which is a power of 2. We use double-hashing, + since we can calculate a second hash value cheaply by taking those bits + of the first hash value that were discarded (masked out) when the table + index was calculated: index = hash & mask, where mask = table->size - 1. + We limit the maximum step size to table->size / 4 (mask >> 2) and make + it odd, since odd numbers are always relative prime to a power of 2. +*/ +#define SECOND_HASH(hash, mask, power) \ + ((((hash) & ~(mask)) >> ((power)-1)) & ((mask) >> 2)) +#define PROBE_STEP(hash, mask, power) \ + ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ +#define INIT_DATA_BUF_SIZE 1024 +#define INIT_ATTS_SIZE 16 +#define INIT_ATTS_VERSION 0xFFFFFFFF +#define INIT_BLOCK_SIZE 1024 +#define INIT_BUFFER_SIZE 1024 + +#define EXPAND_SPARE 24 + +typedef struct binding { + struct prefix *prefix; + struct binding *nextTagBinding; + struct binding *prevPrefixBinding; + const struct attribute_id *attId; + XML_Char *uri; + int uriLen; + int uriAlloc; +} BINDING; + +typedef struct prefix { + const XML_Char *name; + BINDING *binding; +} PREFIX; + +typedef struct { + const XML_Char *str; + const XML_Char *localPart; + const XML_Char *prefix; + int strLen; + int uriLen; + int prefixLen; +} TAG_NAME; + +/* TAG represents an open element. + The name of the element is stored in both the document and API + encodings. The memory buffer 'buf' is a separately-allocated + memory area which stores the name. During the XML_Parse()/ + XMLParseBuffer() when the element is open, the memory for the 'raw' + version of the name (in the document encoding) is shared with the + document buffer. If the element is open across calls to + XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to + contain the 'raw' name as well. + + A parser re-uses these structures, maintaining a list of allocated + TAG objects in a free list. +*/ +typedef struct tag { + struct tag *parent; /* parent of this element */ + const char *rawName; /* tagName in the original encoding */ + int rawNameLength; + TAG_NAME name; /* tagName in the API encoding */ + char *buf; /* buffer for name components */ + char *bufEnd; /* end of the buffer */ + BINDING *bindings; +} TAG; + +typedef struct { + const XML_Char *name; + const XML_Char *textPtr; + int textLen; /* length in XML_Chars */ + int processed; /* # of processed bytes - when suspended */ + const XML_Char *systemId; + const XML_Char *base; + const XML_Char *publicId; + const XML_Char *notation; + XML_Bool open; + XML_Bool is_param; + XML_Bool is_internal; /* true if declared in internal subset outside PE */ +} ENTITY; + +typedef struct { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char *name; + int firstchild; + int lastchild; + int childcnt; + int nextsib; +} CONTENT_SCAFFOLD; + +#define INIT_SCAFFOLD_ELEMENTS 32 + +typedef struct block { + struct block *next; + int size; + XML_Char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + BLOCK *freeBlocks; + const XML_Char *end; + XML_Char *ptr; + XML_Char *start; + const XML_Memory_Handling_Suite *mem; +} STRING_POOL; + +/* The XML_Char before the name is used to determine whether + an attribute has been specified. */ +typedef struct attribute_id { + XML_Char *name; + PREFIX *prefix; + XML_Bool maybeTokenized; + XML_Bool xmlns; +} ATTRIBUTE_ID; + +typedef struct { + const ATTRIBUTE_ID *id; + XML_Bool isCdata; + const XML_Char *value; +} DEFAULT_ATTRIBUTE; + +typedef struct { + unsigned long version; + unsigned long hash; + const XML_Char *uriName; +} NS_ATT; + +typedef struct { + const XML_Char *name; + PREFIX *prefix; + const ATTRIBUTE_ID *idAtt; + int nDefaultAtts; + int allocDefaultAtts; + DEFAULT_ATTRIBUTE *defaultAtts; +} ELEMENT_TYPE; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE elementTypes; + HASH_TABLE attributeIds; + HASH_TABLE prefixes; + STRING_POOL pool; + STRING_POOL entityValuePool; + /* false once a parameter entity reference has been skipped */ + XML_Bool keepProcessing; + /* true once an internal or external PE reference has been encountered; + this includes the reference to an external subset */ + XML_Bool hasParamEntityRefs; + XML_Bool standalone; +#ifdef XML_DTD + /* indicates if external PE has been read */ + XML_Bool paramEntityRead; + HASH_TABLE paramEntities; +#endif /* XML_DTD */ + PREFIX defaultPrefix; + /* === scaffolding for building content model === */ + XML_Bool in_eldecl; + CONTENT_SCAFFOLD *scaffold; + unsigned contentStringLen; + unsigned scaffSize; + unsigned scaffCount; + int scaffLevel; + int *scaffIndex; +} DTD; + +typedef struct open_internal_entity { + const char *internalEventPtr; + const char *internalEventEndPtr; + struct open_internal_entity *next; + ENTITY *entity; + int startTagLevel; + XML_Bool betweenDecl; /* WFC: PE Between Declarations */ +} OPEN_INTERNAL_ENTITY; + +enum XML_Account { + XML_ACCOUNT_DIRECT, /* bytes directly passed to the Expat parser */ + XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity + expansion */ + XML_ACCOUNT_NONE /* i.e. do not account, was accounted already */ +}; + +#ifdef XML_DTD +typedef unsigned long long XmlBigCount; +typedef struct accounting { + XmlBigCount countBytesDirect; + XmlBigCount countBytesIndirect; + int debugLevel; + float maximumAmplificationFactor; // >=1.0 + unsigned long long activationThresholdBytes; +} ACCOUNTING; + +typedef struct entity_stats { + unsigned int countEverOpened; + unsigned int currentDepth; + unsigned int maximumDepthSeen; + int debugLevel; +} ENTITY_STATS; +#endif /* XML_DTD */ + +typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start, + const char *end, const char **endPtr); + +static Processor prologProcessor; +static Processor prologInitProcessor; +static Processor contentProcessor; +static Processor cdataSectionProcessor; +#ifdef XML_DTD +static Processor ignoreSectionProcessor; +static Processor externalParEntProcessor; +static Processor externalParEntInitProcessor; +static Processor entityValueProcessor; +static Processor entityValueInitProcessor; +#endif /* XML_DTD */ +static Processor epilogProcessor; +static Processor errorProcessor; +static Processor externalEntityInitProcessor; +static Processor externalEntityInitProcessor2; +static Processor externalEntityInitProcessor3; +static Processor externalEntityContentProcessor; +static Processor internalEntityProcessor; + +static enum XML_Error handleUnknownEncoding(XML_Parser parser, + const XML_Char *encodingName); +static enum XML_Error processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next); +static enum XML_Error initializeEncoding(XML_Parser parser); +static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc, + const char *s, const char *end, int tok, + const char *next, const char **nextPtr, + XML_Bool haveMore, XML_Bool allowClosingDoctype, + enum XML_Account account); +static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity, + XML_Bool betweenDecl); +static enum XML_Error doContent(XML_Parser parser, int startTagLevel, + const ENCODING *enc, const char *start, + const char *end, const char **endPtr, + XML_Bool haveMore, enum XML_Account account); +static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *, + const char **startPtr, const char *end, + const char **nextPtr, XML_Bool haveMore, + enum XML_Account account); +#ifdef XML_DTD +static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *, + const char **startPtr, const char *end, + const char **nextPtr, XML_Bool haveMore); +#endif /* XML_DTD */ + +static void freeBindings(XML_Parser parser, BINDING *bindings); +static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, + const char *s, TAG_NAME *tagNamePtr, + BINDING **bindingsPtr, + enum XML_Account account); +static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix, + const ATTRIBUTE_ID *attId, const XML_Char *uri, + BINDING **bindingsPtr); +static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, + XML_Bool isId, const XML_Char *dfltValue, + XML_Parser parser); +static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *, + XML_Bool isCdata, const char *, + const char *, STRING_POOL *, + enum XML_Account account); +static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *, + XML_Bool isCdata, const char *, + const char *, STRING_POOL *, + enum XML_Account account); +static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end); +static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); +static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end, + enum XML_Account account); +static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end); +static int reportComment(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end); +static void reportDefault(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end); + +static const XML_Char *getContext(XML_Parser parser); +static XML_Bool setContext(XML_Parser parser, const XML_Char *context); + +static void FASTCALL normalizePublicId(XML_Char *s); + +static DTD *dtdCreate(const XML_Memory_Handling_Suite *ms); +/* do not call if m_parentParser != NULL */ +static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); +static void dtdDestroy(DTD *p, XML_Bool isDocEntity, + const XML_Memory_Handling_Suite *ms); +static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, + const XML_Memory_Handling_Suite *ms); +static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *, STRING_POOL *, + const HASH_TABLE *); +static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, + size_t createSize); +static void FASTCALL hashTableInit(HASH_TABLE *, + const XML_Memory_Handling_Suite *ms); +static void FASTCALL hashTableClear(HASH_TABLE *); +static void FASTCALL hashTableDestroy(HASH_TABLE *); +static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *); + +static void FASTCALL poolInit(STRING_POOL *, + const XML_Memory_Handling_Suite *ms); +static void FASTCALL poolClear(STRING_POOL *); +static void FASTCALL poolDestroy(STRING_POOL *); +static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); +static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool, + const XML_Char *s); +static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, + int n); +static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool, + const XML_Char *s); + +static int FASTCALL nextScaffoldPart(XML_Parser parser); +static XML_Content *build_model(XML_Parser parser); +static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc, + const char *ptr, const char *end); + +static XML_Char *copyString(const XML_Char *s, + const XML_Memory_Handling_Suite *memsuite); + +static unsigned long generate_hash_secret_salt(XML_Parser parser); +static XML_Bool startParsing(XML_Parser parser); + +static XML_Parser parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep, DTD *dtd); + +static void parserInit(XML_Parser parser, const XML_Char *encodingName); + +#ifdef XML_DTD +static float accountingGetCurrentAmplification(XML_Parser rootParser); +static void accountingReportStats(XML_Parser originParser, const char *epilog); +static void accountingOnAbort(XML_Parser originParser); +static void accountingReportDiff(XML_Parser rootParser, + unsigned int levelsAwayFromRootParser, + const char *before, const char *after, + ptrdiff_t bytesMore, int source_line, + enum XML_Account account); +static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok, + const char *before, const char *after, + int source_line, + enum XML_Account account); + +static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity, + const char *action, int sourceLine); +static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity, + int sourceLine); +static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity, + int sourceLine); + +static XML_Parser getRootParserOf(XML_Parser parser, + unsigned int *outLevelDiff); +#endif /* XML_DTD */ + +static unsigned long getDebugLevel(const char *variableName, + unsigned long defaultDebugLevel); + +#define poolStart(pool) ((pool)->start) +#define poolEnd(pool) ((pool)->ptr) +#define poolLength(pool) ((pool)->ptr - (pool)->start) +#define poolChop(pool) ((void)--(pool->ptr)) +#define poolLastChar(pool) (((pool)->ptr)[-1]) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) +#define poolAppendChar(pool, c) \ + (((pool)->ptr == (pool)->end && ! poolGrow(pool)) \ + ? 0 \ + : ((*((pool)->ptr)++ = c), 1)) + +struct XML_ParserStruct { + /* The first member must be m_userData so that the XML_GetUserData + macro works. */ + void *m_userData; + void *m_handlerArg; + char *m_buffer; + const XML_Memory_Handling_Suite m_mem; + /* first character to be parsed */ + const char *m_bufferPtr; + /* past last character to be parsed */ + char *m_bufferEnd; + /* allocated end of m_buffer */ + const char *m_bufferLim; + XML_Index m_parseEndByteIndex; + const char *m_parseEndPtr; + XML_Char *m_dataBuf; + XML_Char *m_dataBufEnd; + XML_StartElementHandler m_startElementHandler; + XML_EndElementHandler m_endElementHandler; + XML_CharacterDataHandler m_characterDataHandler; + XML_ProcessingInstructionHandler m_processingInstructionHandler; + XML_CommentHandler m_commentHandler; + XML_StartCdataSectionHandler m_startCdataSectionHandler; + XML_EndCdataSectionHandler m_endCdataSectionHandler; + XML_DefaultHandler m_defaultHandler; + XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; + XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; + XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; + XML_NotationDeclHandler m_notationDeclHandler; + XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; + XML_NotStandaloneHandler m_notStandaloneHandler; + XML_ExternalEntityRefHandler m_externalEntityRefHandler; + XML_Parser m_externalEntityRefHandlerArg; + XML_SkippedEntityHandler m_skippedEntityHandler; + XML_UnknownEncodingHandler m_unknownEncodingHandler; + XML_ElementDeclHandler m_elementDeclHandler; + XML_AttlistDeclHandler m_attlistDeclHandler; + XML_EntityDeclHandler m_entityDeclHandler; + XML_XmlDeclHandler m_xmlDeclHandler; + const ENCODING *m_encoding; + INIT_ENCODING m_initEncoding; + const ENCODING *m_internalEncoding; + const XML_Char *m_protocolEncodingName; + XML_Bool m_ns; + XML_Bool m_ns_triplets; + void *m_unknownEncodingMem; + void *m_unknownEncodingData; + void *m_unknownEncodingHandlerData; + void(XMLCALL *m_unknownEncodingRelease)(void *); + PROLOG_STATE m_prologState; + Processor *m_processor; + enum XML_Error m_errorCode; + const char *m_eventPtr; + const char *m_eventEndPtr; + const char *m_positionPtr; + OPEN_INTERNAL_ENTITY *m_openInternalEntities; + OPEN_INTERNAL_ENTITY *m_freeInternalEntities; + XML_Bool m_defaultExpandInternalEntities; + int m_tagLevel; + ENTITY *m_declEntity; + const XML_Char *m_doctypeName; + const XML_Char *m_doctypeSysid; + const XML_Char *m_doctypePubid; + const XML_Char *m_declAttributeType; + const XML_Char *m_declNotationName; + const XML_Char *m_declNotationPublicId; + ELEMENT_TYPE *m_declElementType; + ATTRIBUTE_ID *m_declAttributeId; + XML_Bool m_declAttributeIsCdata; + XML_Bool m_declAttributeIsId; + DTD *m_dtd; + const XML_Char *m_curBase; + TAG *m_tagStack; + TAG *m_freeTagList; + BINDING *m_inheritedBindings; + BINDING *m_freeBindingList; + int m_attsSize; + int m_nSpecifiedAtts; + int m_idAttIndex; + ATTRIBUTE *m_atts; + NS_ATT *m_nsAtts; + unsigned long m_nsAttsVersion; + unsigned char m_nsAttsPower; +#ifdef XML_ATTR_INFO + XML_AttrInfo *m_attInfo; +#endif + POSITION m_position; + STRING_POOL m_tempPool; + STRING_POOL m_temp2Pool; + char *m_groupConnector; + unsigned int m_groupSize; + XML_Char m_namespaceSeparator; + XML_Parser m_parentParser; + XML_ParsingStatus m_parsingStatus; +#ifdef XML_DTD + XML_Bool m_isParamEntity; + XML_Bool m_useForeignDTD; + enum XML_ParamEntityParsing m_paramEntityParsing; +#endif + unsigned long m_hash_secret_salt; +#ifdef XML_DTD + ACCOUNTING m_accounting; + ENTITY_STATS m_entity_stats; +#endif +}; + +#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) +#define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s))) +#define FREE(parser, p) (parser->m_mem.free_fcn((p))) + +XML_Parser XMLCALL +XML_ParserCreate(const XML_Char *encodingName) { + return XML_ParserCreate_MM(encodingName, NULL, NULL); +} + +XML_Parser XMLCALL +XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) { + XML_Char tmp[2] = {nsSep, 0}; + return XML_ParserCreate_MM(encodingName, NULL, tmp); +} + +// "xml=http://www.w3.org/XML/1998/namespace" +static const XML_Char implicitContext[] + = {ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, + ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, + ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, + ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, + ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, + ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, + ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e, + ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, + '\0'}; + +/* To avoid warnings about unused functions: */ +#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) + +# if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) + +/* Obtain entropy on Linux 3.17+ */ +static int +writeRandomBytes_getrandom_nonblock(void *target, size_t count) { + int success = 0; /* full count bytes written? */ + size_t bytesWrittenTotal = 0; + const unsigned int getrandomFlags = GRND_NONBLOCK; + + do { + void *const currentTarget = (void *)((char *)target + bytesWrittenTotal); + const size_t bytesToWrite = count - bytesWrittenTotal; + + const int bytesWrittenMore = +# if defined(HAVE_GETRANDOM) + getrandom(currentTarget, bytesToWrite, getrandomFlags); +# else + syscall(SYS_getrandom, currentTarget, bytesToWrite, getrandomFlags); +# endif + + if (bytesWrittenMore > 0) { + bytesWrittenTotal += bytesWrittenMore; + if (bytesWrittenTotal >= count) + success = 1; + } + } while (! success && (errno == EINTR)); + + return success; +} + +# endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */ + +# if ! defined(_WIN32) && defined(XML_DEV_URANDOM) + +/* Extract entropy from /dev/urandom */ +static int +writeRandomBytes_dev_urandom(void *target, size_t count) { + int success = 0; /* full count bytes written? */ + size_t bytesWrittenTotal = 0; + + const int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + return 0; + } + + do { + void *const currentTarget = (void *)((char *)target + bytesWrittenTotal); + const size_t bytesToWrite = count - bytesWrittenTotal; + + const ssize_t bytesWrittenMore = read(fd, currentTarget, bytesToWrite); + + if (bytesWrittenMore > 0) { + bytesWrittenTotal += bytesWrittenMore; + if (bytesWrittenTotal >= count) + success = 1; + } + } while (! success && (errno == EINTR)); + + close(fd); + return success; +} + +# endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */ + +#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */ + +#if defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) + +static void +writeRandomBytes_arc4random(void *target, size_t count) { + size_t bytesWrittenTotal = 0; + + while (bytesWrittenTotal < count) { + const uint32_t random32 = arc4random(); + size_t i = 0; + + for (; (i < sizeof(random32)) && (bytesWrittenTotal < count); + i++, bytesWrittenTotal++) { + const uint8_t random8 = (uint8_t)(random32 >> (i * 8)); + ((uint8_t *)target)[bytesWrittenTotal] = random8; + } + } +} + +#endif /* defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) */ + +#ifdef _WIN32 + +/* Provide declaration of rand_s() for MinGW-32 (not 64, which has it), + as it didn't declare it in its header prior to version 5.3.0 of its + runtime package (mingwrt, containing stdlib.h). The upstream fix + was introduced at https://osdn.net/projects/mingw/ticket/39658 . */ +# if defined(__MINGW32__) && defined(__MINGW32_VERSION) \ + && __MINGW32_VERSION < 5003000L && ! defined(__MINGW64_VERSION_MAJOR) +__declspec(dllimport) int rand_s(unsigned int *); +# endif + +/* Obtain entropy on Windows using the rand_s() function which + * generates cryptographically secure random numbers. Internally it + * uses RtlGenRandom API which is present in Windows XP and later. + */ +static int +writeRandomBytes_rand_s(void *target, size_t count) { + size_t bytesWrittenTotal = 0; + + while (bytesWrittenTotal < count) { + unsigned int random32 = 0; + size_t i = 0; + + if (rand_s(&random32)) + return 0; /* failure */ + + for (; (i < sizeof(random32)) && (bytesWrittenTotal < count); + i++, bytesWrittenTotal++) { + const uint8_t random8 = (uint8_t)(random32 >> (i * 8)); + ((uint8_t *)target)[bytesWrittenTotal] = random8; + } + } + return 1; /* success */ +} + +#endif /* _WIN32 */ + +#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) + +static unsigned long +gather_time_entropy(void) { +# ifdef _WIN32 + FILETIME ft; + GetSystemTimeAsFileTime(&ft); /* never fails */ + return ft.dwHighDateTime ^ ft.dwLowDateTime; +# else + struct timeval tv; + int gettimeofday_res; + + gettimeofday_res = gettimeofday(&tv, NULL); + +# if defined(NDEBUG) + (void)gettimeofday_res; +# else + assert(gettimeofday_res == 0); +# endif /* defined(NDEBUG) */ + + /* Microseconds time is <20 bits entropy */ + return tv.tv_usec; +# endif +} + +#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */ + +static unsigned long +ENTROPY_DEBUG(const char *label, unsigned long entropy) { + if (getDebugLevel("EXPAT_ENTROPY_DEBUG", 0) >= 1u) { + fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label, + (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy)); + } + return entropy; +} + +static unsigned long +generate_hash_secret_salt(XML_Parser parser) { + unsigned long entropy; + (void)parser; + + /* "Failproof" high quality providers: */ +#if defined(HAVE_ARC4RANDOM_BUF) + arc4random_buf(&entropy, sizeof(entropy)); + return ENTROPY_DEBUG("arc4random_buf", entropy); +#elif defined(HAVE_ARC4RANDOM) + writeRandomBytes_arc4random((void *)&entropy, sizeof(entropy)); + return ENTROPY_DEBUG("arc4random", entropy); +#else + /* Try high quality providers first .. */ +# ifdef _WIN32 + if (writeRandomBytes_rand_s((void *)&entropy, sizeof(entropy))) { + return ENTROPY_DEBUG("rand_s", entropy); + } +# elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) + if (writeRandomBytes_getrandom_nonblock((void *)&entropy, sizeof(entropy))) { + return ENTROPY_DEBUG("getrandom", entropy); + } +# endif +# if ! defined(_WIN32) && defined(XML_DEV_URANDOM) + if (writeRandomBytes_dev_urandom((void *)&entropy, sizeof(entropy))) { + return ENTROPY_DEBUG("/dev/urandom", entropy); + } +# endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */ + /* .. and self-made low quality for backup: */ + + /* Process ID is 0 bits entropy if attacker has local access */ + entropy = gather_time_entropy() ^ getpid(); + + /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */ + if (sizeof(unsigned long) == 4) { + return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647); + } else { + return ENTROPY_DEBUG("fallback(8)", + entropy * (unsigned long)2305843009213693951ULL); + } +#endif +} + +static unsigned long +get_hash_secret_salt(XML_Parser parser) { + if (parser->m_parentParser != NULL) + return get_hash_secret_salt(parser->m_parentParser); + return parser->m_hash_secret_salt; +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) { + /* hash functions must be initialized before setContext() is called */ + if (parser->m_hash_secret_salt == 0) + parser->m_hash_secret_salt = generate_hash_secret_salt(parser); + if (parser->m_ns) { + /* implicit context only set for root parser, since child + parsers (i.e. external entity parsers) will inherit it + */ + return setContext(parser, implicitContext); + } + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) { + return parserCreate(encodingName, memsuite, nameSep, NULL); +} + +static XML_Parser +parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep, + DTD *dtd) { + XML_Parser parser; + + if (memsuite) { + XML_Memory_Handling_Suite *mtemp; + parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = memsuite->malloc_fcn; + mtemp->realloc_fcn = memsuite->realloc_fcn; + mtemp->free_fcn = memsuite->free_fcn; + } + } else { + XML_Memory_Handling_Suite *mtemp; + parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = malloc; + mtemp->realloc_fcn = realloc; + mtemp->free_fcn = free; + } + } + + if (! parser) + return parser; + + parser->m_buffer = NULL; + parser->m_bufferLim = NULL; + + parser->m_attsSize = INIT_ATTS_SIZE; + parser->m_atts + = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE)); + if (parser->m_atts == NULL) { + FREE(parser, parser); + return NULL; + } +#ifdef XML_ATTR_INFO + parser->m_attInfo = (XML_AttrInfo *)MALLOC( + parser, parser->m_attsSize * sizeof(XML_AttrInfo)); + if (parser->m_attInfo == NULL) { + FREE(parser, parser->m_atts); + FREE(parser, parser); + return NULL; + } +#endif + parser->m_dataBuf + = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char)); + if (parser->m_dataBuf == NULL) { + FREE(parser, parser->m_atts); +#ifdef XML_ATTR_INFO + FREE(parser, parser->m_attInfo); +#endif + FREE(parser, parser); + return NULL; + } + parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE; + + if (dtd) + parser->m_dtd = dtd; + else { + parser->m_dtd = dtdCreate(&parser->m_mem); + if (parser->m_dtd == NULL) { + FREE(parser, parser->m_dataBuf); + FREE(parser, parser->m_atts); +#ifdef XML_ATTR_INFO + FREE(parser, parser->m_attInfo); +#endif + FREE(parser, parser); + return NULL; + } + } + + parser->m_freeBindingList = NULL; + parser->m_freeTagList = NULL; + parser->m_freeInternalEntities = NULL; + + parser->m_groupSize = 0; + parser->m_groupConnector = NULL; + + parser->m_unknownEncodingHandler = NULL; + parser->m_unknownEncodingHandlerData = NULL; + + parser->m_namespaceSeparator = ASCII_EXCL; + parser->m_ns = XML_FALSE; + parser->m_ns_triplets = XML_FALSE; + + parser->m_nsAtts = NULL; + parser->m_nsAttsVersion = 0; + parser->m_nsAttsPower = 0; + + parser->m_protocolEncodingName = NULL; + + poolInit(&parser->m_tempPool, &(parser->m_mem)); + poolInit(&parser->m_temp2Pool, &(parser->m_mem)); + parserInit(parser, encodingName); + + if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } + XML_ParserFree(parser); + return NULL; + } + + if (nameSep) { + parser->m_ns = XML_TRUE; + parser->m_internalEncoding = XmlGetInternalEncodingNS(); + parser->m_namespaceSeparator = *nameSep; + } else { + parser->m_internalEncoding = XmlGetInternalEncoding(); + } + + return parser; +} + +static void +parserInit(XML_Parser parser, const XML_Char *encodingName) { + parser->m_processor = prologInitProcessor; + XmlPrologStateInit(&parser->m_prologState); + if (encodingName != NULL) { + parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); + } + parser->m_curBase = NULL; + XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0); + parser->m_userData = NULL; + parser->m_handlerArg = NULL; + parser->m_startElementHandler = NULL; + parser->m_endElementHandler = NULL; + parser->m_characterDataHandler = NULL; + parser->m_processingInstructionHandler = NULL; + parser->m_commentHandler = NULL; + parser->m_startCdataSectionHandler = NULL; + parser->m_endCdataSectionHandler = NULL; + parser->m_defaultHandler = NULL; + parser->m_startDoctypeDeclHandler = NULL; + parser->m_endDoctypeDeclHandler = NULL; + parser->m_unparsedEntityDeclHandler = NULL; + parser->m_notationDeclHandler = NULL; + parser->m_startNamespaceDeclHandler = NULL; + parser->m_endNamespaceDeclHandler = NULL; + parser->m_notStandaloneHandler = NULL; + parser->m_externalEntityRefHandler = NULL; + parser->m_externalEntityRefHandlerArg = parser; + parser->m_skippedEntityHandler = NULL; + parser->m_elementDeclHandler = NULL; + parser->m_attlistDeclHandler = NULL; + parser->m_entityDeclHandler = NULL; + parser->m_xmlDeclHandler = NULL; + parser->m_bufferPtr = parser->m_buffer; + parser->m_bufferEnd = parser->m_buffer; + parser->m_parseEndByteIndex = 0; + parser->m_parseEndPtr = NULL; + parser->m_declElementType = NULL; + parser->m_declAttributeId = NULL; + parser->m_declEntity = NULL; + parser->m_doctypeName = NULL; + parser->m_doctypeSysid = NULL; + parser->m_doctypePubid = NULL; + parser->m_declAttributeType = NULL; + parser->m_declNotationName = NULL; + parser->m_declNotationPublicId = NULL; + parser->m_declAttributeIsCdata = XML_FALSE; + parser->m_declAttributeIsId = XML_FALSE; + memset(&parser->m_position, 0, sizeof(POSITION)); + parser->m_errorCode = XML_ERROR_NONE; + parser->m_eventPtr = NULL; + parser->m_eventEndPtr = NULL; + parser->m_positionPtr = NULL; + parser->m_openInternalEntities = NULL; + parser->m_defaultExpandInternalEntities = XML_TRUE; + parser->m_tagLevel = 0; + parser->m_tagStack = NULL; + parser->m_inheritedBindings = NULL; + parser->m_nSpecifiedAtts = 0; + parser->m_unknownEncodingMem = NULL; + parser->m_unknownEncodingRelease = NULL; + parser->m_unknownEncodingData = NULL; + parser->m_parentParser = NULL; + parser->m_parsingStatus.parsing = XML_INITIALIZED; +#ifdef XML_DTD + parser->m_isParamEntity = XML_FALSE; + parser->m_useForeignDTD = XML_FALSE; + parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif + parser->m_hash_secret_salt = 0; + +#ifdef XML_DTD + memset(&parser->m_accounting, 0, sizeof(ACCOUNTING)); + parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u); + parser->m_accounting.maximumAmplificationFactor + = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT; + parser->m_accounting.activationThresholdBytes + = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT; + + memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS)); + parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u); +#endif +} + +/* moves list of bindings to m_freeBindingList */ +static void FASTCALL +moveToFreeBindingList(XML_Parser parser, BINDING *bindings) { + while (bindings) { + BINDING *b = bindings; + bindings = bindings->nextTagBinding; + b->nextTagBinding = parser->m_freeBindingList; + parser->m_freeBindingList = b; + } +} + +XML_Bool XMLCALL +XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) { + TAG *tStk; + OPEN_INTERNAL_ENTITY *openEntityList; + + if (parser == NULL) + return XML_FALSE; + + if (parser->m_parentParser) + return XML_FALSE; + /* move m_tagStack to m_freeTagList */ + tStk = parser->m_tagStack; + while (tStk) { + TAG *tag = tStk; + tStk = tStk->parent; + tag->parent = parser->m_freeTagList; + moveToFreeBindingList(parser, tag->bindings); + tag->bindings = NULL; + parser->m_freeTagList = tag; + } + /* move m_openInternalEntities to m_freeInternalEntities */ + openEntityList = parser->m_openInternalEntities; + while (openEntityList) { + OPEN_INTERNAL_ENTITY *openEntity = openEntityList; + openEntityList = openEntity->next; + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + } + moveToFreeBindingList(parser, parser->m_inheritedBindings); + FREE(parser, parser->m_unknownEncodingMem); + if (parser->m_unknownEncodingRelease) + parser->m_unknownEncodingRelease(parser->m_unknownEncodingData); + poolClear(&parser->m_tempPool); + poolClear(&parser->m_temp2Pool); + FREE(parser, (void *)parser->m_protocolEncodingName); + parser->m_protocolEncodingName = NULL; + parserInit(parser, encodingName); + dtdReset(parser->m_dtd, &parser->m_mem); + return XML_TRUE; +} + +enum XML_Status XMLCALL +XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) { + if (parser == NULL) + return XML_STATUS_ERROR; + /* Block after XML_Parse()/XML_ParseBuffer() has been called. + XXX There's no way for the caller to determine which of the + XXX possible error cases caused the XML_STATUS_ERROR return. + */ + if (parser->m_parsingStatus.parsing == XML_PARSING + || parser->m_parsingStatus.parsing == XML_SUSPENDED) + return XML_STATUS_ERROR; + + /* Get rid of any previous encoding name */ + FREE(parser, (void *)parser->m_protocolEncodingName); + + if (encodingName == NULL) + /* No new encoding name */ + parser->m_protocolEncodingName = NULL; + else { + /* Copy the new encoding name into allocated memory */ + parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); + if (! parser->m_protocolEncodingName) + return XML_STATUS_ERROR; + } + return XML_STATUS_OK; +} + +XML_Parser XMLCALL +XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, + const XML_Char *encodingName) { + XML_Parser parser = oldParser; + DTD *newDtd = NULL; + DTD *oldDtd; + XML_StartElementHandler oldStartElementHandler; + XML_EndElementHandler oldEndElementHandler; + XML_CharacterDataHandler oldCharacterDataHandler; + XML_ProcessingInstructionHandler oldProcessingInstructionHandler; + XML_CommentHandler oldCommentHandler; + XML_StartCdataSectionHandler oldStartCdataSectionHandler; + XML_EndCdataSectionHandler oldEndCdataSectionHandler; + XML_DefaultHandler oldDefaultHandler; + XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler; + XML_NotationDeclHandler oldNotationDeclHandler; + XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler; + XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler; + XML_NotStandaloneHandler oldNotStandaloneHandler; + XML_ExternalEntityRefHandler oldExternalEntityRefHandler; + XML_SkippedEntityHandler oldSkippedEntityHandler; + XML_UnknownEncodingHandler oldUnknownEncodingHandler; + XML_ElementDeclHandler oldElementDeclHandler; + XML_AttlistDeclHandler oldAttlistDeclHandler; + XML_EntityDeclHandler oldEntityDeclHandler; + XML_XmlDeclHandler oldXmlDeclHandler; + ELEMENT_TYPE *oldDeclElementType; + + void *oldUserData; + void *oldHandlerArg; + XML_Bool oldDefaultExpandInternalEntities; + XML_Parser oldExternalEntityRefHandlerArg; +#ifdef XML_DTD + enum XML_ParamEntityParsing oldParamEntityParsing; + int oldInEntityValue; +#endif + XML_Bool oldns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt; + + /* Validate the oldParser parameter before we pull everything out of it */ + if (oldParser == NULL) + return NULL; + + /* Stash the original parser contents on the stack */ + oldDtd = parser->m_dtd; + oldStartElementHandler = parser->m_startElementHandler; + oldEndElementHandler = parser->m_endElementHandler; + oldCharacterDataHandler = parser->m_characterDataHandler; + oldProcessingInstructionHandler = parser->m_processingInstructionHandler; + oldCommentHandler = parser->m_commentHandler; + oldStartCdataSectionHandler = parser->m_startCdataSectionHandler; + oldEndCdataSectionHandler = parser->m_endCdataSectionHandler; + oldDefaultHandler = parser->m_defaultHandler; + oldUnparsedEntityDeclHandler = parser->m_unparsedEntityDeclHandler; + oldNotationDeclHandler = parser->m_notationDeclHandler; + oldStartNamespaceDeclHandler = parser->m_startNamespaceDeclHandler; + oldEndNamespaceDeclHandler = parser->m_endNamespaceDeclHandler; + oldNotStandaloneHandler = parser->m_notStandaloneHandler; + oldExternalEntityRefHandler = parser->m_externalEntityRefHandler; + oldSkippedEntityHandler = parser->m_skippedEntityHandler; + oldUnknownEncodingHandler = parser->m_unknownEncodingHandler; + oldElementDeclHandler = parser->m_elementDeclHandler; + oldAttlistDeclHandler = parser->m_attlistDeclHandler; + oldEntityDeclHandler = parser->m_entityDeclHandler; + oldXmlDeclHandler = parser->m_xmlDeclHandler; + oldDeclElementType = parser->m_declElementType; + + oldUserData = parser->m_userData; + oldHandlerArg = parser->m_handlerArg; + oldDefaultExpandInternalEntities = parser->m_defaultExpandInternalEntities; + oldExternalEntityRefHandlerArg = parser->m_externalEntityRefHandlerArg; +#ifdef XML_DTD + oldParamEntityParsing = parser->m_paramEntityParsing; + oldInEntityValue = parser->m_prologState.inEntityValue; +#endif + oldns_triplets = parser->m_ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + oldhash_secret_salt = parser->m_hash_secret_salt; + +#ifdef XML_DTD + if (! context) + newDtd = oldDtd; +#endif /* XML_DTD */ + + /* Note that the magical uses of the pre-processor to make field + access look more like C++ require that `parser' be overwritten + here. This makes this function more painful to follow than it + would be otherwise. + */ + if (parser->m_ns) { + XML_Char tmp[2] = {parser->m_namespaceSeparator, 0}; + parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); + } else { + parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); + } + + if (! parser) + return NULL; + + parser->m_startElementHandler = oldStartElementHandler; + parser->m_endElementHandler = oldEndElementHandler; + parser->m_characterDataHandler = oldCharacterDataHandler; + parser->m_processingInstructionHandler = oldProcessingInstructionHandler; + parser->m_commentHandler = oldCommentHandler; + parser->m_startCdataSectionHandler = oldStartCdataSectionHandler; + parser->m_endCdataSectionHandler = oldEndCdataSectionHandler; + parser->m_defaultHandler = oldDefaultHandler; + parser->m_unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; + parser->m_notationDeclHandler = oldNotationDeclHandler; + parser->m_startNamespaceDeclHandler = oldStartNamespaceDeclHandler; + parser->m_endNamespaceDeclHandler = oldEndNamespaceDeclHandler; + parser->m_notStandaloneHandler = oldNotStandaloneHandler; + parser->m_externalEntityRefHandler = oldExternalEntityRefHandler; + parser->m_skippedEntityHandler = oldSkippedEntityHandler; + parser->m_unknownEncodingHandler = oldUnknownEncodingHandler; + parser->m_elementDeclHandler = oldElementDeclHandler; + parser->m_attlistDeclHandler = oldAttlistDeclHandler; + parser->m_entityDeclHandler = oldEntityDeclHandler; + parser->m_xmlDeclHandler = oldXmlDeclHandler; + parser->m_declElementType = oldDeclElementType; + parser->m_userData = oldUserData; + if (oldUserData == oldHandlerArg) + parser->m_handlerArg = parser->m_userData; + else + parser->m_handlerArg = parser; + if (oldExternalEntityRefHandlerArg != oldParser) + parser->m_externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities; + parser->m_ns_triplets = oldns_triplets; + parser->m_hash_secret_salt = oldhash_secret_salt; + parser->m_parentParser = oldParser; +#ifdef XML_DTD + parser->m_paramEntityParsing = oldParamEntityParsing; + parser->m_prologState.inEntityValue = oldInEntityValue; + if (context) { +#endif /* XML_DTD */ + if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem) + || ! setContext(parser, context)) { + XML_ParserFree(parser); + return NULL; + } + parser->m_processor = externalEntityInitProcessor; +#ifdef XML_DTD + } else { + /* The DTD instance referenced by parser->m_dtd is shared between the + document's root parser and external PE parsers, therefore one does not + need to call setContext. In addition, one also *must* not call + setContext, because this would overwrite existing prefix->binding + pointers in parser->m_dtd with ones that get destroyed with the external + PE parser. This would leave those prefixes with dangling pointers. + */ + parser->m_isParamEntity = XML_TRUE; + XmlPrologStateInitExternalEntity(&parser->m_prologState); + parser->m_processor = externalParEntInitProcessor; + } +#endif /* XML_DTD */ + return parser; +} + +static void FASTCALL +destroyBindings(BINDING *bindings, XML_Parser parser) { + for (;;) { + BINDING *b = bindings; + if (! b) + break; + bindings = b->nextTagBinding; + FREE(parser, b->uri); + FREE(parser, b); + } +} + +void XMLCALL +XML_ParserFree(XML_Parser parser) { + TAG *tagList; + OPEN_INTERNAL_ENTITY *entityList; + if (parser == NULL) + return; + /* free m_tagStack and m_freeTagList */ + tagList = parser->m_tagStack; + for (;;) { + TAG *p; + if (tagList == NULL) { + if (parser->m_freeTagList == NULL) + break; + tagList = parser->m_freeTagList; + parser->m_freeTagList = NULL; + } + p = tagList; + tagList = tagList->parent; + FREE(parser, p->buf); + destroyBindings(p->bindings, parser); + FREE(parser, p); + } + /* free m_openInternalEntities and m_freeInternalEntities */ + entityList = parser->m_openInternalEntities; + for (;;) { + OPEN_INTERNAL_ENTITY *openEntity; + if (entityList == NULL) { + if (parser->m_freeInternalEntities == NULL) + break; + entityList = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = NULL; + } + openEntity = entityList; + entityList = entityList->next; + FREE(parser, openEntity); + } + + destroyBindings(parser->m_freeBindingList, parser); + destroyBindings(parser->m_inheritedBindings, parser); + poolDestroy(&parser->m_tempPool); + poolDestroy(&parser->m_temp2Pool); + FREE(parser, (void *)parser->m_protocolEncodingName); +#ifdef XML_DTD + /* external parameter entity parsers share the DTD structure + parser->m_dtd with the root parser, so we must not destroy it + */ + if (! parser->m_isParamEntity && parser->m_dtd) +#else + if (parser->m_dtd) +#endif /* XML_DTD */ + dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, + &parser->m_mem); + FREE(parser, (void *)parser->m_atts); +#ifdef XML_ATTR_INFO + FREE(parser, (void *)parser->m_attInfo); +#endif + FREE(parser, parser->m_groupConnector); + FREE(parser, parser->m_buffer); + FREE(parser, parser->m_dataBuf); + FREE(parser, parser->m_nsAtts); + FREE(parser, parser->m_unknownEncodingMem); + if (parser->m_unknownEncodingRelease) + parser->m_unknownEncodingRelease(parser->m_unknownEncodingData); + FREE(parser, parser); +} + +void XMLCALL +XML_UseParserAsHandlerArg(XML_Parser parser) { + if (parser != NULL) + parser->m_handlerArg = parser; +} + +enum XML_Error XMLCALL +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) { + if (parser == NULL) + return XML_ERROR_INVALID_ARGUMENT; +#ifdef XML_DTD + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (parser->m_parsingStatus.parsing == XML_PARSING + || parser->m_parsingStatus.parsing == XML_SUSPENDED) + return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING; + parser->m_useForeignDTD = useDTD; + return XML_ERROR_NONE; +#else + UNUSED_P(useDTD); + return XML_ERROR_FEATURE_REQUIRES_XML_DTD; +#endif +} + +void XMLCALL +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) { + if (parser == NULL) + return; + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (parser->m_parsingStatus.parsing == XML_PARSING + || parser->m_parsingStatus.parsing == XML_SUSPENDED) + return; + parser->m_ns_triplets = do_nst ? XML_TRUE : XML_FALSE; +} + +void XMLCALL +XML_SetUserData(XML_Parser parser, void *p) { + if (parser == NULL) + return; + if (parser->m_handlerArg == parser->m_userData) + parser->m_handlerArg = parser->m_userData = p; + else + parser->m_userData = p; +} + +enum XML_Status XMLCALL +XML_SetBase(XML_Parser parser, const XML_Char *p) { + if (parser == NULL) + return XML_STATUS_ERROR; + if (p) { + p = poolCopyString(&parser->m_dtd->pool, p); + if (! p) + return XML_STATUS_ERROR; + parser->m_curBase = p; + } else + parser->m_curBase = NULL; + return XML_STATUS_OK; +} + +const XML_Char *XMLCALL +XML_GetBase(XML_Parser parser) { + if (parser == NULL) + return NULL; + return parser->m_curBase; +} + +int XMLCALL +XML_GetSpecifiedAttributeCount(XML_Parser parser) { + if (parser == NULL) + return -1; + return parser->m_nSpecifiedAtts; +} + +int XMLCALL +XML_GetIdAttributeIndex(XML_Parser parser) { + if (parser == NULL) + return -1; + return parser->m_idAttIndex; +} + +#ifdef XML_ATTR_INFO +const XML_AttrInfo *XMLCALL +XML_GetAttributeInfo(XML_Parser parser) { + if (parser == NULL) + return NULL; + return parser->m_attInfo; +} +#endif + +void XMLCALL +XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, + XML_EndElementHandler end) { + if (parser == NULL) + return; + parser->m_startElementHandler = start; + parser->m_endElementHandler = end; +} + +void XMLCALL +XML_SetStartElementHandler(XML_Parser parser, XML_StartElementHandler start) { + if (parser != NULL) + parser->m_startElementHandler = start; +} + +void XMLCALL +XML_SetEndElementHandler(XML_Parser parser, XML_EndElementHandler end) { + if (parser != NULL) + parser->m_endElementHandler = end; +} + +void XMLCALL +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler) { + if (parser != NULL) + parser->m_characterDataHandler = handler; +} + +void XMLCALL +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler) { + if (parser != NULL) + parser->m_processingInstructionHandler = handler; +} + +void XMLCALL +XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler) { + if (parser != NULL) + parser->m_commentHandler = handler; +} + +void XMLCALL +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end) { + if (parser == NULL) + return; + parser->m_startCdataSectionHandler = start; + parser->m_endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start) { + if (parser != NULL) + parser->m_startCdataSectionHandler = start; +} + +void XMLCALL +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end) { + if (parser != NULL) + parser->m_endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler handler) { + if (parser == NULL) + return; + parser->m_defaultHandler = handler; + parser->m_defaultExpandInternalEntities = XML_FALSE; +} + +void XMLCALL +XML_SetDefaultHandlerExpand(XML_Parser parser, XML_DefaultHandler handler) { + if (parser == NULL) + return; + parser->m_defaultHandler = handler; + parser->m_defaultExpandInternalEntities = XML_TRUE; +} + +void XMLCALL +XML_SetDoctypeDeclHandler(XML_Parser parser, XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end) { + if (parser == NULL) + return; + parser->m_startDoctypeDeclHandler = start; + parser->m_endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start) { + if (parser != NULL) + parser->m_startDoctypeDeclHandler = start; +} + +void XMLCALL +XML_SetEndDoctypeDeclHandler(XML_Parser parser, XML_EndDoctypeDeclHandler end) { + if (parser != NULL) + parser->m_endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler) { + if (parser != NULL) + parser->m_unparsedEntityDeclHandler = handler; +} + +void XMLCALL +XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler handler) { + if (parser != NULL) + parser->m_notationDeclHandler = handler; +} + +void XMLCALL +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end) { + if (parser == NULL) + return; + parser->m_startNamespaceDeclHandler = start; + parser->m_endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start) { + if (parser != NULL) + parser->m_startNamespaceDeclHandler = start; +} + +void XMLCALL +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end) { + if (parser != NULL) + parser->m_endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler) { + if (parser != NULL) + parser->m_notStandaloneHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler) { + if (parser != NULL) + parser->m_externalEntityRefHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) { + if (parser == NULL) + return; + if (arg) + parser->m_externalEntityRefHandlerArg = (XML_Parser)arg; + else + parser->m_externalEntityRefHandlerArg = parser; +} + +void XMLCALL +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler) { + if (parser != NULL) + parser->m_skippedEntityHandler = handler; +} + +void XMLCALL +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, void *data) { + if (parser == NULL) + return; + parser->m_unknownEncodingHandler = handler; + parser->m_unknownEncodingHandlerData = data; +} + +void XMLCALL +XML_SetElementDeclHandler(XML_Parser parser, XML_ElementDeclHandler eldecl) { + if (parser != NULL) + parser->m_elementDeclHandler = eldecl; +} + +void XMLCALL +XML_SetAttlistDeclHandler(XML_Parser parser, XML_AttlistDeclHandler attdecl) { + if (parser != NULL) + parser->m_attlistDeclHandler = attdecl; +} + +void XMLCALL +XML_SetEntityDeclHandler(XML_Parser parser, XML_EntityDeclHandler handler) { + if (parser != NULL) + parser->m_entityDeclHandler = handler; +} + +void XMLCALL +XML_SetXmlDeclHandler(XML_Parser parser, XML_XmlDeclHandler handler) { + if (parser != NULL) + parser->m_xmlDeclHandler = handler; +} + +int XMLCALL +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing peParsing) { + if (parser == NULL) + return 0; + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (parser->m_parsingStatus.parsing == XML_PARSING + || parser->m_parsingStatus.parsing == XML_SUSPENDED) + return 0; +#ifdef XML_DTD + parser->m_paramEntityParsing = peParsing; + return 1; +#else + return peParsing == XML_PARAM_ENTITY_PARSING_NEVER; +#endif +} + +int XMLCALL +XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) { + if (parser == NULL) + return 0; + if (parser->m_parentParser) + return XML_SetHashSalt(parser->m_parentParser, hash_salt); + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (parser->m_parsingStatus.parsing == XML_PARSING + || parser->m_parsingStatus.parsing == XML_SUSPENDED) + return 0; + parser->m_hash_secret_salt = hash_salt; + return 1; +} + +enum XML_Status XMLCALL +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { + if ((parser == NULL) || (len < 0) || ((s == NULL) && (len != 0))) { + if (parser != NULL) + parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT; + return XML_STATUS_ERROR; + } + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + parser->m_errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + parser->m_errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parser->m_parentParser == NULL && ! startParsing(parser)) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } + /* fall through */ + default: + parser->m_parsingStatus.parsing = XML_PARSING; + } + + if (len == 0) { + parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal; + if (! isFinal) + return XML_STATUS_OK; + parser->m_positionPtr = parser->m_bufferPtr; + parser->m_parseEndPtr = parser->m_bufferEnd; + + /* If data are left over from last buffer, and we now know that these + data are the final chunk of input, then we have to check them again + to detect errors based on that fact. + */ + parser->m_errorCode + = parser->m_processor(parser, parser->m_bufferPtr, + parser->m_parseEndPtr, &parser->m_bufferPtr); + + if (parser->m_errorCode == XML_ERROR_NONE) { + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + /* It is hard to be certain, but it seems that this case + * cannot occur. This code is cleaning up a previous parse + * with no new data (since len == 0). Changing the parsing + * state requires getting to execute a handler function, and + * there doesn't seem to be an opportunity for that while in + * this circumstance. + * + * Given the uncertainty, we retain the code but exclude it + * from coverage tests. + * + * LCOV_EXCL_START + */ + XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, + parser->m_bufferPtr, &parser->m_position); + parser->m_positionPtr = parser->m_bufferPtr; + return XML_STATUS_SUSPENDED; + /* LCOV_EXCL_STOP */ + case XML_INITIALIZED: + case XML_PARSING: + parser->m_parsingStatus.parsing = XML_FINISHED; + /* fall through */ + default: + return XML_STATUS_OK; + } + } + parser->m_eventEndPtr = parser->m_eventPtr; + parser->m_processor = errorProcessor; + return XML_STATUS_ERROR; + } +#ifndef XML_CONTEXT_BYTES + else if (parser->m_bufferPtr == parser->m_bufferEnd) { + const char *end; + int nLeftOver; + enum XML_Status result; + /* Detect overflow (a+b > MAX <==> b > MAX-a) */ + if ((XML_Size)len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + parser->m_eventPtr = parser->m_eventEndPtr = NULL; + parser->m_processor = errorProcessor; + return XML_STATUS_ERROR; + } + parser->m_parseEndByteIndex += len; + parser->m_positionPtr = s; + parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal; + + parser->m_errorCode + = parser->m_processor(parser, s, parser->m_parseEndPtr = s + len, &end); + + if (parser->m_errorCode != XML_ERROR_NONE) { + parser->m_eventEndPtr = parser->m_eventPtr; + parser->m_processor = errorProcessor; + return XML_STATUS_ERROR; + } else { + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (isFinal) { + parser->m_parsingStatus.parsing = XML_FINISHED; + return XML_STATUS_OK; + } + /* fall through */ + default: + result = XML_STATUS_OK; + } + } + + XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, end, + &parser->m_position); + nLeftOver = s + len - end; + if (nLeftOver) { + if (parser->m_buffer == NULL + || nLeftOver > parser->m_bufferLim - parser->m_buffer) { + /* avoid _signed_ integer overflow */ + char *temp = NULL; + const int bytesToAllocate = (int)((unsigned)len * 2U); + if (bytesToAllocate > 0) { + temp = (char *)REALLOC(parser, parser->m_buffer, bytesToAllocate); + } + if (temp == NULL) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + parser->m_eventPtr = parser->m_eventEndPtr = NULL; + parser->m_processor = errorProcessor; + return XML_STATUS_ERROR; + } + parser->m_buffer = temp; + parser->m_bufferLim = parser->m_buffer + bytesToAllocate; + } + memcpy(parser->m_buffer, end, nLeftOver); + } + parser->m_bufferPtr = parser->m_buffer; + parser->m_bufferEnd = parser->m_buffer + nLeftOver; + parser->m_positionPtr = parser->m_bufferPtr; + parser->m_parseEndPtr = parser->m_bufferEnd; + parser->m_eventPtr = parser->m_bufferPtr; + parser->m_eventEndPtr = parser->m_bufferPtr; + return result; + } +#endif /* not defined XML_CONTEXT_BYTES */ + else { + void *buff = XML_GetBuffer(parser, len); + if (buff == NULL) + return XML_STATUS_ERROR; + else { + memcpy(buff, s, len); + return XML_ParseBuffer(parser, len, isFinal); + } + } +} + +enum XML_Status XMLCALL +XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { + const char *start; + enum XML_Status result = XML_STATUS_OK; + + if (parser == NULL) + return XML_STATUS_ERROR; + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + parser->m_errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + parser->m_errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + case XML_INITIALIZED: + /* Has someone called XML_GetBuffer successfully before? */ + if (! parser->m_bufferPtr) { + parser->m_errorCode = XML_ERROR_NO_BUFFER; + return XML_STATUS_ERROR; + } + + if (parser->m_parentParser == NULL && ! startParsing(parser)) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } + /* fall through */ + default: + parser->m_parsingStatus.parsing = XML_PARSING; + } + + start = parser->m_bufferPtr; + parser->m_positionPtr = start; + parser->m_bufferEnd += len; + parser->m_parseEndPtr = parser->m_bufferEnd; + parser->m_parseEndByteIndex += len; + parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal; + + parser->m_errorCode = parser->m_processor( + parser, start, parser->m_parseEndPtr, &parser->m_bufferPtr); + + if (parser->m_errorCode != XML_ERROR_NONE) { + parser->m_eventEndPtr = parser->m_eventPtr; + parser->m_processor = errorProcessor; + return XML_STATUS_ERROR; + } else { + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (isFinal) { + parser->m_parsingStatus.parsing = XML_FINISHED; + return result; + } + default:; /* should not happen */ + } + } + + XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, + parser->m_bufferPtr, &parser->m_position); + parser->m_positionPtr = parser->m_bufferPtr; + return result; +} + +void *XMLCALL +XML_GetBuffer(XML_Parser parser, int len) { + if (parser == NULL) + return NULL; + if (len < 0) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + parser->m_errorCode = XML_ERROR_SUSPENDED; + return NULL; + case XML_FINISHED: + parser->m_errorCode = XML_ERROR_FINISHED; + return NULL; + default:; + } + + if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) { +#ifdef XML_CONTEXT_BYTES + int keep; +#endif /* defined XML_CONTEXT_BYTES */ + /* Do not invoke signed arithmetic overflow: */ + int neededSize = (int)((unsigned)len + + (unsigned)EXPAT_SAFE_PTR_DIFF( + parser->m_bufferEnd, parser->m_bufferPtr)); + if (neededSize < 0) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } +#ifdef XML_CONTEXT_BYTES + keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer); + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + /* Detect and prevent integer overflow */ + if (keep > INT_MAX - neededSize) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } + neededSize += keep; +#endif /* defined XML_CONTEXT_BYTES */ + if (neededSize + <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) { +#ifdef XML_CONTEXT_BYTES + if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) { + int offset + = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer) + - keep; + /* The buffer pointers cannot be NULL here; we have at least some bytes + * in the buffer */ + memmove(parser->m_buffer, &parser->m_buffer[offset], + parser->m_bufferEnd - parser->m_bufferPtr + keep); + parser->m_bufferEnd -= offset; + parser->m_bufferPtr -= offset; + } +#else + if (parser->m_buffer && parser->m_bufferPtr) { + memmove(parser->m_buffer, parser->m_bufferPtr, + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)); + parser->m_bufferEnd + = parser->m_buffer + + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr); + parser->m_bufferPtr = parser->m_buffer; + } +#endif /* not defined XML_CONTEXT_BYTES */ + } else { + char *newBuf; + int bufferSize + = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr); + if (bufferSize == 0) + bufferSize = INIT_BUFFER_SIZE; + do { + /* Do not invoke signed arithmetic overflow: */ + bufferSize = (int)(2U * (unsigned)bufferSize); + } while (bufferSize < neededSize && bufferSize > 0); + if (bufferSize <= 0) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } + newBuf = (char *)MALLOC(parser, bufferSize); + if (newBuf == 0) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } + parser->m_bufferLim = newBuf + bufferSize; +#ifdef XML_CONTEXT_BYTES + if (parser->m_bufferPtr) { + memcpy(newBuf, &parser->m_bufferPtr[-keep], + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) + + keep); + FREE(parser, parser->m_buffer); + parser->m_buffer = newBuf; + parser->m_bufferEnd + = parser->m_buffer + + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) + + keep; + parser->m_bufferPtr = parser->m_buffer + keep; + } else { + /* This must be a brand new buffer with no data in it yet */ + parser->m_bufferEnd = newBuf; + parser->m_bufferPtr = parser->m_buffer = newBuf; + } +#else + if (parser->m_bufferPtr) { + memcpy(newBuf, parser->m_bufferPtr, + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)); + FREE(parser, parser->m_buffer); + parser->m_bufferEnd + = newBuf + + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr); + } else { + /* This must be a brand new buffer with no data in it yet */ + parser->m_bufferEnd = newBuf; + } + parser->m_bufferPtr = parser->m_buffer = newBuf; +#endif /* not defined XML_CONTEXT_BYTES */ + } + parser->m_eventPtr = parser->m_eventEndPtr = NULL; + parser->m_positionPtr = NULL; + } + return parser->m_bufferEnd; +} + +enum XML_Status XMLCALL +XML_StopParser(XML_Parser parser, XML_Bool resumable) { + if (parser == NULL) + return XML_STATUS_ERROR; + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + if (resumable) { + parser->m_errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + } + parser->m_parsingStatus.parsing = XML_FINISHED; + break; + case XML_FINISHED: + parser->m_errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + if (resumable) { +#ifdef XML_DTD + if (parser->m_isParamEntity) { + parser->m_errorCode = XML_ERROR_SUSPEND_PE; + return XML_STATUS_ERROR; + } +#endif + parser->m_parsingStatus.parsing = XML_SUSPENDED; + } else + parser->m_parsingStatus.parsing = XML_FINISHED; + } + return XML_STATUS_OK; +} + +enum XML_Status XMLCALL +XML_ResumeParser(XML_Parser parser) { + enum XML_Status result = XML_STATUS_OK; + + if (parser == NULL) + return XML_STATUS_ERROR; + if (parser->m_parsingStatus.parsing != XML_SUSPENDED) { + parser->m_errorCode = XML_ERROR_NOT_SUSPENDED; + return XML_STATUS_ERROR; + } + parser->m_parsingStatus.parsing = XML_PARSING; + + parser->m_errorCode = parser->m_processor( + parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr); + + if (parser->m_errorCode != XML_ERROR_NONE) { + parser->m_eventEndPtr = parser->m_eventPtr; + parser->m_processor = errorProcessor; + return XML_STATUS_ERROR; + } else { + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (parser->m_parsingStatus.finalBuffer) { + parser->m_parsingStatus.parsing = XML_FINISHED; + return result; + } + default:; + } + } + + XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, + parser->m_bufferPtr, &parser->m_position); + parser->m_positionPtr = parser->m_bufferPtr; + return result; +} + +void XMLCALL +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) { + if (parser == NULL) + return; + assert(status != NULL); + *status = parser->m_parsingStatus; +} + +enum XML_Error XMLCALL +XML_GetErrorCode(XML_Parser parser) { + if (parser == NULL) + return XML_ERROR_INVALID_ARGUMENT; + return parser->m_errorCode; +} + +XML_Index XMLCALL +XML_GetCurrentByteIndex(XML_Parser parser) { + if (parser == NULL) + return -1; + if (parser->m_eventPtr) + return (XML_Index)(parser->m_parseEndByteIndex + - (parser->m_parseEndPtr - parser->m_eventPtr)); + return -1; +} + +int XMLCALL +XML_GetCurrentByteCount(XML_Parser parser) { + if (parser == NULL) + return 0; + if (parser->m_eventEndPtr && parser->m_eventPtr) + return (int)(parser->m_eventEndPtr - parser->m_eventPtr); + return 0; +} + +const char *XMLCALL +XML_GetInputContext(XML_Parser parser, int *offset, int *size) { +#ifdef XML_CONTEXT_BYTES + if (parser == NULL) + return NULL; + if (parser->m_eventPtr && parser->m_buffer) { + if (offset != NULL) + *offset = (int)(parser->m_eventPtr - parser->m_buffer); + if (size != NULL) + *size = (int)(parser->m_bufferEnd - parser->m_buffer); + return parser->m_buffer; + } +#else + (void)parser; + (void)offset; + (void)size; +#endif /* defined XML_CONTEXT_BYTES */ + return (const char *)0; +} + +XML_Size XMLCALL +XML_GetCurrentLineNumber(XML_Parser parser) { + if (parser == NULL) + return 0; + if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) { + XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, + parser->m_eventPtr, &parser->m_position); + parser->m_positionPtr = parser->m_eventPtr; + } + return parser->m_position.lineNumber + 1; +} + +XML_Size XMLCALL +XML_GetCurrentColumnNumber(XML_Parser parser) { + if (parser == NULL) + return 0; + if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) { + XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, + parser->m_eventPtr, &parser->m_position); + parser->m_positionPtr = parser->m_eventPtr; + } + return parser->m_position.columnNumber; +} + +void XMLCALL +XML_FreeContentModel(XML_Parser parser, XML_Content *model) { + if (parser != NULL) + FREE(parser, model); +} + +void *XMLCALL +XML_MemMalloc(XML_Parser parser, size_t size) { + if (parser == NULL) + return NULL; + return MALLOC(parser, size); +} + +void *XMLCALL +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) { + if (parser == NULL) + return NULL; + return REALLOC(parser, ptr, size); +} + +void XMLCALL +XML_MemFree(XML_Parser parser, void *ptr) { + if (parser != NULL) + FREE(parser, ptr); +} + +void XMLCALL +XML_DefaultCurrent(XML_Parser parser) { + if (parser == NULL) + return; + if (parser->m_defaultHandler) { + if (parser->m_openInternalEntities) + reportDefault(parser, parser->m_internalEncoding, + parser->m_openInternalEntities->internalEventPtr, + parser->m_openInternalEntities->internalEventEndPtr); + else + reportDefault(parser, parser->m_encoding, parser->m_eventPtr, + parser->m_eventEndPtr); + } +} + +const XML_LChar *XMLCALL +XML_ErrorString(enum XML_Error code) { + switch (code) { + case XML_ERROR_NONE: + return NULL; + case XML_ERROR_NO_MEMORY: + return XML_L("out of memory"); + case XML_ERROR_SYNTAX: + return XML_L("syntax error"); + case XML_ERROR_NO_ELEMENTS: + return XML_L("no element found"); + case XML_ERROR_INVALID_TOKEN: + return XML_L("not well-formed (invalid token)"); + case XML_ERROR_UNCLOSED_TOKEN: + return XML_L("unclosed token"); + case XML_ERROR_PARTIAL_CHAR: + return XML_L("partial character"); + case XML_ERROR_TAG_MISMATCH: + return XML_L("mismatched tag"); + case XML_ERROR_DUPLICATE_ATTRIBUTE: + return XML_L("duplicate attribute"); + case XML_ERROR_JUNK_AFTER_DOC_ELEMENT: + return XML_L("junk after document element"); + case XML_ERROR_PARAM_ENTITY_REF: + return XML_L("illegal parameter entity reference"); + case XML_ERROR_UNDEFINED_ENTITY: + return XML_L("undefined entity"); + case XML_ERROR_RECURSIVE_ENTITY_REF: + return XML_L("recursive entity reference"); + case XML_ERROR_ASYNC_ENTITY: + return XML_L("asynchronous entity"); + case XML_ERROR_BAD_CHAR_REF: + return XML_L("reference to invalid character number"); + case XML_ERROR_BINARY_ENTITY_REF: + return XML_L("reference to binary entity"); + case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF: + return XML_L("reference to external entity in attribute"); + case XML_ERROR_MISPLACED_XML_PI: + return XML_L("XML or text declaration not at start of entity"); + case XML_ERROR_UNKNOWN_ENCODING: + return XML_L("unknown encoding"); + case XML_ERROR_INCORRECT_ENCODING: + return XML_L("encoding specified in XML declaration is incorrect"); + case XML_ERROR_UNCLOSED_CDATA_SECTION: + return XML_L("unclosed CDATA section"); + case XML_ERROR_EXTERNAL_ENTITY_HANDLING: + return XML_L("error in processing external entity reference"); + case XML_ERROR_NOT_STANDALONE: + return XML_L("document is not standalone"); + case XML_ERROR_UNEXPECTED_STATE: + return XML_L("unexpected parser state - please send a bug report"); + case XML_ERROR_ENTITY_DECLARED_IN_PE: + return XML_L("entity declared in parameter entity"); + case XML_ERROR_FEATURE_REQUIRES_XML_DTD: + return XML_L("requested feature requires XML_DTD support in Expat"); + case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING: + return XML_L("cannot change setting once parsing has begun"); + /* Added in 1.95.7. */ + case XML_ERROR_UNBOUND_PREFIX: + return XML_L("unbound prefix"); + /* Added in 1.95.8. */ + case XML_ERROR_UNDECLARING_PREFIX: + return XML_L("must not undeclare prefix"); + case XML_ERROR_INCOMPLETE_PE: + return XML_L("incomplete markup in parameter entity"); + case XML_ERROR_XML_DECL: + return XML_L("XML declaration not well-formed"); + case XML_ERROR_TEXT_DECL: + return XML_L("text declaration not well-formed"); + case XML_ERROR_PUBLICID: + return XML_L("illegal character(s) in public id"); + case XML_ERROR_SUSPENDED: + return XML_L("parser suspended"); + case XML_ERROR_NOT_SUSPENDED: + return XML_L("parser not suspended"); + case XML_ERROR_ABORTED: + return XML_L("parsing aborted"); + case XML_ERROR_FINISHED: + return XML_L("parsing finished"); + case XML_ERROR_SUSPEND_PE: + return XML_L("cannot suspend in external parameter entity"); + /* Added in 2.0.0. */ + case XML_ERROR_RESERVED_PREFIX_XML: + return XML_L( + "reserved prefix (xml) must not be undeclared or bound to another namespace name"); + case XML_ERROR_RESERVED_PREFIX_XMLNS: + return XML_L("reserved prefix (xmlns) must not be declared or undeclared"); + case XML_ERROR_RESERVED_NAMESPACE_URI: + return XML_L( + "prefix must not be bound to one of the reserved namespace names"); + /* Added in 2.2.5. */ + case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */ + return XML_L("invalid argument"); + /* Added in 2.3.0. */ + case XML_ERROR_NO_BUFFER: + return XML_L( + "a successful prior call to function XML_GetBuffer is required"); + /* Added in 2.4.0. */ + case XML_ERROR_AMPLIFICATION_LIMIT_BREACH: + return XML_L( + "limit on input amplification factor (from DTD and entities) breached"); + } + return NULL; +} + +const XML_LChar *XMLCALL +XML_ExpatVersion(void) { + /* V1 is used to string-ize the version number. However, it would + string-ize the actual version macro *names* unless we get them + substituted before being passed to V1. CPP is defined to expand + a macro, then rescan for more expansions. Thus, we use V2 to expand + the version macros, then CPP will expand the resulting V1() macro + with the correct numerals. */ + /* ### I'm assuming cpp is portable in this respect... */ + +#define V1(a, b, c) XML_L(#a) XML_L(".") XML_L(#b) XML_L(".") XML_L(#c) +#define V2(a, b, c) XML_L("expat_") V1(a, b, c) + + return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION); + +#undef V1 +#undef V2 +} + +XML_Expat_Version XMLCALL +XML_ExpatVersionInfo(void) { + XML_Expat_Version version; + + version.major = XML_MAJOR_VERSION; + version.minor = XML_MINOR_VERSION; + version.micro = XML_MICRO_VERSION; + + return version; +} + +const XML_Feature *XMLCALL +XML_GetFeatureList(void) { + static const XML_Feature features[] = { + {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"), + sizeof(XML_Char)}, + {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"), + sizeof(XML_LChar)}, +#ifdef XML_UNICODE + {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0}, +#endif +#ifdef XML_UNICODE_WCHAR_T + {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0}, +#endif +#ifdef XML_DTD + {XML_FEATURE_DTD, XML_L("XML_DTD"), 0}, +#endif +#ifdef XML_CONTEXT_BYTES + {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"), + XML_CONTEXT_BYTES}, +#endif +#ifdef XML_MIN_SIZE + {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0}, +#endif +#ifdef XML_NS + {XML_FEATURE_NS, XML_L("XML_NS"), 0}, +#endif +#ifdef XML_LARGE_SIZE + {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0}, +#endif +#ifdef XML_ATTR_INFO + {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0}, +#endif +#ifdef XML_DTD + /* Added in Expat 2.4.0. */ + {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT, + XML_L("XML_BLAP_MAX_AMP"), + (long int) + EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT}, + {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT, + XML_L("XML_BLAP_ACT_THRES"), + EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT}, +#endif + {XML_FEATURE_END, NULL, 0}}; + + return features; +} + +#ifdef XML_DTD +XML_Bool XMLCALL +XML_SetBillionLaughsAttackProtectionMaximumAmplification( + XML_Parser parser, float maximumAmplificationFactor) { + if ((parser == NULL) || (parser->m_parentParser != NULL) + || isnan(maximumAmplificationFactor) + || (maximumAmplificationFactor < 1.0f)) { + return XML_FALSE; + } + parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor; + return XML_TRUE; +} + +XML_Bool XMLCALL +XML_SetBillionLaughsAttackProtectionActivationThreshold( + XML_Parser parser, unsigned long long activationThresholdBytes) { + if ((parser == NULL) || (parser->m_parentParser != NULL)) { + return XML_FALSE; + } + parser->m_accounting.activationThresholdBytes = activationThresholdBytes; + return XML_TRUE; +} +#endif /* XML_DTD */ + +/* Initially tag->rawName always points into the parse buffer; + for those TAG instances opened while the current parse buffer was + processed, and not yet closed, we need to store tag->rawName in a more + permanent location, since the parse buffer is about to be discarded. +*/ +static XML_Bool +storeRawNames(XML_Parser parser) { + TAG *tag = parser->m_tagStack; + while (tag) { + int bufSize; + int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); + size_t rawNameLen; + char *rawNameBuf = tag->buf + nameLen; + /* Stop if already stored. Since m_tagStack is a stack, we can stop + at the first entry that has already been copied; everything + below it in the stack is already been accounted for in a + previous call to this function. + */ + if (tag->rawName == rawNameBuf) + break; + /* For re-use purposes we need to ensure that the + size of tag->buf is a multiple of sizeof(XML_Char). + */ + rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); + /* Detect and prevent integer overflow. */ + if (rawNameLen > (size_t)INT_MAX - nameLen) + return XML_FALSE; + bufSize = nameLen + (int)rawNameLen; + if (bufSize > tag->bufEnd - tag->buf) { + char *temp = (char *)REALLOC(parser, tag->buf, bufSize); + if (temp == NULL) + return XML_FALSE; + /* if tag->name.str points to tag->buf (only when namespace + processing is off) then we have to update it + */ + if (tag->name.str == (XML_Char *)tag->buf) + tag->name.str = (XML_Char *)temp; + /* if tag->name.localPart is set (when namespace processing is on) + then update it as well, since it will always point into tag->buf + */ + if (tag->name.localPart) + tag->name.localPart + = (XML_Char *)temp + (tag->name.localPart - (XML_Char *)tag->buf); + tag->buf = temp; + tag->bufEnd = temp + bufSize; + rawNameBuf = temp + nameLen; + } + memcpy(rawNameBuf, tag->rawName, tag->rawNameLength); + tag->rawName = rawNameBuf; + tag = tag->parent; + } + return XML_TRUE; +} + +static enum XML_Error PTRCALL +contentProcessor(XML_Parser parser, const char *start, const char *end, + const char **endPtr) { + enum XML_Error result = doContent( + parser, 0, parser->m_encoding, start, end, endPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT); + if (result == XML_ERROR_NONE) { + if (! storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor(XML_Parser parser, const char *start, + const char *end, const char **endPtr) { + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + parser->m_processor = externalEntityInitProcessor2; + return externalEntityInitProcessor2(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor2(XML_Parser parser, const char *start, + const char *end, const char **endPtr) { + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(parser->m_encoding, start, end, &next); + switch (tok) { + case XML_TOK_BOM: +#ifdef XML_DTD + if (! accountingDiffTolerated(parser, tok, start, next, __LINE__, + XML_ACCOUNT_DIRECT)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +#endif /* XML_DTD */ + + /* If we are at the end of the buffer, this would cause the next stage, + i.e. externalEntityInitProcessor3, to pass control directly to + doContent (by detecting XML_TOK_NONE) without processing any xml text + declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent. + */ + if (next == end && ! parser->m_parsingStatus.finalBuffer) { + *endPtr = next; + return XML_ERROR_NONE; + } + start = next; + break; + case XML_TOK_PARTIAL: + if (! parser->m_parsingStatus.finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + parser->m_eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (! parser->m_parsingStatus.finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + parser->m_eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + parser->m_processor = externalEntityInitProcessor3; + return externalEntityInitProcessor3(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor3(XML_Parser parser, const char *start, + const char *end, const char **endPtr) { + int tok; + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + parser->m_eventPtr = start; + tok = XmlContentTok(parser->m_encoding, start, end, &next); + /* Note: These bytes are accounted later in: + - processXmlDecl + - externalEntityContentProcessor + */ + parser->m_eventEndPtr = next; + + switch (tok) { + case XML_TOK_XML_DECL: { + enum XML_Error result; + result = processXmlDecl(parser, 1, start, next); + if (result != XML_ERROR_NONE) + return result; + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + *endPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + start = next; + } + } break; + case XML_TOK_PARTIAL: + if (! parser->m_parsingStatus.finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (! parser->m_parsingStatus.finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + } + parser->m_processor = externalEntityContentProcessor; + parser->m_tagLevel = 1; + return externalEntityContentProcessor(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityContentProcessor(XML_Parser parser, const char *start, + const char *end, const char **endPtr) { + enum XML_Error result + = doContent(parser, 1, parser->m_encoding, start, end, endPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, + XML_ACCOUNT_ENTITY_EXPANSION); + if (result == XML_ERROR_NONE) { + if (! storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error +doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + const char *s, const char *end, const char **nextPtr, + XML_Bool haveMore, enum XML_Account account) { + /* save one level of indirection */ + DTD *const dtd = parser->m_dtd; + + const char **eventPP; + const char **eventEndPP; + if (enc == parser->m_encoding) { + eventPP = &parser->m_eventPtr; + eventEndPP = &parser->m_eventEndPtr; + } else { + eventPP = &(parser->m_openInternalEntities->internalEventPtr); + eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + + for (;;) { + const char *next = s; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(enc, s, end, &next); +#ifdef XML_DTD + const char *accountAfter + = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR)) + ? (haveMore ? s /* i.e. 0 bytes */ : end) + : next; + if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__, + account)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +#endif + *eventEndPP = next; + switch (tok) { + case XML_TOK_TRAILING_CR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + *eventEndPP = end; + if (parser->m_characterDataHandler) { + XML_Char c = 0xA; + parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) + return XML_ERROR_NO_ELEMENTS; + if (parser->m_tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (startTagLevel > 0) { + if (parser->m_tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_NO_ELEMENTS; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_ENTITY_REF: { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = (XML_Char)XmlPredefinedEntityName( + enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); + if (ch) { +#ifdef XML_DTD + /* NOTE: We are replacing 4-6 characters original input for 1 character + * so there is no amplification and hence recording without + * protection. */ + accountingDiffTolerated(parser, tok, (char *)&ch, + ((char *)&ch) + sizeof(XML_Char), __LINE__, + XML_ACCOUNT_ENTITY_EXPANSION); +#endif /* XML_DTD */ + if (parser->m_characterDataHandler) + parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1); + else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + name = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); + poolDiscard(&dtd->pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity or default handler. + */ + if (! dtd->hasParamEntityRefs || dtd->standalone) { + if (! entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (! entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } else if (! entity) { + if (parser->m_skippedEntityHandler) + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); + else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->notation) + return XML_ERROR_BINARY_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + if (! parser->m_defaultExpandInternalEntities) { + if (parser->m_skippedEntityHandler) + parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name, + 0); + else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + result = processInternalEntity(parser, entity, XML_FALSE); + if (result != XML_ERROR_NONE) + return result; + } else if (parser->m_externalEntityRefHandler) { + const XML_Char *context; + entity->open = XML_TRUE; + context = getContext(parser); + entity->open = XML_FALSE; + if (! context) + return XML_ERROR_NO_MEMORY; + if (! parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, context, entity->base, + entity->systemId, entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&parser->m_tempPool); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + case XML_TOK_START_TAG_NO_ATTS: + /* fall through */ + case XML_TOK_START_TAG_WITH_ATTS: { + TAG *tag; + enum XML_Error result; + XML_Char *toPtr; + if (parser->m_freeTagList) { + tag = parser->m_freeTagList; + parser->m_freeTagList = parser->m_freeTagList->parent; + } else { + tag = (TAG *)MALLOC(parser, sizeof(TAG)); + if (! tag) + return XML_ERROR_NO_MEMORY; + tag->buf = (char *)MALLOC(parser, INIT_TAG_BUF_SIZE); + if (! tag->buf) { + FREE(parser, tag); + return XML_ERROR_NO_MEMORY; + } + tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; + } + tag->bindings = NULL; + tag->parent = parser->m_tagStack; + parser->m_tagStack = tag; + tag->name.localPart = NULL; + tag->name.prefix = NULL; + tag->rawName = s + enc->minBytesPerChar; + tag->rawNameLength = XmlNameLength(enc, tag->rawName); + ++parser->m_tagLevel; + { + const char *rawNameEnd = tag->rawName + tag->rawNameLength; + const char *fromPtr = tag->rawName; + toPtr = (XML_Char *)tag->buf; + for (;;) { + int bufSize; + int convLen; + const enum XML_Convert_Result convert_res + = XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr, + (ICHAR *)tag->bufEnd - 1); + convLen = (int)(toPtr - (XML_Char *)tag->buf); + if ((fromPtr >= rawNameEnd) + || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) { + tag->name.strLen = convLen; + break; + } + bufSize = (int)(tag->bufEnd - tag->buf) << 1; + { + char *temp = (char *)REALLOC(parser, tag->buf, bufSize); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + tag->buf = temp; + tag->bufEnd = temp + bufSize; + toPtr = (XML_Char *)temp + convLen; + } + } + } + tag->name.str = (XML_Char *)tag->buf; + *toPtr = XML_T('\0'); + result + = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account); + if (result) + return result; + if (parser->m_startElementHandler) + parser->m_startElementHandler(parser->m_handlerArg, tag->name.str, + (const XML_Char **)parser->m_atts); + else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&parser->m_tempPool); + break; + } + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + /* fall through */ + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: { + const char *rawName = s + enc->minBytesPerChar; + enum XML_Error result; + BINDING *bindings = NULL; + XML_Bool noElmHandlers = XML_TRUE; + TAG_NAME name; + name.str = poolStoreString(&parser->m_tempPool, enc, rawName, + rawName + XmlNameLength(enc, rawName)); + if (! name.str) + return XML_ERROR_NO_MEMORY; + poolFinish(&parser->m_tempPool); + result = storeAtts(parser, enc, s, &name, &bindings, + XML_ACCOUNT_NONE /* token spans whole start tag */); + if (result != XML_ERROR_NONE) { + freeBindings(parser, bindings); + return result; + } + poolFinish(&parser->m_tempPool); + if (parser->m_startElementHandler) { + parser->m_startElementHandler(parser->m_handlerArg, name.str, + (const XML_Char **)parser->m_atts); + noElmHandlers = XML_FALSE; + } + if (parser->m_endElementHandler) { + if (parser->m_startElementHandler) + *eventPP = *eventEndPP; + parser->m_endElementHandler(parser->m_handlerArg, name.str); + noElmHandlers = XML_FALSE; + } + if (noElmHandlers && parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&parser->m_tempPool); + freeBindings(parser, bindings); + } + if ((parser->m_tagLevel == 0) + && (parser->m_parsingStatus.parsing != XML_FINISHED)) { + if (parser->m_parsingStatus.parsing == XML_SUSPENDED) + parser->m_processor = epilogProcessor; + else + return epilogProcessor(parser, next, end, nextPtr); + } + break; + case XML_TOK_END_TAG: + if (parser->m_tagLevel == startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + else { + int len; + const char *rawName; + TAG *tag = parser->m_tagStack; + rawName = s + enc->minBytesPerChar * 2; + len = XmlNameLength(enc, rawName); + if (len != tag->rawNameLength + || memcmp(tag->rawName, rawName, len) != 0) { + *eventPP = rawName; + return XML_ERROR_TAG_MISMATCH; + } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; + --parser->m_tagLevel; + if (parser->m_endElementHandler) { + const XML_Char *localPart; + const XML_Char *prefix; + XML_Char *uri; + localPart = tag->name.localPart; + if (parser->m_ns && localPart) { + /* localPart and prefix may have been overwritten in + tag->name.str, since this points to the binding->uri + buffer which gets re-used; so we have to add them again + */ + uri = (XML_Char *)tag->name.str + tag->name.uriLen; + /* don't need to check for space - already done in storeAtts() */ + while (*localPart) + *uri++ = *localPart++; + prefix = (XML_Char *)tag->name.prefix; + if (parser->m_ns_triplets && prefix) { + *uri++ = parser->m_namespaceSeparator; + while (*prefix) + *uri++ = *prefix++; + } + *uri = XML_T('\0'); + } + parser->m_endElementHandler(parser->m_handlerArg, tag->name.str); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + while (tag->bindings) { + BINDING *b = tag->bindings; + if (parser->m_endNamespaceDeclHandler) + parser->m_endNamespaceDeclHandler(parser->m_handlerArg, + b->prefix->name); + tag->bindings = tag->bindings->nextTagBinding; + b->nextTagBinding = parser->m_freeBindingList; + parser->m_freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + if ((parser->m_tagLevel == 0) + && (parser->m_parsingStatus.parsing != XML_FINISHED)) { + if (parser->m_parsingStatus.parsing == XML_SUSPENDED) + parser->m_processor = epilogProcessor; + else + return epilogProcessor(parser, next, end, nextPtr); + } + } + break; + case XML_TOK_CHAR_REF: { + int n = XmlCharRefNumber(enc, s); + if (n < 0) + return XML_ERROR_BAD_CHAR_REF; + if (parser->m_characterDataHandler) { + XML_Char buf[XML_ENCODE_MAX]; + parser->m_characterDataHandler(parser->m_handlerArg, buf, + XmlEncode(n, (ICHAR *)buf)); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + } break; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + case XML_TOK_DATA_NEWLINE: + if (parser->m_characterDataHandler) { + XML_Char c = 0xA; + parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_CDATA_SECT_OPEN: { + enum XML_Error result; + if (parser->m_startCdataSectionHandler) + parser->m_startCdataSectionHandler(parser->m_handlerArg); + /* BEGIN disabled code */ + /* Suppose you doing a transformation on a document that involves + changing only the character data. You set up a defaultHandler + and a characterDataHandler. The defaultHandler simply copies + characters through. The characterDataHandler does the + transformation and writes the characters out escaping them as + necessary. This case will fail to work if we leave out the + following two lines (because & and < inside CDATA sections will + be incorrectly escaped). + + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. + */ + else if (0 && parser->m_characterDataHandler) + parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, + 0); + /* END disabled code */ + else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + result + = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account); + if (result != XML_ERROR_NONE) + return result; + else if (! next) { + parser->m_processor = cdataSectionProcessor; + return result; + } + } break; + case XML_TOK_TRAILING_RSQB: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (parser->m_characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd); + parser->m_characterDataHandler( + parser->m_handlerArg, parser->m_dataBuf, + (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); + } else + parser->m_characterDataHandler( + parser->m_handlerArg, (XML_Char *)s, + (int)((XML_Char *)end - (XML_Char *)s)); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) { + *eventPP = end; + return XML_ERROR_NO_ELEMENTS; + } + if (parser->m_tagLevel != startTagLevel) { + *eventPP = end; + return XML_ERROR_ASYNC_ENTITY; + } + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_DATA_CHARS: { + XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler; + if (charDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf; + const enum XML_Convert_Result convert_res = XmlConvert( + enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd); + *eventEndPP = s; + charDataHandler(parser->m_handlerArg, parser->m_dataBuf, + (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); + if ((convert_res == XML_CONVERT_COMPLETED) + || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) + break; + *eventPP = s; + } + } else + charDataHandler(parser->m_handlerArg, (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + } break; + case XML_TOK_PI: + if (! reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (! reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + default: + /* All of the tokens produced by XmlContentTok() have their own + * explicit cases, so this default is not strictly necessary. + * However it is a useful safety net, so we retain the code and + * simply exclude it from the coverage tests. + * + * LCOV_EXCL_START + */ + if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + /* LCOV_EXCL_STOP */ + } + *eventPP = s = next; + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default:; + } + } + /* not reached */ +} + +/* This function does not call free() on the allocated memory, merely + * moving it to the parser's m_freeBindingList where it can be freed or + * reused as appropriate. + */ +static void +freeBindings(XML_Parser parser, BINDING *bindings) { + while (bindings) { + BINDING *b = bindings; + + /* m_startNamespaceDeclHandler will have been called for this + * binding in addBindings(), so call the end handler now. + */ + if (parser->m_endNamespaceDeclHandler) + parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name); + + bindings = bindings->nextTagBinding; + b->nextTagBinding = parser->m_freeBindingList; + parser->m_freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } +} + +/* Precondition: all arguments must be non-NULL; + Purpose: + - normalize attributes + - check attributes for well-formedness + - generate namespace aware attribute names (URI, prefix) + - build list of attributes for startElementHandler + - default attributes + - process namespace declarations (check and report them) + - generate namespace aware element name (URI, prefix) +*/ +static enum XML_Error +storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, + TAG_NAME *tagNamePtr, BINDING **bindingsPtr, + enum XML_Account account) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + ELEMENT_TYPE *elementType; + int nDefaultAtts; + const XML_Char **appAtts; /* the attribute list for the application */ + int attIndex = 0; + int prefixLen; + int i; + int n; + XML_Char *uri; + int nPrefixes = 0; + BINDING *binding; + const XML_Char *localPart; + + /* lookup the element type name */ + elementType + = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str, 0); + if (! elementType) { + const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); + if (! name) + return XML_ERROR_NO_MEMORY; + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, + sizeof(ELEMENT_TYPE)); + if (! elementType) + return XML_ERROR_NO_MEMORY; + if (parser->m_ns && ! setElementTypePrefix(parser, elementType)) + return XML_ERROR_NO_MEMORY; + } + nDefaultAtts = elementType->nDefaultAtts; + + /* get the attributes from the tokenizer */ + n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts); + + /* Detect and prevent integer overflow */ + if (n > INT_MAX - nDefaultAtts) { + return XML_ERROR_NO_MEMORY; + } + + if (n + nDefaultAtts > parser->m_attsSize) { + int oldAttsSize = parser->m_attsSize; + ATTRIBUTE *temp; +#ifdef XML_ATTR_INFO + XML_AttrInfo *temp2; +#endif + + /* Detect and prevent integer overflow */ + if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE) + || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) { + return XML_ERROR_NO_MEMORY; + } + + parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) { + parser->m_attsSize = oldAttsSize; + return XML_ERROR_NO_MEMORY; + } +#endif + + temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, + parser->m_attsSize * sizeof(ATTRIBUTE)); + if (temp == NULL) { + parser->m_attsSize = oldAttsSize; + return XML_ERROR_NO_MEMORY; + } + parser->m_atts = temp; +#ifdef XML_ATTR_INFO + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +# if UINT_MAX >= SIZE_MAX + if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) { + parser->m_attsSize = oldAttsSize; + return XML_ERROR_NO_MEMORY; + } +# endif + + temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, + parser->m_attsSize * sizeof(XML_AttrInfo)); + if (temp2 == NULL) { + parser->m_attsSize = oldAttsSize; + return XML_ERROR_NO_MEMORY; + } + parser->m_attInfo = temp2; +#endif + if (n > oldAttsSize) + XmlGetAttributes(enc, attStr, n, parser->m_atts); + } + + appAtts = (const XML_Char **)parser->m_atts; + for (i = 0; i < n; i++) { + ATTRIBUTE *currAtt = &parser->m_atts[i]; +#ifdef XML_ATTR_INFO + XML_AttrInfo *currAttInfo = &parser->m_attInfo[i]; +#endif + /* add the name and value to the attribute list */ + ATTRIBUTE_ID *attId + = getAttributeId(parser, enc, currAtt->name, + currAtt->name + XmlNameLength(enc, currAtt->name)); + if (! attId) + return XML_ERROR_NO_MEMORY; +#ifdef XML_ATTR_INFO + currAttInfo->nameStart + = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->name); + currAttInfo->nameEnd + = currAttInfo->nameStart + XmlNameLength(enc, currAtt->name); + currAttInfo->valueStart = parser->m_parseEndByteIndex + - (parser->m_parseEndPtr - currAtt->valuePtr); + currAttInfo->valueEnd = parser->m_parseEndByteIndex + - (parser->m_parseEndPtr - currAtt->valueEnd); +#endif + /* Detect duplicate attributes by their QNames. This does not work when + namespace processing is turned on and different prefixes for the same + namespace are used. For this case we have a check further down. + */ + if ((attId->name)[-1]) { + if (enc == parser->m_encoding) + parser->m_eventPtr = parser->m_atts[i].name; + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + (attId->name)[-1] = 1; + appAtts[attIndex++] = attId->name; + if (! parser->m_atts[i].normalized) { + enum XML_Error result; + XML_Bool isCdata = XML_TRUE; + + /* figure out whether declared as other than CDATA */ + if (attId->maybeTokenized) { + int j; + for (j = 0; j < nDefaultAtts; j++) { + if (attId == elementType->defaultAtts[j].id) { + isCdata = elementType->defaultAtts[j].isCdata; + break; + } + } + } + + /* normalize the attribute value */ + result = storeAttributeValue( + parser, enc, isCdata, parser->m_atts[i].valuePtr, + parser->m_atts[i].valueEnd, &parser->m_tempPool, account); + if (result) + return result; + appAtts[attIndex] = poolStart(&parser->m_tempPool); + poolFinish(&parser->m_tempPool); + } else { + /* the value did not need normalizing */ + appAtts[attIndex] = poolStoreString(&parser->m_tempPool, enc, + parser->m_atts[i].valuePtr, + parser->m_atts[i].valueEnd); + if (appAtts[attIndex] == 0) + return XML_ERROR_NO_MEMORY; + poolFinish(&parser->m_tempPool); + } + /* handle prefixed attribute names */ + if (attId->prefix) { + if (attId->xmlns) { + /* deal with namespace declarations here */ + enum XML_Error result = addBinding(parser, attId->prefix, attId, + appAtts[attIndex], bindingsPtr); + if (result) + return result; + --attIndex; + } else { + /* deal with other prefixed names later */ + attIndex++; + nPrefixes++; + (attId->name)[-1] = 2; + } + } else + attIndex++; + } + + /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */ + parser->m_nSpecifiedAtts = attIndex; + if (elementType->idAtt && (elementType->idAtt->name)[-1]) { + for (i = 0; i < attIndex; i += 2) + if (appAtts[i] == elementType->idAtt->name) { + parser->m_idAttIndex = i; + break; + } + } else + parser->m_idAttIndex = -1; + + /* do attribute defaulting */ + for (i = 0; i < nDefaultAtts; i++) { + const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i; + if (! (da->id->name)[-1] && da->value) { + if (da->id->prefix) { + if (da->id->xmlns) { + enum XML_Error result = addBinding(parser, da->id->prefix, da->id, + da->value, bindingsPtr); + if (result) + return result; + } else { + (da->id->name)[-1] = 2; + nPrefixes++; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } else { + (da->id->name)[-1] = 1; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + } + appAtts[attIndex] = 0; + + /* expand prefixed attribute names, check for duplicates, + and clear flags that say whether attributes were specified */ + i = 0; + if (nPrefixes) { + int j; /* hash table index */ + unsigned long version = parser->m_nsAttsVersion; + + /* Detect and prevent invalid shift */ + if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) { + return XML_ERROR_NO_MEMORY; + } + + unsigned int nsAttsSize = 1u << parser->m_nsAttsPower; + unsigned char oldNsAttsPower = parser->m_nsAttsPower; + /* size of hash table must be at least 2 * (# of prefixed attributes) */ + if ((nPrefixes << 1) + >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */ + NS_ATT *temp; + /* hash table size must also be a power of 2 and >= 8 */ + while (nPrefixes >> parser->m_nsAttsPower++) + ; + if (parser->m_nsAttsPower < 3) + parser->m_nsAttsPower = 3; + + /* Detect and prevent invalid shift */ + if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) { + /* Restore actual size of memory in m_nsAtts */ + parser->m_nsAttsPower = oldNsAttsPower; + return XML_ERROR_NO_MEMORY; + } + + nsAttsSize = 1u << parser->m_nsAttsPower; + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) { + /* Restore actual size of memory in m_nsAtts */ + parser->m_nsAttsPower = oldNsAttsPower; + return XML_ERROR_NO_MEMORY; + } +#endif + + temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, + nsAttsSize * sizeof(NS_ATT)); + if (! temp) { + /* Restore actual size of memory in m_nsAtts */ + parser->m_nsAttsPower = oldNsAttsPower; + return XML_ERROR_NO_MEMORY; + } + parser->m_nsAtts = temp; + version = 0; /* force re-initialization of m_nsAtts hash table */ + } + /* using a version flag saves us from initializing m_nsAtts every time */ + if (! version) { /* initialize version flags when version wraps around */ + version = INIT_ATTS_VERSION; + for (j = nsAttsSize; j != 0;) + parser->m_nsAtts[--j].version = version; + } + parser->m_nsAttsVersion = --version; + + /* expand prefixed names and check for duplicates */ + for (; i < attIndex; i += 2) { + const XML_Char *s = appAtts[i]; + if (s[-1] == 2) { /* prefixed */ + ATTRIBUTE_ID *id; + const BINDING *b; + unsigned long uriHash; + struct siphash sip_state; + struct sipkey sip_key; + + copy_salt_to_sipkey(parser, &sip_key); + sip24_init(&sip_state, &sip_key); + + ((XML_Char *)s)[-1] = 0; /* clear flag */ + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); + if (! id || ! id->prefix) { + /* This code is walking through the appAtts array, dealing + * with (in this case) a prefixed attribute name. To be in + * the array, the attribute must have already been bound, so + * has to have passed through the hash table lookup once + * already. That implies that an entry for it already + * exists, so the lookup above will return a pointer to + * already allocated memory. There is no opportunaity for + * the allocator to fail, so the condition above cannot be + * fulfilled. + * + * Since it is difficult to be certain that the above + * analysis is complete, we retain the test and merely + * remove the code from coverage tests. + */ + return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */ + } + b = id->prefix->binding; + if (! b) + return XML_ERROR_UNBOUND_PREFIX; + + for (j = 0; j < b->uriLen; j++) { + const XML_Char c = b->uri[j]; + if (! poolAppendChar(&parser->m_tempPool, c)) + return XML_ERROR_NO_MEMORY; + } + + sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char)); + + while (*s++ != XML_T(ASCII_COLON)) + ; + + sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char)); + + do { /* copies null terminator */ + if (! poolAppendChar(&parser->m_tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + + uriHash = (unsigned long)sip24_final(&sip_state); + + { /* Check hash table for duplicate of expanded name (uriName). + Derived from code in lookup(parser, HASH_TABLE *table, ...). + */ + unsigned char step = 0; + unsigned long mask = nsAttsSize - 1; + j = uriHash & mask; /* index into hash table */ + while (parser->m_nsAtts[j].version == version) { + /* for speed we compare stored hash values first */ + if (uriHash == parser->m_nsAtts[j].hash) { + const XML_Char *s1 = poolStart(&parser->m_tempPool); + const XML_Char *s2 = parser->m_nsAtts[j].uriName; + /* s1 is null terminated, but not s2 */ + for (; *s1 == *s2 && *s1 != 0; s1++, s2++) + ; + if (*s1 == 0) + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + if (! step) + step = PROBE_STEP(uriHash, mask, parser->m_nsAttsPower); + j < step ? (j += nsAttsSize - step) : (j -= step); + } + } + + if (parser->m_ns_triplets) { /* append namespace separator and prefix */ + parser->m_tempPool.ptr[-1] = parser->m_namespaceSeparator; + s = b->prefix->name; + do { + if (! poolAppendChar(&parser->m_tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + } + + /* store expanded name in attribute list */ + s = poolStart(&parser->m_tempPool); + poolFinish(&parser->m_tempPool); + appAtts[i] = s; + + /* fill empty slot with new version, uriName and hash value */ + parser->m_nsAtts[j].version = version; + parser->m_nsAtts[j].hash = uriHash; + parser->m_nsAtts[j].uriName = s; + + if (! --nPrefixes) { + i += 2; + break; + } + } else /* not prefixed */ + ((XML_Char *)s)[-1] = 0; /* clear flag */ + } + } + /* clear flags for the remaining attributes */ + for (; i < attIndex; i += 2) + ((XML_Char *)(appAtts[i]))[-1] = 0; + for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) + binding->attId->name[-1] = 0; + + if (! parser->m_ns) + return XML_ERROR_NONE; + + /* expand the element type name */ + if (elementType->prefix) { + binding = elementType->prefix->binding; + if (! binding) + return XML_ERROR_UNBOUND_PREFIX; + localPart = tagNamePtr->str; + while (*localPart++ != XML_T(ASCII_COLON)) + ; + } else if (dtd->defaultPrefix.binding) { + binding = dtd->defaultPrefix.binding; + localPart = tagNamePtr->str; + } else + return XML_ERROR_NONE; + prefixLen = 0; + if (parser->m_ns_triplets && binding->prefix->name) { + for (; binding->prefix->name[prefixLen++];) + ; /* prefixLen includes null terminator */ + } + tagNamePtr->localPart = localPart; + tagNamePtr->uriLen = binding->uriLen; + tagNamePtr->prefix = binding->prefix->name; + tagNamePtr->prefixLen = prefixLen; + for (i = 0; localPart[i++];) + ; /* i includes null terminator */ + + /* Detect and prevent integer overflow */ + if (binding->uriLen > INT_MAX - prefixLen + || i > INT_MAX - (binding->uriLen + prefixLen)) { + return XML_ERROR_NO_MEMORY; + } + + n = i + binding->uriLen + prefixLen; + if (n > binding->uriAlloc) { + TAG *p; + + /* Detect and prevent integer overflow */ + if (n > INT_MAX - EXPAND_SPARE) { + return XML_ERROR_NO_MEMORY; + } + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + return XML_ERROR_NO_MEMORY; + } +#endif + + uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); + if (! uri) + return XML_ERROR_NO_MEMORY; + binding->uriAlloc = n + EXPAND_SPARE; + memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); + for (p = parser->m_tagStack; p; p = p->parent) + if (p->name.str == binding->uri) + p->name.str = uri; + FREE(parser, binding->uri); + binding->uri = uri; + } + /* if m_namespaceSeparator != '\0' then uri includes it already */ + uri = binding->uri + binding->uriLen; + memcpy(uri, localPart, i * sizeof(XML_Char)); + /* we always have a namespace separator between localPart and prefix */ + if (prefixLen) { + uri += i - 1; + *uri = parser->m_namespaceSeparator; /* replace null terminator */ + memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char)); + } + tagNamePtr->str = binding->uri; + return XML_ERROR_NONE; +} + +static XML_Bool +is_rfc3986_uri_char(XML_Char candidate) { + // For the RFC 3986 ANBF grammar see + // https://datatracker.ietf.org/doc/html/rfc3986#appendix-A + + switch (candidate) { + // From rule "ALPHA" (uppercase half) + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + + // From rule "ALPHA" (lowercase half) + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + + // From rule "DIGIT" + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + + // From rule "pct-encoded" + case '%': + + // From rule "unreserved" + case '-': + case '.': + case '_': + case '~': + + // From rule "gen-delims" + case ':': + case '/': + case '?': + case '#': + case '[': + case ']': + case '@': + + // From rule "sub-delims" + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + return XML_TRUE; + + default: + return XML_FALSE; + } +} + +/* addBinding() overwrites the value of prefix->binding without checking. + Therefore one must keep track of the old value outside of addBinding(). +*/ +static enum XML_Error +addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr) { + // "http://www.w3.org/XML/1998/namespace" + static const XML_Char xmlNamespace[] + = {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, + ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, + ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, + ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, + ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, + ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, + ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c, + ASCII_e, '\0'}; + static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1; + // "http://www.w3.org/2000/xmlns/" + static const XML_Char xmlnsNamespace[] + = {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, + ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, + ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, + ASCII_2, ASCII_0, ASCII_0, ASCII_0, ASCII_SLASH, ASCII_x, + ASCII_m, ASCII_l, ASCII_n, ASCII_s, ASCII_SLASH, '\0'}; + static const int xmlnsLen + = (int)sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1; + + XML_Bool mustBeXML = XML_FALSE; + XML_Bool isXML = XML_TRUE; + XML_Bool isXMLNS = XML_TRUE; + + BINDING *b; + int len; + + /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */ + if (*uri == XML_T('\0') && prefix->name) + return XML_ERROR_UNDECLARING_PREFIX; + + if (prefix->name && prefix->name[0] == XML_T(ASCII_x) + && prefix->name[1] == XML_T(ASCII_m) + && prefix->name[2] == XML_T(ASCII_l)) { + /* Not allowed to bind xmlns */ + if (prefix->name[3] == XML_T(ASCII_n) && prefix->name[4] == XML_T(ASCII_s) + && prefix->name[5] == XML_T('\0')) + return XML_ERROR_RESERVED_PREFIX_XMLNS; + + if (prefix->name[3] == XML_T('\0')) + mustBeXML = XML_TRUE; + } + + for (len = 0; uri[len]; len++) { + if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) + isXML = XML_FALSE; + + if (! mustBeXML && isXMLNS + && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) + isXMLNS = XML_FALSE; + + // NOTE: While Expat does not validate namespace URIs against RFC 3986 + // today (and is not REQUIRED to do so with regard to the XML 1.0 + // namespaces specification) we have to at least make sure, that + // the application on top of Expat (that is likely splitting expanded + // element names ("qualified names") of form + // "[uri sep] local [sep prefix] '\0'" back into 1, 2 or 3 pieces + // in its element handler code) cannot be confused by an attacker + // putting additional namespace separator characters into namespace + // declarations. That would be ambiguous and not to be expected. + // + // While the HTML API docs of function XML_ParserCreateNS have been + // advising against use of a namespace separator character that can + // appear in a URI for >20 years now, some widespread applications + // are using URI characters (':' (colon) in particular) for a + // namespace separator, in practice. To keep these applications + // functional, we only reject namespaces URIs containing the + // application-chosen namespace separator if the chosen separator + // is a non-URI character with regard to RFC 3986. + if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator) + && ! is_rfc3986_uri_char(uri[len])) { + return XML_ERROR_SYNTAX; + } + } + isXML = isXML && len == xmlLen; + isXMLNS = isXMLNS && len == xmlnsLen; + + if (mustBeXML != isXML) + return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML + : XML_ERROR_RESERVED_NAMESPACE_URI; + + if (isXMLNS) + return XML_ERROR_RESERVED_NAMESPACE_URI; + + if (parser->m_namespaceSeparator) + len++; + if (parser->m_freeBindingList) { + b = parser->m_freeBindingList; + if (len > b->uriAlloc) { + /* Detect and prevent integer overflow */ + if (len > INT_MAX - EXPAND_SPARE) { + return XML_ERROR_NO_MEMORY; + } + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + return XML_ERROR_NO_MEMORY; + } +#endif + + XML_Char *temp = (XML_Char *)REALLOC( + parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + b->uri = temp; + b->uriAlloc = len + EXPAND_SPARE; + } + parser->m_freeBindingList = b->nextTagBinding; + } else { + b = (BINDING *)MALLOC(parser, sizeof(BINDING)); + if (! b) + return XML_ERROR_NO_MEMORY; + + /* Detect and prevent integer overflow */ + if (len > INT_MAX - EXPAND_SPARE) { + return XML_ERROR_NO_MEMORY; + } + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + return XML_ERROR_NO_MEMORY; + } +#endif + + b->uri + = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (! b->uri) { + FREE(parser, b); + return XML_ERROR_NO_MEMORY; + } + b->uriAlloc = len + EXPAND_SPARE; + } + b->uriLen = len; + memcpy(b->uri, uri, len * sizeof(XML_Char)); + if (parser->m_namespaceSeparator) + b->uri[len - 1] = parser->m_namespaceSeparator; + b->prefix = prefix; + b->attId = attId; + b->prevPrefixBinding = prefix->binding; + /* NULL binding when default namespace undeclared */ + if (*uri == XML_T('\0') && prefix == &parser->m_dtd->defaultPrefix) + prefix->binding = NULL; + else + prefix->binding = b; + b->nextTagBinding = *bindingsPtr; + *bindingsPtr = b; + /* if attId == NULL then we are not starting a namespace scope */ + if (attId && parser->m_startNamespaceDeclHandler) + parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name, + prefix->binding ? uri : 0); + return XML_ERROR_NONE; +} + +/* The idea here is to avoid using stack for each CDATA section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +cdataSectionProcessor(XML_Parser parser, const char *start, const char *end, + const char **endPtr) { + enum XML_Error result = doCdataSection( + parser, parser->m_encoding, &start, end, endPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT); + if (result != XML_ERROR_NONE) + return result; + if (start) { + if (parser->m_parentParser) { /* we are parsing an external entity */ + parser->m_processor = externalEntityContentProcessor; + return externalEntityContentProcessor(parser, start, end, endPtr); + } else { + parser->m_processor = contentProcessor; + return contentProcessor(parser, start, end, endPtr); + } + } + return result; +} + +/* startPtr gets set to non-null if the section is closed, and to null if + the section is not yet closed. +*/ +static enum XML_Error +doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore, + enum XML_Account account) { + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == parser->m_encoding) { + eventPP = &parser->m_eventPtr; + *eventPP = s; + eventEndPP = &parser->m_eventEndPtr; + } else { + eventPP = &(parser->m_openInternalEntities->internalEventPtr); + eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = NULL; + + for (;;) { + const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */ + int tok = XmlCdataSectionTok(enc, s, end, &next); +#ifdef XML_DTD + if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +#else + UNUSED_P(account); +#endif + *eventEndPP = next; + switch (tok) { + case XML_TOK_CDATA_SECT_CLOSE: + if (parser->m_endCdataSectionHandler) + parser->m_endCdataSectionHandler(parser->m_handlerArg); + /* BEGIN disabled code */ + /* see comment under XML_TOK_CDATA_SECT_OPEN */ + else if (0 && parser->m_characterDataHandler) + parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, + 0); + /* END disabled code */ + else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (parser->m_parsingStatus.parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_DATA_NEWLINE: + if (parser->m_characterDataHandler) { + XML_Char c = 0xA; + parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_DATA_CHARS: { + XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler; + if (charDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf; + const enum XML_Convert_Result convert_res = XmlConvert( + enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd); + *eventEndPP = next; + charDataHandler(parser->m_handlerArg, parser->m_dataBuf, + (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); + if ((convert_res == XML_CONVERT_COMPLETED) + || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) + break; + *eventPP = s; + } + } else + charDataHandler(parser->m_handlerArg, (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + } break; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_CDATA_SECTION; + default: + /* Every token returned by XmlCdataSectionTok() has its own + * explicit case, so this default case will never be executed. + * We retain it as a safety net and exclude it from the coverage + * statistics. + * + * LCOV_EXCL_START + */ + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + /* LCOV_EXCL_STOP */ + } + + *eventPP = s = next; + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default:; + } + } + /* not reached */ +} + +#ifdef XML_DTD + +/* The idea here is to avoid using stack for each IGNORE section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +ignoreSectionProcessor(XML_Parser parser, const char *start, const char *end, + const char **endPtr) { + enum XML_Error result + = doIgnoreSection(parser, parser->m_encoding, &start, end, endPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer); + if (result != XML_ERROR_NONE) + return result; + if (start) { + parser->m_processor = prologProcessor; + return prologProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null + if the section is not yet closed. +*/ +static enum XML_Error +doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore) { + const char *next = *startPtr; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */ + int tok; + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == parser->m_encoding) { + eventPP = &parser->m_eventPtr; + *eventPP = s; + eventEndPP = &parser->m_eventEndPtr; + } else { + /* It's not entirely clear, but it seems the following two lines + * of code cannot be executed. The only occasions on which 'enc' + * is not 'encoding' are when this function is called + * from the internal entity processing, and IGNORE sections are an + * error in internal entities. + * + * Since it really isn't clear that this is true, we keep the code + * and just remove it from our coverage tests. + * + * LCOV_EXCL_START + */ + eventPP = &(parser->m_openInternalEntities->internalEventPtr); + eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr); + /* LCOV_EXCL_STOP */ + } + *eventPP = s; + *startPtr = NULL; + tok = XmlIgnoreSectionTok(enc, s, end, &next); +# ifdef XML_DTD + if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, + XML_ACCOUNT_DIRECT)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +# endif + *eventEndPP = next; + switch (tok) { + case XML_TOK_IGNORE_SECT: + if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (parser->m_parsingStatus.parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ + default: + /* All of the tokens that XmlIgnoreSectionTok() returns have + * explicit cases to handle them, so this default case is never + * executed. We keep it as a safety net anyway, and remove it + * from our test coverage statistics. + * + * LCOV_EXCL_START + */ + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + /* LCOV_EXCL_STOP */ + } + /* not reached */ +} + +#endif /* XML_DTD */ + +static enum XML_Error +initializeEncoding(XML_Parser parser) { + const char *s; +#ifdef XML_UNICODE + char encodingBuf[128]; + /* See comments about `protocolEncodingName` in parserInit() */ + if (! parser->m_protocolEncodingName) + s = NULL; + else { + int i; + for (i = 0; parser->m_protocolEncodingName[i]; i++) { + if (i == sizeof(encodingBuf) - 1 + || (parser->m_protocolEncodingName[i] & ~0x7f) != 0) { + encodingBuf[0] = '\0'; + break; + } + encodingBuf[i] = (char)parser->m_protocolEncodingName[i]; + } + encodingBuf[i] = '\0'; + s = encodingBuf; + } +#else + s = parser->m_protocolEncodingName; +#endif + if ((parser->m_ns ? XmlInitEncodingNS : XmlInitEncoding)( + &parser->m_initEncoding, &parser->m_encoding, s)) + return XML_ERROR_NONE; + return handleUnknownEncoding(parser, parser->m_protocolEncodingName); +} + +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s, + const char *next) { + const char *encodingName = NULL; + const XML_Char *storedEncName = NULL; + const ENCODING *newEncoding = NULL; + const char *version = NULL; + const char *versionend = NULL; + const XML_Char *storedversion = NULL; + int standalone = -1; + +#ifdef XML_DTD + if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__, + XML_ACCOUNT_DIRECT)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +#endif + + if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)( + isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr, + &version, &versionend, &encodingName, &newEncoding, &standalone)) { + if (isGeneralTextEntity) + return XML_ERROR_TEXT_DECL; + else + return XML_ERROR_XML_DECL; + } + if (! isGeneralTextEntity && standalone == 1) { + parser->m_dtd->standalone = XML_TRUE; +#ifdef XML_DTD + if (parser->m_paramEntityParsing + == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) + parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif /* XML_DTD */ + } + if (parser->m_xmlDeclHandler) { + if (encodingName != NULL) { + storedEncName = poolStoreString( + &parser->m_temp2Pool, parser->m_encoding, encodingName, + encodingName + XmlNameLength(parser->m_encoding, encodingName)); + if (! storedEncName) + return XML_ERROR_NO_MEMORY; + poolFinish(&parser->m_temp2Pool); + } + if (version) { + storedversion + = poolStoreString(&parser->m_temp2Pool, parser->m_encoding, version, + versionend - parser->m_encoding->minBytesPerChar); + if (! storedversion) + return XML_ERROR_NO_MEMORY; + } + parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName, + standalone); + } else if (parser->m_defaultHandler) + reportDefault(parser, parser->m_encoding, s, next); + if (parser->m_protocolEncodingName == NULL) { + if (newEncoding) { + /* Check that the specified encoding does not conflict with what + * the parser has already deduced. Do we have the same number + * of bytes in the smallest representation of a character? If + * this is UTF-16, is it the same endianness? + */ + if (newEncoding->minBytesPerChar != parser->m_encoding->minBytesPerChar + || (newEncoding->minBytesPerChar == 2 + && newEncoding != parser->m_encoding)) { + parser->m_eventPtr = encodingName; + return XML_ERROR_INCORRECT_ENCODING; + } + parser->m_encoding = newEncoding; + } else if (encodingName) { + enum XML_Error result; + if (! storedEncName) { + storedEncName = poolStoreString( + &parser->m_temp2Pool, parser->m_encoding, encodingName, + encodingName + XmlNameLength(parser->m_encoding, encodingName)); + if (! storedEncName) + return XML_ERROR_NO_MEMORY; + } + result = handleUnknownEncoding(parser, storedEncName); + poolClear(&parser->m_temp2Pool); + if (result == XML_ERROR_UNKNOWN_ENCODING) + parser->m_eventPtr = encodingName; + return result; + } + } + + if (storedEncName || storedversion) + poolClear(&parser->m_temp2Pool); + + return XML_ERROR_NONE; +} + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) { + if (parser->m_unknownEncodingHandler) { + XML_Encoding info; + int i; + for (i = 0; i < 256; i++) + info.map[i] = -1; + info.convert = NULL; + info.data = NULL; + info.release = NULL; + if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData, + encodingName, &info)) { + ENCODING *enc; + parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding()); + if (! parser->m_unknownEncodingMem) { + if (info.release) + info.release(info.data); + return XML_ERROR_NO_MEMORY; + } + enc = (parser->m_ns ? XmlInitUnknownEncodingNS : XmlInitUnknownEncoding)( + parser->m_unknownEncodingMem, info.map, info.convert, info.data); + if (enc) { + parser->m_unknownEncodingData = info.data; + parser->m_unknownEncodingRelease = info.release; + parser->m_encoding = enc; + return XML_ERROR_NONE; + } + } + if (info.release != NULL) + info.release(info.data); + } + return XML_ERROR_UNKNOWN_ENCODING; +} + +static enum XML_Error PTRCALL +prologInitProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + parser->m_processor = prologProcessor; + return prologProcessor(parser, s, end, nextPtr); +} + +#ifdef XML_DTD + +static enum XML_Error PTRCALL +externalParEntInitProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + + /* we know now that XML_Parse(Buffer) has been called, + so we consider the external parameter entity read */ + parser->m_dtd->paramEntityRead = XML_TRUE; + + if (parser->m_prologState.inEntityValue) { + parser->m_processor = entityValueInitProcessor; + return entityValueInitProcessor(parser, s, end, nextPtr); + } else { + parser->m_processor = externalParEntProcessor; + return externalParEntProcessor(parser, s, end, nextPtr); + } +} + +static enum XML_Error PTRCALL +entityValueInitProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + int tok; + const char *start = s; + const char *next = start; + parser->m_eventPtr = start; + + for (;;) { + tok = XmlPrologTok(parser->m_encoding, start, end, &next); + /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in: + - storeEntityValue + - processXmlDecl + */ + parser->m_eventEndPtr = next; + if (tok <= 0) { + if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, parser->m_encoding, s, end, + XML_ACCOUNT_DIRECT); + } else if (tok == XML_TOK_XML_DECL) { + enum XML_Error result; + result = processXmlDecl(parser, 0, start, next); + if (result != XML_ERROR_NONE) + return result; + /* At this point, m_parsingStatus.parsing cannot be XML_SUSPENDED. For + * that to happen, a parameter entity parsing handler must have attempted + * to suspend the parser, which fails and raises an error. The parser can + * be aborted, but can't be suspended. + */ + if (parser->m_parsingStatus.parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + *nextPtr = next; + /* stop scanning for text declaration - we found one */ + parser->m_processor = entityValueProcessor; + return entityValueProcessor(parser, next, end, nextPtr); + } + /* If we are at the end of the buffer, this would cause XmlPrologTok to + return XML_TOK_NONE on the next call, which would then cause the + function to exit with *nextPtr set to s - that is what we want for other + tokens, but not for the BOM - we would rather like to skip it; + then, when this routine is entered the next time, XmlPrologTok will + return XML_TOK_INVALID, since the BOM is still in the buffer + */ + else if (tok == XML_TOK_BOM && next == end + && ! parser->m_parsingStatus.finalBuffer) { +# ifdef XML_DTD + if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, + XML_ACCOUNT_DIRECT)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +# endif + + *nextPtr = next; + return XML_ERROR_NONE; + } + /* If we get this token, we have the start of what might be a + normal tag, but not a declaration (i.e. it doesn't begin with + "m_eventPtr = start; + } +} + +static enum XML_Error PTRCALL +externalParEntProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + const char *next = s; + int tok; + + tok = XmlPrologTok(parser->m_encoding, s, end, &next); + if (tok <= 0) { + if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + } + /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM. + However, when parsing an external subset, doProlog will not accept a BOM + as valid, and report a syntax error, so we have to skip the BOM, and + account for the BOM bytes. + */ + else if (tok == XML_TOK_BOM) { + if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, + XML_ACCOUNT_DIRECT)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } + + s = next; + tok = XmlPrologTok(parser->m_encoding, s, end, &next); + } + + parser->m_processor = prologProcessor; + return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE, + XML_ACCOUNT_DIRECT); +} + +static enum XML_Error PTRCALL +entityValueProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + const char *start = s; + const char *next = s; + const ENCODING *enc = parser->m_encoding; + int tok; + + for (;;) { + tok = XmlPrologTok(enc, start, end, &next); + /* Note: These bytes are accounted later in: + - storeEntityValue + */ + if (tok <= 0) { + if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT); + } + start = next; + } +} + +#endif /* XML_DTD */ + +static enum XML_Error PTRCALL +prologProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + const char *next = s; + int tok = XmlPrologTok(parser->m_encoding, s, end, &next); + return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE, + XML_ACCOUNT_DIRECT); +} + +static enum XML_Error +doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + int tok, const char *next, const char **nextPtr, XML_Bool haveMore, + XML_Bool allowClosingDoctype, enum XML_Account account) { +#ifdef XML_DTD + static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'}; +#endif /* XML_DTD */ + static const XML_Char atypeCDATA[] + = {ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'}; + static const XML_Char atypeID[] = {ASCII_I, ASCII_D, '\0'}; + static const XML_Char atypeIDREF[] + = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0'}; + static const XML_Char atypeIDREFS[] + = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0'}; + static const XML_Char atypeENTITY[] + = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0'}; + static const XML_Char atypeENTITIES[] + = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, + ASCII_I, ASCII_E, ASCII_S, '\0'}; + static const XML_Char atypeNMTOKEN[] + = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0'}; + static const XML_Char atypeNMTOKENS[] + = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, + ASCII_E, ASCII_N, ASCII_S, '\0'}; + static const XML_Char notationPrefix[] + = {ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, + ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0'}; + static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'}; + static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'}; + +#ifndef XML_DTD + UNUSED_P(account); +#endif + + /* save one level of indirection */ + DTD *const dtd = parser->m_dtd; + + const char **eventPP; + const char **eventEndPP; + enum XML_Content_Quant quant; + + if (enc == parser->m_encoding) { + eventPP = &parser->m_eventPtr; + eventEndPP = &parser->m_eventEndPtr; + } else { + eventPP = &(parser->m_openInternalEntities->internalEventPtr); + eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr); + } + + for (;;) { + int role; + XML_Bool handleDefault = XML_TRUE; + *eventPP = s; + *eventEndPP = next; + if (tok <= 0) { + if (haveMore && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case -XML_TOK_PROLOG_S: + tok = -tok; + break; + case XML_TOK_NONE: +#ifdef XML_DTD + /* for internal PE NOT referenced between declarations */ + if (enc != parser->m_encoding + && ! parser->m_openInternalEntities->betweenDecl) { + *nextPtr = s; + return XML_ERROR_NONE; + } + /* WFC: PE Between Declarations - must check that PE contains + complete markup, not only for external PEs, but also for + internal PEs if the reference occurs between declarations. + */ + if (parser->m_isParamEntity || enc != parser->m_encoding) { + if (XmlTokenRole(&parser->m_prologState, XML_TOK_NONE, end, end, enc) + == XML_ROLE_ERROR) + return XML_ERROR_INCOMPLETE_PE; + *nextPtr = s; + return XML_ERROR_NONE; + } +#endif /* XML_DTD */ + return XML_ERROR_NO_ELEMENTS; + default: + tok = -tok; + next = end; + break; + } + } + role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc); +#ifdef XML_DTD + switch (role) { + case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor + case XML_ROLE_XML_DECL: // bytes accounted in processXmlDecl + case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl + break; + default: + if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } + } +#endif + switch (role) { + case XML_ROLE_XML_DECL: { + enum XML_Error result = processXmlDecl(parser, 0, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = parser->m_encoding; + handleDefault = XML_FALSE; + } break; + case XML_ROLE_DOCTYPE_NAME: + if (parser->m_startDoctypeDeclHandler) { + parser->m_doctypeName + = poolStoreString(&parser->m_tempPool, enc, s, next); + if (! parser->m_doctypeName) + return XML_ERROR_NO_MEMORY; + poolFinish(&parser->m_tempPool); + parser->m_doctypePubid = NULL; + handleDefault = XML_FALSE; + } + parser->m_doctypeSysid = NULL; /* always initialize to NULL */ + break; + case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: + if (parser->m_startDoctypeDeclHandler) { + parser->m_startDoctypeDeclHandler( + parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid, + parser->m_doctypePubid, 1); + parser->m_doctypeName = NULL; + poolClear(&parser->m_tempPool); + handleDefault = XML_FALSE; + } + break; +#ifdef XML_DTD + case XML_ROLE_TEXT_DECL: { + enum XML_Error result = processXmlDecl(parser, 1, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = parser->m_encoding; + handleDefault = XML_FALSE; + } break; +#endif /* XML_DTD */ + case XML_ROLE_DOCTYPE_PUBLIC_ID: +#ifdef XML_DTD + parser->m_useForeignDTD = XML_FALSE; + parser->m_declEntity = (ENTITY *)lookup( + parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); + if (! parser->m_declEntity) + return XML_ERROR_NO_MEMORY; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (parser->m_startDoctypeDeclHandler) { + XML_Char *pubId; + if (! XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + pubId = poolStoreString(&parser->m_tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! pubId) + return XML_ERROR_NO_MEMORY; + normalizePublicId(pubId); + poolFinish(&parser->m_tempPool); + parser->m_doctypePubid = pubId; + handleDefault = XML_FALSE; + goto alreadyChecked; + } + /* fall through */ + case XML_ROLE_ENTITY_PUBLIC_ID: + if (! XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + alreadyChecked: + if (dtd->keepProcessing && parser->m_declEntity) { + XML_Char *tem + = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + parser->m_declEntity->publicId = tem; + poolFinish(&dtd->pool); + /* Don't suppress the default handler if we fell through from + * the XML_ROLE_DOCTYPE_PUBLIC_ID case. + */ + if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_PUBLIC_ID) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_DOCTYPE_CLOSE: + if (allowClosingDoctype != XML_TRUE) { + /* Must not close doctype from within expanded parameter entities */ + return XML_ERROR_INVALID_TOKEN; + } + + if (parser->m_doctypeName) { + parser->m_startDoctypeDeclHandler( + parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid, + parser->m_doctypePubid, 0); + poolClear(&parser->m_tempPool); + handleDefault = XML_FALSE; + } + /* parser->m_doctypeSysid will be non-NULL in the case of a previous + XML_ROLE_DOCTYPE_SYSTEM_ID, even if parser->m_startDoctypeDeclHandler + was not set, indicating an external subset + */ +#ifdef XML_DTD + if (parser->m_doctypeSysid || parser->m_useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (parser->m_paramEntityParsing + && parser->m_externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, + externalSubsetName, sizeof(ENTITY)); + if (! entity) { + /* The external subset name "#" will have already been + * inserted into the hash table at the start of the + * external entity parsing, so no allocation will happen + * and lookup() cannot fail. + */ + return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */ + } + if (parser->m_useForeignDTD) + entity->base = parser->m_curBase; + dtd->paramEntityRead = XML_FALSE; + if (! parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (! dtd->standalone && parser->m_notStandaloneHandler + && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else if (! parser->m_doctypeSysid) + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + parser->m_useForeignDTD = XML_FALSE; + } +#endif /* XML_DTD */ + if (parser->m_endDoctypeDeclHandler) { + parser->m_endDoctypeDeclHandler(parser->m_handlerArg); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_INSTANCE_START: +#ifdef XML_DTD + /* if there is no DOCTYPE declaration then now is the + last chance to read the foreign DTD + */ + if (parser->m_useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (parser->m_paramEntityParsing + && parser->m_externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, + externalSubsetName, sizeof(ENTITY)); + if (! entity) + return XML_ERROR_NO_MEMORY; + entity->base = parser->m_curBase; + dtd->paramEntityRead = XML_FALSE; + if (! parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (! dtd->standalone && parser->m_notStandaloneHandler + && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + } +#endif /* XML_DTD */ + parser->m_processor = contentProcessor; + return contentProcessor(parser, s, end, nextPtr); + case XML_ROLE_ATTLIST_ELEMENT_NAME: + parser->m_declElementType = getElementType(parser, enc, s, next); + if (! parser->m_declElementType) + return XML_ERROR_NO_MEMORY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_NAME: + parser->m_declAttributeId = getAttributeId(parser, enc, s, next); + if (! parser->m_declAttributeId) + return XML_ERROR_NO_MEMORY; + parser->m_declAttributeIsCdata = XML_FALSE; + parser->m_declAttributeType = NULL; + parser->m_declAttributeIsId = XML_FALSE; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_CDATA: + parser->m_declAttributeIsCdata = XML_TRUE; + parser->m_declAttributeType = atypeCDATA; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ID: + parser->m_declAttributeIsId = XML_TRUE; + parser->m_declAttributeType = atypeID; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREF: + parser->m_declAttributeType = atypeIDREF; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREFS: + parser->m_declAttributeType = atypeIDREFS; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITY: + parser->m_declAttributeType = atypeENTITY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES: + parser->m_declAttributeType = atypeENTITIES; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN: + parser->m_declAttributeType = atypeNMTOKEN; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS: + parser->m_declAttributeType = atypeNMTOKENS; + checkAttListDeclHandler: + if (dtd->keepProcessing && parser->m_attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTRIBUTE_ENUM_VALUE: + case XML_ROLE_ATTRIBUTE_NOTATION_VALUE: + if (dtd->keepProcessing && parser->m_attlistDeclHandler) { + const XML_Char *prefix; + if (parser->m_declAttributeType) { + prefix = enumValueSep; + } else { + prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE ? notationPrefix + : enumValueStart); + } + if (! poolAppendString(&parser->m_tempPool, prefix)) + return XML_ERROR_NO_MEMORY; + if (! poolAppend(&parser->m_tempPool, enc, s, next)) + return XML_ERROR_NO_MEMORY; + parser->m_declAttributeType = parser->m_tempPool.start; + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: + case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + if (! defineAttribute(parser->m_declElementType, + parser->m_declAttributeId, + parser->m_declAttributeIsCdata, + parser->m_declAttributeIsId, 0, parser)) + return XML_ERROR_NO_MEMORY; + if (parser->m_attlistDeclHandler && parser->m_declAttributeType) { + if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN) + || (*parser->m_declAttributeType == XML_T(ASCII_N) + && parser->m_declAttributeType[1] == XML_T(ASCII_O))) { + /* Enumerated or Notation type */ + if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN)) + || ! poolAppendChar(&parser->m_tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + parser->m_declAttributeType = parser->m_tempPool.start; + poolFinish(&parser->m_tempPool); + } + *eventEndPP = s; + parser->m_attlistDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, + parser->m_declAttributeId->name, parser->m_declAttributeType, 0, + role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); + handleDefault = XML_FALSE; + } + } + poolClear(&parser->m_tempPool); + break; + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + const XML_Char *attVal; + enum XML_Error result = storeAttributeValue( + parser, enc, parser->m_declAttributeIsCdata, + s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool, + XML_ACCOUNT_NONE); + if (result) + return result; + attVal = poolStart(&dtd->pool); + poolFinish(&dtd->pool); + /* ID attributes aren't allowed to have a default */ + if (! defineAttribute( + parser->m_declElementType, parser->m_declAttributeId, + parser->m_declAttributeIsCdata, XML_FALSE, attVal, parser)) + return XML_ERROR_NO_MEMORY; + if (parser->m_attlistDeclHandler && parser->m_declAttributeType) { + if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN) + || (*parser->m_declAttributeType == XML_T(ASCII_N) + && parser->m_declAttributeType[1] == XML_T(ASCII_O))) { + /* Enumerated or Notation type */ + if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN)) + || ! poolAppendChar(&parser->m_tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + parser->m_declAttributeType = parser->m_tempPool.start; + poolFinish(&parser->m_tempPool); + } + *eventEndPP = s; + parser->m_attlistDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, + parser->m_declAttributeId->name, parser->m_declAttributeType, + attVal, role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); + poolClear(&parser->m_tempPool); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_ENTITY_VALUE: + if (dtd->keepProcessing) { + enum XML_Error result + = storeEntityValue(parser, enc, s + enc->minBytesPerChar, + next - enc->minBytesPerChar, XML_ACCOUNT_NONE); + if (parser->m_declEntity) { + parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool); + parser->m_declEntity->textLen + = (int)(poolLength(&dtd->entityValuePool)); + poolFinish(&dtd->entityValuePool); + if (parser->m_entityDeclHandler) { + *eventEndPP = s; + parser->m_entityDeclHandler( + parser->m_handlerArg, parser->m_declEntity->name, + parser->m_declEntity->is_param, parser->m_declEntity->textPtr, + parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0); + handleDefault = XML_FALSE; + } + } else + poolDiscard(&dtd->entityValuePool); + if (result != XML_ERROR_NONE) + return result; + } + break; + case XML_ROLE_DOCTYPE_SYSTEM_ID: +#ifdef XML_DTD + parser->m_useForeignDTD = XML_FALSE; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (parser->m_startDoctypeDeclHandler) { + parser->m_doctypeSysid = poolStoreString(&parser->m_tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (parser->m_doctypeSysid == NULL) + return XML_ERROR_NO_MEMORY; + poolFinish(&parser->m_tempPool); + handleDefault = XML_FALSE; + } +#ifdef XML_DTD + else + /* use externalSubsetName to make parser->m_doctypeSysid non-NULL + for the case where no parser->m_startDoctypeDeclHandler is set */ + parser->m_doctypeSysid = externalSubsetName; +#endif /* XML_DTD */ + if (! dtd->standalone +#ifdef XML_DTD + && ! parser->m_paramEntityParsing +#endif /* XML_DTD */ + && parser->m_notStandaloneHandler + && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) + return XML_ERROR_NOT_STANDALONE; +#ifndef XML_DTD + break; +#else /* XML_DTD */ + if (! parser->m_declEntity) { + parser->m_declEntity = (ENTITY *)lookup( + parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY)); + if (! parser->m_declEntity) + return XML_ERROR_NO_MEMORY; + parser->m_declEntity->publicId = NULL; + } +#endif /* XML_DTD */ + /* fall through */ + case XML_ROLE_ENTITY_SYSTEM_ID: + if (dtd->keepProcessing && parser->m_declEntity) { + parser->m_declEntity->systemId + = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! parser->m_declEntity->systemId) + return XML_ERROR_NO_MEMORY; + parser->m_declEntity->base = parser->m_curBase; + poolFinish(&dtd->pool); + /* Don't suppress the default handler if we fell through from + * the XML_ROLE_DOCTYPE_SYSTEM_ID case. + */ + if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_SYSTEM_ID) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_COMPLETE: + if (dtd->keepProcessing && parser->m_declEntity + && parser->m_entityDeclHandler) { + *eventEndPP = s; + parser->m_entityDeclHandler( + parser->m_handlerArg, parser->m_declEntity->name, + parser->m_declEntity->is_param, 0, 0, parser->m_declEntity->base, + parser->m_declEntity->systemId, parser->m_declEntity->publicId, 0); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_NOTATION_NAME: + if (dtd->keepProcessing && parser->m_declEntity) { + parser->m_declEntity->notation + = poolStoreString(&dtd->pool, enc, s, next); + if (! parser->m_declEntity->notation) + return XML_ERROR_NO_MEMORY; + poolFinish(&dtd->pool); + if (parser->m_unparsedEntityDeclHandler) { + *eventEndPP = s; + parser->m_unparsedEntityDeclHandler( + parser->m_handlerArg, parser->m_declEntity->name, + parser->m_declEntity->base, parser->m_declEntity->systemId, + parser->m_declEntity->publicId, parser->m_declEntity->notation); + handleDefault = XML_FALSE; + } else if (parser->m_entityDeclHandler) { + *eventEndPP = s; + parser->m_entityDeclHandler( + parser->m_handlerArg, parser->m_declEntity->name, 0, 0, 0, + parser->m_declEntity->base, parser->m_declEntity->systemId, + parser->m_declEntity->publicId, parser->m_declEntity->notation); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_GENERAL_ENTITY_NAME: { + if (XmlPredefinedEntityName(enc, s, next)) { + parser->m_declEntity = NULL; + break; + } + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (! name) + return XML_ERROR_NO_MEMORY; + parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, + name, sizeof(ENTITY)); + if (! parser->m_declEntity) + return XML_ERROR_NO_MEMORY; + if (parser->m_declEntity->name != name) { + poolDiscard(&dtd->pool); + parser->m_declEntity = NULL; + } else { + poolFinish(&dtd->pool); + parser->m_declEntity->publicId = NULL; + parser->m_declEntity->is_param = XML_FALSE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + parser->m_declEntity->is_internal + = ! (parser->m_parentParser || parser->m_openInternalEntities); + if (parser->m_entityDeclHandler) + handleDefault = XML_FALSE; + } + } else { + poolDiscard(&dtd->pool); + parser->m_declEntity = NULL; + } + } break; + case XML_ROLE_PARAM_ENTITY_NAME: +#ifdef XML_DTD + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (! name) + return XML_ERROR_NO_MEMORY; + parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, + name, sizeof(ENTITY)); + if (! parser->m_declEntity) + return XML_ERROR_NO_MEMORY; + if (parser->m_declEntity->name != name) { + poolDiscard(&dtd->pool); + parser->m_declEntity = NULL; + } else { + poolFinish(&dtd->pool); + parser->m_declEntity->publicId = NULL; + parser->m_declEntity->is_param = XML_TRUE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + parser->m_declEntity->is_internal + = ! (parser->m_parentParser || parser->m_openInternalEntities); + if (parser->m_entityDeclHandler) + handleDefault = XML_FALSE; + } + } else { + poolDiscard(&dtd->pool); + parser->m_declEntity = NULL; + } +#else /* not XML_DTD */ + parser->m_declEntity = NULL; +#endif /* XML_DTD */ + break; + case XML_ROLE_NOTATION_NAME: + parser->m_declNotationPublicId = NULL; + parser->m_declNotationName = NULL; + if (parser->m_notationDeclHandler) { + parser->m_declNotationName + = poolStoreString(&parser->m_tempPool, enc, s, next); + if (! parser->m_declNotationName) + return XML_ERROR_NO_MEMORY; + poolFinish(&parser->m_tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_PUBLIC_ID: + if (! XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + if (parser + ->m_declNotationName) { /* means m_notationDeclHandler != NULL */ + XML_Char *tem = poolStoreString(&parser->m_tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + parser->m_declNotationPublicId = tem; + poolFinish(&parser->m_tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_SYSTEM_ID: + if (parser->m_declNotationName && parser->m_notationDeclHandler) { + const XML_Char *systemId = poolStoreString(&parser->m_tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! systemId) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + parser->m_notationDeclHandler( + parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase, + systemId, parser->m_declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&parser->m_tempPool); + break; + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) { + *eventEndPP = s; + parser->m_notationDeclHandler( + parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase, + 0, parser->m_declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&parser->m_tempPool); + break; + case XML_ROLE_ERROR: + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + /* PE references in internal subset are + not allowed within declarations. */ + return XML_ERROR_PARAM_ENTITY_REF; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + default: + return XML_ERROR_SYNTAX; + } +#ifdef XML_DTD + case XML_ROLE_IGNORE_SECT: { + enum XML_Error result; + if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + handleDefault = XML_FALSE; + result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore); + if (result != XML_ERROR_NONE) + return result; + else if (! next) { + parser->m_processor = ignoreSectionProcessor; + return result; + } + } break; +#endif /* XML_DTD */ + case XML_ROLE_GROUP_OPEN: + if (parser->m_prologState.level >= parser->m_groupSize) { + if (parser->m_groupSize) { + { + /* Detect and prevent integer overflow */ + if (parser->m_groupSize > (unsigned int)(-1) / 2u) { + return XML_ERROR_NO_MEMORY; + } + + char *const new_connector = (char *)REALLOC( + parser, parser->m_groupConnector, parser->m_groupSize *= 2); + if (new_connector == NULL) { + parser->m_groupSize /= 2; + return XML_ERROR_NO_MEMORY; + } + parser->m_groupConnector = new_connector; + } + + if (dtd->scaffIndex) { + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) { + return XML_ERROR_NO_MEMORY; + } +#endif + + int *const new_scaff_index = (int *)REALLOC( + parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int)); + if (new_scaff_index == NULL) + return XML_ERROR_NO_MEMORY; + dtd->scaffIndex = new_scaff_index; + } + } else { + parser->m_groupConnector + = (char *)MALLOC(parser, parser->m_groupSize = 32); + if (! parser->m_groupConnector) { + parser->m_groupSize = 0; + return XML_ERROR_NO_MEMORY; + } + } + } + parser->m_groupConnector[parser->m_prologState.level] = 0; + if (dtd->in_eldecl) { + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + assert(dtd->scaffIndex != NULL); + dtd->scaffIndex[dtd->scaffLevel] = myindex; + dtd->scaffLevel++; + dtd->scaffold[myindex].type = XML_CTYPE_SEQ; + if (parser->m_elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_GROUP_SEQUENCE: + if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_PIPE) + return XML_ERROR_SYNTAX; + parser->m_groupConnector[parser->m_prologState.level] = ASCII_COMMA; + if (dtd->in_eldecl && parser->m_elementDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_GROUP_CHOICE: + if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_COMMA) + return XML_ERROR_SYNTAX; + if (dtd->in_eldecl + && ! parser->m_groupConnector[parser->m_prologState.level] + && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + != XML_CTYPE_MIXED)) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_CHOICE; + if (parser->m_elementDeclHandler) + handleDefault = XML_FALSE; + } + parser->m_groupConnector[parser->m_prologState.level] = ASCII_PIPE; + break; + case XML_ROLE_PARAM_ENTITY_REF: +#ifdef XML_DTD + case XML_ROLE_INNER_PARAM_ENTITY_REF: + dtd->hasParamEntityRefs = XML_TRUE; + if (! parser->m_paramEntityParsing) + dtd->keepProcessing = dtd->standalone; + else { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); + poolDiscard(&dtd->pool); + /* first, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity handler + */ + if (parser->m_prologState.documentEntity + && (dtd->standalone ? ! parser->m_openInternalEntities + : ! dtd->hasParamEntityRefs)) { + if (! entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (! entity->is_internal) { + /* It's hard to exhaustively search the code to be sure, + * but there doesn't seem to be a way of executing the + * following line. There are two cases: + * + * If 'standalone' is false, the DTD must have no + * parameter entities or we wouldn't have passed the outer + * 'if' statement. That means the only entity in the hash + * table is the external subset name "#" which cannot be + * given as a parameter entity name in XML syntax, so the + * lookup must have returned NULL and we don't even reach + * the test for an internal entity. + * + * If 'standalone' is true, it does not seem to be + * possible to create entities taking this code path that + * are not internal entities, so fail the test above. + * + * Because this analysis is very uncertain, the code is + * being left in place and merely removed from the + * coverage test statistics. + */ + return XML_ERROR_ENTITY_DECLARED_IN_PE; /* LCOV_EXCL_LINE */ + } + } else if (! entity) { + dtd->keepProcessing = dtd->standalone; + /* cannot report skipped entities in declarations */ + if ((role == XML_ROLE_PARAM_ENTITY_REF) + && parser->m_skippedEntityHandler) { + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1); + handleDefault = XML_FALSE; + } + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + XML_Bool betweenDecl + = (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); + result = processInternalEntity(parser, entity, betweenDecl); + if (result != XML_ERROR_NONE) + return result; + handleDefault = XML_FALSE; + break; + } + if (parser->m_externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + entityTrackingOnOpen(parser, entity, __LINE__); + if (! parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId)) { + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + handleDefault = XML_FALSE; + if (! dtd->paramEntityRead) { + dtd->keepProcessing = dtd->standalone; + break; + } + } else { + dtd->keepProcessing = dtd->standalone; + break; + } + } +#endif /* XML_DTD */ + if (! dtd->standalone && parser->m_notStandaloneHandler + && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) + return XML_ERROR_NOT_STANDALONE; + break; + + /* Element declaration stuff */ + + case XML_ROLE_ELEMENT_NAME: + if (parser->m_elementDeclHandler) { + parser->m_declElementType = getElementType(parser, enc, s, next); + if (! parser->m_declElementType) + return XML_ERROR_NO_MEMORY; + dtd->scaffLevel = 0; + dtd->scaffCount = 0; + dtd->in_eldecl = XML_TRUE; + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ANY: + case XML_ROLE_CONTENT_EMPTY: + if (dtd->in_eldecl) { + if (parser->m_elementDeclHandler) { + XML_Content *content + = (XML_Content *)MALLOC(parser, sizeof(XML_Content)); + if (! content) + return XML_ERROR_NO_MEMORY; + content->quant = XML_CQUANT_NONE; + content->name = NULL; + content->numchildren = 0; + content->children = NULL; + content->type = ((role == XML_ROLE_CONTENT_ANY) ? XML_CTYPE_ANY + : XML_CTYPE_EMPTY); + *eventEndPP = s; + parser->m_elementDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, content); + handleDefault = XML_FALSE; + } + dtd->in_eldecl = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_PCDATA: + if (dtd->in_eldecl) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_MIXED; + if (parser->m_elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ELEMENT: + quant = XML_CQUANT_NONE; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_OPT: + quant = XML_CQUANT_OPT; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_REP: + quant = XML_CQUANT_REP; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_PLUS: + quant = XML_CQUANT_PLUS; + elementContent: + if (dtd->in_eldecl) { + ELEMENT_TYPE *el; + const XML_Char *name; + size_t nameLen; + const char *nxt + = (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar); + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd->scaffold[myindex].type = XML_CTYPE_NAME; + dtd->scaffold[myindex].quant = quant; + el = getElementType(parser, enc, s, nxt); + if (! el) + return XML_ERROR_NO_MEMORY; + name = el->name; + dtd->scaffold[myindex].name = name; + nameLen = 0; + for (; name[nameLen++];) + ; + + /* Detect and prevent integer overflow */ + if (nameLen > UINT_MAX - dtd->contentStringLen) { + return XML_ERROR_NO_MEMORY; + } + + dtd->contentStringLen += (unsigned)nameLen; + if (parser->m_elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_GROUP_CLOSE: + quant = XML_CQUANT_NONE; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_OPT: + quant = XML_CQUANT_OPT; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_REP: + quant = XML_CQUANT_REP; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_PLUS: + quant = XML_CQUANT_PLUS; + closeGroup: + if (dtd->in_eldecl) { + if (parser->m_elementDeclHandler) + handleDefault = XML_FALSE; + dtd->scaffLevel--; + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant; + if (dtd->scaffLevel == 0) { + if (! handleDefault) { + XML_Content *model = build_model(parser); + if (! model) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + parser->m_elementDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, model); + } + dtd->in_eldecl = XML_FALSE; + dtd->contentStringLen = 0; + } + } + break; + /* End element declaration stuff */ + + case XML_ROLE_PI: + if (! reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_COMMENT: + if (! reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_NONE: + switch (tok) { + case XML_TOK_BOM: + handleDefault = XML_FALSE; + break; + } + break; + case XML_ROLE_DOCTYPE_NONE: + if (parser->m_startDoctypeDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ENTITY_NONE: + if (dtd->keepProcessing && parser->m_entityDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_NOTATION_NONE: + if (parser->m_notationDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTLIST_NONE: + if (dtd->keepProcessing && parser->m_attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ELEMENT_NONE: + if (parser->m_elementDeclHandler) + handleDefault = XML_FALSE; + break; + } /* end of big switch */ + + if (handleDefault && parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + s = next; + tok = XmlPrologTok(enc, s, end, &next); + } + } + /* not reached */ +} + +static enum XML_Error PTRCALL +epilogProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + parser->m_processor = epilogProcessor; + parser->m_eventPtr = s; + for (;;) { + const char *next = NULL; + int tok = XmlPrologTok(parser->m_encoding, s, end, &next); +#ifdef XML_DTD + if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, + XML_ACCOUNT_DIRECT)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +#endif + parser->m_eventEndPtr = next; + switch (tok) { + /* report partial linebreak - it might be the last token */ + case -XML_TOK_PROLOG_S: + if (parser->m_defaultHandler) { + reportDefault(parser, parser->m_encoding, s, next); + if (parser->m_parsingStatus.parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + } + *nextPtr = next; + return XML_ERROR_NONE; + case XML_TOK_NONE: + *nextPtr = s; + return XML_ERROR_NONE; + case XML_TOK_PROLOG_S: + if (parser->m_defaultHandler) + reportDefault(parser, parser->m_encoding, s, next); + break; + case XML_TOK_PI: + if (! reportProcessingInstruction(parser, parser->m_encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (! reportComment(parser, parser->m_encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_INVALID: + parser->m_eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (! parser->m_parsingStatus.finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (! parser->m_parsingStatus.finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + default: + return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; + } + parser->m_eventPtr = s = next; + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default:; + } + } +} + +static enum XML_Error +processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) { + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity; + + if (parser->m_freeInternalEntities) { + openEntity = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity->next; + } else { + openEntity + = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY)); + if (! openEntity) + return XML_ERROR_NO_MEMORY; + } + entity->open = XML_TRUE; +#ifdef XML_DTD + entityTrackingOnOpen(parser, entity, __LINE__); +#endif + entity->processed = 0; + openEntity->next = parser->m_openInternalEntities; + parser->m_openInternalEntities = openEntity; + openEntity->entity = entity; + openEntity->startTagLevel = parser->m_tagLevel; + openEntity->betweenDecl = betweenDecl; + openEntity->internalEventPtr = NULL; + openEntity->internalEventEndPtr = NULL; + textStart = (const char *)entity->textPtr; + textEnd = (const char *)(entity->textPtr + entity->textLen); + /* Set a safe default value in case 'next' does not get set */ + next = textStart; + +#ifdef XML_DTD + if (entity->is_param) { + int tok + = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, + tok, next, &next, XML_FALSE, XML_FALSE, + XML_ACCOUNT_ENTITY_EXPANSION); + } else +#endif /* XML_DTD */ + result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding, + textStart, textEnd, &next, XML_FALSE, + XML_ACCOUNT_ENTITY_EXPANSION); + + if (result == XML_ERROR_NONE) { + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + entity->processed = (int)(next - textStart); + parser->m_processor = internalEntityProcessor; + } else { +#ifdef XML_DTD + entityTrackingOnClose(parser, entity, __LINE__); +#endif /* XML_DTD */ + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + } + } + return result; +} + +static enum XML_Error PTRCALL +internalEntityProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + ENTITY *entity; + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity = parser->m_openInternalEntities; + if (! openEntity) + return XML_ERROR_UNEXPECTED_STATE; + + entity = openEntity->entity; + textStart = ((const char *)entity->textPtr) + entity->processed; + textEnd = (const char *)(entity->textPtr + entity->textLen); + /* Set a safe default value in case 'next' does not get set */ + next = textStart; + +#ifdef XML_DTD + if (entity->is_param) { + int tok + = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, + tok, next, &next, XML_FALSE, XML_TRUE, + XML_ACCOUNT_ENTITY_EXPANSION); + } else +#endif /* XML_DTD */ + result = doContent(parser, openEntity->startTagLevel, + parser->m_internalEncoding, textStart, textEnd, &next, + XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION); + + if (result != XML_ERROR_NONE) + return result; + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + entity->processed = (int)(next - (const char *)entity->textPtr); + return result; + } + +#ifdef XML_DTD + entityTrackingOnClose(parser, entity, __LINE__); +#endif + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; + } + +#ifdef XML_DTD + if (entity->is_param) { + int tok; + parser->m_processor = prologProcessor; + tok = XmlPrologTok(parser->m_encoding, s, end, &next); + return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE, + XML_ACCOUNT_DIRECT); + } else +#endif /* XML_DTD */ + { + parser->m_processor = contentProcessor; + /* see externalEntityContentProcessor vs contentProcessor */ + result = doContent(parser, parser->m_parentParser ? 1 : 0, + parser->m_encoding, s, end, nextPtr, + (XML_Bool)! parser->m_parsingStatus.finalBuffer, + XML_ACCOUNT_DIRECT); + if (result == XML_ERROR_NONE) { + if (! storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; + } +} + +static enum XML_Error PTRCALL +errorProcessor(XML_Parser parser, const char *s, const char *end, + const char **nextPtr) { + UNUSED_P(s); + UNUSED_P(end); + UNUSED_P(nextPtr); + return parser->m_errorCode; +} + +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, STRING_POOL *pool, + enum XML_Account account) { + enum XML_Error result + = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account); + if (result) + return result; + if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) + poolChop(pool); + if (! poolAppendChar(pool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + return XML_ERROR_NONE; +} + +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, STRING_POOL *pool, + enum XML_Account account) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ +#ifndef XML_DTD + UNUSED_P(account); +#endif + + for (;;) { + const char *next + = ptr; /* XmlAttributeValueTok doesn't always set the last arg */ + int tok = XmlAttributeValueTok(enc, ptr, end, &next); +#ifdef XML_DTD + if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) { + accountingOnAbort(parser); + return XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + } +#endif + switch (tok) { + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_INVALID: + if (enc == parser->m_encoding) + parser->m_eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (enc == parser->m_encoding) + parser->m_eventPtr = ptr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_CHAR_REF: { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, ptr); + if (n < 0) { + if (enc == parser->m_encoding) + parser->m_eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + if (! isCdata && n == 0x20 /* space */ + && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + n = XmlEncode(n, (ICHAR *)buf); + /* The XmlEncode() functions can never return 0 here. That + * error return happens if the code point passed in is either + * negative or greater than or equal to 0x110000. The + * XmlCharRefNumber() functions will all return a number + * strictly less than 0x110000 or a negative value if an error + * occurred. The negative value is intercepted above, so + * XmlEncode() is never passed a value it might return an + * error for. + */ + for (i = 0; i < n; i++) { + if (! poolAppendChar(pool, buf[i])) + return XML_ERROR_NO_MEMORY; + } + } break; + case XML_TOK_DATA_CHARS: + if (! poolAppend(pool, enc, ptr, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_TRAILING_CR: + next = ptr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_ATTRIBUTE_VALUE_S: + case XML_TOK_DATA_NEWLINE: + if (! isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + if (! poolAppendChar(pool, 0x20)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_ENTITY_REF: { + const XML_Char *name; + ENTITY *entity; + char checkEntityDecl; + XML_Char ch = (XML_Char)XmlPredefinedEntityName( + enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar); + if (ch) { +#ifdef XML_DTD + /* NOTE: We are replacing 4-6 characters original input for 1 character + * so there is no amplification and hence recording without + * protection. */ + accountingDiffTolerated(parser, tok, (char *)&ch, + ((char *)&ch) + sizeof(XML_Char), __LINE__, + XML_ACCOUNT_ENTITY_EXPANSION); +#endif /* XML_DTD */ + if (! poolAppendChar(pool, ch)) + return XML_ERROR_NO_MEMORY; + break; + } + name = poolStoreString(&parser->m_temp2Pool, enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); + poolDiscard(&parser->m_temp2Pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal. + */ + if (pool == &dtd->pool) /* are we called from prolog? */ + checkEntityDecl = +#ifdef XML_DTD + parser->m_prologState.documentEntity && +#endif /* XML_DTD */ + (dtd->standalone ? ! parser->m_openInternalEntities + : ! dtd->hasParamEntityRefs); + else /* if (pool == &parser->m_tempPool): we are called from content */ + checkEntityDecl = ! dtd->hasParamEntityRefs || dtd->standalone; + if (checkEntityDecl) { + if (! entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (! entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } else if (! entity) { + /* Cannot report skipped entity here - see comments on + parser->m_skippedEntityHandler. + if (parser->m_skippedEntityHandler) + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); + */ + /* Cannot call the default handler because this would be + out of sync with the call to the startElementHandler. + if ((pool == &parser->m_tempPool) && parser->m_defaultHandler) + reportDefault(parser, enc, ptr, next); + */ + break; + } + if (entity->open) { + if (enc == parser->m_encoding) { + /* It does not appear that this line can be executed. + * + * The "if (entity->open)" check catches recursive entity + * definitions. In order to be called with an open + * entity, it must have gone through this code before and + * been through the recursive call to + * appendAttributeValue() some lines below. That call + * sets the local encoding ("enc") to the parser's + * internal encoding (internal_utf8 or internal_utf16), + * which can never be the same as the principle encoding. + * It doesn't appear there is another code path that gets + * here with entity->open being TRUE. + * + * Since it is not certain that this logic is watertight, + * we keep the line and merely exclude it from coverage + * tests. + */ + parser->m_eventPtr = ptr; /* LCOV_EXCL_LINE */ + } + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + if (entity->notation) { + if (enc == parser->m_encoding) + parser->m_eventPtr = ptr; + return XML_ERROR_BINARY_ENTITY_REF; + } + if (! entity->textPtr) { + if (enc == parser->m_encoding) + parser->m_eventPtr = ptr; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + } else { + enum XML_Error result; + const XML_Char *textEnd = entity->textPtr + entity->textLen; + entity->open = XML_TRUE; +#ifdef XML_DTD + entityTrackingOnOpen(parser, entity, __LINE__); +#endif + result = appendAttributeValue(parser, parser->m_internalEncoding, + isCdata, (const char *)entity->textPtr, + (const char *)textEnd, pool, + XML_ACCOUNT_ENTITY_EXPANSION); +#ifdef XML_DTD + entityTrackingOnClose(parser, entity, __LINE__); +#endif + entity->open = XML_FALSE; + if (result) + return result; + } + } break; + default: + /* The only token returned by XmlAttributeValueTok() that does + * not have an explicit case here is XML_TOK_PARTIAL_CHAR. + * Getting that would require an entity name to contain an + * incomplete XML character (e.g. \xE2\x82); however previous + * tokenisers will have already recognised and rejected such + * names before XmlAttributeValueTok() gets a look-in. This + * default case should be retained as a safety net, but the code + * excluded from coverage tests. + * + * LCOV_EXCL_START + */ + if (enc == parser->m_encoding) + parser->m_eventPtr = ptr; + return XML_ERROR_UNEXPECTED_STATE; + /* LCOV_EXCL_STOP */ + } + ptr = next; + } + /* not reached */ +} + +static enum XML_Error +storeEntityValue(XML_Parser parser, const ENCODING *enc, + const char *entityTextPtr, const char *entityTextEnd, + enum XML_Account account) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + STRING_POOL *pool = &(dtd->entityValuePool); + enum XML_Error result = XML_ERROR_NONE; +#ifdef XML_DTD + int oldInEntityValue = parser->m_prologState.inEntityValue; + parser->m_prologState.inEntityValue = 1; +#else + UNUSED_P(account); +#endif /* XML_DTD */ + /* never return Null for the value argument in EntityDeclHandler, + since this would indicate an external entity; therefore we + have to make sure that entityValuePool.start is not null */ + if (! pool->blocks) { + if (! poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + } + + for (;;) { + const char *next + = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */ + int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); + +#ifdef XML_DTD + if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__, + account)) { + accountingOnAbort(parser); + result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH; + goto endEntityValue; + } +#endif + + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: +#ifdef XML_DTD + if (parser->m_isParamEntity || enc != parser->m_encoding) { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&parser->m_tempPool, enc, + entityTextPtr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (! name) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); + poolDiscard(&parser->m_tempPool); + if (! entity) { + /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ + /* cannot report skipped entity here - see comments on + parser->m_skippedEntityHandler + if (parser->m_skippedEntityHandler) + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); + */ + dtd->keepProcessing = dtd->standalone; + goto endEntityValue; + } + if (entity->open) { + if (enc == parser->m_encoding) + parser->m_eventPtr = entityTextPtr; + result = XML_ERROR_RECURSIVE_ENTITY_REF; + goto endEntityValue; + } + if (entity->systemId) { + if (parser->m_externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + entityTrackingOnOpen(parser, entity, __LINE__); + if (! parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId)) { + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; + goto endEntityValue; + } + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + if (! dtd->paramEntityRead) + dtd->keepProcessing = dtd->standalone; + } else + dtd->keepProcessing = dtd->standalone; + } else { + entity->open = XML_TRUE; + entityTrackingOnOpen(parser, entity, __LINE__); + result = storeEntityValue( + parser, parser->m_internalEncoding, (const char *)entity->textPtr, + (const char *)(entity->textPtr + entity->textLen), + XML_ACCOUNT_ENTITY_EXPANSION); + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + if (result) + goto endEntityValue; + } + break; + } +#endif /* XML_DTD */ + /* In the internal subset, PE references are not legal + within markup declarations, e.g entity values in this case. */ + parser->m_eventPtr = entityTextPtr; + result = XML_ERROR_PARAM_ENTITY_REF; + goto endEntityValue; + case XML_TOK_NONE: + result = XML_ERROR_NONE; + goto endEntityValue; + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (! poolAppend(pool, enc, entityTextPtr, next)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + break; + case XML_TOK_TRAILING_CR: + next = entityTextPtr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_DATA_NEWLINE: + if (pool->end == pool->ptr && ! poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = 0xA; + break; + case XML_TOK_CHAR_REF: { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, entityTextPtr); + if (n < 0) { + if (enc == parser->m_encoding) + parser->m_eventPtr = entityTextPtr; + result = XML_ERROR_BAD_CHAR_REF; + goto endEntityValue; + } + n = XmlEncode(n, (ICHAR *)buf); + /* The XmlEncode() functions can never return 0 here. That + * error return happens if the code point passed in is either + * negative or greater than or equal to 0x110000. The + * XmlCharRefNumber() functions will all return a number + * strictly less than 0x110000 or a negative value if an error + * occurred. The negative value is intercepted above, so + * XmlEncode() is never passed a value it might return an + * error for. + */ + for (i = 0; i < n; i++) { + if (pool->end == pool->ptr && ! poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = buf[i]; + } + } break; + case XML_TOK_PARTIAL: + if (enc == parser->m_encoding) + parser->m_eventPtr = entityTextPtr; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + case XML_TOK_INVALID: + if (enc == parser->m_encoding) + parser->m_eventPtr = next; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + default: + /* This default case should be unnecessary -- all the tokens + * that XmlEntityValueTok() can return have their own explicit + * cases -- but should be retained for safety. We do however + * exclude it from the coverage statistics. + * + * LCOV_EXCL_START + */ + if (enc == parser->m_encoding) + parser->m_eventPtr = entityTextPtr; + result = XML_ERROR_UNEXPECTED_STATE; + goto endEntityValue; + /* LCOV_EXCL_STOP */ + } + entityTextPtr = next; + } +endEntityValue: +#ifdef XML_DTD + parser->m_prologState.inEntityValue = oldInEntityValue; +#endif /* XML_DTD */ + return result; +} + +static void FASTCALL +normalizeLines(XML_Char *s) { + XML_Char *p; + for (;; s++) { + if (*s == XML_T('\0')) + return; + if (*s == 0xD) + break; + } + p = s; + do { + if (*s == 0xD) { + *p++ = 0xA; + if (*++s == 0xA) + s++; + } else + *p++ = *s++; + } while (*s); + *p = XML_T('\0'); +} + +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) { + const XML_Char *target; + XML_Char *data; + const char *tem; + if (! parser->m_processingInstructionHandler) { + if (parser->m_defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + start += enc->minBytesPerChar * 2; + tem = start + XmlNameLength(enc, start); + target = poolStoreString(&parser->m_tempPool, enc, start, tem); + if (! target) + return 0; + poolFinish(&parser->m_tempPool); + data = poolStoreString(&parser->m_tempPool, enc, XmlSkipS(enc, tem), + end - enc->minBytesPerChar * 2); + if (! data) + return 0; + normalizeLines(data); + parser->m_processingInstructionHandler(parser->m_handlerArg, target, data); + poolClear(&parser->m_tempPool); + return 1; +} + +static int +reportComment(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end) { + XML_Char *data; + if (! parser->m_commentHandler) { + if (parser->m_defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + data = poolStoreString(&parser->m_tempPool, enc, + start + enc->minBytesPerChar * 4, + end - enc->minBytesPerChar * 3); + if (! data) + return 0; + normalizeLines(data); + parser->m_commentHandler(parser->m_handlerArg, data); + poolClear(&parser->m_tempPool); + return 1; +} + +static void +reportDefault(XML_Parser parser, const ENCODING *enc, const char *s, + const char *end) { + if (MUST_CONVERT(enc, s)) { + enum XML_Convert_Result convert_res; + const char **eventPP; + const char **eventEndPP; + if (enc == parser->m_encoding) { + eventPP = &parser->m_eventPtr; + eventEndPP = &parser->m_eventEndPtr; + } else { + /* To get here, two things must be true; the parser must be + * using a character encoding that is not the same as the + * encoding passed in, and the encoding passed in must need + * conversion to the internal format (UTF-8 unless XML_UNICODE + * is defined). The only occasions on which the encoding passed + * in is not the same as the parser's encoding are when it is + * the internal encoding (e.g. a previously defined parameter + * entity, already converted to internal format). This by + * definition doesn't need conversion, so the whole branch never + * gets executed. + * + * For safety's sake we don't delete these lines and merely + * exclude them from coverage statistics. + * + * LCOV_EXCL_START + */ + eventPP = &(parser->m_openInternalEntities->internalEventPtr); + eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr); + /* LCOV_EXCL_STOP */ + } + do { + ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf; + convert_res + = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd); + *eventEndPP = s; + parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf, + (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); + *eventPP = s; + } while ((convert_res != XML_CONVERT_COMPLETED) + && (convert_res != XML_CONVERT_INPUT_INCOMPLETE)); + } else + parser->m_defaultHandler(parser->m_handlerArg, (XML_Char *)s, + (int)((XML_Char *)end - (XML_Char *)s)); +} + +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, + XML_Bool isId, const XML_Char *value, XML_Parser parser) { + DEFAULT_ATTRIBUTE *att; + if (value || isId) { + /* The handling of default attributes gets messed up if we have + a default which duplicates a non-default. */ + int i; + for (i = 0; i < type->nDefaultAtts; i++) + if (attId == type->defaultAtts[i].id) + return 1; + if (isId && ! type->idAtt && ! attId->xmlns) + type->idAtt = attId; + } + if (type->nDefaultAtts == type->allocDefaultAtts) { + if (type->allocDefaultAtts == 0) { + type->allocDefaultAtts = 8; + type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC( + parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + if (! type->defaultAtts) { + type->allocDefaultAtts = 0; + return 0; + } + } else { + DEFAULT_ATTRIBUTE *temp; + + /* Detect and prevent integer overflow */ + if (type->allocDefaultAtts > INT_MAX / 2) { + return 0; + } + + int count = type->allocDefaultAtts * 2; + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) { + return 0; + } +#endif + + temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts, + (count * sizeof(DEFAULT_ATTRIBUTE))); + if (temp == NULL) + return 0; + type->allocDefaultAtts = count; + type->defaultAtts = temp; + } + } + att = type->defaultAtts + type->nDefaultAtts; + att->id = attId; + att->value = value; + att->isCdata = isCdata; + if (! isCdata) + attId->maybeTokenized = XML_TRUE; + type->nDefaultAtts += 1; + return 1; +} + +static int +setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + const XML_Char *name; + for (name = elementType->name; *name; name++) { + if (*name == XML_T(ASCII_COLON)) { + PREFIX *prefix; + const XML_Char *s; + for (s = elementType->name; s != name; s++) { + if (! poolAppendChar(&dtd->pool, *s)) + return 0; + } + if (! poolAppendChar(&dtd->pool, XML_T('\0'))) + return 0; + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), + sizeof(PREFIX)); + if (! prefix) + return 0; + if (prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + elementType->prefix = prefix; + break; + } + } + return 1; +} + +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + ATTRIBUTE_ID *id; + const XML_Char *name; + if (! poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + name = poolStoreString(&dtd->pool, enc, start, end); + if (! name) + return NULL; + /* skip quotation mark - its storage will be re-used (like in name[-1]) */ + ++name; + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, + sizeof(ATTRIBUTE_ID)); + if (! id) + return NULL; + if (id->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (! parser->m_ns) + ; + else if (name[0] == XML_T(ASCII_x) && name[1] == XML_T(ASCII_m) + && name[2] == XML_T(ASCII_l) && name[3] == XML_T(ASCII_n) + && name[4] == XML_T(ASCII_s) + && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) { + if (name[5] == XML_T('\0')) + id->prefix = &dtd->defaultPrefix; + else + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, + sizeof(PREFIX)); + id->xmlns = XML_TRUE; + } else { + int i; + for (i = 0; name[i]; i++) { + /* attributes without prefix are *not* in the default namespace */ + if (name[i] == XML_T(ASCII_COLON)) { + int j; + for (j = 0; j < i; j++) { + if (! poolAppendChar(&dtd->pool, name[j])) + return NULL; + } + if (! poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, + poolStart(&dtd->pool), sizeof(PREFIX)); + if (! id->prefix) + return NULL; + if (id->prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + break; + } + } + } + } + return id; +} + +#define CONTEXT_SEP XML_T(ASCII_FF) + +static const XML_Char * +getContext(XML_Parser parser) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + HASH_TABLE_ITER iter; + XML_Bool needSep = XML_FALSE; + + if (dtd->defaultPrefix.binding) { + int i; + int len; + if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS))) + return NULL; + len = dtd->defaultPrefix.binding->uriLen; + if (parser->m_namespaceSeparator) + len--; + for (i = 0; i < len; i++) { + if (! poolAppendChar(&parser->m_tempPool, + dtd->defaultPrefix.binding->uri[i])) { + /* Because of memory caching, I don't believe this line can be + * executed. + * + * This is part of a loop copying the default prefix binding + * URI into the parser's temporary string pool. Previously, + * that URI was copied into the same string pool, with a + * terminating NUL character, as part of setContext(). When + * the pool was cleared, that leaves a block definitely big + * enough to hold the URI on the free block list of the pool. + * The URI copy in getContext() therefore cannot run out of + * memory. + * + * If the pool is used between the setContext() and + * getContext() calls, the worst it can do is leave a bigger + * block on the front of the free list. Given that this is + * all somewhat inobvious and program logic can be changed, we + * don't delete the line but we do exclude it from the test + * coverage statistics. + */ + return NULL; /* LCOV_EXCL_LINE */ + } + } + needSep = XML_TRUE; + } + + hashTableIterInit(&iter, &(dtd->prefixes)); + for (;;) { + int i; + int len; + const XML_Char *s; + PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); + if (! prefix) + break; + if (! prefix->binding) { + /* This test appears to be (justifiable) paranoia. There does + * not seem to be a way of injecting a prefix without a binding + * that doesn't get errored long before this function is called. + * The test should remain for safety's sake, so we instead + * exclude the following line from the coverage statistics. + */ + continue; /* LCOV_EXCL_LINE */ + } + if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP)) + return NULL; + for (s = prefix->name; *s; s++) + if (! poolAppendChar(&parser->m_tempPool, *s)) + return NULL; + if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS))) + return NULL; + len = prefix->binding->uriLen; + if (parser->m_namespaceSeparator) + len--; + for (i = 0; i < len; i++) + if (! poolAppendChar(&parser->m_tempPool, prefix->binding->uri[i])) + return NULL; + needSep = XML_TRUE; + } + + hashTableIterInit(&iter, &(dtd->generalEntities)); + for (;;) { + const XML_Char *s; + ENTITY *e = (ENTITY *)hashTableIterNext(&iter); + if (! e) + break; + if (! e->open) + continue; + if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP)) + return NULL; + for (s = e->name; *s; s++) + if (! poolAppendChar(&parser->m_tempPool, *s)) + return 0; + needSep = XML_TRUE; + } + + if (! poolAppendChar(&parser->m_tempPool, XML_T('\0'))) + return NULL; + return parser->m_tempPool.start; +} + +static XML_Bool +setContext(XML_Parser parser, const XML_Char *context) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + const XML_Char *s = context; + + while (*context != XML_T('\0')) { + if (*s == CONTEXT_SEP || *s == XML_T('\0')) { + ENTITY *e; + if (! poolAppendChar(&parser->m_tempPool, XML_T('\0'))) + return XML_FALSE; + e = (ENTITY *)lookup(parser, &dtd->generalEntities, + poolStart(&parser->m_tempPool), 0); + if (e) + e->open = XML_TRUE; + if (*s != XML_T('\0')) + s++; + context = s; + poolDiscard(&parser->m_tempPool); + } else if (*s == XML_T(ASCII_EQUALS)) { + PREFIX *prefix; + if (poolLength(&parser->m_tempPool) == 0) + prefix = &dtd->defaultPrefix; + else { + if (! poolAppendChar(&parser->m_tempPool, XML_T('\0'))) + return XML_FALSE; + prefix + = (PREFIX *)lookup(parser, &dtd->prefixes, + poolStart(&parser->m_tempPool), sizeof(PREFIX)); + if (! prefix) + return XML_FALSE; + if (prefix->name == poolStart(&parser->m_tempPool)) { + prefix->name = poolCopyString(&dtd->pool, prefix->name); + if (! prefix->name) + return XML_FALSE; + } + poolDiscard(&parser->m_tempPool); + } + for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); + context++) + if (! poolAppendChar(&parser->m_tempPool, *context)) + return XML_FALSE; + if (! poolAppendChar(&parser->m_tempPool, XML_T('\0'))) + return XML_FALSE; + if (addBinding(parser, prefix, NULL, poolStart(&parser->m_tempPool), + &parser->m_inheritedBindings) + != XML_ERROR_NONE) + return XML_FALSE; + poolDiscard(&parser->m_tempPool); + if (*context != XML_T('\0')) + ++context; + s = context; + } else { + if (! poolAppendChar(&parser->m_tempPool, *s)) + return XML_FALSE; + s++; + } + } + return XML_TRUE; +} + +static void FASTCALL +normalizePublicId(XML_Char *publicId) { + XML_Char *p = publicId; + XML_Char *s; + for (s = publicId; *s; s++) { + switch (*s) { + case 0x20: + case 0xD: + case 0xA: + if (p != publicId && p[-1] != 0x20) + *p++ = 0x20; + break; + default: + *p++ = *s; + } + } + if (p != publicId && p[-1] == 0x20) + --p; + *p = XML_T('\0'); +} + +static DTD * +dtdCreate(const XML_Memory_Handling_Suite *ms) { + DTD *p = ms->malloc_fcn(sizeof(DTD)); + if (p == NULL) + return p; + poolInit(&(p->pool), ms); + poolInit(&(p->entityValuePool), ms); + hashTableInit(&(p->generalEntities), ms); + hashTableInit(&(p->elementTypes), ms); + hashTableInit(&(p->attributeIds), ms); + hashTableInit(&(p->prefixes), ms); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableInit(&(p->paramEntities), ms); +#endif /* XML_DTD */ + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + p->scaffIndex = NULL; + p->scaffold = NULL; + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; + return p; +} + +static void +dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (! e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableClear(&(p->generalEntities)); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableClear(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableClear(&(p->elementTypes)); + hashTableClear(&(p->attributeIds)); + hashTableClear(&(p->prefixes)); + poolClear(&(p->pool)); + poolClear(&(p->entityValuePool)); + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + + ms->free_fcn(p->scaffIndex); + p->scaffIndex = NULL; + ms->free_fcn(p->scaffold); + p->scaffold = NULL; + + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; +} + +static void +dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (! e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableDestroy(&(p->generalEntities)); +#ifdef XML_DTD + hashTableDestroy(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableDestroy(&(p->elementTypes)); + hashTableDestroy(&(p->attributeIds)); + hashTableDestroy(&(p->prefixes)); + poolDestroy(&(p->pool)); + poolDestroy(&(p->entityValuePool)); + if (isDocEntity) { + ms->free_fcn(p->scaffIndex); + ms->free_fcn(p->scaffold); + } + ms->free_fcn(p); +} + +/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. + The new DTD has already been initialized. +*/ +static int +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, + const XML_Memory_Handling_Suite *ms) { + HASH_TABLE_ITER iter; + + /* Copy the prefix table. */ + + hashTableIterInit(&iter, &(oldDtd->prefixes)); + for (;;) { + const XML_Char *name; + const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); + if (! oldP) + break; + name = poolCopyString(&(newDtd->pool), oldP->name); + if (! name) + return 0; + if (! lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) + return 0; + } + + hashTableIterInit(&iter, &(oldDtd->attributeIds)); + + /* Copy the attribute id table. */ + + for (;;) { + ATTRIBUTE_ID *newA; + const XML_Char *name; + const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); + + if (! oldA) + break; + /* Remember to allocate the scratch byte before the name. */ + if (! poolAppendChar(&(newDtd->pool), XML_T('\0'))) + return 0; + name = poolCopyString(&(newDtd->pool), oldA->name); + if (! name) + return 0; + ++name; + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, + sizeof(ATTRIBUTE_ID)); + if (! newA) + return 0; + newA->maybeTokenized = oldA->maybeTokenized; + if (oldA->prefix) { + newA->xmlns = oldA->xmlns; + if (oldA->prefix == &oldDtd->defaultPrefix) + newA->prefix = &newDtd->defaultPrefix; + else + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), + oldA->prefix->name, 0); + } + } + + /* Copy the element type table. */ + + hashTableIterInit(&iter, &(oldDtd->elementTypes)); + + for (;;) { + int i; + ELEMENT_TYPE *newE; + const XML_Char *name; + const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (! oldE) + break; + name = poolCopyString(&(newDtd->pool), oldE->name); + if (! name) + return 0; + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, + sizeof(ELEMENT_TYPE)); + if (! newE) + return 0; + if (oldE->nDefaultAtts) { + newE->defaultAtts + = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + if (! newE->defaultAtts) { + return 0; + } + } + if (oldE->idAtt) + newE->idAtt = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), + oldE->idAtt->name, 0); + newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; + if (oldE->prefix) + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), + oldE->prefix->name, 0); + for (i = 0; i < newE->nDefaultAtts; i++) { + newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup( + oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; + if (oldE->defaultAtts[i].value) { + newE->defaultAtts[i].value + = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); + if (! newE->defaultAtts[i].value) + return 0; + } else + newE->defaultAtts[i].value = NULL; + } + } + + /* Copy the entity tables. */ + if (! copyEntityTable(oldParser, &(newDtd->generalEntities), &(newDtd->pool), + &(oldDtd->generalEntities))) + return 0; + +#ifdef XML_DTD + if (! copyEntityTable(oldParser, &(newDtd->paramEntities), &(newDtd->pool), + &(oldDtd->paramEntities))) + return 0; + newDtd->paramEntityRead = oldDtd->paramEntityRead; +#endif /* XML_DTD */ + + newDtd->keepProcessing = oldDtd->keepProcessing; + newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs; + newDtd->standalone = oldDtd->standalone; + + /* Don't want deep copying for scaffolding */ + newDtd->in_eldecl = oldDtd->in_eldecl; + newDtd->scaffold = oldDtd->scaffold; + newDtd->contentStringLen = oldDtd->contentStringLen; + newDtd->scaffSize = oldDtd->scaffSize; + newDtd->scaffLevel = oldDtd->scaffLevel; + newDtd->scaffIndex = oldDtd->scaffIndex; + + return 1; +} /* End dtdCopy */ + +static int +copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, + STRING_POOL *newPool, const HASH_TABLE *oldTable) { + HASH_TABLE_ITER iter; + const XML_Char *cachedOldBase = NULL; + const XML_Char *cachedNewBase = NULL; + + hashTableIterInit(&iter, oldTable); + + for (;;) { + ENTITY *newE; + const XML_Char *name; + const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); + if (! oldE) + break; + name = poolCopyString(newPool, oldE->name); + if (! name) + return 0; + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); + if (! newE) + return 0; + if (oldE->systemId) { + const XML_Char *tem = poolCopyString(newPool, oldE->systemId); + if (! tem) + return 0; + newE->systemId = tem; + if (oldE->base) { + if (oldE->base == cachedOldBase) + newE->base = cachedNewBase; + else { + cachedOldBase = oldE->base; + tem = poolCopyString(newPool, cachedOldBase); + if (! tem) + return 0; + cachedNewBase = newE->base = tem; + } + } + if (oldE->publicId) { + tem = poolCopyString(newPool, oldE->publicId); + if (! tem) + return 0; + newE->publicId = tem; + } + } else { + const XML_Char *tem + = poolCopyStringN(newPool, oldE->textPtr, oldE->textLen); + if (! tem) + return 0; + newE->textPtr = tem; + newE->textLen = oldE->textLen; + } + if (oldE->notation) { + const XML_Char *tem = poolCopyString(newPool, oldE->notation); + if (! tem) + return 0; + newE->notation = tem; + } + newE->is_param = oldE->is_param; + newE->is_internal = oldE->is_internal; + } + return 1; +} + +#define INIT_POWER 6 + +static XML_Bool FASTCALL +keyeq(KEY s1, KEY s2) { + for (; *s1 == *s2; s1++, s2++) + if (*s1 == 0) + return XML_TRUE; + return XML_FALSE; +} + +static size_t +keylen(KEY s) { + size_t len = 0; + for (; *s; s++, len++) + ; + return len; +} + +static void +copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key) { + key->k[0] = 0; + key->k[1] = get_hash_secret_salt(parser); +} + +static unsigned long FASTCALL +hash(XML_Parser parser, KEY s) { + struct siphash state; + struct sipkey key; + (void)sip24_valid; + copy_salt_to_sipkey(parser, &key); + sip24_init(&state, &key); + sip24_update(&state, s, keylen(s) * sizeof(XML_Char)); + return (unsigned long)sip24_final(&state); +} + +static NAMED * +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { + size_t i; + if (table->size == 0) { + size_t tsize; + if (! createSize) + return NULL; + table->power = INIT_POWER; + /* table->size is a power of 2 */ + table->size = (size_t)1 << INIT_POWER; + tsize = table->size * sizeof(NAMED *); + table->v = table->mem->malloc_fcn(tsize); + if (! table->v) { + table->size = 0; + return NULL; + } + memset(table->v, 0, tsize); + i = hash(parser, name) & ((unsigned long)table->size - 1); + } else { + unsigned long h = hash(parser, name); + unsigned long mask = (unsigned long)table->size - 1; + unsigned char step = 0; + i = h & mask; + while (table->v[i]) { + if (keyeq(name, table->v[i]->name)) + return table->v[i]; + if (! step) + step = PROBE_STEP(h, mask, table->power); + i < step ? (i += table->size - step) : (i -= step); + } + if (! createSize) + return NULL; + + /* check for overflow (table is half full) */ + if (table->used >> (table->power - 1)) { + unsigned char newPower = table->power + 1; + + /* Detect and prevent invalid shift */ + if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) { + return NULL; + } + + size_t newSize = (size_t)1 << newPower; + unsigned long newMask = (unsigned long)newSize - 1; + + /* Detect and prevent integer overflow */ + if (newSize > (size_t)(-1) / sizeof(NAMED *)) { + return NULL; + } + + size_t tsize = newSize * sizeof(NAMED *); + NAMED **newV = table->mem->malloc_fcn(tsize); + if (! newV) + return NULL; + memset(newV, 0, tsize); + for (i = 0; i < table->size; i++) + if (table->v[i]) { + unsigned long newHash = hash(parser, table->v[i]->name); + size_t j = newHash & newMask; + step = 0; + while (newV[j]) { + if (! step) + step = PROBE_STEP(newHash, newMask, newPower); + j < step ? (j += newSize - step) : (j -= step); + } + newV[j] = table->v[i]; + } + table->mem->free_fcn(table->v); + table->v = newV; + table->power = newPower; + table->size = newSize; + i = h & newMask; + step = 0; + while (table->v[i]) { + if (! step) + step = PROBE_STEP(h, newMask, newPower); + i < step ? (i += newSize - step) : (i -= step); + } + } + } + table->v[i] = table->mem->malloc_fcn(createSize); + if (! table->v[i]) + return NULL; + memset(table->v[i], 0, createSize); + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +static void FASTCALL +hashTableClear(HASH_TABLE *table) { + size_t i; + for (i = 0; i < table->size; i++) { + table->mem->free_fcn(table->v[i]); + table->v[i] = NULL; + } + table->used = 0; +} + +static void FASTCALL +hashTableDestroy(HASH_TABLE *table) { + size_t i; + for (i = 0; i < table->size; i++) + table->mem->free_fcn(table->v[i]); + table->mem->free_fcn(table->v); +} + +static void FASTCALL +hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) { + p->power = 0; + p->size = 0; + p->used = 0; + p->v = NULL; + p->mem = ms; +} + +static void FASTCALL +hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) { + iter->p = table->v; + iter->end = iter->p ? iter->p + table->size : NULL; +} + +static NAMED *FASTCALL +hashTableIterNext(HASH_TABLE_ITER *iter) { + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return NULL; +} + +static void FASTCALL +poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) { + pool->blocks = NULL; + pool->freeBlocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; + pool->mem = ms; +} + +static void FASTCALL +poolClear(STRING_POOL *pool) { + if (! pool->freeBlocks) + pool->freeBlocks = pool->blocks; + else { + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + p->next = pool->freeBlocks; + pool->freeBlocks = p; + p = tem; + } + } + pool->blocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; +} + +static void FASTCALL +poolDestroy(STRING_POOL *pool) { + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } + p = pool->freeBlocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } +} + +static XML_Char * +poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr, + const char *end) { + if (! pool->ptr && ! poolGrow(pool)) + return NULL; + for (;;) { + const enum XML_Convert_Result convert_res = XmlConvert( + enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); + if ((convert_res == XML_CONVERT_COMPLETED) + || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) + break; + if (! poolGrow(pool)) + return NULL; + } + return pool->start; +} + +static const XML_Char *FASTCALL +poolCopyString(STRING_POOL *pool, const XML_Char *s) { + do { + if (! poolAppendChar(pool, *s)) + return NULL; + } while (*s++); + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) { + if (! pool->ptr && ! poolGrow(pool)) { + /* The following line is unreachable given the current usage of + * poolCopyStringN(). Currently it is called from exactly one + * place to copy the text of a simple general entity. By that + * point, the name of the entity is already stored in the pool, so + * pool->ptr cannot be NULL. + * + * If poolCopyStringN() is used elsewhere as it well might be, + * this line may well become executable again. Regardless, this + * sort of check shouldn't be removed lightly, so we just exclude + * it from the coverage statistics. + */ + return NULL; /* LCOV_EXCL_LINE */ + } + for (; n > 0; --n, s++) { + if (! poolAppendChar(pool, *s)) + return NULL; + } + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char *FASTCALL +poolAppendString(STRING_POOL *pool, const XML_Char *s) { + while (*s) { + if (! poolAppendChar(pool, *s)) + return NULL; + s++; + } + return pool->start; +} + +static XML_Char * +poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr, + const char *end) { + if (! poolAppend(pool, enc, ptr, end)) + return NULL; + if (pool->ptr == pool->end && ! poolGrow(pool)) + return NULL; + *(pool->ptr)++ = 0; + return pool->start; +} + +static size_t +poolBytesToAllocateFor(int blockSize) { + /* Unprotected math would be: + ** return offsetof(BLOCK, s) + blockSize * sizeof(XML_Char); + ** + ** Detect overflow, avoiding _signed_ overflow undefined behavior + ** For a + b * c we check b * c in isolation first, so that addition of a + ** on top has no chance of making us accept a small non-negative number + */ + const size_t stretch = sizeof(XML_Char); /* can be 4 bytes */ + + if (blockSize <= 0) + return 0; + + if (blockSize > (int)(INT_MAX / stretch)) + return 0; + + { + const int stretchedBlockSize = blockSize * (int)stretch; + const int bytesToAllocate + = (int)(offsetof(BLOCK, s) + (unsigned)stretchedBlockSize); + if (bytesToAllocate < 0) + return 0; + + return (size_t)bytesToAllocate; + } +} + +static XML_Bool FASTCALL +poolGrow(STRING_POOL *pool) { + if (pool->freeBlocks) { + if (pool->start == 0) { + pool->blocks = pool->freeBlocks; + pool->freeBlocks = pool->freeBlocks->next; + pool->blocks->next = NULL; + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + pool->ptr = pool->start; + return XML_TRUE; + } + if (pool->end - pool->start < pool->freeBlocks->size) { + BLOCK *tem = pool->freeBlocks->next; + pool->freeBlocks->next = pool->blocks; + pool->blocks = pool->freeBlocks; + pool->freeBlocks = tem; + memcpy(pool->blocks->s, pool->start, + (pool->end - pool->start) * sizeof(XML_Char)); + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + return XML_TRUE; + } + } + if (pool->blocks && pool->start == pool->blocks->s) { + BLOCK *temp; + int blockSize = (int)((unsigned)(pool->end - pool->start) * 2U); + size_t bytesToAllocate; + + /* NOTE: Needs to be calculated prior to calling `realloc` + to avoid dangling pointers: */ + const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start; + + if (blockSize < 0) { + /* This condition traps a situation where either more than + * INT_MAX/2 bytes have already been allocated. This isn't + * readily testable, since it is unlikely that an average + * machine will have that much memory, so we exclude it from the + * coverage statistics. + */ + return XML_FALSE; /* LCOV_EXCL_LINE */ + } + + bytesToAllocate = poolBytesToAllocateFor(blockSize); + if (bytesToAllocate == 0) + return XML_FALSE; + + temp = (BLOCK *)pool->mem->realloc_fcn(pool->blocks, + (unsigned)bytesToAllocate); + if (temp == NULL) + return XML_FALSE; + pool->blocks = temp; + pool->blocks->size = blockSize; + pool->ptr = pool->blocks->s + offsetInsideBlock; + pool->start = pool->blocks->s; + pool->end = pool->start + blockSize; + } else { + BLOCK *tem; + int blockSize = (int)(pool->end - pool->start); + size_t bytesToAllocate; + + if (blockSize < 0) { + /* This condition traps a situation where either more than + * INT_MAX bytes have already been allocated (which is prevented + * by various pieces of program logic, not least this one, never + * mind the unlikelihood of actually having that much memory) or + * the pool control fields have been corrupted (which could + * conceivably happen in an extremely buggy user handler + * function). Either way it isn't readily testable, so we + * exclude it from the coverage statistics. + */ + return XML_FALSE; /* LCOV_EXCL_LINE */ + } + + if (blockSize < INIT_BLOCK_SIZE) + blockSize = INIT_BLOCK_SIZE; + else { + /* Detect overflow, avoiding _signed_ overflow undefined behavior */ + if ((int)((unsigned)blockSize * 2U) < 0) { + return XML_FALSE; + } + blockSize *= 2; + } + + bytesToAllocate = poolBytesToAllocateFor(blockSize); + if (bytesToAllocate == 0) + return XML_FALSE; + + tem = pool->mem->malloc_fcn(bytesToAllocate); + if (! tem) + return XML_FALSE; + tem->size = blockSize; + tem->next = pool->blocks; + pool->blocks = tem; + if (pool->ptr != pool->start) + memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char)); + pool->ptr = tem->s + (pool->ptr - pool->start); + pool->start = tem->s; + pool->end = tem->s + blockSize; + } + return XML_TRUE; +} + +static int FASTCALL +nextScaffoldPart(XML_Parser parser) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + CONTENT_SCAFFOLD *me; + int next; + + if (! dtd->scaffIndex) { + dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int)); + if (! dtd->scaffIndex) + return -1; + dtd->scaffIndex[0] = 0; + } + + if (dtd->scaffCount >= dtd->scaffSize) { + CONTENT_SCAFFOLD *temp; + if (dtd->scaffold) { + /* Detect and prevent integer overflow */ + if (dtd->scaffSize > UINT_MAX / 2u) { + return -1; + } + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) { + return -1; + } +#endif + + temp = (CONTENT_SCAFFOLD *)REALLOC( + parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize *= 2; + } else { + temp = (CONTENT_SCAFFOLD *)MALLOC(parser, INIT_SCAFFOLD_ELEMENTS + * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; + } + dtd->scaffold = temp; + } + next = dtd->scaffCount++; + me = &dtd->scaffold[next]; + if (dtd->scaffLevel) { + CONTENT_SCAFFOLD *parent + = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]]; + if (parent->lastchild) { + dtd->scaffold[parent->lastchild].nextsib = next; + } + if (! parent->childcnt) + parent->firstchild = next; + parent->lastchild = next; + parent->childcnt++; + } + me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0; + return next; +} + +static XML_Content * +build_model(XML_Parser parser) { + /* Function build_model transforms the existing parser->m_dtd->scaffold + * array of CONTENT_SCAFFOLD tree nodes into a new array of + * XML_Content tree nodes followed by a gapless list of zero-terminated + * strings. */ + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + XML_Content *ret; + XML_Char *str; /* the current string writing location */ + + /* Detect and prevent integer overflow. + * The preprocessor guard addresses the "always false" warning + * from -Wtype-limits on platforms where + * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ +#if UINT_MAX >= SIZE_MAX + if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) { + return NULL; + } + if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) { + return NULL; + } +#endif + if (dtd->scaffCount * sizeof(XML_Content) + > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) { + return NULL; + } + + const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content) + + (dtd->contentStringLen * sizeof(XML_Char))); + + ret = (XML_Content *)MALLOC(parser, allocsize); + if (! ret) + return NULL; + + /* What follows is an iterative implementation (of what was previously done + * recursively in a dedicated function called "build_node". The old recursive + * build_node could be forced into stack exhaustion from input as small as a + * few megabyte, and so that was a security issue. Hence, a function call + * stack is avoided now by resolving recursion.) + * + * The iterative approach works as follows: + * + * - We have two writing pointers, both walking up the result array; one does + * the work, the other creates "jobs" for its colleague to do, and leads + * the way: + * + * - The faster one, pointer jobDest, always leads and writes "what job + * to do" by the other, once they reach that place in the + * array: leader "jobDest" stores the source node array index (relative + * to array dtd->scaffold) in field "numchildren". + * + * - The slower one, pointer dest, looks at the value stored in the + * "numchildren" field (which actually holds a source node array index + * at that time) and puts the real data from dtd->scaffold in. + * + * - Before the loop starts, jobDest writes source array index 0 + * (where the root node is located) so that dest will have something to do + * when it starts operation. + * + * - Whenever nodes with children are encountered, jobDest appends + * them as new jobs, in order. As a result, tree node siblings are + * adjacent in the resulting array, for example: + * + * [0] root, has two children + * [1] first child of 0, has three children + * [3] first child of 1, does not have children + * [4] second child of 1, does not have children + * [5] third child of 1, does not have children + * [2] second child of 0, does not have children + * + * Or (the same data) presented in flat array view: + * + * [0] root, has two children + * + * [1] first child of 0, has three children + * [2] second child of 0, does not have children + * + * [3] first child of 1, does not have children + * [4] second child of 1, does not have children + * [5] third child of 1, does not have children + * + * - The algorithm repeats until all target array indices have been processed. + */ + XML_Content *dest = ret; /* tree node writing location, moves upwards */ + XML_Content *const destLimit = &ret[dtd->scaffCount]; + XML_Content *jobDest = ret; /* next free writing location in target array */ + str = (XML_Char *)&ret[dtd->scaffCount]; + + /* Add the starting job, the root node (index 0) of the source tree */ + (jobDest++)->numchildren = 0; + + for (; dest < destLimit; dest++) { + /* Retrieve source tree array index from job storage */ + const int src_node = (int)dest->numchildren; + + /* Convert item */ + dest->type = dtd->scaffold[src_node].type; + dest->quant = dtd->scaffold[src_node].quant; + if (dest->type == XML_CTYPE_NAME) { + const XML_Char *src; + dest->name = str; + src = dtd->scaffold[src_node].name; + for (;;) { + *str++ = *src; + if (! *src) + break; + src++; + } + dest->numchildren = 0; + dest->children = NULL; + } else { + unsigned int i; + int cn; + dest->name = NULL; + dest->numchildren = dtd->scaffold[src_node].childcnt; + dest->children = jobDest; + + /* Append scaffold indices of children to array */ + for (i = 0, cn = dtd->scaffold[src_node].firstchild; + i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib) + (jobDest++)->numchildren = (unsigned int)cn; + } + } + + return ret; +} + +static ELEMENT_TYPE * +getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, + const char *end) { + DTD *const dtd = parser->m_dtd; /* save one level of indirection */ + const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end); + ELEMENT_TYPE *ret; + + if (! name) + return NULL; + ret = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, + sizeof(ELEMENT_TYPE)); + if (! ret) + return NULL; + if (ret->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (! setElementTypePrefix(parser, ret)) + return NULL; + } + return ret; +} + +static XML_Char * +copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { + size_t charsRequired = 0; + XML_Char *result; + + /* First determine how long the string is */ + while (s[charsRequired] != 0) { + charsRequired++; + } + /* Include the terminator */ + charsRequired++; + + /* Now allocate space for the copy */ + result = memsuite->malloc_fcn(charsRequired * sizeof(XML_Char)); + if (result == NULL) + return NULL; + /* Copy the original into place */ + memcpy(result, s, charsRequired * sizeof(XML_Char)); + return result; +} + +#ifdef XML_DTD + +static float +accountingGetCurrentAmplification(XML_Parser rootParser) { + const XmlBigCount countBytesOutput + = rootParser->m_accounting.countBytesDirect + + rootParser->m_accounting.countBytesIndirect; + const float amplificationFactor + = rootParser->m_accounting.countBytesDirect + ? (countBytesOutput + / (float)(rootParser->m_accounting.countBytesDirect)) + : 1.0f; + assert(! rootParser->m_parentParser); + return amplificationFactor; +} + +static void +accountingReportStats(XML_Parser originParser, const char *epilog) { + const XML_Parser rootParser = getRootParserOf(originParser, NULL); + assert(! rootParser->m_parentParser); + + if (rootParser->m_accounting.debugLevel < 1) { + return; + } + + const float amplificationFactor + = accountingGetCurrentAmplification(rootParser); + fprintf(stderr, + "expat: Accounting(%p): Direct " EXPAT_FMT_ULL( + "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s", + (void *)rootParser, rootParser->m_accounting.countBytesDirect, + rootParser->m_accounting.countBytesIndirect, + (double)amplificationFactor, epilog); +} + +static void +accountingOnAbort(XML_Parser originParser) { + accountingReportStats(originParser, " ABORTING\n"); +} + +static void +accountingReportDiff(XML_Parser rootParser, + unsigned int levelsAwayFromRootParser, const char *before, + const char *after, ptrdiff_t bytesMore, int source_line, + enum XML_Account account) { + assert(! rootParser->m_parentParser); + + fprintf(stderr, + " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"", + bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP", + levelsAwayFromRootParser, source_line, 10, ""); + + const char ellipis[] = "[..]"; + const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1; + const unsigned int contextLength = 10; + + /* Note: Performance is of no concern here */ + const char *walker = before; + if ((rootParser->m_accounting.debugLevel >= 3) + || (after - before) + <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) { + for (; walker < after; walker++) { + fprintf(stderr, "%s", unsignedCharToPrintable(walker[0])); + } + } else { + for (; walker < before + contextLength; walker++) { + fprintf(stderr, "%s", unsignedCharToPrintable(walker[0])); + } + fprintf(stderr, ellipis); + walker = after - contextLength; + for (; walker < after; walker++) { + fprintf(stderr, "%s", unsignedCharToPrintable(walker[0])); + } + } + fprintf(stderr, "\"\n"); +} + +static XML_Bool +accountingDiffTolerated(XML_Parser originParser, int tok, const char *before, + const char *after, int source_line, + enum XML_Account account) { + /* Note: We need to check the token type *first* to be sure that + * we can even access variable , safely. + * E.g. for XML_TOK_NONE may hold an invalid pointer. */ + switch (tok) { + case XML_TOK_INVALID: + case XML_TOK_PARTIAL: + case XML_TOK_PARTIAL_CHAR: + case XML_TOK_NONE: + return XML_TRUE; + } + + if (account == XML_ACCOUNT_NONE) + return XML_TRUE; /* because these bytes have been accounted for, already */ + + unsigned int levelsAwayFromRootParser; + const XML_Parser rootParser + = getRootParserOf(originParser, &levelsAwayFromRootParser); + assert(! rootParser->m_parentParser); + + const int isDirect + = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser); + const ptrdiff_t bytesMore = after - before; + + XmlBigCount *const additionTarget + = isDirect ? &rootParser->m_accounting.countBytesDirect + : &rootParser->m_accounting.countBytesIndirect; + + /* Detect and avoid integer overflow */ + if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore) + return XML_FALSE; + *additionTarget += bytesMore; + + const XmlBigCount countBytesOutput + = rootParser->m_accounting.countBytesDirect + + rootParser->m_accounting.countBytesIndirect; + const float amplificationFactor + = accountingGetCurrentAmplification(rootParser); + const XML_Bool tolerated + = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes) + || (amplificationFactor + <= rootParser->m_accounting.maximumAmplificationFactor); + + if (rootParser->m_accounting.debugLevel >= 2) { + accountingReportStats(rootParser, ""); + accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after, + bytesMore, source_line, account); + } + + return tolerated; +} + +unsigned long long +testingAccountingGetCountBytesDirect(XML_Parser parser) { + if (! parser) + return 0; + return parser->m_accounting.countBytesDirect; +} + +unsigned long long +testingAccountingGetCountBytesIndirect(XML_Parser parser) { + if (! parser) + return 0; + return parser->m_accounting.countBytesIndirect; +} + +static void +entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity, + const char *action, int sourceLine) { + assert(! rootParser->m_parentParser); + if (rootParser->m_entity_stats.debugLevel < 1) + return; + +# if defined(XML_UNICODE) + const char *const entityName = "[..]"; +# else + const char *const entityName = entity->name; +# endif + + fprintf( + stderr, + "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n", + (void *)rootParser, rootParser->m_entity_stats.countEverOpened, + rootParser->m_entity_stats.currentDepth, + rootParser->m_entity_stats.maximumDepthSeen, + (rootParser->m_entity_stats.currentDepth - 1) * 2, "", + entity->is_param ? "%" : "&", entityName, action, entity->textLen, + sourceLine); +} + +static void +entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) { + const XML_Parser rootParser = getRootParserOf(originParser, NULL); + assert(! rootParser->m_parentParser); + + rootParser->m_entity_stats.countEverOpened++; + rootParser->m_entity_stats.currentDepth++; + if (rootParser->m_entity_stats.currentDepth + > rootParser->m_entity_stats.maximumDepthSeen) { + rootParser->m_entity_stats.maximumDepthSeen++; + } + + entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine); +} + +static void +entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) { + const XML_Parser rootParser = getRootParserOf(originParser, NULL); + assert(! rootParser->m_parentParser); + + entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine); + rootParser->m_entity_stats.currentDepth--; +} + +static XML_Parser +getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) { + XML_Parser rootParser = parser; + unsigned int stepsTakenUpwards = 0; + while (rootParser->m_parentParser) { + rootParser = rootParser->m_parentParser; + stepsTakenUpwards++; + } + assert(! rootParser->m_parentParser); + if (outLevelDiff != NULL) { + *outLevelDiff = stepsTakenUpwards; + } + return rootParser; +} + +const char * +unsignedCharToPrintable(unsigned char c) { + switch (c) { + case 0: + return "\\0"; + case 1: + return "\\x1"; + case 2: + return "\\x2"; + case 3: + return "\\x3"; + case 4: + return "\\x4"; + case 5: + return "\\x5"; + case 6: + return "\\x6"; + case 7: + return "\\x7"; + case 8: + return "\\x8"; + case 9: + return "\\t"; + case 10: + return "\\n"; + case 11: + return "\\xB"; + case 12: + return "\\xC"; + case 13: + return "\\r"; + case 14: + return "\\xE"; + case 15: + return "\\xF"; + case 16: + return "\\x10"; + case 17: + return "\\x11"; + case 18: + return "\\x12"; + case 19: + return "\\x13"; + case 20: + return "\\x14"; + case 21: + return "\\x15"; + case 22: + return "\\x16"; + case 23: + return "\\x17"; + case 24: + return "\\x18"; + case 25: + return "\\x19"; + case 26: + return "\\x1A"; + case 27: + return "\\x1B"; + case 28: + return "\\x1C"; + case 29: + return "\\x1D"; + case 30: + return "\\x1E"; + case 31: + return "\\x1F"; + case 32: + return " "; + case 33: + return "!"; + case 34: + return "\\\""; + case 35: + return "#"; + case 36: + return "$"; + case 37: + return "%"; + case 38: + return "&"; + case 39: + return "'"; + case 40: + return "("; + case 41: + return ")"; + case 42: + return "*"; + case 43: + return "+"; + case 44: + return ","; + case 45: + return "-"; + case 46: + return "."; + case 47: + return "/"; + case 48: + return "0"; + case 49: + return "1"; + case 50: + return "2"; + case 51: + return "3"; + case 52: + return "4"; + case 53: + return "5"; + case 54: + return "6"; + case 55: + return "7"; + case 56: + return "8"; + case 57: + return "9"; + case 58: + return ":"; + case 59: + return ";"; + case 60: + return "<"; + case 61: + return "="; + case 62: + return ">"; + case 63: + return "?"; + case 64: + return "@"; + case 65: + return "A"; + case 66: + return "B"; + case 67: + return "C"; + case 68: + return "D"; + case 69: + return "E"; + case 70: + return "F"; + case 71: + return "G"; + case 72: + return "H"; + case 73: + return "I"; + case 74: + return "J"; + case 75: + return "K"; + case 76: + return "L"; + case 77: + return "M"; + case 78: + return "N"; + case 79: + return "O"; + case 80: + return "P"; + case 81: + return "Q"; + case 82: + return "R"; + case 83: + return "S"; + case 84: + return "T"; + case 85: + return "U"; + case 86: + return "V"; + case 87: + return "W"; + case 88: + return "X"; + case 89: + return "Y"; + case 90: + return "Z"; + case 91: + return "["; + case 92: + return "\\\\"; + case 93: + return "]"; + case 94: + return "^"; + case 95: + return "_"; + case 96: + return "`"; + case 97: + return "a"; + case 98: + return "b"; + case 99: + return "c"; + case 100: + return "d"; + case 101: + return "e"; + case 102: + return "f"; + case 103: + return "g"; + case 104: + return "h"; + case 105: + return "i"; + case 106: + return "j"; + case 107: + return "k"; + case 108: + return "l"; + case 109: + return "m"; + case 110: + return "n"; + case 111: + return "o"; + case 112: + return "p"; + case 113: + return "q"; + case 114: + return "r"; + case 115: + return "s"; + case 116: + return "t"; + case 117: + return "u"; + case 118: + return "v"; + case 119: + return "w"; + case 120: + return "x"; + case 121: + return "y"; + case 122: + return "z"; + case 123: + return "{"; + case 124: + return "|"; + case 125: + return "}"; + case 126: + return "~"; + case 127: + return "\\x7F"; + case 128: + return "\\x80"; + case 129: + return "\\x81"; + case 130: + return "\\x82"; + case 131: + return "\\x83"; + case 132: + return "\\x84"; + case 133: + return "\\x85"; + case 134: + return "\\x86"; + case 135: + return "\\x87"; + case 136: + return "\\x88"; + case 137: + return "\\x89"; + case 138: + return "\\x8A"; + case 139: + return "\\x8B"; + case 140: + return "\\x8C"; + case 141: + return "\\x8D"; + case 142: + return "\\x8E"; + case 143: + return "\\x8F"; + case 144: + return "\\x90"; + case 145: + return "\\x91"; + case 146: + return "\\x92"; + case 147: + return "\\x93"; + case 148: + return "\\x94"; + case 149: + return "\\x95"; + case 150: + return "\\x96"; + case 151: + return "\\x97"; + case 152: + return "\\x98"; + case 153: + return "\\x99"; + case 154: + return "\\x9A"; + case 155: + return "\\x9B"; + case 156: + return "\\x9C"; + case 157: + return "\\x9D"; + case 158: + return "\\x9E"; + case 159: + return "\\x9F"; + case 160: + return "\\xA0"; + case 161: + return "\\xA1"; + case 162: + return "\\xA2"; + case 163: + return "\\xA3"; + case 164: + return "\\xA4"; + case 165: + return "\\xA5"; + case 166: + return "\\xA6"; + case 167: + return "\\xA7"; + case 168: + return "\\xA8"; + case 169: + return "\\xA9"; + case 170: + return "\\xAA"; + case 171: + return "\\xAB"; + case 172: + return "\\xAC"; + case 173: + return "\\xAD"; + case 174: + return "\\xAE"; + case 175: + return "\\xAF"; + case 176: + return "\\xB0"; + case 177: + return "\\xB1"; + case 178: + return "\\xB2"; + case 179: + return "\\xB3"; + case 180: + return "\\xB4"; + case 181: + return "\\xB5"; + case 182: + return "\\xB6"; + case 183: + return "\\xB7"; + case 184: + return "\\xB8"; + case 185: + return "\\xB9"; + case 186: + return "\\xBA"; + case 187: + return "\\xBB"; + case 188: + return "\\xBC"; + case 189: + return "\\xBD"; + case 190: + return "\\xBE"; + case 191: + return "\\xBF"; + case 192: + return "\\xC0"; + case 193: + return "\\xC1"; + case 194: + return "\\xC2"; + case 195: + return "\\xC3"; + case 196: + return "\\xC4"; + case 197: + return "\\xC5"; + case 198: + return "\\xC6"; + case 199: + return "\\xC7"; + case 200: + return "\\xC8"; + case 201: + return "\\xC9"; + case 202: + return "\\xCA"; + case 203: + return "\\xCB"; + case 204: + return "\\xCC"; + case 205: + return "\\xCD"; + case 206: + return "\\xCE"; + case 207: + return "\\xCF"; + case 208: + return "\\xD0"; + case 209: + return "\\xD1"; + case 210: + return "\\xD2"; + case 211: + return "\\xD3"; + case 212: + return "\\xD4"; + case 213: + return "\\xD5"; + case 214: + return "\\xD6"; + case 215: + return "\\xD7"; + case 216: + return "\\xD8"; + case 217: + return "\\xD9"; + case 218: + return "\\xDA"; + case 219: + return "\\xDB"; + case 220: + return "\\xDC"; + case 221: + return "\\xDD"; + case 222: + return "\\xDE"; + case 223: + return "\\xDF"; + case 224: + return "\\xE0"; + case 225: + return "\\xE1"; + case 226: + return "\\xE2"; + case 227: + return "\\xE3"; + case 228: + return "\\xE4"; + case 229: + return "\\xE5"; + case 230: + return "\\xE6"; + case 231: + return "\\xE7"; + case 232: + return "\\xE8"; + case 233: + return "\\xE9"; + case 234: + return "\\xEA"; + case 235: + return "\\xEB"; + case 236: + return "\\xEC"; + case 237: + return "\\xED"; + case 238: + return "\\xEE"; + case 239: + return "\\xEF"; + case 240: + return "\\xF0"; + case 241: + return "\\xF1"; + case 242: + return "\\xF2"; + case 243: + return "\\xF3"; + case 244: + return "\\xF4"; + case 245: + return "\\xF5"; + case 246: + return "\\xF6"; + case 247: + return "\\xF7"; + case 248: + return "\\xF8"; + case 249: + return "\\xF9"; + case 250: + return "\\xFA"; + case 251: + return "\\xFB"; + case 252: + return "\\xFC"; + case 253: + return "\\xFD"; + case 254: + return "\\xFE"; + case 255: + return "\\xFF"; + default: + assert(0); /* never gets here */ + return "dead code"; + } + assert(0); /* never gets here */ +} + +#endif /* XML_DTD */ + +static unsigned long +getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) { + const char *const valueOrNull = getenv(variableName); + if (valueOrNull == NULL) { + return defaultDebugLevel; + } + const char *const value = valueOrNull; + + errno = 0; + char *afterValue = (char *)value; + unsigned long debugLevel = strtoul(value, &afterValue, 10); + if ((errno != 0) || (afterValue[0] != '\0')) { + errno = 0; + return defaultDebugLevel; + } + + return debugLevel; +} diff --git a/src/3rdparty/expat/src/xmlrole.c b/src/3rdparty/expat/src/xmlrole.c new file mode 100644 index 00000000..3f0f5c15 --- /dev/null +++ b/src/3rdparty/expat/src/xmlrole.c @@ -0,0 +1,1255 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Greg Stein + Copyright (c) 2002-2006 Karl Waclawek + Copyright (c) 2002-2003 Fred L. Drake, Jr. + Copyright (c) 2005-2009 Steven Solie + Copyright (c) 2016-2021 Sebastian Pipping + Copyright (c) 2017 Rhodri James + Copyright (c) 2019 David Loffredo + Copyright (c) 2021 Dong-hee Na + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include + +#ifdef _WIN32 +# include "winconfig.h" +#endif + +#include "expat_external.h" +#include "internal.h" +#include "xmlrole.h" +#include "ascii.h" + +/* Doesn't check: + + that ,| are not mixed in a model group + content of literals + +*/ + +static const char KW_ANY[] = {ASCII_A, ASCII_N, ASCII_Y, '\0'}; +static const char KW_ATTLIST[] + = {ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0'}; +static const char KW_CDATA[] + = {ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'}; +static const char KW_DOCTYPE[] + = {ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0'}; +static const char KW_ELEMENT[] + = {ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0'}; +static const char KW_EMPTY[] + = {ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0'}; +static const char KW_ENTITIES[] = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, + ASCII_I, ASCII_E, ASCII_S, '\0'}; +static const char KW_ENTITY[] + = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0'}; +static const char KW_FIXED[] + = {ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0'}; +static const char KW_ID[] = {ASCII_I, ASCII_D, '\0'}; +static const char KW_IDREF[] + = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0'}; +static const char KW_IDREFS[] + = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0'}; +#ifdef XML_DTD +static const char KW_IGNORE[] + = {ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0'}; +#endif +static const char KW_IMPLIED[] + = {ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0'}; +#ifdef XML_DTD +static const char KW_INCLUDE[] + = {ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0'}; +#endif +static const char KW_NDATA[] + = {ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'}; +static const char KW_NMTOKEN[] + = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0'}; +static const char KW_NMTOKENS[] = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, + ASCII_E, ASCII_N, ASCII_S, '\0'}; +static const char KW_NOTATION[] = {ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, + ASCII_I, ASCII_O, ASCII_N, '\0'}; +static const char KW_PCDATA[] + = {ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'}; +static const char KW_PUBLIC[] + = {ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0'}; +static const char KW_REQUIRED[] = {ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, + ASCII_R, ASCII_E, ASCII_D, '\0'}; +static const char KW_SYSTEM[] + = {ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0'}; + +#ifndef MIN_BYTES_PER_CHAR +# define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) +#endif + +#ifdef XML_DTD +# define setTopLevel(state) \ + ((state)->handler \ + = ((state)->documentEntity ? internalSubset : externalSubset1)) +#else /* not XML_DTD */ +# define setTopLevel(state) ((state)->handler = internalSubset) +#endif /* not XML_DTD */ + +typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, int tok, + const char *ptr, const char *end, + const ENCODING *enc); + +static PROLOG_HANDLER prolog0, prolog1, prolog2, doctype0, doctype1, doctype2, + doctype3, doctype4, doctype5, internalSubset, entity0, entity1, entity2, + entity3, entity4, entity5, entity6, entity7, entity8, entity9, entity10, + notation0, notation1, notation2, notation3, notation4, attlist0, attlist1, + attlist2, attlist3, attlist4, attlist5, attlist6, attlist7, attlist8, + attlist9, element0, element1, element2, element3, element4, element5, + element6, element7, +#ifdef XML_DTD + externalSubset0, externalSubset1, condSect0, condSect1, condSect2, +#endif /* XML_DTD */ + declClose, error; + +static int FASTCALL common(PROLOG_STATE *state, int tok); + +static int PTRCALL +prolog0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_XML_DECL: + state->handler = prolog1; + return XML_ROLE_XML_DECL; + case XML_TOK_PI: + state->handler = prolog1; + return XML_ROLE_PI; + case XML_TOK_COMMENT: + state->handler = prolog1; + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (! XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + /* This case can never arise. To reach this role function, the + * parse must have passed through prolog0 and therefore have had + * some form of input, even if only a space. At that point, a + * byte order mark is no longer a valid character (though + * technically it should be interpreted as a non-breaking space), + * so will be rejected by the tokenizing stages. + */ + return XML_ROLE_NONE; /* LCOV_EXCL_LINE */ + case XML_TOK_DECL_OPEN: + if (! XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +doctype0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = doctype1; + return XML_ROLE_DOCTYPE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +doctype1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = doctype3; + return XML_ROLE_DOCTYPE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = doctype2; + return XML_ROLE_DOCTYPE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +doctype2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype3; + return XML_ROLE_DOCTYPE_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype4; + return XML_ROLE_DOCTYPE_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +doctype5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +internalSubset(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, + KW_ENTITY)) { + state->handler = entity0; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, + KW_ATTLIST)) { + state->handler = attlist0; + return XML_ROLE_ATTLIST_NONE; + } + if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, + KW_ELEMENT)) { + state->handler = element0; + return XML_ROLE_ELEMENT_NONE; + } + if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, + KW_NOTATION)) { + state->handler = notation0; + return XML_ROLE_NOTATION_NONE; + } + break; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_PARAM_ENTITY_REF: + return XML_ROLE_PARAM_ENTITY_REF; + case XML_TOK_CLOSE_BRACKET: + state->handler = doctype5; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NONE: + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +externalSubset0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + state->handler = externalSubset1; + if (tok == XML_TOK_XML_DECL) + return XML_ROLE_TEXT_DECL; + return externalSubset1(state, tok, ptr, end, enc); +} + +static int PTRCALL +externalSubset1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_COND_SECT_OPEN: + state->handler = condSect0; + return XML_ROLE_NONE; + case XML_TOK_COND_SECT_CLOSE: + if (state->includeLevel == 0) + break; + state->includeLevel -= 1; + return XML_ROLE_NONE; + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_BRACKET: + break; + case XML_TOK_NONE: + if (state->includeLevel) + break; + return XML_ROLE_NONE; + default: + return internalSubset(state, tok, ptr, end, enc); + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +entity0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_PERCENT: + state->handler = entity1; + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity2; + return XML_ROLE_GENERAL_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity7; + return XML_ROLE_PARAM_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity4; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity3; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity4; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity5; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { + state->handler = entity6; + return XML_ROLE_ENTITY_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +entity6(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity7(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity9; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity8; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity8(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity9; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity9(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity10; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity10(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + } + return common(state, tok); +} + +static int PTRCALL +notation0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + state->handler = notation1; + return XML_ROLE_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +notation1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = notation3; + return XML_ROLE_NOTATION_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = notation2; + return XML_ROLE_NOTATION_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +notation2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = notation4; + return XML_ROLE_NOTATION_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NOTATION_NO_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +attlist0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist1; + return XML_ROLE_ATTLIST_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist2; + return XML_ROLE_ATTRIBUTE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: { + static const char *const types[] = { + KW_CDATA, KW_ID, KW_IDREF, KW_IDREFS, + KW_ENTITY, KW_ENTITIES, KW_NMTOKEN, KW_NMTOKENS, + }; + int i; + for (i = 0; i < (int)(sizeof(types) / sizeof(types[0])); i++) + if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { + state->handler = attlist8; + return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; + } + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { + state->handler = attlist5; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NMTOKEN: + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist4; + return XML_ROLE_ATTRIBUTE_ENUM_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OPEN_PAREN: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist6(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + state->handler = attlist7; + return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist7(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +/* default value */ +static int PTRCALL +attlist8(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, + KW_IMPLIED)) { + state->handler = attlist1; + return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, + KW_REQUIRED)) { + state->handler = attlist1; + return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, + KW_FIXED)) { + state->handler = attlist9; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist9(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_FIXED_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +element0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element1; + return XML_ROLE_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +element1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_EMPTY; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_ANY; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = element2; + state->level = 1; + return XML_ROLE_GROUP_OPEN; + } + return common(state, tok); +} + +static int PTRCALL +element2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, + KW_PCDATA)) { + state->handler = element3; + return XML_ROLE_CONTENT_PCDATA; + } + break; + case XML_TOK_OPEN_PAREN: + state->level = 2; + state->handler = element6; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element3(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element4(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element5; + return XML_ROLE_CONTENT_ELEMENT; + } + return common(state, tok); +} + +static int PTRCALL +element5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element6(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_OPEN_PAREN: + state->level += 1; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element7(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_CLOSE_PAREN_QUESTION: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_OPT; + case XML_TOK_CLOSE_PAREN_PLUS: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_PLUS; + case XML_TOK_COMMA: + state->handler = element6; + return XML_ROLE_GROUP_SEQUENCE; + case XML_TOK_OR: + state->handler = element6; + return XML_ROLE_GROUP_CHOICE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +condSect0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { + state->handler = condSect1; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { + state->handler = condSect2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +condSect1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + state->includeLevel += 1; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static int PTRCALL +condSect2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + return XML_ROLE_IGNORE_SECT; + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +declClose(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + switch (tok) { + case XML_TOK_PROLOG_S: + return state->role_none; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return state->role_none; + } + return common(state, tok); +} + +/* This function will only be invoked if the internal logic of the + * parser has broken down. It is used in two cases: + * + * 1: When the XML prolog has been finished. At this point the + * processor (the parser level above these role handlers) should + * switch from prologProcessor to contentProcessor and reinitialise + * the handler function. + * + * 2: When an error has been detected (via common() below). At this + * point again the processor should be switched to errorProcessor, + * which will never call a handler. + * + * The result of this is that error() can only be called if the + * processor switch failed to happen, which is an internal error and + * therefore we shouldn't be able to provoke it simply by using the + * library. It is a necessary backstop, however, so we merely exclude + * it from the coverage statistics. + * + * LCOV_EXCL_START + */ +static int PTRCALL +error(PROLOG_STATE *state, int tok, const char *ptr, const char *end, + const ENCODING *enc) { + UNUSED_P(state); + UNUSED_P(tok); + UNUSED_P(ptr); + UNUSED_P(end); + UNUSED_P(enc); + return XML_ROLE_NONE; +} +/* LCOV_EXCL_STOP */ + +static int FASTCALL +common(PROLOG_STATE *state, int tok) { +#ifdef XML_DTD + if (! state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) + return XML_ROLE_INNER_PARAM_ENTITY_REF; +#else + UNUSED_P(tok); +#endif + state->handler = error; + return XML_ROLE_ERROR; +} + +void +XmlPrologStateInit(PROLOG_STATE *state) { + state->handler = prolog0; +#ifdef XML_DTD + state->documentEntity = 1; + state->includeLevel = 0; + state->inEntityValue = 0; +#endif /* XML_DTD */ +} + +#ifdef XML_DTD + +void +XmlPrologStateInitExternalEntity(PROLOG_STATE *state) { + state->handler = externalSubset0; + state->documentEntity = 0; + state->includeLevel = 0; +} + +#endif /* XML_DTD */ diff --git a/src/3rdparty/expat/src/xmlrole.h b/src/3rdparty/expat/src/xmlrole.h new file mode 100644 index 00000000..d6e1fa15 --- /dev/null +++ b/src/3rdparty/expat/src/xmlrole.h @@ -0,0 +1,142 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Karl Waclawek + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2017 Sebastian Pipping + Licensed under the MIT license: + + 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 XmlRole_INCLUDED +#define XmlRole_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +# define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt +#endif + +#include "xmltok.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + XML_ROLE_ERROR = -1, + XML_ROLE_NONE = 0, + XML_ROLE_XML_DECL, + XML_ROLE_INSTANCE_START, + XML_ROLE_DOCTYPE_NONE, + XML_ROLE_DOCTYPE_NAME, + XML_ROLE_DOCTYPE_SYSTEM_ID, + XML_ROLE_DOCTYPE_PUBLIC_ID, + XML_ROLE_DOCTYPE_INTERNAL_SUBSET, + XML_ROLE_DOCTYPE_CLOSE, + XML_ROLE_GENERAL_ENTITY_NAME, + XML_ROLE_PARAM_ENTITY_NAME, + XML_ROLE_ENTITY_NONE, + XML_ROLE_ENTITY_VALUE, + XML_ROLE_ENTITY_SYSTEM_ID, + XML_ROLE_ENTITY_PUBLIC_ID, + XML_ROLE_ENTITY_COMPLETE, + XML_ROLE_ENTITY_NOTATION_NAME, + XML_ROLE_NOTATION_NONE, + XML_ROLE_NOTATION_NAME, + XML_ROLE_NOTATION_SYSTEM_ID, + XML_ROLE_NOTATION_NO_SYSTEM_ID, + XML_ROLE_NOTATION_PUBLIC_ID, + XML_ROLE_ATTRIBUTE_NAME, + XML_ROLE_ATTRIBUTE_TYPE_CDATA, + XML_ROLE_ATTRIBUTE_TYPE_ID, + XML_ROLE_ATTRIBUTE_TYPE_IDREF, + XML_ROLE_ATTRIBUTE_TYPE_IDREFS, + XML_ROLE_ATTRIBUTE_TYPE_ENTITY, + XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, + XML_ROLE_ATTRIBUTE_ENUM_VALUE, + XML_ROLE_ATTRIBUTE_NOTATION_VALUE, + XML_ROLE_ATTLIST_NONE, + XML_ROLE_ATTLIST_ELEMENT_NAME, + XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, + XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, + XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, + XML_ROLE_FIXED_ATTRIBUTE_VALUE, + XML_ROLE_ELEMENT_NONE, + XML_ROLE_ELEMENT_NAME, + XML_ROLE_CONTENT_ANY, + XML_ROLE_CONTENT_EMPTY, + XML_ROLE_CONTENT_PCDATA, + XML_ROLE_GROUP_OPEN, + XML_ROLE_GROUP_CLOSE, + XML_ROLE_GROUP_CLOSE_REP, + XML_ROLE_GROUP_CLOSE_OPT, + XML_ROLE_GROUP_CLOSE_PLUS, + XML_ROLE_GROUP_CHOICE, + XML_ROLE_GROUP_SEQUENCE, + XML_ROLE_CONTENT_ELEMENT, + XML_ROLE_CONTENT_ELEMENT_REP, + XML_ROLE_CONTENT_ELEMENT_OPT, + XML_ROLE_CONTENT_ELEMENT_PLUS, + XML_ROLE_PI, + XML_ROLE_COMMENT, +#ifdef XML_DTD + XML_ROLE_TEXT_DECL, + XML_ROLE_IGNORE_SECT, + XML_ROLE_INNER_PARAM_ENTITY_REF, +#endif /* XML_DTD */ + XML_ROLE_PARAM_ENTITY_REF +}; + +typedef struct prolog_state { + int(PTRCALL *handler)(struct prolog_state *state, int tok, const char *ptr, + const char *end, const ENCODING *enc); + unsigned level; + int role_none; +#ifdef XML_DTD + unsigned includeLevel; + int documentEntity; + int inEntityValue; +#endif /* XML_DTD */ +} PROLOG_STATE; + +void XmlPrologStateInit(PROLOG_STATE *); +#ifdef XML_DTD +void XmlPrologStateInitExternalEntity(PROLOG_STATE *); +#endif /* XML_DTD */ + +#define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlRole_INCLUDED */ diff --git a/src/3rdparty/expat/src/xmltok.c b/src/3rdparty/expat/src/xmltok.c new file mode 100644 index 00000000..2b7012a5 --- /dev/null +++ b/src/3rdparty/expat/src/xmltok.c @@ -0,0 +1,1677 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2001-2003 Fred L. Drake, Jr. + Copyright (c) 2002 Greg Stein + Copyright (c) 2002-2016 Karl Waclawek + Copyright (c) 2005-2009 Steven Solie + Copyright (c) 2016-2022 Sebastian Pipping + Copyright (c) 2016 Pascal Cuoq + Copyright (c) 2016 Don Lewis + Copyright (c) 2017 Rhodri James + Copyright (c) 2017 Alexander Bluhm + Copyright (c) 2017 Benbuck Nason + Copyright (c) 2017 José Gutiérrez de la Concha + Copyright (c) 2019 David Loffredo + Copyright (c) 2021 Dong-hee Na + Copyright (c) 2022 Martin Ettl + Licensed under the MIT license: + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include /* memcpy */ +#include + +#ifdef _WIN32 +# include "winconfig.h" +#endif + +#include "expat_external.h" +#include "internal.h" +#include "xmltok.h" +#include "nametab.h" + +#ifdef XML_DTD +# define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) +#else +# define IGNORE_SECTION_TOK_VTABLE /* as nothing */ +#endif + +#define VTABLE1 \ + {PREFIX(prologTok), PREFIX(contentTok), \ + PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE}, \ + {PREFIX(attributeValueTok), PREFIX(entityValueTok)}, \ + PREFIX(nameMatchesAscii), PREFIX(nameLength), PREFIX(skipS), \ + PREFIX(getAtts), PREFIX(charRefNumber), PREFIX(predefinedEntityName), \ + PREFIX(updatePosition), PREFIX(isPublicId) + +#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) + +#define UCS2_GET_NAMING(pages, hi, lo) \ + (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1u << ((lo)&0x1F))) + +/* A 2 byte UTF-8 representation splits the characters 11 bits between + the bottom 5 and 6 bits of the bytes. We need 8 bits to index into + pages, 3 bits to add to that index and 5 bits to generate the mask. +*/ +#define UTF8_GET_NAMING2(pages, byte) \ + (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + + ((((byte)[0]) & 3) << 1) + ((((byte)[1]) >> 5) & 1)] \ + & (1u << (((byte)[1]) & 0x1F))) + +/* A 3 byte UTF-8 representation splits the characters 16 bits between + the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index + into pages, 3 bits to add to that index and 5 bits to generate the + mask. +*/ +#define UTF8_GET_NAMING3(pages, byte) \ + (namingBitmap \ + [((pages)[((((byte)[0]) & 0xF) << 4) + ((((byte)[1]) >> 2) & 0xF)] \ + << 3) \ + + ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)] \ + & (1u << (((byte)[2]) & 0x1F))) + +/* Detection of invalid UTF-8 sequences is based on Table 3.1B + of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/ + with the additional restriction of not allowing the Unicode + code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE). + Implementation details: + (A & 0x80) == 0 means A < 0x80 + and + (A & 0xC0) == 0xC0 means A > 0xBF +*/ + +#define UTF8_INVALID2(p) \ + ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0) + +#define UTF8_INVALID3(p) \ + (((p)[2] & 0x80) == 0 \ + || ((*p) == 0xEF && (p)[1] == 0xBF ? (p)[2] > 0xBD \ + : ((p)[2] & 0xC0) == 0xC0) \ + || ((*p) == 0xE0 \ + ? (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \ + : ((p)[1] & 0x80) == 0 \ + || ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0))) + +#define UTF8_INVALID4(p) \ + (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 || ((p)[2] & 0x80) == 0 \ + || ((p)[2] & 0xC0) == 0xC0 \ + || ((*p) == 0xF0 \ + ? (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \ + : ((p)[1] & 0x80) == 0 \ + || ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0))) + +static int PTRFASTCALL +isNever(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + UNUSED_P(p); + return 0; +} + +static int PTRFASTCALL +utf8_isName2(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isName3(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); +} + +#define utf8_isName4 isNever + +static int PTRFASTCALL +utf8_isNmstrt2(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isNmstrt3(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); +} + +#define utf8_isNmstrt4 isNever + +static int PTRFASTCALL +utf8_isInvalid2(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return UTF8_INVALID2((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid3(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return UTF8_INVALID3((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid4(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return UTF8_INVALID4((const unsigned char *)p); +} + +struct normal_encoding { + ENCODING enc; + unsigned char type[256]; +#ifdef XML_MIN_SIZE + int(PTRFASTCALL *byteType)(const ENCODING *, const char *); + int(PTRFASTCALL *isNameMin)(const ENCODING *, const char *); + int(PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *); + int(PTRFASTCALL *byteToAscii)(const ENCODING *, const char *); + int(PTRCALL *charMatches)(const ENCODING *, const char *, int); +#endif /* XML_MIN_SIZE */ + int(PTRFASTCALL *isName2)(const ENCODING *, const char *); + int(PTRFASTCALL *isName3)(const ENCODING *, const char *); + int(PTRFASTCALL *isName4)(const ENCODING *, const char *); + int(PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *); + int(PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *); + int(PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *); + int(PTRFASTCALL *isInvalid2)(const ENCODING *, const char *); + int(PTRFASTCALL *isInvalid3)(const ENCODING *, const char *); + int(PTRFASTCALL *isInvalid4)(const ENCODING *, const char *); +}; + +#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *)(enc)) + +#ifdef XML_MIN_SIZE + +# define STANDARD_VTABLE(E) \ + E##byteType, E##isNameMin, E##isNmstrtMin, E##byteToAscii, E##charMatches, + +#else + +# define STANDARD_VTABLE(E) /* as nothing */ + +#endif + +#define NORMAL_VTABLE(E) \ + E##isName2, E##isName3, E##isName4, E##isNmstrt2, E##isNmstrt3, \ + E##isNmstrt4, E##isInvalid2, E##isInvalid3, E##isInvalid4 + +#define NULL_VTABLE \ + /* isName2 */ NULL, /* isName3 */ NULL, /* isName4 */ NULL, \ + /* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \ + /* isInvalid2 */ NULL, /* isInvalid3 */ NULL, /* isInvalid4 */ NULL + +static int FASTCALL checkCharRefNumber(int); + +#include "xmltok_impl.h" +#include "ascii.h" + +#ifdef XML_MIN_SIZE +# define sb_isNameMin isNever +# define sb_isNmstrtMin isNever +#endif + +#ifdef XML_MIN_SIZE +# define MINBPC(enc) ((enc)->minBytesPerChar) +#else +/* minimum bytes per character */ +# define MINBPC(enc) 1 +#endif + +#define SB_BYTE_TYPE(enc, p) \ + (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) + +#ifdef XML_MIN_SIZE +static int PTRFASTCALL +sb_byteType(const ENCODING *enc, const char *p) { + return SB_BYTE_TYPE(enc, p); +} +# define BYTE_TYPE(enc, p) (AS_NORMAL_ENCODING(enc)->byteType(enc, p)) +#else +# define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) +#endif + +#ifdef XML_MIN_SIZE +# define BYTE_TO_ASCII(enc, p) (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p)) +static int PTRFASTCALL +sb_byteToAscii(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return *p; +} +#else +# define BYTE_TO_ASCII(enc, p) (*(p)) +#endif + +#define IS_NAME_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isName##n(enc, p)) +#define IS_NMSTRT_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isNmstrt##n(enc, p)) +#ifdef XML_MIN_SIZE +# define IS_INVALID_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isInvalid##n \ + && AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p)) +#else +# define IS_INVALID_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p)) +#endif + +#ifdef XML_MIN_SIZE +# define IS_NAME_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p)) +# define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p)) +#else +# define IS_NAME_CHAR_MINBPC(enc, p) (0) +# define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) +#endif + +#ifdef XML_MIN_SIZE +# define CHAR_MATCHES(enc, p, c) \ + (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c)) +static int PTRCALL +sb_charMatches(const ENCODING *enc, const char *p, int c) { + UNUSED_P(enc); + return *p == c; +} +#else +/* c is an ASCII character */ +# define CHAR_MATCHES(enc, p, c) (*(p) == (c)) +#endif + +#define PREFIX(ident) normal_##ident +#define XML_TOK_IMPL_C +#include "xmltok_impl.c" +#undef XML_TOK_IMPL_C + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ + UTF8_cval1 = 0x00, + UTF8_cval2 = 0xc0, + UTF8_cval3 = 0xe0, + UTF8_cval4 = 0xf0 +}; + +void +_INTERNAL_trim_to_complete_utf8_characters(const char *from, + const char **fromLimRef) { + const char *fromLim = *fromLimRef; + size_t walked = 0; + for (; fromLim > from; fromLim--, walked++) { + const unsigned char prev = (unsigned char)fromLim[-1]; + if ((prev & 0xf8u) + == 0xf0u) { /* 4-byte character, lead by 0b11110xxx byte */ + if (walked + 1 >= 4) { + fromLim += 4 - 1; + break; + } else { + walked = 0; + } + } else if ((prev & 0xf0u) + == 0xe0u) { /* 3-byte character, lead by 0b1110xxxx byte */ + if (walked + 1 >= 3) { + fromLim += 3 - 1; + break; + } else { + walked = 0; + } + } else if ((prev & 0xe0u) + == 0xc0u) { /* 2-byte character, lead by 0b110xxxxx byte */ + if (walked + 1 >= 2) { + fromLim += 2 - 1; + break; + } else { + walked = 0; + } + } else if ((prev & 0x80u) + == 0x00u) { /* 1-byte character, matching 0b0xxxxxxx */ + break; + } + } + *fromLimRef = fromLim; +} + +static enum XML_Convert_Result PTRCALL +utf8_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, + char **toP, const char *toLim) { + bool input_incomplete = false; + bool output_exhausted = false; + + /* Avoid copying partial characters (due to limited space). */ + const ptrdiff_t bytesAvailable = fromLim - *fromP; + const ptrdiff_t bytesStorable = toLim - *toP; + UNUSED_P(enc); + if (bytesAvailable > bytesStorable) { + fromLim = *fromP + bytesStorable; + output_exhausted = true; + } + + /* Avoid copying partial characters (from incomplete input). */ + { + const char *const fromLimBefore = fromLim; + _INTERNAL_trim_to_complete_utf8_characters(*fromP, &fromLim); + if (fromLim < fromLimBefore) { + input_incomplete = true; + } + } + + { + const ptrdiff_t bytesToCopy = fromLim - *fromP; + memcpy(*toP, *fromP, bytesToCopy); + *fromP += bytesToCopy; + *toP += bytesToCopy; + } + + if (output_exhausted) /* needs to go first */ + return XML_CONVERT_OUTPUT_EXHAUSTED; + else if (input_incomplete) + return XML_CONVERT_INPUT_INCOMPLETE; + else + return XML_CONVERT_COMPLETED; +} + +static enum XML_Convert_Result PTRCALL +utf8_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) { + enum XML_Convert_Result res = XML_CONVERT_COMPLETED; + unsigned short *to = *toP; + const char *from = *fromP; + while (from < fromLim && to < toLim) { + switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { + case BT_LEAD2: + if (fromLim - from < 2) { + res = XML_CONVERT_INPUT_INCOMPLETE; + goto after; + } + *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f)); + from += 2; + break; + case BT_LEAD3: + if (fromLim - from < 3) { + res = XML_CONVERT_INPUT_INCOMPLETE; + goto after; + } + *to++ = (unsigned short)(((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) + | (from[2] & 0x3f)); + from += 3; + break; + case BT_LEAD4: { + unsigned long n; + if (toLim - to < 2) { + res = XML_CONVERT_OUTPUT_EXHAUSTED; + goto after; + } + if (fromLim - from < 4) { + res = XML_CONVERT_INPUT_INCOMPLETE; + goto after; + } + n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) + | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); + n -= 0x10000; + to[0] = (unsigned short)((n >> 10) | 0xD800); + to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); + to += 2; + from += 4; + } break; + default: + *to++ = *from++; + break; + } + } + if (from < fromLim) + res = XML_CONVERT_OUTPUT_EXHAUSTED; +after: + *fromP = from; + *toP = to; + return res; +} + +#ifdef XML_NS +static const struct normal_encoding utf8_encoding_ns + = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0}, + { +# include "asciitab.h" +# include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)}; +#endif + +static const struct normal_encoding utf8_encoding + = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0}, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)}; + +#ifdef XML_NS + +static const struct normal_encoding internal_utf8_encoding_ns + = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0}, + { +# include "iasciitab.h" +# include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)}; + +#endif + +static const struct normal_encoding internal_utf8_encoding + = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0}, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)}; + +static enum XML_Convert_Result PTRCALL +latin1_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, + char **toP, const char *toLim) { + UNUSED_P(enc); + for (;;) { + unsigned char c; + if (*fromP == fromLim) + return XML_CONVERT_COMPLETED; + c = (unsigned char)**fromP; + if (c & 0x80) { + if (toLim - *toP < 2) + return XML_CONVERT_OUTPUT_EXHAUSTED; + *(*toP)++ = (char)((c >> 6) | UTF8_cval2); + *(*toP)++ = (char)((c & 0x3f) | 0x80); + (*fromP)++; + } else { + if (*toP == toLim) + return XML_CONVERT_OUTPUT_EXHAUSTED; + *(*toP)++ = *(*fromP)++; + } + } +} + +static enum XML_Convert_Result PTRCALL +latin1_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) { + UNUSED_P(enc); + while (*fromP < fromLim && *toP < toLim) + *(*toP)++ = (unsigned char)*(*fromP)++; + + if ((*toP == toLim) && (*fromP < fromLim)) + return XML_CONVERT_OUTPUT_EXHAUSTED; + else + return XML_CONVERT_COMPLETED; +} + +#ifdef XML_NS + +static const struct normal_encoding latin1_encoding_ns + = {{VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0}, + { +# include "asciitab.h" +# include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) NULL_VTABLE}; + +#endif + +static const struct normal_encoding latin1_encoding + = {{VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0}, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) NULL_VTABLE}; + +static enum XML_Convert_Result PTRCALL +ascii_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, + char **toP, const char *toLim) { + UNUSED_P(enc); + while (*fromP < fromLim && *toP < toLim) + *(*toP)++ = *(*fromP)++; + + if ((*toP == toLim) && (*fromP < fromLim)) + return XML_CONVERT_OUTPUT_EXHAUSTED; + else + return XML_CONVERT_COMPLETED; +} + +#ifdef XML_NS + +static const struct normal_encoding ascii_encoding_ns + = {{VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0}, + { +# include "asciitab.h" + /* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) NULL_VTABLE}; + +#endif + +static const struct normal_encoding ascii_encoding + = {{VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0}, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON + /* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) NULL_VTABLE}; + +static int PTRFASTCALL +unicode_byte_type(char hi, char lo) { + switch ((unsigned char)hi) { + /* 0xD800-0xDBFF first 16-bit code unit or high surrogate (W1) */ + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + return BT_LEAD4; + /* 0xDC00-0xDFFF second 16-bit code unit or low surrogate (W2) */ + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + return BT_TRAIL; + case 0xFF: + switch ((unsigned char)lo) { + case 0xFF: /* noncharacter-FFFF */ + case 0xFE: /* noncharacter-FFFE */ + return BT_NONXML; + } + break; + } + return BT_NONASCII; +} + +#define DEFINE_UTF16_TO_UTF8(E) \ + static enum XML_Convert_Result PTRCALL E##toUtf8( \ + const ENCODING *enc, const char **fromP, const char *fromLim, \ + char **toP, const char *toLim) { \ + const char *from = *fromP; \ + UNUSED_P(enc); \ + fromLim = from + (((fromLim - from) >> 1) << 1); /* shrink to even */ \ + for (; from < fromLim; from += 2) { \ + int plane; \ + unsigned char lo2; \ + unsigned char lo = GET_LO(from); \ + unsigned char hi = GET_HI(from); \ + switch (hi) { \ + case 0: \ + if (lo < 0x80) { \ + if (*toP == toLim) { \ + *fromP = from; \ + return XML_CONVERT_OUTPUT_EXHAUSTED; \ + } \ + *(*toP)++ = lo; \ + break; \ + } \ + /* fall through */ \ + case 0x1: \ + case 0x2: \ + case 0x3: \ + case 0x4: \ + case 0x5: \ + case 0x6: \ + case 0x7: \ + if (toLim - *toP < 2) { \ + *fromP = from; \ + return XML_CONVERT_OUTPUT_EXHAUSTED; \ + } \ + *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + default: \ + if (toLim - *toP < 3) { \ + *fromP = from; \ + return XML_CONVERT_OUTPUT_EXHAUSTED; \ + } \ + /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ + *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ + *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + case 0xD8: \ + case 0xD9: \ + case 0xDA: \ + case 0xDB: \ + if (toLim - *toP < 4) { \ + *fromP = from; \ + return XML_CONVERT_OUTPUT_EXHAUSTED; \ + } \ + if (fromLim - from < 4) { \ + *fromP = from; \ + return XML_CONVERT_INPUT_INCOMPLETE; \ + } \ + plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ + *(*toP)++ = (char)((plane >> 2) | UTF8_cval4); \ + *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ + from += 2; \ + lo2 = GET_LO(from); \ + *(*toP)++ = (((lo & 0x3) << 4) | ((GET_HI(from) & 0x3) << 2) \ + | (lo2 >> 6) | 0x80); \ + *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ + break; \ + } \ + } \ + *fromP = from; \ + if (from < fromLim) \ + return XML_CONVERT_INPUT_INCOMPLETE; \ + else \ + return XML_CONVERT_COMPLETED; \ + } + +#define DEFINE_UTF16_TO_UTF16(E) \ + static enum XML_Convert_Result PTRCALL E##toUtf16( \ + const ENCODING *enc, const char **fromP, const char *fromLim, \ + unsigned short **toP, const unsigned short *toLim) { \ + enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \ + UNUSED_P(enc); \ + fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1); /* shrink to even */ \ + /* Avoid copying first half only of surrogate */ \ + if (fromLim - *fromP > ((toLim - *toP) << 1) \ + && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \ + fromLim -= 2; \ + res = XML_CONVERT_INPUT_INCOMPLETE; \ + } \ + for (; *fromP < fromLim && *toP < toLim; *fromP += 2) \ + *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ + if ((*toP == toLim) && (*fromP < fromLim)) \ + return XML_CONVERT_OUTPUT_EXHAUSTED; \ + else \ + return res; \ + } + +#define SET2(ptr, ch) (((ptr)[0] = ((ch)&0xff)), ((ptr)[1] = ((ch) >> 8))) +#define GET_LO(ptr) ((unsigned char)(ptr)[0]) +#define GET_HI(ptr) ((unsigned char)(ptr)[1]) + +DEFINE_UTF16_TO_UTF8(little2_) +DEFINE_UTF16_TO_UTF16(little2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define SET2(ptr, ch) (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch)&0xFF))) +#define GET_LO(ptr) ((unsigned char)(ptr)[1]) +#define GET_HI(ptr) ((unsigned char)(ptr)[0]) + +DEFINE_UTF16_TO_UTF8(big2_) +DEFINE_UTF16_TO_UTF16(big2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define LITTLE2_BYTE_TYPE(enc, p) \ + ((p)[1] == 0 ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ + : unicode_byte_type((p)[1], (p)[0])) +#define LITTLE2_BYTE_TO_ASCII(p) ((p)[1] == 0 ? (p)[0] : -1) +#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == (c)) +#define LITTLE2_IS_NAME_CHAR_MINBPC(p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) +#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +little2_byteType(const ENCODING *enc, const char *p) { + return LITTLE2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +little2_byteToAscii(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return LITTLE2_BYTE_TO_ASCII(p); +} + +static int PTRCALL +little2_charMatches(const ENCODING *enc, const char *p, int c) { + UNUSED_P(enc); + return LITTLE2_CHAR_MATCHES(p, c); +} + +static int PTRFASTCALL +little2_isNameMin(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return LITTLE2_IS_NAME_CHAR_MINBPC(p); +} + +static int PTRFASTCALL +little2_isNmstrtMin(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return LITTLE2_IS_NMSTRT_CHAR_MINBPC(p); +} + +# undef VTABLE +# define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +# undef PREFIX +# define PREFIX(ident) little2_##ident +# define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +# define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) +# define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(p) +# define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(p, c) +# define IS_NAME_CHAR(enc, p, n) 0 +# define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(p) +# define IS_NMSTRT_CHAR(enc, p, n) (0) +# define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) + +# define XML_TOK_IMPL_C +# include "xmltok_impl.c" +# undef XML_TOK_IMPL_C + +# undef MINBPC +# undef BYTE_TYPE +# undef BYTE_TO_ASCII +# undef CHAR_MATCHES +# undef IS_NAME_CHAR +# undef IS_NAME_CHAR_MINBPC +# undef IS_NMSTRT_CHAR +# undef IS_NMSTRT_CHAR_MINBPC +# undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding little2_encoding_ns + = {{VTABLE, 2, 0, +# if BYTEORDER == 1234 + 1 +# else + 0 +# endif + }, + { +# include "asciitab.h" +# include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_VTABLE}; + +#endif + +static const struct normal_encoding little2_encoding + = {{VTABLE, 2, 0, +#if BYTEORDER == 1234 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_VTABLE}; + +#if BYTEORDER != 4321 + +# ifdef XML_NS + +static const struct normal_encoding internal_little2_encoding_ns + = {{VTABLE, 2, 0, 1}, + { +# include "iasciitab.h" +# include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_VTABLE}; + +# endif + +static const struct normal_encoding internal_little2_encoding + = {{VTABLE, 2, 0, 1}, + { +# define BT_COLON BT_NMSTRT +# include "iasciitab.h" +# undef BT_COLON +# include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) NULL_VTABLE}; + +#endif + +#define BIG2_BYTE_TYPE(enc, p) \ + ((p)[0] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ + : unicode_byte_type((p)[0], (p)[1])) +#define BIG2_BYTE_TO_ASCII(p) ((p)[0] == 0 ? (p)[1] : -1) +#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == (c)) +#define BIG2_IS_NAME_CHAR_MINBPC(p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) +#define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +big2_byteType(const ENCODING *enc, const char *p) { + return BIG2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +big2_byteToAscii(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return BIG2_BYTE_TO_ASCII(p); +} + +static int PTRCALL +big2_charMatches(const ENCODING *enc, const char *p, int c) { + UNUSED_P(enc); + return BIG2_CHAR_MATCHES(p, c); +} + +static int PTRFASTCALL +big2_isNameMin(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return BIG2_IS_NAME_CHAR_MINBPC(p); +} + +static int PTRFASTCALL +big2_isNmstrtMin(const ENCODING *enc, const char *p) { + UNUSED_P(enc); + return BIG2_IS_NMSTRT_CHAR_MINBPC(p); +} + +# undef VTABLE +# define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +# undef PREFIX +# define PREFIX(ident) big2_##ident +# define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +# define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) +# define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(p) +# define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(p, c) +# define IS_NAME_CHAR(enc, p, n) 0 +# define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(p) +# define IS_NMSTRT_CHAR(enc, p, n) (0) +# define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(p) + +# define XML_TOK_IMPL_C +# include "xmltok_impl.c" +# undef XML_TOK_IMPL_C + +# undef MINBPC +# undef BYTE_TYPE +# undef BYTE_TO_ASCII +# undef CHAR_MATCHES +# undef IS_NAME_CHAR +# undef IS_NAME_CHAR_MINBPC +# undef IS_NMSTRT_CHAR +# undef IS_NMSTRT_CHAR_MINBPC +# undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding big2_encoding_ns + = {{VTABLE, 2, 0, +# if BYTEORDER == 4321 + 1 +# else + 0 +# endif + }, + { +# include "asciitab.h" +# include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) NULL_VTABLE}; + +#endif + +static const struct normal_encoding big2_encoding + = {{VTABLE, 2, 0, +#if BYTEORDER == 4321 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) NULL_VTABLE}; + +#if BYTEORDER != 1234 + +# ifdef XML_NS + +static const struct normal_encoding internal_big2_encoding_ns + = {{VTABLE, 2, 0, 1}, + { +# include "iasciitab.h" +# include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) NULL_VTABLE}; + +# endif + +static const struct normal_encoding internal_big2_encoding + = {{VTABLE, 2, 0, 1}, + { +# define BT_COLON BT_NMSTRT +# include "iasciitab.h" +# undef BT_COLON +# include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) NULL_VTABLE}; + +#endif + +#undef PREFIX + +static int FASTCALL +streqci(const char *s1, const char *s2) { + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if (ASCII_a <= c1 && c1 <= ASCII_z) + c1 += ASCII_A - ASCII_a; + if (ASCII_a <= c2 && c2 <= ASCII_z) + /* The following line will never get executed. streqci() is + * only called from two places, both of which guarantee to put + * upper-case strings into s2. + */ + c2 += ASCII_A - ASCII_a; /* LCOV_EXCL_LINE */ + if (c1 != c2) + return 0; + if (! c1) + break; + } + return 1; +} + +static void PTRCALL +initUpdatePosition(const ENCODING *enc, const char *ptr, const char *end, + POSITION *pos) { + UNUSED_P(enc); + normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); +} + +static int +toAscii(const ENCODING *enc, const char *ptr, const char *end) { + char buf[1]; + char *p = buf; + XmlUtf8Convert(enc, &ptr, end, &p, p + 1); + if (p == buf) + return -1; + else + return buf[0]; +} + +static int FASTCALL +isSpace(int c) { + switch (c) { + case 0x20: + case 0xD: + case 0xA: + case 0x9: + return 1; + } + return 0; +} + +/* Return 1 if there's just optional white space or there's an S + followed by name=val. +*/ +static int +parsePseudoAttribute(const ENCODING *enc, const char *ptr, const char *end, + const char **namePtr, const char **nameEndPtr, + const char **valPtr, const char **nextTokPtr) { + int c; + char open; + if (ptr == end) { + *namePtr = NULL; + return 1; + } + if (! isSpace(toAscii(enc, ptr, end))) { + *nextTokPtr = ptr; + return 0; + } + do { + ptr += enc->minBytesPerChar; + } while (isSpace(toAscii(enc, ptr, end))); + if (ptr == end) { + *namePtr = NULL; + return 1; + } + *namePtr = ptr; + for (;;) { + c = toAscii(enc, ptr, end); + if (c == -1) { + *nextTokPtr = ptr; + return 0; + } + if (c == ASCII_EQUALS) { + *nameEndPtr = ptr; + break; + } + if (isSpace(c)) { + *nameEndPtr = ptr; + do { + ptr += enc->minBytesPerChar; + } while (isSpace(c = toAscii(enc, ptr, end))); + if (c != ASCII_EQUALS) { + *nextTokPtr = ptr; + return 0; + } + break; + } + ptr += enc->minBytesPerChar; + } + if (ptr == *namePtr) { + *nextTokPtr = ptr; + return 0; + } + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + while (isSpace(c)) { + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + } + if (c != ASCII_QUOT && c != ASCII_APOS) { + *nextTokPtr = ptr; + return 0; + } + open = (char)c; + ptr += enc->minBytesPerChar; + *valPtr = ptr; + for (;; ptr += enc->minBytesPerChar) { + c = toAscii(enc, ptr, end); + if (c == open) + break; + if (! (ASCII_a <= c && c <= ASCII_z) && ! (ASCII_A <= c && c <= ASCII_Z) + && ! (ASCII_0 <= c && c <= ASCII_9) && c != ASCII_PERIOD + && c != ASCII_MINUS && c != ASCII_UNDERSCORE) { + *nextTokPtr = ptr; + return 0; + } + } + *nextTokPtr = ptr + enc->minBytesPerChar; + return 1; +} + +static const char KW_version[] + = {ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'}; + +static const char KW_encoding[] = {ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, + ASCII_i, ASCII_n, ASCII_g, '\0'}; + +static const char KW_standalone[] + = {ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, + ASCII_l, ASCII_o, ASCII_n, ASCII_e, '\0'}; + +static const char KW_yes[] = {ASCII_y, ASCII_e, ASCII_s, '\0'}; + +static const char KW_no[] = {ASCII_n, ASCII_o, '\0'}; + +static int +doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, const char *, + const char *), + int isGeneralTextEntity, const ENCODING *enc, const char *ptr, + const char *end, const char **badPtr, const char **versionPtr, + const char **versionEndPtr, const char **encodingName, + const ENCODING **encoding, int *standalone) { + const char *val = NULL; + const char *name = NULL; + const char *nameEnd = NULL; + ptr += 5 * enc->minBytesPerChar; + end -= 2 * enc->minBytesPerChar; + if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) + || ! name) { + *badPtr = ptr; + return 0; + } + if (! XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { + if (! isGeneralTextEntity) { + *badPtr = name; + return 0; + } + } else { + if (versionPtr) + *versionPtr = val; + if (versionEndPtr) + *versionEndPtr = ptr; + if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (! name) { + if (isGeneralTextEntity) { + /* a TextDecl must have an EncodingDecl */ + *badPtr = ptr; + return 0; + } + return 1; + } + } + if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { + int c = toAscii(enc, val, end); + if (! (ASCII_a <= c && c <= ASCII_z) && ! (ASCII_A <= c && c <= ASCII_Z)) { + *badPtr = val; + return 0; + } + if (encodingName) + *encodingName = val; + if (encoding) + *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); + if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (! name) + return 1; + } + if (! XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) + || isGeneralTextEntity) { + *badPtr = name; + return 0; + } + if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { + if (standalone) + *standalone = 1; + } else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { + if (standalone) + *standalone = 0; + } else { + *badPtr = val; + return 0; + } + while (isSpace(toAscii(enc, ptr, end))) + ptr += enc->minBytesPerChar; + if (ptr != end) { + *badPtr = ptr; + return 0; + } + return 1; +} + +static int FASTCALL +checkCharRefNumber(int result) { + switch (result >> 8) { + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + return -1; + case 0: + if (latin1_encoding.type[result] == BT_NONXML) + return -1; + break; + case 0xFF: + if (result == 0xFFFE || result == 0xFFFF) + return -1; + break; + } + return result; +} + +int FASTCALL +XmlUtf8Encode(int c, char *buf) { + enum { + /* minN is minimum legal resulting value for N byte sequence */ + min2 = 0x80, + min3 = 0x800, + min4 = 0x10000 + }; + + if (c < 0) + return 0; /* LCOV_EXCL_LINE: this case is always eliminated beforehand */ + if (c < min2) { + buf[0] = (char)(c | UTF8_cval1); + return 1; + } + if (c < min3) { + buf[0] = (char)((c >> 6) | UTF8_cval2); + buf[1] = (char)((c & 0x3f) | 0x80); + return 2; + } + if (c < min4) { + buf[0] = (char)((c >> 12) | UTF8_cval3); + buf[1] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[2] = (char)((c & 0x3f) | 0x80); + return 3; + } + if (c < 0x110000) { + buf[0] = (char)((c >> 18) | UTF8_cval4); + buf[1] = (char)(((c >> 12) & 0x3f) | 0x80); + buf[2] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[3] = (char)((c & 0x3f) | 0x80); + return 4; + } + return 0; /* LCOV_EXCL_LINE: this case too is eliminated before calling */ +} + +int FASTCALL +XmlUtf16Encode(int charNum, unsigned short *buf) { + if (charNum < 0) + return 0; + if (charNum < 0x10000) { + buf[0] = (unsigned short)charNum; + return 1; + } + if (charNum < 0x110000) { + charNum -= 0x10000; + buf[0] = (unsigned short)((charNum >> 10) + 0xD800); + buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00); + return 2; + } + return 0; +} + +struct unknown_encoding { + struct normal_encoding normal; + CONVERTER convert; + void *userData; + unsigned short utf16[256]; + char utf8[256][4]; +}; + +#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *)(enc)) + +int +XmlSizeOfUnknownEncoding(void) { + return sizeof(struct unknown_encoding); +} + +static int PTRFASTCALL +unknown_isName(const ENCODING *enc, const char *p) { + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isNmstrt(const ENCODING *enc, const char *p) { + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isInvalid(const ENCODING *enc, const char *p) { + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; +} + +static enum XML_Convert_Result PTRCALL +unknown_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, + char **toP, const char *toLim) { + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + char buf[XML_UTF8_ENCODE_MAX]; + for (;;) { + const char *utf8; + int n; + if (*fromP == fromLim) + return XML_CONVERT_COMPLETED; + utf8 = uenc->utf8[(unsigned char)**fromP]; + n = *utf8++; + if (n == 0) { + int c = uenc->convert(uenc->userData, *fromP); + n = XmlUtf8Encode(c, buf); + if (n > toLim - *toP) + return XML_CONVERT_OUTPUT_EXHAUSTED; + utf8 = buf; + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } else { + if (n > toLim - *toP) + return XML_CONVERT_OUTPUT_EXHAUSTED; + (*fromP)++; + } + memcpy(*toP, utf8, n); + *toP += n; + } +} + +static enum XML_Convert_Result PTRCALL +unknown_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) { + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + while (*fromP < fromLim && *toP < toLim) { + unsigned short c = uenc->utf16[(unsigned char)**fromP]; + if (c == 0) { + c = (unsigned short)uenc->convert(uenc->userData, *fromP); + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } else + (*fromP)++; + *(*toP)++ = c; + } + + if ((*toP == toLim) && (*fromP < fromLim)) + return XML_CONVERT_OUTPUT_EXHAUSTED; + else + return XML_CONVERT_COMPLETED; +} + +ENCODING * +XmlInitUnknownEncoding(void *mem, int *table, CONVERTER convert, + void *userData) { + int i; + struct unknown_encoding *e = (struct unknown_encoding *)mem; + memcpy(mem, &latin1_encoding, sizeof(struct normal_encoding)); + for (i = 0; i < 128; i++) + if (latin1_encoding.type[i] != BT_OTHER + && latin1_encoding.type[i] != BT_NONXML && table[i] != i) + return 0; + for (i = 0; i < 256; i++) { + int c = table[i]; + if (c == -1) { + e->normal.type[i] = BT_MALFORM; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } else if (c < 0) { + if (c < -4) + return 0; + /* Multi-byte sequences need a converter function */ + if (! convert) + return 0; + e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2)); + e->utf8[i][0] = 0; + e->utf16[i] = 0; + } else if (c < 0x80) { + if (latin1_encoding.type[c] != BT_OTHER + && latin1_encoding.type[c] != BT_NONXML && c != i) + return 0; + e->normal.type[i] = latin1_encoding.type[c]; + e->utf8[i][0] = 1; + e->utf8[i][1] = (char)c; + e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c); + } else if (checkCharRefNumber(c) < 0) { + e->normal.type[i] = BT_NONXML; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } else { + if (c > 0xFFFF) + return 0; + if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NMSTRT; + else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NAME; + else + e->normal.type[i] = BT_OTHER; + e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); + e->utf16[i] = (unsigned short)c; + } + } + e->userData = userData; + e->convert = convert; + if (convert) { + e->normal.isName2 = unknown_isName; + e->normal.isName3 = unknown_isName; + e->normal.isName4 = unknown_isName; + e->normal.isNmstrt2 = unknown_isNmstrt; + e->normal.isNmstrt3 = unknown_isNmstrt; + e->normal.isNmstrt4 = unknown_isNmstrt; + e->normal.isInvalid2 = unknown_isInvalid; + e->normal.isInvalid3 = unknown_isInvalid; + e->normal.isInvalid4 = unknown_isInvalid; + } + e->normal.enc.utf8Convert = unknown_toUtf8; + e->normal.enc.utf16Convert = unknown_toUtf16; + return &(e->normal.enc); +} + +/* If this enumeration is changed, getEncodingIndex and encodings +must also be changed. */ +enum { + UNKNOWN_ENC = -1, + ISO_8859_1_ENC = 0, + US_ASCII_ENC, + UTF_8_ENC, + UTF_16_ENC, + UTF_16BE_ENC, + UTF_16LE_ENC, + /* must match encodingNames up to here */ + NO_ENC +}; + +static const char KW_ISO_8859_1[] + = {ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, + ASCII_5, ASCII_9, ASCII_MINUS, ASCII_1, '\0'}; +static const char KW_US_ASCII[] + = {ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, + ASCII_C, ASCII_I, ASCII_I, '\0'}; +static const char KW_UTF_8[] + = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'}; +static const char KW_UTF_16[] + = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'}; +static const char KW_UTF_16BE[] + = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, + ASCII_6, ASCII_B, ASCII_E, '\0'}; +static const char KW_UTF_16LE[] + = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, + ASCII_6, ASCII_L, ASCII_E, '\0'}; + +static int FASTCALL +getEncodingIndex(const char *name) { + static const char *const encodingNames[] = { + KW_ISO_8859_1, KW_US_ASCII, KW_UTF_8, KW_UTF_16, KW_UTF_16BE, KW_UTF_16LE, + }; + int i; + if (name == NULL) + return NO_ENC; + for (i = 0; i < (int)(sizeof(encodingNames) / sizeof(encodingNames[0])); i++) + if (streqci(name, encodingNames[i])) + return i; + return UNKNOWN_ENC; +} + +/* For binary compatibility, we store the index of the encoding + specified at initialization in the isUtf16 member. +*/ + +#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) +#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) + +/* This is what detects the encoding. encodingTable maps from + encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of + the external (protocol) specified encoding; state is + XML_CONTENT_STATE if we're parsing an external text entity, and + XML_PROLOG_STATE otherwise. +*/ + +static int +initScan(const ENCODING *const *encodingTable, const INIT_ENCODING *enc, + int state, const char *ptr, const char *end, const char **nextTokPtr) { + const ENCODING **encPtr; + + if (ptr >= end) + return XML_TOK_NONE; + encPtr = enc->encPtr; + if (ptr + 1 == end) { + /* only a single byte available for auto-detection */ +#ifndef XML_DTD /* FIXME */ + /* a well-formed document entity must have more than one byte */ + if (state != XML_CONTENT_STATE) + return XML_TOK_PARTIAL; +#endif + /* so we're parsing an external text entity... */ + /* if UTF-16 was externally specified, then we need at least 2 bytes */ + switch (INIT_ENC_INDEX(enc)) { + case UTF_16_ENC: + case UTF_16LE_ENC: + case UTF_16BE_ENC: + return XML_TOK_PARTIAL; + } + switch ((unsigned char)*ptr) { + case 0xFE: + case 0xFF: + case 0xEF: /* possibly first byte of UTF-8 BOM */ + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE) + break; + /* fall through */ + case 0x00: + case 0x3C: + return XML_TOK_PARTIAL; + } + } else { + switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { + case 0xFEFF: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XML_TOK_BOM; + /* 00 3C is handled in the default case */ + case 0x3C00: + if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC + || INIT_ENC_INDEX(enc) == UTF_16_ENC) + && state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFFFE: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XML_TOK_BOM; + case 0xEFBB: + /* Maybe a UTF-8 BOM (EF BB BF) */ + /* If there's an explicitly specified (external) encoding + of ISO-8859-1 or some flavour of UTF-16 + and this is an external text entity, + don't look for the BOM, + because it might be a legal data. + */ + if (state == XML_CONTENT_STATE) { + int e = INIT_ENC_INDEX(enc); + if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC + || e == UTF_16_ENC) + break; + } + if (ptr + 2 == end) + return XML_TOK_PARTIAL; + if ((unsigned char)ptr[2] == 0xBF) { + *nextTokPtr = ptr + 3; + *encPtr = encodingTable[UTF_8_ENC]; + return XML_TOK_BOM; + } + break; + default: + if (ptr[0] == '\0') { + /* 0 isn't a legal data character. Furthermore a document + entity can only start with ASCII characters. So the only + way this can fail to be big-endian UTF-16 if it it's an + external parsed general entity that's labelled as + UTF-16LE. + */ + if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) + break; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } else if (ptr[1] == '\0') { + /* We could recover here in the case: + - parsing an external entity + - second byte is 0 + - no externally specified encoding + - no encoding declaration + by assuming UTF-16LE. But we don't, because this would mean when + presented just with a single byte, we couldn't reliably determine + whether we needed further bytes. + */ + if (state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + break; + } + } + *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); +} + +#define NS(x) x +#define ns(x) x +#define XML_TOK_NS_C +#include "xmltok_ns.c" +#undef XML_TOK_NS_C +#undef NS +#undef ns + +#ifdef XML_NS + +# define NS(x) x##NS +# define ns(x) x##_ns + +# define XML_TOK_NS_C +# include "xmltok_ns.c" +# undef XML_TOK_NS_C + +# undef NS +# undef ns + +ENCODING * +XmlInitUnknownEncodingNS(void *mem, int *table, CONVERTER convert, + void *userData) { + ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); + if (enc) + ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; + return enc; +} + +#endif /* XML_NS */ diff --git a/src/3rdparty/expat/src/xmltok.h b/src/3rdparty/expat/src/xmltok.h new file mode 100644 index 00000000..6f630c2f --- /dev/null +++ b/src/3rdparty/expat/src/xmltok.h @@ -0,0 +1,319 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2002-2005 Karl Waclawek + Copyright (c) 2016-2017 Sebastian Pipping + Copyright (c) 2017 Rhodri James + Licensed under the MIT license: + + 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 XmlTok_INCLUDED +#define XmlTok_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* The following token may be returned by XmlContentTok */ +#define XML_TOK_TRAILING_RSQB \ + -5 /* ] or ]] at the end of the scan; might be \ + start of illegal ]]> sequence */ +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_NONE -4 /* The string to be scanned is empty */ +#define XML_TOK_TRAILING_CR \ + -3 /* A CR at the end of the scan; \ + might be part of CRLF sequence */ +#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +#define XML_TOK_PARTIAL -1 /* only part of a token */ +#define XML_TOK_INVALID 0 + +/* The following tokens are returned by XmlContentTok; some are also + returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok. +*/ +#define XML_TOK_START_TAG_WITH_ATTS 1 +#define XML_TOK_START_TAG_NO_ATTS 2 +#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag */ +#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +#define XML_TOK_END_TAG 5 +#define XML_TOK_DATA_CHARS 6 +#define XML_TOK_DATA_NEWLINE 7 +#define XML_TOK_CDATA_SECT_OPEN 8 +#define XML_TOK_ENTITY_REF 9 +#define XML_TOK_CHAR_REF 10 /* numeric character reference */ + +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_PI 11 /* processing instruction */ +#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +#define XML_TOK_COMMENT 13 +#define XML_TOK_BOM 14 /* Byte order mark */ + +/* The following tokens are returned only by XmlPrologTok */ +#define XML_TOK_PROLOG_S 15 +#define XML_TOK_DECL_OPEN 16 /* */ +#define XML_TOK_NAME 18 +#define XML_TOK_NMTOKEN 19 +#define XML_TOK_POUND_NAME 20 /* #name */ +#define XML_TOK_OR 21 /* | */ +#define XML_TOK_PERCENT 22 +#define XML_TOK_OPEN_PAREN 23 +#define XML_TOK_CLOSE_PAREN 24 +#define XML_TOK_OPEN_BRACKET 25 +#define XML_TOK_CLOSE_BRACKET 26 +#define XML_TOK_LITERAL 27 +#define XML_TOK_PARAM_ENTITY_REF 28 +#define XML_TOK_INSTANCE_START 29 + +/* The following occur only in element type declarations */ +#define XML_TOK_NAME_QUESTION 30 /* name? */ +#define XML_TOK_NAME_ASTERISK 31 /* name* */ +#define XML_TOK_NAME_PLUS 32 /* name+ */ +#define XML_TOK_COND_SECT_OPEN 33 /* */ +#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +#define XML_TOK_COMMA 38 + +/* The following token is returned only by XmlAttributeValueTok */ +#define XML_TOK_ATTRIBUTE_VALUE_S 39 + +/* The following token is returned only by XmlCdataSectionTok */ +#define XML_TOK_CDATA_SECT_CLOSE 40 + +/* With namespace processing this is returned by XmlPrologTok for a + name with a colon. +*/ +#define XML_TOK_PREFIXED_NAME 41 + +#ifdef XML_DTD +# define XML_TOK_IGNORE_SECT 42 +#endif /* XML_DTD */ + +#ifdef XML_DTD +# define XML_N_STATES 4 +#else /* not XML_DTD */ +# define XML_N_STATES 3 +#endif /* not XML_DTD */ + +#define XML_PROLOG_STATE 0 +#define XML_CONTENT_STATE 1 +#define XML_CDATA_SECTION_STATE 2 +#ifdef XML_DTD +# define XML_IGNORE_SECTION_STATE 3 +#endif /* XML_DTD */ + +#define XML_N_LITERAL_TYPES 2 +#define XML_ATTRIBUTE_VALUE_LITERAL 0 +#define XML_ENTITY_VALUE_LITERAL 1 + +/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ +#define XML_UTF8_ENCODE_MAX 4 +/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ +#define XML_UTF16_ENCODE_MAX 2 + +typedef struct position { + /* first line and first column are 0 not 1 */ + XML_Size lineNumber; + XML_Size columnNumber; +} POSITION; + +typedef struct { + const char *name; + const char *valuePtr; + const char *valueEnd; + char normalized; +} ATTRIBUTE; + +struct encoding; +typedef struct encoding ENCODING; + +typedef int(PTRCALL *SCANNER)(const ENCODING *, const char *, const char *, + const char **); + +enum XML_Convert_Result { + XML_CONVERT_COMPLETED = 0, + XML_CONVERT_INPUT_INCOMPLETE = 1, + XML_CONVERT_OUTPUT_EXHAUSTED + = 2 /* and therefore potentially input remaining as well */ +}; + +struct encoding { + SCANNER scanners[XML_N_STATES]; + SCANNER literalScanners[XML_N_LITERAL_TYPES]; + int(PTRCALL *nameMatchesAscii)(const ENCODING *, const char *, const char *, + const char *); + int(PTRFASTCALL *nameLength)(const ENCODING *, const char *); + const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *); + int(PTRCALL *getAtts)(const ENCODING *enc, const char *ptr, int attsMax, + ATTRIBUTE *atts); + int(PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr); + int(PTRCALL *predefinedEntityName)(const ENCODING *, const char *, + const char *); + void(PTRCALL *updatePosition)(const ENCODING *, const char *ptr, + const char *end, POSITION *); + int(PTRCALL *isPublicId)(const ENCODING *enc, const char *ptr, + const char *end, const char **badPtr); + enum XML_Convert_Result(PTRCALL *utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, char **toP, + const char *toLim); + enum XML_Convert_Result(PTRCALL *utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); + int minBytesPerChar; + char isUtf8; + char isUtf16; +}; + +/* Scan the string starting at ptr until the end of the next complete + token, but do not scan past eptr. Return an integer giving the + type of token. + + Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. + + Return XML_TOK_PARTIAL when the string does not contain a complete + token; nextTokPtr will not be set. + + Return XML_TOK_INVALID when the string does not start a valid + token; nextTokPtr will be set to point to the character which made + the token invalid. + + Otherwise the string starts with a valid token; nextTokPtr will be + set to point to the character following the end of that token. + + Each data character counts as a single token, but adjacent data + characters may be returned together. Similarly for characters in + the prolog outside literals, comments and processing instructions. +*/ + +#define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) + +#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) + +#define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) + +#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) + +#ifdef XML_DTD + +# define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) + +#endif /* XML_DTD */ + +/* This is used for performing a 2nd-level tokenization on the content + of a literal that has already been returned by XmlTok. +*/ +#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) + +#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) + +#define XmlNameLength(enc, ptr) (((enc)->nameLength)(enc, ptr)) + +#define XmlSkipS(enc, ptr) (((enc)->skipS)(enc, ptr)) + +#define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) + +#define XmlCharRefNumber(enc, ptr) (((enc)->charRefNumber)(enc, ptr)) + +#define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) + +#define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) + +#define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) + +#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) + +#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) + +typedef struct { + ENCODING initEnc; + const ENCODING **encPtr; +} INIT_ENCODING; + +int XmlParseXmlDecl(int isGeneralTextEntity, const ENCODING *enc, + const char *ptr, const char *end, const char **badPtr, + const char **versionPtr, const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, int *standalonePtr); + +int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncoding(void); +const ENCODING *XmlGetUtf16InternalEncoding(void); +int FASTCALL XmlUtf8Encode(int charNumber, char *buf); +int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf); +int XmlSizeOfUnknownEncoding(void); + +typedef int(XMLCALL *CONVERTER)(void *userData, const char *p); + +ENCODING *XmlInitUnknownEncoding(void *mem, int *table, CONVERTER convert, + void *userData); + +int XmlParseXmlDeclNS(int isGeneralTextEntity, const ENCODING *enc, + const char *ptr, const char *end, const char **badPtr, + const char **versionPtr, const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, int *standalonePtr); + +int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncodingNS(void); +const ENCODING *XmlGetUtf16InternalEncodingNS(void); +ENCODING *XmlInitUnknownEncodingNS(void *mem, int *table, CONVERTER convert, + void *userData); +#ifdef __cplusplus +} +#endif + +#endif /* not XmlTok_INCLUDED */ diff --git a/src/3rdparty/expat/src/xmltok_impl.c b/src/3rdparty/expat/src/xmltok_impl.c new file mode 100644 index 00000000..1971d74b --- /dev/null +++ b/src/3rdparty/expat/src/xmltok_impl.c @@ -0,0 +1,1819 @@ +/* This file is included (from xmltok.c, 1-3 times depending on XML_MIN_SIZE)! + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2002-2016 Karl Waclawek + Copyright (c) 2016-2022 Sebastian Pipping + Copyright (c) 2017 Rhodri James + Copyright (c) 2018 Benjamin Peterson + Copyright (c) 2018 Anton Maklakov + Copyright (c) 2019 David Loffredo + Copyright (c) 2020 Boris Kolpackov + Copyright (c) 2022 Martin Ettl + Licensed under the MIT license: + + 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. +*/ + +#ifdef XML_TOK_IMPL_C + +# ifndef IS_INVALID_CHAR // i.e. for UTF-16 and XML_MIN_SIZE not defined +# define IS_INVALID_CHAR(enc, ptr, n) (0) +# endif + +# define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ + case BT_LEAD##n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +# define INVALID_CASES(ptr, nextTokPtr) \ + INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ + case BT_NONXML: \ + case BT_MALFORM: \ + case BT_TRAIL: \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; + +# define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD##n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NAME_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +# define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (! IS_NAME_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + /* fall through */ \ + case BT_NMSTRT: \ + case BT_HEX: \ + case BT_DIGIT: \ + case BT_NAME: \ + case BT_MINUS: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) + +# define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD##n: \ + if ((end) - (ptr) < (n)) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +# define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (! IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + /* fall through */ \ + case BT_NMSTRT: \ + case BT_HEX: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) + +# ifndef PREFIX +# define PREFIX(ident) ident +# endif + +# define HAS_CHARS(enc, ptr, end, count) \ + ((end) - (ptr) >= ((count)*MINBPC(enc))) + +# define HAS_CHAR(enc, ptr, end) HAS_CHARS(enc, ptr, end, 1) + +# define REQUIRE_CHARS(enc, ptr, end, count) \ + { \ + if (! HAS_CHARS(enc, ptr, end, count)) { \ + return XML_TOK_PARTIAL; \ + } \ + } + +# define REQUIRE_CHAR(enc, ptr, end) REQUIRE_CHARS(enc, ptr, end, 1) + +/* ptr points to character following " */ + switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { + case BT_S: + case BT_CR: + case BT_LF: + case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* fall through */ + case BT_S: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DECL_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, const char *end, + int *tokPtr) { + int upper = 0; + UNUSED_P(enc); + *tokPtr = XML_TOK_PI; + if (end - ptr != MINBPC(enc) * 3) + return 1; + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_x: + break; + case ASCII_X: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_m: + break; + case ASCII_M: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + break; + case ASCII_L: + upper = 1; + break; + default: + return 1; + } + if (upper) + return 0; + *tokPtr = XML_TOK_XML_DECL; + return 1; +} + +/* ptr points to character following "= end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_RSQB: + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + if (! CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + if (! CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CDATA_SECT_CLOSE; + case BT_CR: + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { +# define LEAD_CASE(n) \ + case BT_LEAD##n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + case BT_RSQB: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "= end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_LT: + return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_AMP: + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_CR: + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + case BT_RSQB: + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + return XML_TOK_TRAILING_RSQB; + if (! CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + return XML_TOK_TRAILING_RSQB; + if (! CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { +# define LEAD_CASE(n) \ + case BT_LEAD##n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_RSQB: + if (HAS_CHARS(enc, ptr, end, 2)) { + if (! CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) { + ptr += MINBPC(enc); + break; + } + if (HAS_CHARS(enc, ptr, end, 3)) { + if (! CHAR_MATCHES(enc, ptr + 2 * MINBPC(enc), ASCII_GT)) { + ptr += MINBPC(enc); + break; + } + *nextTokPtr = ptr + 2 * MINBPC(enc); + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_AMP: + case BT_LT: + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "%" */ + +static int PTRCALL +PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + REQUIRE_CHAR(enc, ptr, end); + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: + case BT_LF: + case BT_CR: + case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_PERCENT; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_PARAM_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + REQUIRE_CHAR(enc, ptr, end); + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_CR: + case BT_LF: + case BT_S: + case BT_RPAR: + case BT_GT: + case BT_PERCNT: + case BT_VERBAR: + *nextTokPtr = ptr; + return XML_TOK_POUND_NAME; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -XML_TOK_POUND_NAME; +} + +static int PTRCALL +PREFIX(scanLit)(int open, const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + while (HAS_CHAR(enc, ptr, end)) { + int t = BYTE_TYPE(enc, ptr); + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUOT: + case BT_APOS: + ptr += MINBPC(enc); + if (t != open) + break; + if (! HAS_CHAR(enc, ptr, end)) + return -XML_TOK_LITERAL; + *nextTokPtr = ptr; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: + case BT_CR: + case BT_LF: + case BT_GT: + case BT_PERCNT: + case BT_LSQB: + return XML_TOK_LITERAL; + default: + return XML_TOK_INVALID; + } + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + int tok; + if (ptr >= end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_QUOT: + return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_APOS: + return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LT: { + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + switch (BYTE_TYPE(enc, ptr)) { + case BT_EXCL: + return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_NMSTRT: + case BT_HEX: + case BT_NONASCII: + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + *nextTokPtr = ptr - MINBPC(enc); + return XML_TOK_INSTANCE_START; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + case BT_CR: + if (ptr + MINBPC(enc) == end) { + *nextTokPtr = end; + /* indicate that this might be part of a CR/LF pair */ + return -XML_TOK_PROLOG_S; + } + /* fall through */ + case BT_S: + case BT_LF: + for (;;) { + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + break; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: + case BT_LF: + break; + case BT_CR: + /* don't split CR/LF pair */ + if (ptr + MINBPC(enc) != end) + break; + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + } + } + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + case BT_PERCNT: + return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_COMMA: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMA; + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_BRACKET; + case BT_RSQB: + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + return -XML_TOK_CLOSE_BRACKET; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + REQUIRE_CHARS(enc, ptr, end, 2); + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { + *nextTokPtr = ptr + 2 * MINBPC(enc); + return XML_TOK_COND_SECT_CLOSE; + } + } + *nextTokPtr = ptr; + return XML_TOK_CLOSE_BRACKET; + case BT_LPAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_PAREN; + case BT_RPAR: + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + return -XML_TOK_CLOSE_PAREN; + switch (BYTE_TYPE(enc, ptr)) { + case BT_AST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_ASTERISK; + case BT_QUEST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_QUESTION; + case BT_PLUS: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_PLUS; + case BT_CR: + case BT_LF: + case BT_S: + case BT_GT: + case BT_COMMA: + case BT_VERBAR: + case BT_RPAR: + *nextTokPtr = ptr; + return XML_TOK_CLOSE_PAREN; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_VERBAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OR; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DECL_CLOSE; + case BT_NUM: + return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); +# define LEAD_CASE(n) \ + case BT_LEAD##n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NAME; \ + break; \ + } \ + if (IS_NAME_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NMTOKEN; \ + break; \ + } \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_NMSTRT: + case BT_HEX: + tok = XML_TOK_NAME; + ptr += MINBPC(enc); + break; + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: +# ifdef XML_NS + case BT_COLON: +# endif + tok = XML_TOK_NMTOKEN; + ptr += MINBPC(enc); + break; + case BT_NONASCII: + if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NAME; + break; + } + if (IS_NAME_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NMTOKEN; + break; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: + case BT_RPAR: + case BT_COMMA: + case BT_VERBAR: + case BT_LSQB: + case BT_PERCNT: + case BT_S: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return tok; +# ifdef XML_NS + case BT_COLON: + ptr += MINBPC(enc); + switch (tok) { + case XML_TOK_NAME: + REQUIRE_CHAR(enc, ptr, end); + tok = XML_TOK_PREFIXED_NAME; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + default: + tok = XML_TOK_NMTOKEN; + break; + } + break; + case XML_TOK_PREFIXED_NAME: + tok = XML_TOK_NMTOKEN; + break; + } + break; +# endif + case BT_PLUS: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_PLUS; + case BT_AST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_ASTERISK; + case BT_QUEST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_QUESTION; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -tok; +} + +static int PTRCALL +PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + const char *start; + if (ptr >= end) + return XML_TOK_NONE; + else if (! HAS_CHAR(enc, ptr, end)) { + /* This line cannot be executed. The incoming data has already + * been tokenized once, so incomplete characters like this have + * already been eliminated from the input. Retaining the paranoia + * check is still valuable, however. + */ + return XML_TOK_PARTIAL; /* LCOV_EXCL_LINE */ + } + start = ptr; + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { +# define LEAD_CASE(n) \ + case BT_LEAD##n: \ + ptr += n; /* NOTE: The encoding has already been validated. */ \ + break; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LT: + /* this is for inside entity references */ + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_S: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ATTRIBUTE_VALUE_S; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static int PTRCALL +PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + const char *start; + if (ptr >= end) + return XML_TOK_NONE; + else if (! HAS_CHAR(enc, ptr, end)) { + /* This line cannot be executed. The incoming data has already + * been tokenized once, so incomplete characters like this have + * already been eliminated from the input. Retaining the paranoia + * check is still valuable, however. + */ + return XML_TOK_PARTIAL; /* LCOV_EXCL_LINE */ + } + start = ptr; + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { +# define LEAD_CASE(n) \ + case BT_LEAD##n: \ + ptr += n; /* NOTE: The encoding has already been validated. */ \ + break; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_PERCNT: + if (ptr == start) { + int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (! HAS_CHAR(enc, ptr, end)) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +# ifdef XML_DTD + +static int PTRCALL +PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + int level = 0; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + end = ptr + n; + } + } + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_LT: + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { + ++level; + ptr += MINBPC(enc); + } + } + break; + case BT_RSQB: + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + ptr += MINBPC(enc); + REQUIRE_CHAR(enc, ptr, end); + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr += MINBPC(enc); + if (level == 0) { + *nextTokPtr = ptr; + return XML_TOK_IGNORE_SECT; + } + --level; + } + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +# endif /* XML_DTD */ + +static int PTRCALL +PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr) { + ptr += MINBPC(enc); + end -= MINBPC(enc); + for (; HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + case BT_MINUS: + case BT_APOS: + case BT_LPAR: + case BT_RPAR: + case BT_PLUS: + case BT_COMMA: + case BT_SOL: + case BT_EQUALS: + case BT_QUEST: + case BT_CR: + case BT_LF: + case BT_SEMI: + case BT_EXCL: + case BT_AST: + case BT_PERCNT: + case BT_NUM: +# ifdef XML_NS + case BT_COLON: +# endif + break; + case BT_S: + if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { + *badPtr = ptr; + return 0; + } + break; + case BT_NAME: + case BT_NMSTRT: + if (! (BYTE_TO_ASCII(enc, ptr) & ~0x7f)) + break; + /* fall through */ + default: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 0x24: /* $ */ + case 0x40: /* @ */ + break; + default: + *badPtr = ptr; + return 0; + } + break; + } + } + return 1; +} + +/* This must only be called for a well-formed start-tag or empty + element tag. Returns the number of attributes. Pointers to the + first attsMax attributes are stored in atts. +*/ + +static int PTRCALL +PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax, + ATTRIBUTE *atts) { + enum { other, inName, inValue } state = inName; + int nAtts = 0; + int open = 0; /* defined when state == inValue; + initialization just to shut up compilers */ + + for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { +# define START_NAME \ + if (state == other) { \ + if (nAtts < attsMax) { \ + atts[nAtts].name = ptr; \ + atts[nAtts].normalized = 1; \ + } \ + state = inName; \ + } +# define LEAD_CASE(n) \ + case BT_LEAD##n: /* NOTE: The encoding has already been validated. */ \ + START_NAME ptr += (n - MINBPC(enc)); \ + break; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + START_NAME + break; +# undef START_NAME + case BT_QUOT: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_QUOT; + } else if (open == BT_QUOT) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_APOS: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_APOS; + } else if (open == BT_APOS) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_AMP: + if (nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_S: + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax && atts[nAtts].normalized + && (ptr == atts[nAtts].valuePtr + || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE + || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE + || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) + atts[nAtts].normalized = 0; + break; + case BT_CR: + case BT_LF: + /* This case ensures that the first attribute name is counted + Apart from that we could just change state on the quote. */ + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_GT: + case BT_SOL: + if (state != inValue) + return nAtts; + break; + default: + break; + } + } + /* not reached */ +} + +static int PTRFASTCALL +PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) { + int result = 0; + /* skip &# */ + UNUSED_P(enc); + ptr += 2 * MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_x)) { + for (ptr += MINBPC(enc); ! CHAR_MATCHES(enc, ptr, ASCII_SEMI); + ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + switch (c) { + case ASCII_0: + case ASCII_1: + case ASCII_2: + case ASCII_3: + case ASCII_4: + case ASCII_5: + case ASCII_6: + case ASCII_7: + case ASCII_8: + case ASCII_9: + result <<= 4; + result |= (c - ASCII_0); + break; + case ASCII_A: + case ASCII_B: + case ASCII_C: + case ASCII_D: + case ASCII_E: + case ASCII_F: + result <<= 4; + result += 10 + (c - ASCII_A); + break; + case ASCII_a: + case ASCII_b: + case ASCII_c: + case ASCII_d: + case ASCII_e: + case ASCII_f: + result <<= 4; + result += 10 + (c - ASCII_a); + break; + } + if (result >= 0x110000) + return -1; + } + } else { + for (; ! CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + result *= 10; + result += (c - ASCII_0); + if (result >= 0x110000) + return -1; + } + } + return checkCharRefNumber(result); +} + +static int PTRCALL +PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, + const char *end) { + UNUSED_P(enc); + switch ((end - ptr) / MINBPC(enc)) { + case 2: + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + return ASCII_LT; + case ASCII_g: + return ASCII_GT; + } + } + break; + case 3: + if (CHAR_MATCHES(enc, ptr, ASCII_a)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_m)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) + return ASCII_AMP; + } + } + break; + case 4: + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_q: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_u)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_t)) + return ASCII_QUOT; + } + } + break; + case ASCII_a: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_s)) + return ASCII_APOS; + } + } + break; + } + } + return 0; +} + +static int PTRCALL +PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, + const char *end1, const char *ptr2) { + UNUSED_P(enc); + for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { + if (end1 - ptr1 < MINBPC(enc)) { + /* This line cannot be executed. The incoming data has already + * been tokenized once, so incomplete characters like this have + * already been eliminated from the input. Retaining the + * paranoia check is still valuable, however. + */ + return 0; /* LCOV_EXCL_LINE */ + } + if (! CHAR_MATCHES(enc, ptr1, *ptr2)) + return 0; + } + return ptr1 == end1; +} + +static int PTRFASTCALL +PREFIX(nameLength)(const ENCODING *enc, const char *ptr) { + const char *start = ptr; + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { +# define LEAD_CASE(n) \ + case BT_LEAD##n: \ + ptr += n; /* NOTE: The encoding has already been validated. */ \ + break; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: +# ifdef XML_NS + case BT_COLON: +# endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + ptr += MINBPC(enc); + break; + default: + return (int)(ptr - start); + } + } +} + +static const char *PTRFASTCALL +PREFIX(skipS)(const ENCODING *enc, const char *ptr) { + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_LF: + case BT_CR: + case BT_S: + ptr += MINBPC(enc); + break; + default: + return ptr; + } + } +} + +static void PTRCALL +PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end, + POSITION *pos) { + while (HAS_CHAR(enc, ptr, end)) { + switch (BYTE_TYPE(enc, ptr)) { +# define LEAD_CASE(n) \ + case BT_LEAD##n: \ + ptr += n; /* NOTE: The encoding has already been validated. */ \ + pos->columnNumber++; \ + break; + LEAD_CASE(2) + LEAD_CASE(3) + LEAD_CASE(4) +# undef LEAD_CASE + case BT_LF: + pos->columnNumber = 0; + pos->lineNumber++; + ptr += MINBPC(enc); + break; + case BT_CR: + pos->lineNumber++; + ptr += MINBPC(enc); + if (HAS_CHAR(enc, ptr, end) && BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + pos->columnNumber = 0; + break; + default: + ptr += MINBPC(enc); + pos->columnNumber++; + break; + } + } +} + +# undef DO_LEAD_CASE +# undef MULTIBYTE_CASES +# undef INVALID_CASES +# undef CHECK_NAME_CASE +# undef CHECK_NAME_CASES +# undef CHECK_NMSTRT_CASE +# undef CHECK_NMSTRT_CASES + +#endif /* XML_TOK_IMPL_C */ diff --git a/src/3rdparty/expat/src/xmltok_impl.h b/src/3rdparty/expat/src/xmltok_impl.h new file mode 100644 index 00000000..3469c4ae --- /dev/null +++ b/src/3rdparty/expat/src/xmltok_impl.h @@ -0,0 +1,74 @@ +/* + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2017-2019 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +enum { + BT_NONXML, /* e.g. noncharacter-FFFF */ + BT_MALFORM, /* illegal, with regard to encoding */ + BT_LT, /* less than = "<" */ + BT_AMP, /* ampersand = "&" */ + BT_RSQB, /* right square bracket = "[" */ + BT_LEAD2, /* lead byte of a 2-byte UTF-8 character */ + BT_LEAD3, /* lead byte of a 3-byte UTF-8 character */ + BT_LEAD4, /* lead byte of a 4-byte UTF-8 character */ + BT_TRAIL, /* trailing unit, e.g. second 16-bit unit of a 4-byte char. */ + BT_CR, /* carriage return = "\r" */ + BT_LF, /* line feed = "\n" */ + BT_GT, /* greater than = ">" */ + BT_QUOT, /* quotation character = "\"" */ + BT_APOS, /* apostrophe = "'" */ + BT_EQUALS, /* equal sign = "=" */ + BT_QUEST, /* question mark = "?" */ + BT_EXCL, /* exclamation mark = "!" */ + BT_SOL, /* solidus, slash = "/" */ + BT_SEMI, /* semicolon = ";" */ + BT_NUM, /* number sign = "#" */ + BT_LSQB, /* left square bracket = "[" */ + BT_S, /* white space, e.g. "\t", " "[, "\r"] */ + BT_NMSTRT, /* non-hex name start letter = "G".."Z" + "g".."z" + "_" */ + BT_COLON, /* colon = ":" */ + BT_HEX, /* hex letter = "A".."F" + "a".."f" */ + BT_DIGIT, /* digit = "0".."9" */ + BT_NAME, /* dot and middle dot = "." + chr(0xb7) */ + BT_MINUS, /* minus = "-" */ + BT_OTHER, /* known not to be a name or name start character */ + BT_NONASCII, /* might be a name or name start character */ + BT_PERCNT, /* percent sign = "%" */ + BT_LPAR, /* left parenthesis = "(" */ + BT_RPAR, /* right parenthesis = "(" */ + BT_AST, /* asterisk = "*" */ + BT_PLUS, /* plus sign = "+" */ + BT_COMMA, /* comma = "," */ + BT_VERBAR /* vertical bar = "|" */ +}; + +#include diff --git a/src/3rdparty/expat/src/xmltok_ns.c b/src/3rdparty/expat/src/xmltok_ns.c new file mode 100644 index 00000000..fbdd3e3c --- /dev/null +++ b/src/3rdparty/expat/src/xmltok_ns.c @@ -0,0 +1,122 @@ +/* This file is included! + __ __ _ + ___\ \/ /_ __ __ _| |_ + / _ \\ /| '_ \ / _` | __| + | __// \| |_) | (_| | |_ + \___/_/\_\ .__/ \__,_|\__| + |_| XML parser + + Copyright (c) 1997-2000 Thai Open Source Software Center Ltd + Copyright (c) 2000 Clark Cooper + Copyright (c) 2002 Greg Stein + Copyright (c) 2002 Fred L. Drake, Jr. + Copyright (c) 2002-2006 Karl Waclawek + Copyright (c) 2017-2021 Sebastian Pipping + Licensed under the MIT license: + + 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. +*/ + +#ifdef XML_TOK_NS_C + +const ENCODING * +NS(XmlGetUtf8InternalEncoding)(void) { + return &ns(internal_utf8_encoding).enc; +} + +const ENCODING * +NS(XmlGetUtf16InternalEncoding)(void) { +# if BYTEORDER == 1234 + return &ns(internal_little2_encoding).enc; +# elif BYTEORDER == 4321 + return &ns(internal_big2_encoding).enc; +# else + const short n = 1; + return (*(const char *)&n ? &ns(internal_little2_encoding).enc + : &ns(internal_big2_encoding).enc); +# endif +} + +static const ENCODING *const NS(encodings)[] = { + &ns(latin1_encoding).enc, &ns(ascii_encoding).enc, + &ns(utf8_encoding).enc, &ns(big2_encoding).enc, + &ns(big2_encoding).enc, &ns(little2_encoding).enc, + &ns(utf8_encoding).enc /* NO_ENC */ +}; + +static int PTRCALL +NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, + ptr, end, nextTokPtr); +} + +static int PTRCALL +NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) { + return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, + ptr, end, nextTokPtr); +} + +int +NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, + const char *name) { + int i = getEncodingIndex(name); + if (i == UNKNOWN_ENC) + return 0; + SET_INIT_ENC_INDEX(p, i); + p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); + p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); + p->initEnc.updatePosition = initUpdatePosition; + p->encPtr = encPtr; + *encPtr = &(p->initEnc); + return 1; +} + +static const ENCODING * +NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) { +# define ENCODING_MAX 128 + char buf[ENCODING_MAX] = ""; + char *p = buf; + int i; + XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); + if (ptr != end) + return 0; + *p = 0; + if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) + return enc; + i = getEncodingIndex(buf); + if (i == UNKNOWN_ENC) + return 0; + return NS(encodings)[i]; +} + +int +NS(XmlParseXmlDecl)(int isGeneralTextEntity, const ENCODING *enc, + const char *ptr, const char *end, const char **badPtr, + const char **versionPtr, const char **versionEndPtr, + const char **encodingName, const ENCODING **encoding, + int *standalone) { + return doParseXmlDecl(NS(findEncoding), isGeneralTextEntity, enc, ptr, end, + badPtr, versionPtr, versionEndPtr, encodingName, + encoding, standalone); +} + +#endif /* XML_TOK_NS_C */ diff --git a/src/3rdparty/libcurl/include/curl/curl.h b/src/3rdparty/libcurl/include/curl/curl.h index ea6fcb67..bf71d82f 100644 --- a/src/3rdparty/libcurl/include/curl/curl.h +++ b/src/3rdparty/libcurl/include/curl/curl.h @@ -159,9 +159,9 @@ typedef enum { CURLSSLBACKEND_NONE = 0, CURLSSLBACKEND_OPENSSL = 1, CURLSSLBACKEND_GNUTLS = 2, - CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_NSS CURL_DEPRECATED(8.3.0, "") = 3, CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ - CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_GSKIT CURL_DEPRECATED(8.3.0, "") = 5, CURLSSLBACKEND_POLARSSL CURL_DEPRECATED(7.69.0, "") = 6, CURLSSLBACKEND_WOLFSSL = 7, CURLSSLBACKEND_SCHANNEL = 8, @@ -646,10 +646,10 @@ typedef enum { #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ -/* Previously obsolete error code re-used in 7.38.0 */ +/* Previously obsolete error code reused in 7.38.0 */ #define CURLE_OBSOLETE16 CURLE_HTTP2 -/* Previously obsolete error codes re-used in 7.24.0 */ +/* Previously obsolete error codes reused in 7.24.0 */ #define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED #define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT @@ -1358,7 +1358,7 @@ typedef enum { operation slower and is less friendly for the network. */ CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74), - /* Set to explicitly forbid the upcoming transfer's connection to be re-used + /* Set to explicitly forbid the upcoming transfer's connection to be reused when done. Do not use this unless you're absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75), @@ -1652,7 +1652,7 @@ typedef enum { CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148), CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_CBPOINT, 149), - /* set to 0 to disable session ID re-use for this transfer, default is + /* set to 0 to disable session ID reuse for this transfer, default is enabled (== 1) */ CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150), @@ -2731,6 +2731,20 @@ CURL_EXTERN CURLcode curl_global_init_mem(long flags, */ CURL_EXTERN void curl_global_cleanup(void); +/* + * NAME curl_global_trace() + * + * DESCRIPTION + * + * curl_global_trace() can be invoked at application start to + * configure which components in curl should participate in tracing. + + * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the + * curl_version_info_data.features flag (fetch by curl_version_info()). + + */ +CURL_EXTERN CURLcode curl_global_trace(const char *config); + /* linked-list structure for the CURLOPT_QUOTE option (and other) */ struct curl_slist { char *data; @@ -2810,13 +2824,14 @@ CURL_EXTERN void curl_slist_free_all(struct curl_slist *list); */ CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); -/* info about the certificate chain, only for OpenSSL, GnuTLS, Schannel, NSS - and GSKit builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +/* info about the certificate chain, for SSL backends that support it. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ struct curl_certinfo { int num_of_certs; /* number of certificates with information */ struct curl_slist **certinfo; /* for each index in this array, there's a - linked list with textual information in the - format "name: value" */ + linked list with textual information for a + certificate in the format "name:content". + eg "Subject:foo", "Issuer:bar", etc. */ }; /* Information about the SSL library used and the respective internal SSL diff --git a/src/3rdparty/libcurl/include/curl/curlver.h b/src/3rdparty/libcurl/include/curl/curlver.h index f0db63c1..44e6070d 100644 --- a/src/3rdparty/libcurl/include/curl/curlver.h +++ b/src/3rdparty/libcurl/include/curl/curlver.h @@ -32,13 +32,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "8.2.1" +#define LIBCURL_VERSION "8.4.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 -#define LIBCURL_VERSION_MINOR 2 -#define LIBCURL_VERSION_PATCH 1 +#define LIBCURL_VERSION_MINOR 4 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will @@ -59,7 +59,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x080201 +#define LIBCURL_VERSION_NUM 0x080400 /* * This is the date and time when the full source package was created. The @@ -70,7 +70,7 @@ * * "2007-11-23" */ -#define LIBCURL_TIMESTAMP "2023-07-26" +#define LIBCURL_TIMESTAMP "2023-10-11" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) #define CURL_AT_LEAST_VERSION(x,y,z) \ diff --git a/src/3rdparty/libcurl/include/curl/mprintf.h b/src/3rdparty/libcurl/include/curl/mprintf.h index e652a652..dc5664bc 100644 --- a/src/3rdparty/libcurl/include/curl/mprintf.h +++ b/src/3rdparty/libcurl/include/curl/mprintf.h @@ -32,18 +32,36 @@ extern "C" { #endif -CURL_EXTERN int curl_mprintf(const char *format, ...); -CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); -CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +#if (defined(__GNUC__) || defined(__clang__)) && \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__MINGW32__) && !defined(CURL_NO_FMT_CHECKS) +#define CURL_TEMP_PRINTF(a,b) __attribute__ ((format(printf, a, b))) +#else +#define CURL_TEMP_PRINTF(a,b) +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...) CURL_TEMP_PRINTF(1, 2); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...) + CURL_TEMP_PRINTF(2, 3); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...) + CURL_TEMP_PRINTF(2, 3); CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, - const char *format, ...); -CURL_EXTERN int curl_mvprintf(const char *format, va_list args); -CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); -CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); + const char *format, ...) CURL_TEMP_PRINTF(3, 4); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args) + CURL_TEMP_PRINTF(1, 0); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args) + CURL_TEMP_PRINTF(2, 0); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args) + CURL_TEMP_PRINTF(2, 0); CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, - const char *format, va_list args); -CURL_EXTERN char *curl_maprintf(const char *format, ...); -CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + const char *format, va_list args) + CURL_TEMP_PRINTF(3, 0); +CURL_EXTERN char *curl_maprintf(const char *format, ...) + CURL_TEMP_PRINTF(1, 2); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args) + CURL_TEMP_PRINTF(1, 0); + +#undef CURL_TEMP_PRINTF #ifdef __cplusplus } /* end of extern "C" */ diff --git a/src/3rdparty/libcurl/include/curl/multi.h b/src/3rdparty/libcurl/include/curl/multi.h index 30a3d930..e79b48ff 100644 --- a/src/3rdparty/libcurl/include/curl/multi.h +++ b/src/3rdparty/libcurl/include/curl/multi.h @@ -118,7 +118,7 @@ typedef struct CURLMsg CURLMsg; struct curl_waitfd { curl_socket_t fd; short events; - short revents; /* not supported yet */ + short revents; }; /* @@ -426,6 +426,17 @@ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, void *sockp); +/* + * Name: curl_multi_get_handles() + * + * Desc: Returns an allocated array holding all handles currently added to + * the multi handle. Marks the final entry with a NULL pointer. If + * there is no easy handle added to the multi handle, this function + * returns an array with the first entry as a NULL pointer. + * + * Returns: NULL on failure, otherwise a CURL **array pointer + */ +CURL_EXTERN CURL **curl_multi_get_handles(CURLM *multi_handle); /* * Name: curl_push_callback diff --git a/src/3rdparty/libcurl/include/curl/system.h b/src/3rdparty/libcurl/include/curl/system.h index b2640c8b..97e0d037 100644 --- a/src/3rdparty/libcurl/include/curl/system.h +++ b/src/3rdparty/libcurl/include/curl/system.h @@ -347,6 +347,24 @@ # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 +#elif defined(__hpux) /* HP aCC compiler */ +# if !defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + /* ===================================== */ /* KEEP MSVC THE PENULTIMATE ENTRY */ /* ===================================== */ diff --git a/src/3rdparty/libcurl/include/curl/urlapi.h b/src/3rdparty/libcurl/include/curl/urlapi.h index b3504b68..88cdeb3b 100644 --- a/src/3rdparty/libcurl/include/curl/urlapi.h +++ b/src/3rdparty/libcurl/include/curl/urlapi.h @@ -96,7 +96,8 @@ typedef enum { #define CURLU_NO_AUTHORITY (1<<10) /* Allow empty authority when the scheme is unknown. */ #define CURLU_ALLOW_SPACE (1<<11) /* Allow spaces in the URL */ -#define CURLU_PUNYCODE (1<<12) /* get the host name in pynycode */ +#define CURLU_PUNYCODE (1<<12) /* get the host name in punycode */ +#define CURLU_PUNY2IDN (1<<13) /* punycode => IDN conversion */ typedef struct Curl_URL CURLU; diff --git a/src/3rdparty/libopenssl/include/openssl/opensslv.h b/src/3rdparty/libopenssl/include/openssl/opensslv.h index 0dc99ecc..5667d471 100644 --- a/src/3rdparty/libopenssl/include/openssl/opensslv.h +++ b/src/3rdparty/libopenssl/include/openssl/opensslv.h @@ -39,8 +39,8 @@ extern "C" { * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for * major minor fix final patch/beta) */ -# define OPENSSL_VERSION_NUMBER 0x1010116fL -# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1v 1 Aug 2023" +# define OPENSSL_VERSION_NUMBER 0x1010117fL +# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1w 11 Sep 2023" /*- * The macros below are to be used for shared library (.so, .dll, ...) diff --git a/src/3rdparty/luajit/dynasm/dasm_arm64.lua b/src/3rdparty/luajit/dynasm/dasm_arm64.lua index e69f8ef3..05ea3e22 100644 --- a/src/3rdparty/luajit/dynasm/dasm_arm64.lua +++ b/src/3rdparty/luajit/dynasm/dasm_arm64.lua @@ -549,7 +549,7 @@ end local function parse_load_pair(params, nparams, n, op) if params[n+2] then werror("too many operands") end local pn, p2 = params[n], params[n+1] - local scale = shr(op, 30) == 0 and 2 or 3 + local scale = 2 + shr(op, 31 - band(shr(op, 26), 1)) local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") if not p1 then if not p2 then @@ -806,8 +806,8 @@ map_op = { ["ldrsw_*"] = "98000000DxB|b8800000DxL", -- NOTE: ldur etc. are handled by ldr et al. - ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP", - ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP", + ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP|ac000000DAqP", + ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP|ac400000DAqP", ["ldpsw_*"] = "68400000DAxP", -- Branches. @@ -942,7 +942,7 @@ local function parse_template(params, template, nparams, pos) werror("bad register type") end parse_reg_type = false - elseif p == "x" or p == "w" or p == "d" or p == "s" then + elseif p == "x" or p == "w" or p == "d" or p == "s" or p == "q" then if parse_reg_type ~= p then werror("register size mismatch") end diff --git a/src/3rdparty/luajit/src/Makefile b/src/3rdparty/luajit/src/Makefile index 8c47a16b..224d21e7 100644 --- a/src/3rdparty/luajit/src/Makefile +++ b/src/3rdparty/luajit/src/Makefile @@ -233,7 +233,7 @@ TARGET_ALDFLAGS= $(LDOPTIONS) $(TARGET_XLDFLAGS) $(TARGET_FLAGS) $(TARGET_LDFLAG TARGET_ASHLDFLAGS= $(LDOPTIONS) $(TARGET_XSHLDFLAGS) $(TARGET_FLAGS) $(TARGET_SHLDFLAGS) TARGET_ALIBS= $(TARGET_XLIBS) $(LIBS) $(TARGET_LIBS) -TARGET_TESTARCH=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E lj_arch.h -dM) +TARGET_TESTARCH:=$(shell $(TARGET_CC) $(TARGET_TCFLAGS) -E lj_arch.h -dM) ifneq (,$(findstring LJ_TARGET_X64 ,$(TARGET_TESTARCH))) TARGET_LJARCH= x64 else @@ -475,7 +475,11 @@ DASM_FLAGS= $(DASM_XFLAGS) $(DASM_AFLAGS) DASM_DASC= vm_$(DASM_ARCH).dasc GIT= git -GIT_RELVER= [ -e ../.git ] && $(GIT) show -s --format=%ct >luajit_relver.txt 2>/dev/null || cat ../.relver >luajit_relver.txt 2>/dev/null || : +ifeq (Windows,$(HOST_SYS)$(HOST_MSYS)) + GIT_RELVER= if exist ..\.git ( $(GIT) show -s --format=%%ct >luajit_relver.txt ) else ( type ..\.relver >luajit_relver.txt ) +else + GIT_RELVER= [ -e ../.git ] && $(GIT) show -s --format=%ct >luajit_relver.txt 2>/dev/null || cat ../.relver >luajit_relver.txt 2>/dev/null || : +endif GIT_DEP= $(wildcard ../.git/HEAD ../.git/refs/heads/*) BUILDVM_O= host/buildvm.o host/buildvm_asm.o host/buildvm_peobj.o \ diff --git a/src/3rdparty/luajit/src/host/buildvm_peobj.c b/src/3rdparty/luajit/src/host/buildvm_peobj.c index 5bca6df8..8f04c496 100644 --- a/src/3rdparty/luajit/src/host/buildvm_peobj.c +++ b/src/3rdparty/luajit/src/host/buildvm_peobj.c @@ -9,7 +9,7 @@ #include "buildvm.h" #include "lj_bc.h" -#if LJ_TARGET_X86ORX64 +#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN /* Context for PE object emitter. */ static char *strtab; @@ -93,6 +93,17 @@ typedef struct PEsymaux { #define PEOBJ_RELOC_ADDR32NB 0x03 #define PEOBJ_RELOC_OFS 0 #define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */ +#define PEOBJ_PDATA_NRELOC 6 +#define PEOBJ_XDATA_SIZE (8*2+4+6*2) +#elif LJ_TARGET_ARM64 +#define PEOBJ_ARCH_TARGET 0xaa64 +#define PEOBJ_RELOC_REL32 0x03 /* MS: BRANCH26. */ +#define PEOBJ_RELOC_DIR32 0x01 +#define PEOBJ_RELOC_ADDR32NB 0x02 +#define PEOBJ_RELOC_OFS (-4) +#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */ +#define PEOBJ_PDATA_NRELOC 4 +#define PEOBJ_XDATA_SIZE (4+24+4 +4+8) #endif /* Section numbers (0-based). */ @@ -100,7 +111,7 @@ enum { PEOBJ_SECT_ABS = -2, PEOBJ_SECT_UNDEF = -1, PEOBJ_SECT_TEXT, -#if LJ_TARGET_X64 +#ifdef PEOBJ_PDATA_NRELOC PEOBJ_SECT_PDATA, PEOBJ_SECT_XDATA, #elif LJ_TARGET_X86 @@ -175,6 +186,9 @@ void emit_peobj(BuildCtx *ctx) uint32_t sofs; int i, nrsym; union { uint8_t b; uint32_t u; } host_endian; +#ifdef PEOBJ_PDATA_NRELOC + uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs; +#endif sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection); @@ -188,18 +202,18 @@ void emit_peobj(BuildCtx *ctx) /* Flags: 60 = read+execute, 50 = align16, 20 = code. */ pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS; -#if LJ_TARGET_X64 +#ifdef PEOBJ_PDATA_NRELOC memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1); pesect[PEOBJ_SECT_PDATA].ofs = sofs; - sofs += (pesect[PEOBJ_SECT_PDATA].size = 6*4); + sofs += (pesect[PEOBJ_SECT_PDATA].size = PEOBJ_PDATA_NRELOC*4); pesect[PEOBJ_SECT_PDATA].relocofs = sofs; - sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = 6) * PEOBJ_RELOC_SIZE; + sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = PEOBJ_PDATA_NRELOC) * PEOBJ_RELOC_SIZE; /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ pesect[PEOBJ_SECT_PDATA].flags = 0x40300040; memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1); pesect[PEOBJ_SECT_XDATA].ofs = sofs; - sofs += (pesect[PEOBJ_SECT_XDATA].size = 8*2+4+6*2); /* See below. */ + sofs += (pesect[PEOBJ_SECT_XDATA].size = PEOBJ_XDATA_SIZE); /* See below. */ pesect[PEOBJ_SECT_XDATA].relocofs = sofs; sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE; /* Flags: 40 = read, 30 = align4, 40 = initialized data. */ @@ -234,7 +248,7 @@ void emit_peobj(BuildCtx *ctx) */ nrsym = ctx->nrelocsym; pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym; -#if LJ_TARGET_X64 +#ifdef PEOBJ_PDATA_NRELOC pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */ #endif @@ -259,7 +273,6 @@ void emit_peobj(BuildCtx *ctx) #if LJ_TARGET_X64 { /* Write .pdata section. */ - uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs; uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */ PEreloc reloc; pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0; @@ -308,6 +321,87 @@ void emit_peobj(BuildCtx *ctx) reloc.type = PEOBJ_RELOC_ADDR32NB; owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); } +#elif LJ_TARGET_ARM64 + /* https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling */ + { /* Write .pdata section. */ + uint32_t pdata[4]; + PEreloc reloc; + pdata[0] = 0; + pdata[1] = 0; + pdata[2] = fcofs; + pdata[3] = 4+24+4; + owrite(ctx, &pdata, sizeof(pdata)); + /* Start of .text and start of .xdata. */ + reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1; + reloc.type = PEOBJ_RELOC_ADDR32NB; + owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); + reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2; + reloc.type = PEOBJ_RELOC_ADDR32NB; + owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); + /* Start of vm_ffi_call and start of second part of .xdata. */ + reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2+2+1; + reloc.type = PEOBJ_RELOC_ADDR32NB; + owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); + reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2; + reloc.type = PEOBJ_RELOC_ADDR32NB; + owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); + } + { /* Write .xdata section. */ + uint32_t u32; + uint8_t *p, uwc[24]; + PEreloc reloc; + +#define CBE16(x) (*p = ((x) >> 8) & 0xff, p[1] = (x) & 0xff, p += 2) +#define CALLOC_S(s) (*p++ = ((s) >> 4)) /* s < 512 */ +#define CSAVE_FPLR(o) (*p++ = 0x40 | ((o) >> 3)) /* o <= 504 */ +#define CSAVE_REGP(r,o) CBE16(0xc800 | (((r) - 19) << 6) | ((o) >> 3)) +#define CSAVE_REGS(r1,r2,o1) do { \ + int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_REGP(r, o); \ +} while (0) +#define CSAVE_REGPX(r,o) CBE16(0xcc00 | (((r) - 19) << 6) | (~(o) >> 3)) +#define CSAVE_FREGP(r,o) CBE16(0xd800 | (((r) - 8) << 6) | ((o) >> 3)) +#define CSAVE_FREGS(r1,r2,o1) do { \ + int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_FREGP(r, o); \ +} while (0) +#define CADD_FP(s) CBE16(0xe200 | ((s) >> 3)) /* s < 8*256 */ +#define CODE_NOP 0xe3 +#define CODE_END 0xe4 +#define CEND_ALIGN do { \ + *p++ = CODE_END; \ + while ((p - uwc) & 3) *p++ = CODE_NOP; \ +} while (0) + + /* Unwind codes for .text section with handler. */ + p = uwc; + CADD_FP(192); /* +2 */ + CSAVE_REGS(19, 28, 176); /* +5*2 */ + CSAVE_FREGS(8, 15, 96); /* +4*2 */ + CSAVE_FPLR(192); /* +1 */ + CALLOC_S(208); /* +1 */ + CEND_ALIGN; /* +1 +1 -> 24 */ + + u32 = ((24u >> 2) << 27) | (1u << 20) | (fcofs >> 2); + owrite(ctx, &u32, 4); + owrite(ctx, &uwc, 24); + + u32 = 0; /* Handler RVA to be relocated at 4 + 24. */ + owrite(ctx, &u32, 4); + + /* Unwind codes for vm_ffi_call without handler. */ + p = uwc; + CADD_FP(16); /* +2 */ + CSAVE_FPLR(16); /* +1 */ + CSAVE_REGPX(19, -32); /* +2 */ + CEND_ALIGN; /* +1 +2 -> 8 */ + + u32 = ((8u >> 2) << 27) | (((uint32_t)ctx->codesz - fcofs) >> 2); + owrite(ctx, &u32, 4); + owrite(ctx, &uwc, 8); + + reloc.vaddr = 4 + 24; reloc.symidx = 1+2+nrsym+2+2; + reloc.type = PEOBJ_RELOC_ADDR32NB; + owrite(ctx, &reloc, PEOBJ_RELOC_SIZE); + } #elif LJ_TARGET_X86 /* Write .sxdata section. */ for (i = 0; i < nrsym; i++) { @@ -339,7 +433,7 @@ void emit_peobj(BuildCtx *ctx) emit_peobj_sym(ctx, ctx->relocsym[i], 0, PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN); -#if LJ_TARGET_X64 +#ifdef PEOBJ_PDATA_NRELOC emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA); emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA); emit_peobj_sym(ctx, "lj_err_unwind_win", 0, diff --git a/src/3rdparty/luajit/src/host/genversion.lua b/src/3rdparty/luajit/src/host/genversion.lua index 42b5e6fe..28f7206c 100644 --- a/src/3rdparty/luajit/src/host/genversion.lua +++ b/src/3rdparty/luajit/src/host/genversion.lua @@ -5,9 +5,10 @@ -- Released under the MIT license. See Copyright Notice in luajit.h ---------------------------------------------------------------------------- -local FILE_ROLLING_H = "luajit_rolling.h" -local FILE_RELVER_TXT = "luajit_relver.txt" -local FILE_LUAJIT_H = "luajit.h" +local arg = {...} +local FILE_ROLLING_H = arg[1] or "luajit_rolling.h" +local FILE_RELVER_TXT = arg[2] or "luajit_relver.txt" +local FILE_LUAJIT_H = arg[3] or "luajit.h" local function file_read(file) local fp = assert(io.open(file, "rb"), "run from the wrong directory") diff --git a/src/3rdparty/luajit/src/jit/dis_arm64.lua b/src/3rdparty/luajit/src/jit/dis_arm64.lua index b10e2fb1..a7a29494 100644 --- a/src/3rdparty/luajit/src/jit/dis_arm64.lua +++ b/src/3rdparty/luajit/src/jit/dis_arm64.lua @@ -107,24 +107,20 @@ local map_logsr = { -- Logical, shifted register. [0] = { shift = 29, mask = 3, [0] = { - shift = 21, mask = 7, - [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", - "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" + shift = 21, mask = 1, + [0] = "andDNMSg", "bicDNMSg" }, { - shift = 21, mask = 7, - [0] ="orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", - "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" + shift = 21, mask = 1, + [0] = "orr|movDN0MSg", "orn|mvnDN0MSg" }, { - shift = 21, mask = 7, - [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", - "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" + shift = 21, mask = 1, + [0] = "eorDNMSg", "eonDNMSg" }, { - shift = 21, mask = 7, - [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", - "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" + shift = 21, mask = 1, + [0] = "ands|tstD0NMSg", "bicsDNMSg" } }, false -- unallocated @@ -132,24 +128,20 @@ local map_logsr = { -- Logical, shifted register. { shift = 29, mask = 3, [0] = { - shift = 21, mask = 7, - [0] = "andDNMSg", "bicDNMSg", "andDNMSg", "bicDNMSg", - "andDNMSg", "bicDNMSg", "andDNMg", "bicDNMg" + shift = 21, mask = 1, + [0] = "andDNMSg", "bicDNMSg" }, { - shift = 21, mask = 7, - [0] = "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0MSg", "orn|mvnDN0MSg", - "orr|movDN0MSg", "orn|mvnDN0MSg", "orr|movDN0Mg", "orn|mvnDN0Mg" + shift = 21, mask = 1, + [0] = "orr|movDN0MSg", "orn|mvnDN0MSg" }, { - shift = 21, mask = 7, - [0] = "eorDNMSg", "eonDNMSg", "eorDNMSg", "eonDNMSg", - "eorDNMSg", "eonDNMSg", "eorDNMg", "eonDNMg" + shift = 21, mask = 1, + [0] = "eorDNMSg", "eonDNMSg" }, { - shift = 21, mask = 7, - [0] = "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMSg", "bicsDNMSg", - "ands|tstD0NMSg", "bicsDNMSg", "ands|tstD0NMg", "bicsDNMg" + shift = 21, mask = 1, + [0] = "ands|tstD0NMSg", "bicsDNMSg" } } } @@ -735,7 +727,7 @@ local map_cond = { "hi", "ls", "ge", "lt", "gt", "le", "al", } -local map_shift = { [0] = "lsl", "lsr", "asr", } +local map_shift = { [0] = "lsl", "lsr", "asr", "ror"} local map_extend = { [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx", @@ -956,7 +948,7 @@ local function disass_ins(ctx) elseif p == "U" then local rn = map_regs.x[band(rshift(op, 5), 31)] local sz = band(rshift(op, 30), 3) - local imm12 = lshift(arshift(lshift(op, 10), 20), sz) + local imm12 = lshift(rshift(lshift(op, 10), 20), sz) if imm12 ~= 0 then x = "["..rn..", #"..imm12.."]" else diff --git a/src/3rdparty/luajit/src/lib_base.c b/src/3rdparty/luajit/src/lib_base.c index dd54b9f9..4e6f8a30 100644 --- a/src/3rdparty/luajit/src/lib_base.c +++ b/src/3rdparty/luajit/src/lib_base.c @@ -616,7 +616,10 @@ static int ffh_resume(lua_State *L, lua_State *co, int wrap) setstrV(L, L->base-LJ_FR2, lj_err_str(L, em)); return FFH_RES(2); } - lj_state_growstack(co, (MSize)(L->top - L->base)); + if (lj_state_cpgrowstack(co, (MSize)(L->top - L->base)) != LUA_OK) { + cTValue *msg = --co->top; + lj_err_callermsg(L, strVdata(msg)); + } return FFH_RETRY; } diff --git a/src/3rdparty/luajit/src/lib_ffi.c b/src/3rdparty/luajit/src/lib_ffi.c index 6dee2e74..ba783173 100644 --- a/src/3rdparty/luajit/src/lib_ffi.c +++ b/src/3rdparty/luajit/src/lib_ffi.c @@ -746,7 +746,7 @@ LJLIB_CF(ffi_abi) LJLIB_REC(.) "\003win" #endif #if LJ_ABI_PAUTH - "\007pauth" + "\005pauth" #endif #if LJ_TARGET_UWP "\003uwp" diff --git a/src/3rdparty/luajit/src/lj_api.c b/src/3rdparty/luajit/src/lj_api.c index 386bcada..d4048d79 100644 --- a/src/3rdparty/luajit/src/lj_api.c +++ b/src/3rdparty/luajit/src/lj_api.c @@ -104,7 +104,12 @@ LUA_API int lua_checkstack(lua_State *L, int size) if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) { return 0; /* Stack overflow. */ } else if (size > 0) { - lj_state_checkstack(L, (MSize)size); + int avail = (int)(mref(L->maxstack, TValue) - L->top); + if (size > avail && + lj_state_cpgrowstack(L, (MSize)(size - avail)) != LUA_OK) { + L->top--; + return 0; /* Out of memory. */ + } } return 1; } diff --git a/src/3rdparty/luajit/src/lj_arch.h b/src/3rdparty/luajit/src/lj_arch.h index 915fd769..a81ee1a7 100644 --- a/src/3rdparty/luajit/src/lj_arch.h +++ b/src/3rdparty/luajit/src/lj_arch.h @@ -57,7 +57,7 @@ #define LUAJIT_TARGET LUAJIT_ARCH_X64 #elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM) #define LUAJIT_TARGET LUAJIT_ARCH_ARM -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(_M_ARM64) #define LUAJIT_TARGET LUAJIT_ARCH_ARM64 #elif defined(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC) #define LUAJIT_TARGET LUAJIT_ARCH_PPC @@ -66,7 +66,7 @@ #elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS) #define LUAJIT_TARGET LUAJIT_ARCH_MIPS32 #else -#error "No support for this architecture (yet)" +#error "Architecture not supported (in this version), see: https://luajit.org/status.html#architectures" #endif #endif @@ -237,7 +237,7 @@ #define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */ #define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL -#if __ARM_ARCH == 8 || __ARM_ARCH_8__ || __ARM_ARCH_8A__ +#if __ARM_ARCH >= 8 || __ARM_ARCH_8__ || __ARM_ARCH_8A__ #define LJ_ARCH_VERSION 80 #elif __ARM_ARCH == 7 || __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH_7S__ || __ARM_ARCH_7VE__ #define LJ_ARCH_VERSION 70 @@ -331,6 +331,7 @@ #define LJ_ARCH_NOFFI 1 #elif LJ_ARCH_BITS == 64 #error "No support for PPC64" +#undef LJ_TARGET_PPC #endif #if _ARCH_PWR7 @@ -490,36 +491,45 @@ #elif LJ_TARGET_ARM #if defined(__ARMEB__) #error "No support for big-endian ARM" +#undef LJ_TARGET_ARM #endif #if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__ #error "No support for Cortex-M CPUs" +#undef LJ_TARGET_ARM #endif #if !(__ARM_EABI__ || LJ_TARGET_IOS) #error "Only ARM EABI or iOS 3.0+ ABI is supported" +#undef LJ_TARGET_ARM #endif #elif LJ_TARGET_ARM64 #if defined(_ILP32) #error "No support for ILP32 model on ARM64" +#undef LJ_TARGET_ARM64 #endif #elif LJ_TARGET_PPC #if defined(_LITTLE_ENDIAN) && (!defined(_BYTE_ORDER) || (_BYTE_ORDER == _LITTLE_ENDIAN)) #error "No support for little-endian PPC32" +#undef LJ_TARGET_PPC #endif #if defined(__NO_FPRS__) && !defined(_SOFT_FLOAT) -#error "No support for PPC/e500 anymore (use LuaJIT 2.0)" +#error "No support for PPC/e500, use LuaJIT 2.0" +#undef LJ_TARGET_PPC #endif #elif LJ_TARGET_MIPS32 #if !((defined(_MIPS_SIM_ABI32) && _MIPS_SIM == _MIPS_SIM_ABI32) || (defined(_ABIO32) && _MIPS_SIM == _ABIO32)) #error "Only o32 ABI supported for MIPS32" +#undef LJ_TARGET_MIPS #endif #if LJ_TARGET_MIPSR6 /* Not that useful, since most available r6 CPUs are 64 bit. */ #error "No support for MIPS32R6" +#undef LJ_TARGET_MIPS #endif #elif LJ_TARGET_MIPS64 #if !((defined(_MIPS_SIM_ABI64) && _MIPS_SIM == _MIPS_SIM_ABI64) || (defined(_ABI64) && _MIPS_SIM == _ABI64)) /* MIPS32ON64 aka n32 ABI support might be desirable, but difficult. */ #error "Only n64 ABI supported for MIPS64" +#undef LJ_TARGET_MIPS #endif #endif #endif diff --git a/src/3rdparty/luajit/src/lj_asm.c b/src/3rdparty/luajit/src/lj_asm.c index c02a1b9e..844910ad 100644 --- a/src/3rdparty/luajit/src/lj_asm.c +++ b/src/3rdparty/luajit/src/lj_asm.c @@ -606,7 +606,11 @@ static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow) IRIns *ir = IR(ref); if ((ir->o == IR_KINT64 && k == (int64_t)ir_kint64(ir)->u64) || #if LJ_GC64 +#if LJ_TARGET_ARM64 + (ir->o == IR_KINT && (uint64_t)k == (uint32_t)ir->i) || +#else (ir->o == IR_KINT && k == ir->i) || +#endif (ir->o == IR_KGC && k == (intptr_t)ir_kgc(ir)) || ((ir->o == IR_KPTR || ir->o == IR_KKPTR) && k == (intptr_t)ir_kptr(ir)) diff --git a/src/3rdparty/luajit/src/lj_asm_arm.h b/src/3rdparty/luajit/src/lj_asm_arm.h index b3b1f096..ac3d1b58 100644 --- a/src/3rdparty/luajit/src/lj_asm_arm.h +++ b/src/3rdparty/luajit/src/lj_asm_arm.h @@ -1990,6 +1990,7 @@ static void asm_prof(ASMState *as, IRIns *ir) static void asm_stack_check(ASMState *as, BCReg topslot, IRIns *irp, RegSet allow, ExitNo exitno) { + int savereg = 0; Reg pbase; uint32_t k; if (irp) { @@ -2000,12 +2001,14 @@ static void asm_stack_check(ASMState *as, BCReg topslot, pbase = rset_pickbot(allow); } else { pbase = RID_RET; - emit_lso(as, ARMI_LDR, RID_RET, RID_SP, 0); /* Restore temp. register. */ + savereg = 1; } } else { pbase = RID_BASE; } emit_branch(as, ARMF_CC(ARMI_BL, CC_LS), exitstub_addr(as->J, exitno)); + if (savereg) + emit_lso(as, ARMI_LDR, RID_RET, RID_SP, 0); /* Restore temp. register. */ k = emit_isk12(0, (int32_t)(8*topslot)); lj_assertA(k, "slot offset %d does not fit in K12", 8*topslot); emit_n(as, ARMI_CMP^k, RID_TMP); @@ -2017,7 +2020,7 @@ static void asm_stack_check(ASMState *as, BCReg topslot, if (ra_hasspill(irp->s)) emit_lso(as, ARMI_LDR, pbase, RID_SP, sps_scale(irp->s)); emit_lso(as, ARMI_LDR, RID_TMP, RID_TMP, (i & 4095)); - if (ra_hasspill(irp->s) && !allow) + if (savereg) emit_lso(as, ARMI_STR, RID_RET, RID_SP, 0); /* Save temp. register. */ emit_loadi(as, RID_TMP, (i & ~4095)); } else { @@ -2252,7 +2255,7 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) } if (nslots > as->evenspill) /* Leave room for args in stack slots. */ as->evenspill = nslots; - return REGSP_HINT(RID_RET); + return REGSP_HINT(irt_isfp(ir->t) ? RID_FPRET : RID_RET); } static void asm_setup_target(ASMState *as) diff --git a/src/3rdparty/luajit/src/lj_asm_arm64.h b/src/3rdparty/luajit/src/lj_asm_arm64.h index 5e690308..9f165fa8 100644 --- a/src/3rdparty/luajit/src/lj_asm_arm64.h +++ b/src/3rdparty/luajit/src/lj_asm_arm64.h @@ -84,18 +84,23 @@ static void asm_guardcc(ASMState *as, A64CC cc) emit_cond_branch(as, cc, target); } -/* Emit test and branch instruction to exit for guard. */ -static void asm_guardtnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit) +/* Emit test and branch instruction to exit for guard, if in range. */ +static int asm_guardtnb(ASMState *as, A64Ins ai, Reg r, uint32_t bit) { MCode *target = asm_exitstub_addr(as, as->snapno); MCode *p = as->mcp; + ptrdiff_t delta = target - p; if (LJ_UNLIKELY(p == as->invmcp)) { + if (as->orignins > 1023) return 0; /* Delta might end up too large. */ as->loopinv = 1; - *p = A64I_B | A64F_S26(target-p); - emit_tnb(as, ai^0x01000000u, r, bit, p-1); - return; + *p = A64I_B | A64F_S26(delta); + ai ^= 0x01000000u; + target = p-1; + } else if (LJ_UNLIKELY(delta >= 0x1fff)) { + return 0; } emit_tnb(as, ai, r, bit, target); + return 1; } /* Emit compare and branch instruction to exit for guard. */ @@ -211,16 +216,14 @@ static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow, static uint32_t asm_fuseopm(ASMState *as, A64Ins ai, IRRef ref, RegSet allow) { IRIns *ir = IR(ref); + int logical = (ai & 0x1f000000) == 0x0a000000; if (ra_hasreg(ir->r)) { ra_noweak(as, ir->r); return A64F_M(ir->r); } else if (irref_isk(ref)) { - uint32_t m; int64_t k = get_k64val(as, ref); - if ((ai & 0x1f000000) == 0x0a000000) - m = emit_isk13(k, irt_is64(ir->t)); - else - m = emit_isk12(k); + uint32_t m = logical ? emit_isk13(k, irt_is64(ir->t)) : + emit_isk12(irt_is64(ir->t) ? k : (int32_t)k); if (m) return m; } else if (mayfuse(as, ref)) { @@ -232,7 +235,7 @@ static uint32_t asm_fuseopm(ASMState *as, A64Ins ai, IRRef ref, RegSet allow) (IR(ir->op2)->i & (irt_is64(ir->t) ? 63 : 31)); IRIns *irl = IR(ir->op1); if (sh == A64SH_LSL && - irl->o == IR_CONV && + irl->o == IR_CONV && !logical && irl->op2 == ((IRT_I64<op1, allow); return A64F_M(m) | A64F_SH(sh, shift); } - } else if (ir->o == IR_CONV && + } else if (ir->o == IR_BROR && logical && irref_isk(ir->op2)) { + Reg m = ra_alloc1(as, ir->op1, allow); + int shift = (IR(ir->op2)->i & (irt_is64(ir->t) ? 63 : 31)); + return A64F_M(m) | A64F_SH(A64SH_ROR, shift); + } else if (ir->o == IR_CONV && !logical && ir->op2 == ((IRT_I64<op1, allow); return A64F_M(m) | A64F_EX(A64EX_SXTW); @@ -426,6 +433,11 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) for (gpr = REGARG_FIRSTGPR; gpr <= REGARG_LASTGPR; gpr++) as->cost[gpr] = REGCOST(~0u, ASMREF_L); gpr = REGARG_FIRSTGPR; +#if LJ_HASFFI && LJ_ABI_WIN + if ((ci->flags & CCI_VARARG)) { + fpr = REGARG_LASTFPR+1; + } +#endif for (n = 0; n < nargs; n++) { /* Setup args. */ IRRef ref = args[n]; IRIns *ir = IR(ref); @@ -436,6 +448,11 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) "reg %d not free", fpr); /* Must have been evicted. */ ra_leftov(as, fpr, ref); fpr++; +#if LJ_HASFFI && LJ_ABI_WIN + } else if ((ci->flags & CCI_VARARG) && (gpr <= REGARG_LASTGPR)) { + Reg rf = ra_alloc1(as, ref, RSET_FPR); + emit_dn(as, A64I_FMOV_R_D, gpr++, rf & 31); +#endif } else { Reg r = ra_alloc1(as, ref, RSET_FPR); int32_t al = spalign; @@ -541,8 +558,6 @@ static void asm_retf(ASMState *as, IRIns *ir) as->topslot -= (BCReg)delta; if ((int32_t)as->topslot < 0) as->topslot = 0; irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ - /* Need to force a spill on REF_BASE now to update the stack slot. */ - emit_lso(as, A64I_STRx, base, RID_SP, ra_spill(as, IR(REF_BASE))); emit_setgl(as, base, jit_base); emit_addptr(as, base, -8*delta); asm_guardcc(as, CC_NE); @@ -666,25 +681,22 @@ static void asm_strto(ASMState *as, IRIns *ir) { const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; IRRef args[2]; - Reg dest = 0, tmp; - int destused = ra_used(ir); + Reg tmp; int32_t ofs = 0; ra_evictset(as, RSET_SCRATCH); - if (destused) { + if (ra_used(ir)) { if (ra_hasspill(ir->s)) { ofs = sps_scale(ir->s); - destused = 0; if (ra_hasreg(ir->r)) { ra_free(as, ir->r); ra_modified(as, ir->r); emit_spload(as, ir, ir->r, ofs); } } else { - dest = ra_dest(as, ir, RSET_FPR); + Reg dest = ra_dest(as, ir, RSET_FPR); + emit_lso(as, A64I_LDRd, (dest & 31), RID_SP, 0); } } - if (destused) - emit_lso(as, A64I_LDRd, (dest & 31), RID_SP, 0); asm_guardcnb(as, A64I_CBZ, RID_RET); args[0] = ir->op1; /* GCstr *str */ args[1] = ASMREF_TMP1; /* TValue *n */ @@ -775,113 +787,75 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) int destused = ra_used(ir); Reg dest = ra_dest(as, ir, allow); Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); - Reg key = 0, tmp = RID_TMP; - Reg ftmp = RID_NONE, type = RID_NONE, scr = RID_NONE, tisnum = RID_NONE; + Reg tmp = RID_TMP, type = RID_NONE, key, tkey; IRRef refkey = ir->op2; IRIns *irkey = IR(refkey); - int isk = irref_isk(ir->op2); + int isk = irref_isk(refkey); IRType1 kt = irkey->t; uint32_t k = 0; uint32_t khash; - MCLabel l_end, l_loop, l_next; + MCLabel l_end, l_loop; rset_clear(allow, tab); - if (!isk) { - key = ra_alloc1(as, ir->op2, irt_isnum(kt) ? RSET_FPR : allow); - rset_clear(allow, key); - if (!irt_isstr(kt)) { - tmp = ra_scratch(as, allow); - rset_clear(allow, tmp); - } - } else if (irt_isnum(kt)) { - int64_t val = (int64_t)ir_knum(irkey)->u64; - if (!(k = emit_isk12(val))) { - key = ra_allock(as, val, allow); - rset_clear(allow, key); - } - } else if (!irt_ispri(kt)) { - if (!(k = emit_isk12(irkey->i))) { - key = ra_alloc1(as, refkey, allow); - rset_clear(allow, key); - } - } - - /* Allocate constants early. */ - if (irt_isnum(kt)) { - if (!isk) { - tisnum = ra_allock(as, LJ_TISNUM << 15, allow); - ftmp = ra_scratch(as, rset_exclude(RSET_FPR, key)); - rset_clear(allow, tisnum); - } - } else if (irt_isaddr(kt)) { - if (isk) { - int64_t kk = ((int64_t)irt_toitype(kt) << 47) | irkey[1].tv.u64; - scr = ra_allock(as, kk, allow); + /* Allocate register for tkey outside of the loop. */ + if (isk) { + int64_t kk; + if (irt_isaddr(kt)) { + kk = ((int64_t)irt_toitype(kt) << 47) | irkey[1].tv.u64; + } else if (irt_isnum(kt)) { + kk = (int64_t)ir_knum(irkey)->u64; + /* Assumes -0.0 is already canonicalized to +0.0. */ } else { - scr = ra_scratch(as, allow); + lj_assertA(irt_ispri(kt) && !irt_isnil(kt), "bad HREF key type"); + kk = ~((int64_t)~irt_toitype(kt) << 47); } - rset_clear(allow, scr); + k = emit_isk12(kk); + tkey = k ? 0 : ra_allock(as, kk, allow); } else { - lj_assertA(irt_ispri(kt) && !irt_isnil(kt), "bad HREF key type"); - type = ra_allock(as, ~((int64_t)~irt_toitype(kt) << 47), allow); - scr = ra_scratch(as, rset_clear(allow, type)); - rset_clear(allow, scr); + tkey = ra_scratch(as, allow); } /* Key not found in chain: jump to exit (if merged) or load niltv. */ l_end = emit_label(as); as->invmcp = NULL; - if (merge == IR_NE) + if (merge == IR_NE) { asm_guardcc(as, CC_AL); - else if (destused) - emit_loada(as, dest, niltvg(J2G(as->J))); + } else if (destused) { + uint32_t k12 = emit_isk12(offsetof(global_State, nilnode.val)); + lj_assertA(k12 != 0, "Cannot k12 encode niltv(L)"); + emit_dn(as, A64I_ADDx^k12, dest, RID_GL); + } /* Follow hash chain until the end. */ l_loop = --as->mcp; - emit_n(as, A64I_CMPx^A64I_K12^0, dest); - emit_lso(as, A64I_LDRx, dest, dest, offsetof(Node, next)); - l_next = emit_label(as); + if (destused) + emit_lso(as, A64I_LDRx, dest, dest, offsetof(Node, next)); /* Type and value comparison. */ if (merge == IR_EQ) asm_guardcc(as, CC_EQ); else emit_cond_branch(as, CC_EQ, l_end); + emit_nm(as, A64I_CMPx^k, tmp, tkey); + if (!destused) + emit_lso(as, A64I_LDRx, dest, dest, offsetof(Node, next)); + emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key)); + *l_loop = A64I_X | A64I_CBNZ | A64F_S19(as->mcp - l_loop) | dest; - if (irt_isnum(kt)) { - if (isk) { - /* Assumes -0.0 is already canonicalized to +0.0. */ - if (k) - emit_n(as, A64I_CMPx^k, tmp); - else - emit_nm(as, A64I_CMPx, key, tmp); - emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64)); - } else { - emit_nm(as, A64I_FCMPd, key, ftmp); - emit_dn(as, A64I_FMOV_D_R, (ftmp & 31), (tmp & 31)); - emit_cond_branch(as, CC_LO, l_next); - emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32), tisnum, tmp); - emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.n)); - } - } else if (irt_isaddr(kt)) { - if (isk) { - emit_nm(as, A64I_CMPx, scr, tmp); - emit_lso(as, A64I_LDRx, tmp, dest, offsetof(Node, key.u64)); + /* Construct tkey as canonicalized or tagged key. */ + if (!isk) { + if (irt_isnum(kt)) { + key = ra_alloc1(as, refkey, RSET_FPR); + emit_dnm(as, A64I_CSELx | A64F_CC(CC_EQ), tkey, RID_ZERO, tkey); + /* A64I_FMOV_R_D from key to tkey done below. */ } else { - emit_nm(as, A64I_CMPx, tmp, scr); - emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key.u64)); + lj_assertA(irt_isaddr(kt), "bad HREF key type"); + key = ra_alloc1(as, refkey, allow); + type = ra_allock(as, irt_toitype(kt) << 15, rset_clear(allow, key)); + emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 32), tkey, key, type); } - } else { - emit_nm(as, A64I_CMPx, scr, type); - emit_lso(as, A64I_LDRx, scr, dest, offsetof(Node, key)); } - *l_loop = A64I_BCC | A64F_S19(as->mcp - l_loop) | CC_NE; - if (!isk && irt_isaddr(kt)) { - type = ra_allock(as, (int32_t)irt_toitype(kt), allow); - emit_dnm(as, A64I_ADDx | A64F_SH(A64SH_LSL, 47), tmp, key, type); - rset_clear(allow, type); - } /* Load main position relative to tab->node into dest. */ khash = isk ? ir_khash(as, irkey) : 1; if (khash == 0) { @@ -895,7 +869,6 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) emit_dnm(as, A64I_ANDw, dest, dest, tmphash); emit_lso(as, A64I_LDRw, dest, tab, offsetof(GCtab, hmask)); } else if (irt_isstr(kt)) { - /* Fetch of str->sid is cheaper than ra_allock. */ emit_dnm(as, A64I_ANDw, dest, dest, tmp); emit_lso(as, A64I_LDRw, tmp, key, offsetof(GCstr, sid)); emit_lso(as, A64I_LDRw, dest, tab, offsetof(GCtab, hmask)); @@ -904,23 +877,18 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) emit_lso(as, A64I_LDRw, tmp, tab, offsetof(GCtab, hmask)); emit_dnm(as, A64I_SUBw, dest, dest, tmp); emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT3)), tmp, tmp, tmp); - emit_dnm(as, A64I_EORw, dest, dest, tmp); - emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT2)), dest, dest, dest); + emit_dnm(as, A64I_EORw | A64F_SH(A64SH_ROR, 32-HASH_ROT2), dest, tmp, dest); emit_dnm(as, A64I_SUBw, tmp, tmp, dest); emit_dnm(as, A64I_EXTRw | (A64F_IMMS(32-HASH_ROT1)), dest, dest, dest); - emit_dnm(as, A64I_EORw, tmp, tmp, dest); if (irt_isnum(kt)) { + emit_dnm(as, A64I_EORw, tmp, tkey, dest); emit_dnm(as, A64I_ADDw, dest, dest, dest); - emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, dest); - emit_dm(as, A64I_MOVw, tmp, dest); - emit_dn(as, A64I_FMOV_R_D, dest, (key & 31)); + emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, tkey); + emit_nm(as, A64I_FCMPZd, (key & 31), 0); + emit_dn(as, A64I_FMOV_R_D, tkey, (key & 31)); } else { - checkmclim(as); - emit_dm(as, A64I_MOVw, tmp, key); - emit_dnm(as, A64I_EORw, dest, dest, - ra_allock(as, irt_toitype(kt) << 15, allow)); - emit_dn(as, A64I_LSRx | A64F_IMMR(32)|A64F_IMMS(32), dest, dest); - emit_dm(as, A64I_MOVx, dest, key); + emit_dnm(as, A64I_EORw, tmp, key, dest); + emit_dnm(as, A64I_EORx | A64F_SH(A64SH_LSR, 32), dest, type, key); } } } @@ -935,7 +903,7 @@ static void asm_hrefk(ASMState *as, IRIns *ir) int bigofs = !emit_checkofs(A64I_LDRx, kofs); Reg dest = (ra_used(ir) || bigofs) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; Reg node = ra_alloc1(as, ir->op1, RSET_GPR); - Reg key, idx = node; + Reg idx = node; RegSet allow = rset_exclude(RSET_GPR, node); uint64_t k; lj_assertA(ofs % sizeof(Node) == 0, "unaligned HREFK slot"); @@ -954,9 +922,8 @@ static void asm_hrefk(ASMState *as, IRIns *ir) } else { k = ((uint64_t)irt_toitype(irkey->t) << 47) | (uint64_t)ir_kgc(irkey); } - key = ra_scratch(as, allow); - emit_nm(as, A64I_CMPx, key, ra_allock(as, k, rset_exclude(allow, key))); - emit_lso(as, A64I_LDRx, key, idx, kofs); + emit_nm(as, A64I_CMPx, RID_TMP, ra_allock(as, k, allow)); + emit_lso(as, A64I_LDRx, RID_TMP, idx, kofs); if (bigofs) emit_opk(as, A64I_ADDx, dest, node, ofs, rset_exclude(RSET_GPR, node)); } @@ -969,18 +936,16 @@ static void asm_uref(ASMState *as, IRIns *ir) MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; emit_lsptr(as, A64I_LDRx, dest, v); } else { - Reg uv = ra_scratch(as, RSET_GPR); - Reg func = ra_alloc1(as, ir->op1, RSET_GPR); if (ir->o == IR_UREFC) { - asm_guardcc(as, CC_NE); - emit_n(as, (A64I_CMPx^A64I_K12) | A64F_U12(1), RID_TMP); - emit_opk(as, A64I_ADDx, dest, uv, + asm_guardcnb(as, A64I_CBZ, RID_TMP); + emit_opk(as, A64I_ADDx, dest, dest, (int32_t)offsetof(GCupval, tv), RSET_GPR); - emit_lso(as, A64I_LDRB, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); + emit_lso(as, A64I_LDRB, RID_TMP, dest, + (int32_t)offsetof(GCupval, closed)); } else { - emit_lso(as, A64I_LDRx, dest, uv, (int32_t)offsetof(GCupval, v)); + emit_lso(as, A64I_LDRx, dest, dest, (int32_t)offsetof(GCupval, v)); } - emit_lso(as, A64I_LDRx, uv, func, + emit_lso(as, A64I_LDRx, dest, ra_alloc1(as, ir->op1, RSET_GPR), (int32_t)offsetof(GCfuncL, uvptr) + 8*(int32_t)(ir->op2 >> 8)); } } @@ -1086,7 +1051,7 @@ static void asm_xstore(ASMState *as, IRIns *ir) static void asm_ahuvload(ASMState *as, IRIns *ir) { - Reg idx, tmp, type; + Reg idx, tmp; int32_t ofs = 0; RegSet gpr = RSET_GPR, allow = irt_isnum(ir->t) ? RSET_FPR : RSET_GPR; lj_assertA(irt_isnum(ir->t) || irt_ispri(ir->t) || irt_isaddr(ir->t) || @@ -1105,8 +1070,7 @@ static void asm_ahuvload(ASMState *as, IRIns *ir) } else { tmp = ra_scratch(as, gpr); } - type = ra_scratch(as, rset_clear(gpr, tmp)); - idx = asm_fuseahuref(as, ir->op1, &ofs, rset_clear(gpr, type), A64I_LDRx); + idx = asm_fuseahuref(as, ir->op1, &ofs, rset_clear(gpr, tmp), A64I_LDRx); rset_clear(gpr, idx); if (ofs & FUSE_REG) rset_clear(gpr, ofs & 31); if (ir->o == IR_VLOAD) ofs += 8 * ir->op2; @@ -1118,8 +1082,8 @@ static void asm_ahuvload(ASMState *as, IRIns *ir) emit_nm(as, A64I_CMPx | A64F_SH(A64SH_LSR, 32), ra_allock(as, LJ_TISNUM << 15, gpr), tmp); } else if (irt_isaddr(ir->t)) { - emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(ir->t)), type); - emit_dn(as, A64I_ASRx | A64F_IMMR(47), type, tmp); + emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(ir->t)), RID_TMP); + emit_dn(as, A64I_ASRx | A64F_IMMR(47), RID_TMP, tmp); } else if (irt_isnil(ir->t)) { emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(1), tmp); } else { @@ -1242,9 +1206,8 @@ static void asm_sload(ASMState *as, IRIns *ir) emit_nm(as, A64I_CMPx, ra_allock(as, ~((int64_t)~irt_toitype(t) << 47) , allow), tmp); } else { - Reg type = ra_scratch(as, allow); - emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(t)), type); - emit_dn(as, A64I_ASRx | A64F_IMMR(47), type, tmp); + emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(-irt_toitype(t)), RID_TMP); + emit_dn(as, A64I_ASRx | A64F_IMMR(47), RID_TMP, tmp); } emit_lso(as, A64I_LDRx, tmp, base, ofs); return; @@ -1330,7 +1293,6 @@ static void asm_obar(ASMState *as, IRIns *ir) const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv]; IRRef args[2]; MCLabel l_end; - RegSet allow = RSET_GPR; Reg obj, val, tmp; /* No need for other object barriers (yet). */ lj_assertA(IR(ir->op1)->o == IR_UREFC, "bad OBAR type"); @@ -1341,14 +1303,13 @@ static void asm_obar(ASMState *as, IRIns *ir) asm_gencall(as, ci, args); emit_dm(as, A64I_MOVx, ra_releasetmp(as, ASMREF_TMP1), RID_GL); obj = IR(ir->op1)->r; - tmp = ra_scratch(as, rset_exclude(allow, obj)); - emit_cond_branch(as, CC_EQ, l_end); - emit_n(as, A64I_TSTw^emit_isk13(LJ_GC_BLACK, 0), tmp); + tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj)); + emit_tnb(as, A64I_TBZ, tmp, lj_ffs(LJ_GC_BLACK), l_end); emit_cond_branch(as, CC_EQ, l_end); emit_n(as, A64I_TSTw^emit_isk13(LJ_GC_WHITES, 0), RID_TMP); val = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, obj)); emit_lso(as, A64I_LDRB, tmp, obj, - (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)); + (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv)); emit_lso(as, A64I_LDRB, RID_TMP, val, (int32_t)offsetof(GChead, marked)); } @@ -1390,12 +1351,12 @@ static int asm_swapops(ASMState *as, IRRef lref, IRRef rref) if (irref_isk(lref)) return 1; /* But swap constants to the right. */ ir = IR(rref); - if ((ir->o >= IR_BSHL && ir->o <= IR_BSAR) || + if ((ir->o >= IR_BSHL && ir->o <= IR_BROR) || (ir->o == IR_ADD && ir->op1 == ir->op2) || (ir->o == IR_CONV && ir->op2 == ((IRT_I64<o >= IR_BSHL && ir->o <= IR_BSAR) || + if ((ir->o >= IR_BSHL && ir->o <= IR_BROR) || (ir->o == IR_ADD && ir->op1 == ir->op2) || (ir->o == IR_CONV && ir->op2 == ((IRT_I64<t)) { /* IR_MULOV */ asm_guardcc(as, CC_NE); emit_dm(as, A64I_MOVw, dest, dest); /* Zero-extend. */ - emit_nm(as, A64I_CMPw | A64F_SH(A64SH_ASR, 31), RID_TMP, dest); - emit_dn(as, A64I_ASRx | A64F_IMMR(32), RID_TMP, dest); + emit_nm(as, A64I_CMPx | A64F_EX(A64EX_SXTW), dest, dest); emit_dnm(as, A64I_SMULL, dest, right, left); } else { emit_dnm(as, irt_is64(ir->t) ? A64I_MULx : A64I_MULw, dest, left, right); @@ -1707,16 +1667,15 @@ static void asm_intcomp(ASMState *as, IRIns *ir) if (asm_swapops(as, blref, brref)) { Reg tmp = blref; blref = brref; brref = tmp; } + bleft = ra_alloc1(as, blref, RSET_GPR); if (irref_isk(brref)) { uint64_t k = get_k64val(as, brref); - if (k && !(k & (k-1)) && (cc == CC_EQ || cc == CC_NE)) { - asm_guardtnb(as, cc == CC_EQ ? A64I_TBZ : A64I_TBNZ, - ra_alloc1(as, blref, RSET_GPR), emit_ctz64(k)); + if (k && !(k & (k-1)) && (cc == CC_EQ || cc == CC_NE) && + asm_guardtnb(as, cc == CC_EQ ? A64I_TBZ : A64I_TBNZ, bleft, + emit_ctz64(k))) return; - } m2 = emit_isk13(k, irt_is64(irl->t)); } - bleft = ra_alloc1(as, blref, RSET_GPR); ai = (irt_is64(irl->t) ? A64I_TSTx : A64I_TSTw); if (!m2) m2 = asm_fuseopm(as, ai, brref, rset_exclude(RSET_GPR, bleft)); @@ -1791,37 +1750,28 @@ static void asm_prof(ASMState *as, IRIns *ir) static void asm_stack_check(ASMState *as, BCReg topslot, IRIns *irp, RegSet allow, ExitNo exitno) { - Reg pbase; uint32_t k; + Reg pbase = RID_BASE; if (irp) { - if (!ra_hasspill(irp->s)) { - pbase = irp->r; - lj_assertA(ra_hasreg(pbase), "base reg lost"); - } else if (allow) { - pbase = rset_pickbot(allow); - } else { - pbase = RID_RET; - emit_lso(as, A64I_LDRx, RID_RET, RID_SP, 0); /* Restore temp register. */ - } - } else { - pbase = RID_BASE; + pbase = irp->r; + if (!ra_hasreg(pbase)) + pbase = allow ? (0x40 | rset_pickbot(allow)) : (0xC0 | RID_RET); } emit_cond_branch(as, CC_LS, asm_exitstub_addr(as, exitno)); + if (pbase & 0x80) /* Restore temp. register. */ + emit_lso(as, A64I_LDRx, (pbase & 31), RID_SP, 0); k = emit_isk12((8*topslot)); lj_assertA(k, "slot offset %d does not fit in K12", 8*topslot); emit_n(as, A64I_CMPx^k, RID_TMP); - emit_dnm(as, A64I_SUBx, RID_TMP, RID_TMP, pbase); + emit_dnm(as, A64I_SUBx, RID_TMP, RID_TMP, (pbase & 31)); emit_lso(as, A64I_LDRx, RID_TMP, RID_TMP, (int32_t)offsetof(lua_State, maxstack)); - if (irp) { /* Must not spill arbitrary registers in head of side trace. */ - if (ra_hasspill(irp->s)) - emit_lso(as, A64I_LDRx, pbase, RID_SP, sps_scale(irp->s)); - emit_lso(as, A64I_LDRx, RID_TMP, RID_GL, glofs(as, &J2G(as->J)->cur_L)); - if (ra_hasspill(irp->s) && !allow) - emit_lso(as, A64I_STRx, RID_RET, RID_SP, 0); /* Save temp register. */ - } else { - emit_getgl(as, RID_TMP, cur_L); + if (pbase & 0x40) { + emit_getgl(as, (pbase & 31), jit_base); + if (pbase & 0x80) /* Save temp register. */ + emit_lso(as, A64I_STRx, (pbase & 31), RID_SP, 0); } + emit_getgl(as, RID_TMP, cur_L); } /* Restore Lua stack from on-trace state. */ @@ -1863,7 +1813,7 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap) /* Marker to prevent patching the GC check exit. */ #define ARM64_NOPATCH_GC_CHECK \ - (A64I_ORRx|A64F_D(RID_TMP)|A64F_M(RID_TMP)|A64F_N(RID_TMP)) + (A64I_ORRx|A64F_D(RID_ZERO)|A64F_M(RID_ZERO)|A64F_N(RID_ZERO)) /* Check GC threshold and do one or more GC steps. */ static void asm_gc_check(ASMState *as) @@ -1918,46 +1868,40 @@ static void asm_loop_tail_fixup(ASMState *as) /* -- Head of trace ------------------------------------------------------- */ -/* Reload L register from g->cur_L. */ -static void asm_head_lreg(ASMState *as) -{ - IRIns *ir = IR(ASMREF_L); - if (ra_used(ir)) { - Reg r = ra_dest(as, ir, RSET_GPR); - emit_getgl(as, r, cur_L); - ra_evictk(as); - } -} - /* Coalesce BASE register for a root trace. */ static void asm_head_root_base(ASMState *as) { - IRIns *ir; - asm_head_lreg(as); - ir = IR(REF_BASE); - if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t))) - ra_spill(as, ir); - ra_destreg(as, ir, RID_BASE); + IRIns *ir = IR(REF_BASE); + Reg r = ir->r; + if (ra_hasreg(r)) { + ra_free(as, r); + if (rset_test(as->modset, r) || irt_ismarked(ir->t)) + ir->r = RID_INIT; /* No inheritance for modified BASE register. */ + if (r != RID_BASE) + emit_movrr(as, ir, r, RID_BASE); + } } /* Coalesce BASE register for a side trace. */ static Reg asm_head_side_base(ASMState *as, IRIns *irp) { - IRIns *ir; - asm_head_lreg(as); - ir = IR(REF_BASE); - if (ra_hasreg(ir->r) && (rset_test(as->modset, ir->r) || irt_ismarked(ir->t))) - ra_spill(as, ir); - if (ra_hasspill(irp->s)) { - return ra_dest(as, ir, RSET_GPR); - } else { - Reg r = irp->r; - lj_assertA(ra_hasreg(r), "base reg lost"); - if (r != ir->r && !rset_test(as->freeset, r)) - ra_restore(as, regcost_ref(as->cost[r])); - ra_destreg(as, ir, r); - return r; + IRIns *ir = IR(REF_BASE); + Reg r = ir->r; + if (ra_hasreg(r)) { + ra_free(as, r); + if (rset_test(as->modset, r) || irt_ismarked(ir->t)) + ir->r = RID_INIT; /* No inheritance for modified BASE register. */ + if (irp->r == r) { + return r; /* Same BASE register already coalesced. */ + } else if (ra_hasreg(irp->r) && rset_test(as->freeset, irp->r)) { + /* Move from coalesced parent reg. */ + emit_movrr(as, ir, r, irp->r); + return irp->r; + } else { + emit_getgl(as, r, jit_base); /* Otherwise reload BASE. */ + } } + return RID_NONE; } /* -- Tail of trace ------------------------------------------------------- */ @@ -2009,6 +1953,9 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) int ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; int spofs = 0, spalign = LJ_TARGET_OSX ? 0 : 7, nslots; asm_collectargs(as, ir, ci, args); +#if LJ_ABI_WIN + if ((ci->flags & CCI_VARARG)) nfpr = 0; +#endif for (i = 0; i < nargs; i++) { int al = spalign; if (!args[i]) { @@ -2020,7 +1967,9 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) #endif } else if (irt_isfp(IR(args[i])->t)) { if (nfpr > 0) { nfpr--; continue; } -#if LJ_TARGET_OSX +#if LJ_ABI_WIN + if ((ci->flags & CCI_VARARG) && ngpr > 0) { ngpr--; continue; } +#elif LJ_TARGET_OSX al |= irt_isnum(IR(args[i])->t) ? 7 : 3; #endif } else { @@ -2036,7 +1985,7 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) as->evenspill = nslots; } #endif - return REGSP_HINT(RID_RET); + return REGSP_HINT(irt_isfp(ir->t) ? RID_FPRET : RID_RET); } static void asm_setup_target(ASMState *as) diff --git a/src/3rdparty/luajit/src/lj_asm_x86.h b/src/3rdparty/luajit/src/lj_asm_x86.h index 9f779bf5..c92de3d8 100644 --- a/src/3rdparty/luajit/src/lj_asm_x86.h +++ b/src/3rdparty/luajit/src/lj_asm_x86.h @@ -140,7 +140,8 @@ static IRRef asm_fuseabase(ASMState *as, IRRef ref) } } else if (irb->o == IR_ADD && irref_isk(irb->op2)) { /* Fuse base offset (vararg load). */ - as->mrm.ofs = IR(irb->op2)->i; + IRIns *irk = IR(irb->op2); + as->mrm.ofs = irk->o == IR_KINT ? irk->i : (int32_t)ir_kint64(irk)->u64; return irb->op1; } return ref; /* Otherwise use the given array base. */ diff --git a/src/3rdparty/luajit/src/lj_ccall.c b/src/3rdparty/luajit/src/lj_ccall.c index 00e753b9..5f95f5d8 100644 --- a/src/3rdparty/luajit/src/lj_ccall.c +++ b/src/3rdparty/luajit/src/lj_ccall.c @@ -985,6 +985,14 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, fid = ctf->sib; } +#if LJ_TARGET_ARM64 && LJ_ABI_WIN + if ((ct->info & CTF_VARARG)) { + nsp -= maxgpr * CTSIZE_PTR; /* May end up with negative nsp. */ + ngpr = maxgpr; + nfpr = CCALL_NARG_FPR; + } +#endif + /* Walk through all passed arguments. */ for (o = L->base+1, narg = 1; o < top; o++, narg++) { CTypeID did; @@ -1035,9 +1043,14 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, align = CTSIZE_PTR-1; nsp = (nsp + align) & ~align; } +#if LJ_TARGET_ARM64 && LJ_ABI_WIN + /* A negative nsp points into cc->gpr. Blame MS for their messy ABI. */ + dp = ((uint8_t *)cc->stack) + (int32_t)nsp; +#else dp = ((uint8_t *)cc->stack) + nsp; +#endif nsp += CCALL_PACK_STACKARG ? sz : n * CTSIZE_PTR; - if (nsp > CCALL_SIZE_STACK) { /* Too many arguments. */ + if ((int32_t)nsp > CCALL_SIZE_STACK) { /* Too many arguments. */ err_nyi: lj_err_caller(L, LJ_ERR_FFI_NYICALL); } @@ -1099,6 +1112,9 @@ static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, #endif } if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */ +#if LJ_TARGET_ARM64 && LJ_ABI_WIN + if ((int32_t)nsp < 0) nsp = 0; +#endif #if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP) cc->nfpr = nfpr; /* Required for vararg functions. */ diff --git a/src/3rdparty/luajit/src/lj_crecord.c b/src/3rdparty/luajit/src/lj_crecord.c index d7a522fb..55d0b3ef 100644 --- a/src/3rdparty/luajit/src/lj_crecord.c +++ b/src/3rdparty/luajit/src/lj_crecord.c @@ -1118,12 +1118,8 @@ static TRef crec_call_args(jit_State *J, RecordFFData *rd, ngpr = 1; else if (ctype_cconv(ct->info) == CTCC_FASTCALL) ngpr = 2; -#elif LJ_TARGET_ARM64 -#if LJ_ABI_WIN -#error "NYI: ARM64 Windows ABI calling conventions" -#elif LJ_TARGET_OSX +#elif LJ_TARGET_ARM64 && LJ_TARGET_OSX int ngpr = CCALL_NARG_GPR; -#endif #endif /* Skip initial attributes. */ diff --git a/src/3rdparty/luajit/src/lj_def.h b/src/3rdparty/luajit/src/lj_def.h index 88bc6336..0d6c346b 100644 --- a/src/3rdparty/luajit/src/lj_def.h +++ b/src/3rdparty/luajit/src/lj_def.h @@ -69,7 +69,7 @@ typedef unsigned int uintptr_t; #define LJ_MAX_UPVAL 60 /* Max. # of upvalues. */ #define LJ_MAX_IDXCHAIN 100 /* __index/__newindex chain limit. */ -#define LJ_STACK_EXTRA (5+2*LJ_FR2) /* Extra stack space (metamethods). */ +#define LJ_STACK_EXTRA (5+3*LJ_FR2) /* Extra stack space (metamethods). */ #define LJ_NUM_CBPAGE 1 /* Number of FFI callback pages. */ @@ -146,15 +146,9 @@ typedef uintptr_t BloomFilter; #define LJ_UNLIKELY(x) __builtin_expect(!!(x), 0) #define lj_ffs(x) ((uint32_t)__builtin_ctz(x)) -/* Don't ask ... */ -#if defined(__INTEL_COMPILER) && (defined(__i386__) || defined(__x86_64__)) -static LJ_AINLINE uint32_t lj_fls(uint32_t x) -{ - uint32_t r; __asm__("bsrl %1, %0" : "=r" (r) : "rm" (x) : "cc"); return r; -} -#else #define lj_fls(x) ((uint32_t)(__builtin_clz(x)^31)) -#endif +#define lj_ffs64(x) ((uint32_t)__builtin_ctzll(x)) +#define lj_fls64(x) ((uint32_t)(__builtin_clzll(x)^63)) #if defined(__arm__) static LJ_AINLINE uint32_t lj_bswap(uint32_t x) @@ -265,8 +259,12 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x) #else unsigned char _BitScanForward(unsigned long *, unsigned long); unsigned char _BitScanReverse(unsigned long *, unsigned long); +unsigned char _BitScanForward64(unsigned long *, uint64_t); +unsigned char _BitScanReverse64(unsigned long *, uint64_t); #pragma intrinsic(_BitScanForward) #pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward64) +#pragma intrinsic(_BitScanReverse64) static LJ_AINLINE uint32_t lj_ffs(uint32_t x) { @@ -277,6 +275,16 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x) { unsigned long r; _BitScanReverse(&r, x); return (uint32_t)r; } + +static LJ_AINLINE uint32_t lj_ffs64(uint64_t x) +{ + unsigned long r; _BitScanForward64(&r, x); return (uint32_t)r; +} + +static LJ_AINLINE uint32_t lj_fls64(uint64_t x) +{ + unsigned long r; _BitScanReverse64(&r, x); return (uint32_t)r; +} #endif unsigned long _byteswap_ulong(unsigned long); diff --git a/src/3rdparty/luajit/src/lj_dispatch.c b/src/3rdparty/luajit/src/lj_dispatch.c index 57809e62..b9748bba 100644 --- a/src/3rdparty/luajit/src/lj_dispatch.c +++ b/src/3rdparty/luajit/src/lj_dispatch.c @@ -453,7 +453,7 @@ static int call_init(lua_State *L, GCfunc *fn) int numparams = pt->numparams; int gotparams = (int)(L->top - L->base); int need = pt->framesize; - if ((pt->flags & PROTO_VARARG)) need += 1+gotparams; + if ((pt->flags & PROTO_VARARG)) need += 1+LJ_FR2+gotparams; lj_state_checkstack(L, (MSize)need); numparams -= gotparams; return numparams >= 0 ? numparams : 0; diff --git a/src/3rdparty/luajit/src/lj_emit_arm64.h b/src/3rdparty/luajit/src/lj_emit_arm64.h index 6926c71a..51d0c351 100644 --- a/src/3rdparty/luajit/src/lj_emit_arm64.h +++ b/src/3rdparty/luajit/src/lj_emit_arm64.h @@ -20,7 +20,7 @@ static uint64_t get_k64val(ASMState *as, IRRef ref) } else { lj_assertA(ir->o == IR_KINT || ir->o == IR_KNULL, "bad 64 bit const IR op %d", ir->o); - return ir->i; /* Sign-extended. */ + return (uint32_t)ir->i; /* Zero-extended. */ } } @@ -30,39 +30,31 @@ static uint32_t emit_isk12(int64_t n) uint64_t k = n < 0 ? ~(uint64_t)n+1u : (uint64_t)n; uint32_t m = n < 0 ? 0x40000000 : 0; if (k < 0x1000) { - return A64I_K12|m|A64F_U12(k); + return (uint32_t)(A64I_K12|m|A64F_U12(k)); } else if ((k & 0xfff000) == k) { - return A64I_K12|m|0x400000|A64F_U12(k>>12); + return (uint32_t)(A64I_K12|m|0x400000|A64F_U12(k>>12)); } return 0; } -#define emit_clz64(n) __builtin_clzll(n) -#define emit_ctz64(n) __builtin_ctzll(n) +#define emit_clz64(n) (lj_fls64(n)^63) +#define emit_ctz64(n) lj_ffs64(n) /* Encode constant in K13 format for logical data processing instructions. */ static uint32_t emit_isk13(uint64_t n, int is64) { - int inv = 0, w = 128, lz, tz; - if (n & 1) { n = ~n; w = 64; inv = 1; } /* Avoid wrap-around of ones. */ - if (!n) return 0; /* Neither all-zero nor all-ones are allowed. */ - do { /* Find the repeat width. */ - if (is64 && (uint32_t)(n^(n>>32))) break; - n = (uint32_t)n; - if (!n) return 0; /* Ditto when passing n=0xffffffff and is64=0. */ - w = 32; if ((n^(n>>16)) & 0xffff) break; - n = n & 0xffff; w = 16; if ((n^(n>>8)) & 0xff) break; - n = n & 0xff; w = 8; if ((n^(n>>4)) & 0xf) break; - n = n & 0xf; w = 4; if ((n^(n>>2)) & 0x3) break; - n = n & 0x3; w = 2; - } while (0); - lz = emit_clz64(n); - tz = emit_ctz64(n); - if ((int64_t)(n << lz) >> (lz+tz) != -1ll) return 0; /* Non-contiguous? */ - if (inv) - return A64I_K13 | (((lz-w) & 127) << 16) | (((lz+tz-w-1) & 63) << 10); - else - return A64I_K13 | ((w-tz) << 16) | (((63-lz-tz-w-w) & 63) << 10); + /* Thanks to: https://dougallj.wordpress.com/2021/10/30/ */ + int rot, ones, size, immr, imms; + if (!is64) n = ((uint64_t)n << 32) | (uint32_t)n; + if ((n+1u) <= 1u) return 0; /* Neither all-zero nor all-ones are allowed. */ + rot = (n & (n+1u)) ? emit_ctz64(n & (n+1u)) : 64; + n = lj_ror(n, rot & 63); + ones = emit_ctz64(~n); + size = emit_clz64(n) + ones; + if (lj_ror(n, size & 63) != n) return 0; /* Non-repeating? */ + immr = -rot & (size - 1); + imms = (-(size << 1) | (ones - 1)) & 63; + return A64I_K13 | A64F_IMMR(immr | (size & 64)) | A64F_IMMS(imms); } static uint32_t emit_isfpk64(uint64_t n) @@ -121,9 +113,20 @@ static int emit_checkofs(A64Ins ai, int64_t ofs) } } -static void emit_lso(ASMState *as, A64Ins ai, Reg rd, Reg rn, int64_t ofs) +static LJ_AINLINE uint32_t emit_lso_pair_candidate(A64Ins ai, int ofs, int sc) { - int ot = emit_checkofs(ai, ofs), sc = (ai >> 30) & 3; + if (ofs >= 0) { + return ai | A64F_U12(ofs>>sc); /* Subsequent lj_ror checks ofs. */ + } else if (ofs >= -256) { + return (ai^A64I_LS_U) | A64F_S9(ofs & 0x1ff); + } else { + return A64F_D(31); /* Will mismatch prev. */ + } +} + +static void emit_lso(ASMState *as, A64Ins ai, Reg rd, Reg rn, int64_t ofs64) +{ + int ot = emit_checkofs(ai, ofs64), sc = (ai >> 30) & 3, ofs = (int)ofs64; lj_assertA(ot, "load/store offset %d out of range", ofs); /* Combine LDR/STR pairs to LDP/STP. */ if ((sc == 2 || sc == 3) && @@ -132,11 +135,9 @@ static void emit_lso(ASMState *as, A64Ins ai, Reg rd, Reg rn, int64_t ofs) uint32_t prev = *as->mcp & ~A64F_D(31); int ofsm = ofs - (1<>sc)) || - prev == ((ai^A64I_LS_U) | A64F_N(rn) | A64F_S9(ofsm&0x1ff))) { + if (prev == emit_lso_pair_candidate(ai | A64F_N(rn), ofsm, sc)) { aip = (A64F_A(rd) | A64F_D(*as->mcp & 31)); - } else if (prev == (ai | A64F_N(rn) | A64F_U12(ofsp>>sc)) || - prev == ((ai^A64I_LS_U) | A64F_N(rn) | A64F_S9(ofsp&0x1ff))) { + } else if (prev == emit_lso_pair_candidate(ai | A64F_N(rn), ofsp, sc)) { aip = (A64F_D(rd) | A64F_A(*as->mcp & 31)); ofsm = ofs; } else { @@ -158,13 +159,12 @@ static void emit_lso(ASMState *as, A64Ins ai, Reg rd, Reg rn, int64_t ofs) /* -- Emit loads/stores --------------------------------------------------- */ /* Prefer rematerialization of BASE/L from global_State over spills. */ -#define emit_canremat(ref) ((ref) <= ASMREF_L) +#define emit_canremat(ref) ((ref) <= REF_BASE) -/* Try to find an N-step delta relative to other consts with N < lim. */ -static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim) +/* Try to find a one-step delta relative to other consts. */ +static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int is64) { RegSet work = (~as->freeset & RSET_GPR) | RID2RSET(RID_GL); - if (lim <= 1) return 0; /* Can't beat that. */ while (work) { Reg r = rset_picktop(work); IRRef ref = regcost_ref(as->cost[r]); @@ -173,13 +173,14 @@ static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim) uint64_t kx = ra_iskref(ref) ? (uint64_t)ra_krefk(as, ref) : get_k64val(as, ref); int64_t delta = (int64_t)(k - kx); + if (!is64) delta = (int64_t)(int32_t)delta; /* Sign-extend. */ if (delta == 0) { - emit_dm(as, A64I_MOVx, rd, r); + emit_dm(as, is64|A64I_MOVw, rd, r); return 1; } else { uint32_t k12 = emit_isk12(delta < 0 ? (int64_t)(~(uint64_t)delta+1u) : delta); if (k12) { - emit_dn(as, (delta < 0 ? A64I_SUBx : A64I_ADDx)^k12, rd, r); + emit_dn(as, (delta < 0 ? A64I_SUBw : A64I_ADDw)^is64^k12, rd, r); return 1; } /* Do other ops or multi-step deltas pay off? Probably not. @@ -192,79 +193,101 @@ static int emit_kdelta(ASMState *as, Reg rd, uint64_t k, int lim) return 0; /* Failed. */ } -static void emit_loadk(ASMState *as, Reg rd, uint64_t u64, int is64) +#define glofs(as, k) \ + ((intptr_t)((uintptr_t)(k) - (uintptr_t)&J2GG(as->J)->g)) +#define mcpofs(as, k) \ + ((intptr_t)((uintptr_t)(k) - (uintptr_t)(as->mcp - 1))) +#define checkmcpofs(as, k) \ + (A64F_S_OK(mcpofs(as, k)>>2, 19)) + +/* Try to form a const as ADR or ADRP or ADRP + ADD. */ +static int emit_kadrp(ASMState *as, Reg rd, uint64_t k) +{ + A64Ins ai = A64I_ADR; + int64_t ofs = mcpofs(as, k); + if (!A64F_S_OK((uint64_t)ofs, 21)) { + uint64_t kpage = k & ~0xfffull; + MCode *adrp = as->mcp - 1 - (k != kpage); + ofs = (int64_t)(kpage - ((uint64_t)adrp & ~0xfffull)) >> 12; + if (!A64F_S_OK(ofs, 21)) + return 0; /* Failed. */ + if (k != kpage) + emit_dn(as, (A64I_ADDx^A64I_K12)|A64F_U12(k - kpage), rd, rd); + ai = A64I_ADRP; + } + emit_d(as, ai|(((uint32_t)ofs&3)<<29)|A64F_S19(ofs>>2), rd); + return 1; +} + +static void emit_loadk(ASMState *as, Reg rd, uint64_t u64) { - int i, zeros = 0, ones = 0, neg; - if (!is64) u64 = (int64_t)(int32_t)u64; /* Sign-extend. */ - /* Count homogeneous 16 bit fragments. */ - for (i = 0; i < 4; i++) { - uint64_t frag = (u64 >> i*16) & 0xffff; - zeros += (frag == 0); - ones += (frag == 0xffff); + int zeros = 0, ones = 0, neg, lshift = 0; + int is64 = (u64 >> 32) ? A64I_X : 0, i = is64 ? 4 : 2; + /* Count non-homogeneous 16 bit fragments. */ + while (--i >= 0) { + uint32_t frag = (u64 >> i*16) & 0xffff; + zeros += (frag != 0); + ones += (frag != 0xffff); } - neg = ones > zeros; /* Use MOVN if it pays off. */ - if ((neg ? ones : zeros) < 3) { /* Need 2+ ins. Try shorter K13 encoding. */ + neg = ones < zeros; /* Use MOVN if it pays off. */ + if ((neg ? ones : zeros) > 1) { /* Need 2+ ins. Try 1 ins encodings. */ uint32_t k13 = emit_isk13(u64, is64); if (k13) { emit_dn(as, (is64|A64I_ORRw)^k13, rd, RID_ZERO); return; } - } - if (!emit_kdelta(as, rd, u64, 4 - (neg ? ones : zeros))) { - int shift = 0, lshift = 0; - uint64_t n64 = neg ? ~u64 : u64; - if (n64 != 0) { - /* Find first/last fragment to be filled. */ - shift = (63-emit_clz64(n64)) & ~15; - lshift = emit_ctz64(n64) & ~15; + if (emit_kdelta(as, rd, u64, is64)) { + return; } - /* MOVK requires the original value (u64). */ - while (shift > lshift) { - uint32_t u16 = (u64 >> shift) & 0xffff; - /* Skip fragments that are correctly filled by MOVN/MOVZ. */ - if (u16 != (neg ? 0xffff : 0)) - emit_d(as, is64 | A64I_MOVKw | A64F_U16(u16) | A64F_LSL16(shift), rd); - shift -= 16; + if (emit_kadrp(as, rd, u64)) { /* Either 1 or 2 ins. */ + return; } - /* But MOVN needs an inverted value (n64). */ - emit_d(as, (neg ? A64I_MOVNx : A64I_MOVZx) | - A64F_U16((n64 >> lshift) & 0xffff) | A64F_LSL16(lshift), rd); } + if (neg) { + u64 = ~u64; + if (!is64) u64 = (uint32_t)u64; + } + if (u64) { + /* Find first/last fragment to be filled. */ + int shift = (63-emit_clz64(u64)) & ~15; + lshift = emit_ctz64(u64) & ~15; + for (; shift > lshift; shift -= 16) { + uint32_t frag = (u64 >> shift) & 0xffff; + if (frag == 0) continue; /* Will be correctly filled by MOVN/MOVZ. */ + if (neg) frag ^= 0xffff; /* MOVK requires the original value. */ + emit_d(as, is64 | A64I_MOVKw | A64F_U16(frag) | A64F_LSL16(shift), rd); + } + } + /* But MOVN needs an inverted value. */ + emit_d(as, is64 | (neg ? A64I_MOVNw : A64I_MOVZw) | + A64F_U16((u64 >> lshift) & 0xffff) | A64F_LSL16(lshift), rd); } /* Load a 32 bit constant into a GPR. */ -#define emit_loadi(as, rd, i) emit_loadk(as, rd, i, 0) +#define emit_loadi(as, rd, i) emit_loadk(as, rd, (uint32_t)i) /* Load a 64 bit constant into a GPR. */ -#define emit_loadu64(as, rd, i) emit_loadk(as, rd, i, A64I_X) - -#define emit_loada(as, r, addr) emit_loadu64(as, (r), (uintptr_t)(addr)) - -#define glofs(as, k) \ - ((intptr_t)((uintptr_t)(k) - (uintptr_t)&J2GG(as->J)->g)) -#define mcpofs(as, k) \ - ((intptr_t)((uintptr_t)(k) - (uintptr_t)(as->mcp - 1))) -#define checkmcpofs(as, k) \ - (A64F_S_OK(mcpofs(as, k)>>2, 19)) +#define emit_loadu64(as, rd, i) emit_loadk(as, rd, i) static Reg ra_allock(ASMState *as, intptr_t k, RegSet allow); /* Get/set from constant pointer. */ static void emit_lsptr(ASMState *as, A64Ins ai, Reg r, void *p) { - /* First, check if ip + offset is in range. */ - if ((ai & 0x00400000) && checkmcpofs(as, p)) { + Reg base = RID_GL; + int64_t ofs = glofs(as, p); + if (emit_checkofs(ai, ofs)) { + /* GL + offset, might subsequently fuse to LDP/STP. */ + } else if (ai == A64I_LDRx && checkmcpofs(as, p)) { + /* IP + offset is cheaper than allock, but address must be in range. */ emit_d(as, A64I_LDRLx | A64F_S19(mcpofs(as, p)>>2), r); - } else { - Reg base = RID_GL; /* Next, try GL + offset. */ - int64_t ofs = glofs(as, p); - if (!emit_checkofs(ai, ofs)) { /* Else split up into base reg + offset. */ - int64_t i64 = i64ptr(p); - base = ra_allock(as, (i64 & ~0x7fffull), rset_exclude(RSET_GPR, r)); - ofs = i64 & 0x7fffull; - } - emit_lso(as, ai, r, base, ofs); + return; + } else { /* Split up into base reg + offset. */ + int64_t i64 = i64ptr(p); + base = ra_allock(as, (i64 & ~0x7fffull), rset_exclude(RSET_GPR, r)); + ofs = i64 & 0x7fffull; } + emit_lso(as, ai, r, base, ofs); } /* Load 64 bit IR constant into register. */ diff --git a/src/3rdparty/luajit/src/lj_err.c b/src/3rdparty/luajit/src/lj_err.c index 6e50cbee..7b11e4d0 100644 --- a/src/3rdparty/luajit/src/lj_err.c +++ b/src/3rdparty/luajit/src/lj_err.c @@ -174,12 +174,15 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) case FRAME_PCALL: /* FF pcall() frame. */ case FRAME_PCALLH: /* FF pcall() frame inside hook. */ if (errcode) { + global_State *g; if (errcode == LUA_YIELD) { frame = frame_prevd(frame); break; } + g = G(L); + setgcref(g->cur_L, obj2gco(L)); if (frame_typep(frame) == FRAME_PCALL) - hook_leave(G(L)); + hook_leave(g); L->base = frame_prevd(frame) + 1; L->cframe = cf; unwindstack(L, L->base); @@ -209,11 +212,6 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) ** from 3rd party docs or must be found by trial-and-error. They really ** don't want you to write your own language-specific exception handler ** or to interact gracefully with MSVC. :-( -** -** Apparently MSVC doesn't call C++ destructors for foreign exceptions -** unless you compile your C++ code with /EHa. Unfortunately this means -** catch (...) also catches things like access violations. The use of -** _set_se_translator doesn't really help, because it requires /EHa, too. */ #define WIN32_LEAN_AND_MEAN @@ -261,6 +259,8 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, { #if LJ_TARGET_X86 void *cf = (char *)f - CFRAME_OFS_SEH; +#elif LJ_TARGET_ARM64 + void *cf = (char *)f - CFRAME_SIZE; #else void *cf = f; #endif @@ -268,11 +268,25 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ + if (rec->ExceptionCode == STATUS_LONGJUMP && + rec->ExceptionRecord && + LJ_EXCODE_CHECK(rec->ExceptionRecord->ExceptionCode)) { + errcode = LJ_EXCODE_ERRCODE(rec->ExceptionRecord->ExceptionCode); + if ((rec->ExceptionFlags & 0x20)) { /* EH_TARGET_UNWIND */ + /* Unwinding is about to finish; revert the ExceptionCode so that + ** RtlRestoreContext does not try to restore from a _JUMP_BUFFER. + */ + rec->ExceptionCode = 0; + } + } /* Unwind internal frames. */ err_unwind(L, cf, errcode); } else { void *cf2 = err_unwind(L, cf, 0); if (cf2) { /* We catch it, so start unwinding the upper frames. */ +#if !LJ_TARGET_X86 + EXCEPTION_RECORD rec2; +#endif if (rec->ExceptionCode == LJ_MSVC_EXCODE || rec->ExceptionCode == LJ_GCC_EXCODE) { #if !LJ_TARGET_CYGWIN @@ -295,14 +309,29 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); /* lj_vm_rtlunwind does not return. */ #else + if (LJ_EXCODE_CHECK(rec->ExceptionCode)) { + /* For unwind purposes, wrap the EXCEPTION_RECORD in something that + ** looks like a longjmp, so that MSVC will execute C++ destructors in + ** the frames we unwind over. ExceptionInformation[0] should really + ** contain a _JUMP_BUFFER*, but hopefully nobody is looking too closely + ** at this point. + */ + rec2.ExceptionCode = STATUS_LONGJUMP; + rec2.ExceptionRecord = rec; + rec2.ExceptionAddress = 0; + rec2.NumberParameters = 1; + rec2.ExceptionInformation[0] = (ULONG_PTR)ctx; + rec = &rec2; + } /* Unwind the stack and call all handlers for all lower C frames ** (including ourselves) again with EH_UNWINDING set. Then set - ** stack pointer = cf, result = errcode and jump to the specified target. + ** stack pointer = f, result = errcode and jump to the specified target. */ - RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? - lj_vm_unwind_ff_eh : - lj_vm_unwind_c_eh), - rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); + RtlUnwindEx(f, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? + lj_vm_unwind_ff_eh : + lj_vm_unwind_c_eh), + rec, (void *)(uintptr_t)errcode, dispatch->ContextRecord, + dispatch->HistoryTable); /* RtlUnwindEx should never return. */ #endif } diff --git a/src/3rdparty/luajit/src/lj_ffrecord.c b/src/3rdparty/luajit/src/lj_ffrecord.c index 8ebf4165..1233e5f7 100644 --- a/src/3rdparty/luajit/src/lj_ffrecord.c +++ b/src/3rdparty/luajit/src/lj_ffrecord.c @@ -1130,7 +1130,7 @@ static TRef recff_sbufx_check(jit_State *J, RecordFFData *rd, ptrdiff_t arg) /* Emit BUFHDR for write to extended string buffer. */ static TRef recff_sbufx_write(jit_State *J, TRef ud) { - TRef trbuf = emitir(IRT(IR_ADD, IRT_PGC), ud, lj_ir_kint(J, sizeof(GCudata))); + TRef trbuf = emitir(IRT(IR_ADD, IRT_PGC), ud, lj_ir_kintpgc(J, sizeof(GCudata))); return emitir(IRT(IR_BUFHDR, IRT_PGC), trbuf, IRBUFHDR_WRITE); } @@ -1164,20 +1164,19 @@ static void LJ_FASTCALL recff_buffer_method_reset(jit_State *J, RecordFFData *rd SBufExt *sbx = bufV(&rd->argv[0]); int iscow = (int)sbufiscow(sbx); TRef trl = recff_sbufx_get_L(J, ud); - TRef trcow = emitir(IRT(IR_BAND, IRT_IGC), trl, lj_ir_kint(J, SBUF_FLAG_COW)); - TRef zero = lj_ir_kint(J, 0); - emitir(IRTG(iscow ? IR_NE : IR_EQ, IRT_IGC), trcow, zero); + TRef trcow = emitir(IRT(IR_BAND, IRT_IGC), trl, lj_ir_kintpgc(J, SBUF_FLAG_COW)); + TRef zeropgc = lj_ir_kintpgc(J, 0); + emitir(IRTG(iscow ? IR_NE : IR_EQ, IRT_IGC), trcow, zeropgc); if (iscow) { - trl = emitir(IRT(IR_BXOR, IRT_IGC), trl, - LJ_GC64 ? lj_ir_kint64(J, SBUF_FLAG_COW) : - lj_ir_kint(J, SBUF_FLAG_COW)); - recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, zero); - recff_sbufx_set_ptr(J, ud, IRFL_SBUF_E, zero); - recff_sbufx_set_ptr(J, ud, IRFL_SBUF_B, zero); + TRef zerop = lj_ir_kintp(J, 0); + trl = emitir(IRT(IR_BXOR, IRT_IGC), trl, lj_ir_kintpgc(J, SBUF_FLAG_COW)); + recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, zerop); + recff_sbufx_set_ptr(J, ud, IRFL_SBUF_E, zerop); + recff_sbufx_set_ptr(J, ud, IRFL_SBUF_B, zerop); recff_sbufx_set_L(J, ud, trl); emitir(IRT(IR_FSTORE, IRT_PGC), - emitir(IRT(IR_FREF, IRT_PGC), ud, IRFL_SBUF_REF), zero); - recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, zero); + emitir(IRT(IR_FREF, IRT_PGC), ud, IRFL_SBUF_REF), zeropgc); + recff_sbufx_set_ptr(J, ud, IRFL_SBUF_R, zerop); } else { TRef trb = recff_sbufx_get_ptr(J, ud, IRFL_SBUF_B); recff_sbufx_set_ptr(J, ud, IRFL_SBUF_W, trb); diff --git a/src/3rdparty/luajit/src/lj_ir.h b/src/3rdparty/luajit/src/lj_ir.h index b32bd095..dbfba258 100644 --- a/src/3rdparty/luajit/src/lj_ir.h +++ b/src/3rdparty/luajit/src/lj_ir.h @@ -76,8 +76,8 @@ \ _(ABS, N , ref, ref) \ _(LDEXP, N , ref, ref) \ - _(MIN, C , ref, ref) \ - _(MAX, C , ref, ref) \ + _(MIN, N , ref, ref) \ + _(MAX, N , ref, ref) \ _(FPMATH, N , ref, lit) \ \ /* Overflow-checking arithmetic ops. */ \ diff --git a/src/3rdparty/luajit/src/lj_ircall.h b/src/3rdparty/luajit/src/lj_ircall.h index 569134e9..f342cdd2 100644 --- a/src/3rdparty/luajit/src/lj_ircall.h +++ b/src/3rdparty/luajit/src/lj_ircall.h @@ -63,7 +63,7 @@ typedef struct CCallInfo { /* Helpers for conditional function definitions. */ #define IRCALLCOND_ANY(x) x -#if LJ_TARGET_X86ORX64 +#if LJ_TARGET_X86ORX64 || LJ_TARGET_ARM64 #define IRCALLCOND_FPMATH(x) NULL #else #define IRCALLCOND_FPMATH(x) x diff --git a/src/3rdparty/luajit/src/lj_iropt.h b/src/3rdparty/luajit/src/lj_iropt.h index 458a5511..a71a717b 100644 --- a/src/3rdparty/luajit/src/lj_iropt.h +++ b/src/3rdparty/luajit/src/lj_iropt.h @@ -56,6 +56,12 @@ LJ_FUNC TRef lj_ir_ktrace(jit_State *J); #define lj_ir_kintp(J, k) lj_ir_kint(J, (int32_t)(k)) #endif +#if LJ_GC64 +#define lj_ir_kintpgc lj_ir_kintp +#else +#define lj_ir_kintpgc lj_ir_kint +#endif + static LJ_AINLINE TRef lj_ir_knum(jit_State *J, lua_Number n) { TValue tv; diff --git a/src/3rdparty/luajit/src/lj_mcode.c b/src/3rdparty/luajit/src/lj_mcode.c index 94767937..8a4851dd 100644 --- a/src/3rdparty/luajit/src/lj_mcode.c +++ b/src/3rdparty/luajit/src/lj_mcode.c @@ -29,6 +29,11 @@ #include #endif +#if LJ_TARGET_WINDOWS +#define WIN32_LEAN_AND_MEAN +#include +#endif + #if LJ_TARGET_IOS void sys_icache_invalidate(void *start, size_t len); #endif @@ -41,6 +46,8 @@ void lj_mcode_sync(void *start, void *end) #endif #if LJ_TARGET_X86ORX64 UNUSED(start); UNUSED(end); +#elif LJ_TARGET_WINDOWS + FlushInstructionCache(GetCurrentProcess(), start, (char *)end-(char *)start); #elif LJ_TARGET_IOS sys_icache_invalidate(start, (char *)end-(char *)start); #elif LJ_TARGET_PPC @@ -58,9 +65,6 @@ void lj_mcode_sync(void *start, void *end) #if LJ_TARGET_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include - #define MCPROT_RW PAGE_READWRITE #define MCPROT_RX PAGE_EXECUTE_READ #define MCPROT_RWX PAGE_EXECUTE_READWRITE @@ -363,7 +367,7 @@ void lj_mcode_limiterr(jit_State *J, size_t need) sizemcode = (size_t)J->param[JIT_P_sizemcode] << 10; sizemcode = (sizemcode + LJ_PAGESIZE-1) & ~(size_t)(LJ_PAGESIZE - 1); maxmcode = (size_t)J->param[JIT_P_maxmcode] << 10; - if ((size_t)need > sizemcode) + if (need * sizeof(MCode) > sizemcode) lj_trace_err(J, LJ_TRERR_MCODEOV); /* Too long for any area. */ if (J->szallmcarea + sizemcode > maxmcode) lj_trace_err(J, LJ_TRERR_MCODEAL); diff --git a/src/3rdparty/luajit/src/lj_opt_dce.c b/src/3rdparty/luajit/src/lj_opt_dce.c index c6c3e1bc..e6fcc552 100644 --- a/src/3rdparty/luajit/src/lj_opt_dce.c +++ b/src/3rdparty/luajit/src/lj_opt_dce.c @@ -44,12 +44,12 @@ static void dce_propagate(jit_State *J) IRIns *ir = IR(ins); if (irt_ismarked(ir->t)) { irt_clearmark(ir->t); - pchain[ir->o] = &ir->prev; } else if (!ir_sideeff(ir)) { *pchain[ir->o] = ir->prev; /* Reroute original instruction chain. */ lj_ir_nop(ir); continue; } + pchain[ir->o] = &ir->prev; if (ir->op1 >= REF_FIRST) irt_setmark(IR(ir->op1)->t); if (ir->op2 >= REF_FIRST) irt_setmark(IR(ir->op2)->t); } diff --git a/src/3rdparty/luajit/src/lj_opt_fold.c b/src/3rdparty/luajit/src/lj_opt_fold.c index 48effb8a..743dfb07 100644 --- a/src/3rdparty/luajit/src/lj_opt_fold.c +++ b/src/3rdparty/luajit/src/lj_opt_fold.c @@ -377,10 +377,10 @@ static uint64_t kfold_int64arith(jit_State *J, uint64_t k1, uint64_t k2, case IR_BOR: k1 |= k2; break; case IR_BXOR: k1 ^= k2; break; case IR_BSHL: k1 <<= (k2 & 63); break; - case IR_BSHR: k1 = (int32_t)((uint32_t)k1 >> (k2 & 63)); break; - case IR_BSAR: k1 >>= (k2 & 63); break; - case IR_BROL: k1 = (int32_t)lj_rol((uint32_t)k1, (k2 & 63)); break; - case IR_BROR: k1 = (int32_t)lj_ror((uint32_t)k1, (k2 & 63)); break; + case IR_BSHR: k1 >>= (k2 & 63); break; + case IR_BSAR: k1 = (uint64_t)((int64_t)k1 >> (k2 & 63)); break; + case IR_BROL: k1 = lj_rol(k1, (k2 & 63)); break; + case IR_BROR: k1 = lj_ror(k1, (k2 & 63)); break; default: lj_assertJ(0, "bad IR op %d", op); break; } #else @@ -1972,7 +1972,10 @@ LJFOLD(NE any any) LJFOLDF(comm_equal) { /* For non-numbers only: x == x ==> drop; x ~= x ==> fail */ - if (fins->op1 == fins->op2 && !irt_isnum(fins->t)) + if (fins->op1 == fins->op2 && + (!irt_isnum(fins->t) || + (fleft->o == IR_CONV && /* Converted integers cannot be NaN. */ + (uint32_t)(fleft->op2 & IRCONV_SRCMASK) - (uint32_t)IRT_I8 <= (uint32_t)(IRT_U64 - IRT_U8)))) return CONDFOLD(fins->o == IR_EQ); return fold_comm_swap(J); } diff --git a/src/3rdparty/luajit/src/lj_record.c b/src/3rdparty/luajit/src/lj_record.c index 9d0021a6..d44f7737 100644 --- a/src/3rdparty/luajit/src/lj_record.c +++ b/src/3rdparty/luajit/src/lj_record.c @@ -1599,10 +1599,16 @@ TRef lj_record_idx(jit_State *J, RecordIndex *ix) lj_assertJ(!hasmm, "inconsistent metamethod handling"); if (oldv == niltvg(J2G(J))) { /* Need to insert a new key. */ TRef key = ix->key; - if (tref_isinteger(key)) /* NEWREF needs a TValue as a key. */ + if (tref_isinteger(key)) { /* NEWREF needs a TValue as a key. */ key = emitir(IRTN(IR_CONV), key, IRCONV_NUM_INT); - else if (tref_isnumber(key) && tref_isk(key) && tvismzero(&ix->keyv)) - key = lj_ir_knum_zero(J); /* Canonicalize -0.0 to +0.0. */ + } else if (tref_isnum(key)) { + if (tref_isk(key)) { + if (tvismzero(&ix->keyv)) + key = lj_ir_knum_zero(J); /* Canonicalize -0.0 to +0.0. */ + } else { + emitir(IRTG(IR_EQ, IRT_NUM), key, key); /* Check for !NaN. */ + } + } xref = emitir(IRT(IR_NEWREF, IRT_PGC), ix->tab, key); keybarrier = 0; /* NEWREF already takes care of the key barrier. */ #ifdef LUAJIT_ENABLE_TABLE_BUMP @@ -1775,7 +1781,7 @@ static TRef rec_upvalue(jit_State *J, uint32_t uv, TRef val) emitir(IRTG(IR_EQ, IRT_PGC), REF_BASE, emitir(IRT(IR_ADD, IRT_PGC), uref, - lj_ir_kint(J, (slot - 1 - LJ_FR2) * -8))); + lj_ir_kintpgc(J, (slot - 1 - LJ_FR2) * -8))); slot -= (int32_t)J->baseslot; /* Note: slot number may be negative! */ if (val == 0) { return getslot(J, slot); @@ -1788,7 +1794,7 @@ static TRef rec_upvalue(jit_State *J, uint32_t uv, TRef val) } emitir(IRTG(IR_UGT, IRT_PGC), emitir(IRT(IR_SUB, IRT_PGC), uref, REF_BASE), - lj_ir_kint(J, (J->baseslot + J->maxslot) * 8)); + lj_ir_kintpgc(J, (J->baseslot + J->maxslot) * 8)); } else { needbarrier = 1; uref = tref_ref(emitir(IRTG(IR_UREFC, IRT_PGC), fn, uv)); @@ -1966,7 +1972,8 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults) emitir(IRTGI(IR_EQ), fr, lj_ir_kint(J, (int32_t)frame_ftsz(J->L->base-1))); vbase = emitir(IRT(IR_SUB, IRT_IGC), REF_BASE, fr); - vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase, lj_ir_kint(J, frofs-8*(1+LJ_FR2))); + vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase, + lj_ir_kintpgc(J, frofs-8*(1+LJ_FR2))); for (i = 0; i < nload; i++) { IRType t = itype2irt(&J->L->base[i-1-LJ_FR2-nvararg]); J->base[dst+i] = lj_record_vload(J, vbase, (MSize)i, t); @@ -1985,8 +1992,11 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults) TRef tr = TREF_NIL; ptrdiff_t idx = lj_ffrecord_select_mode(J, tridx, &J->L->base[dst-1]); if (idx < 0) goto nyivarg; - if (idx != 0 && !tref_isinteger(tridx)) + if (idx != 0 && !tref_isinteger(tridx)) { + if (tref_isstr(tridx)) + tridx = emitir(IRTG(IR_STRTO, IRT_NUM), tridx, 0); tridx = emitir(IRTGI(IR_CONV), tridx, IRCONV_INT_NUM|IRCONV_INDEX); + } if (idx != 0 && tref_isk(tridx)) { emitir(IRTGI(idx <= nvararg ? IR_GE : IR_LT), fr, lj_ir_kint(J, frofs+8*(int32_t)idx)); @@ -2014,7 +2024,7 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults) IRType t; TRef aref, vbase = emitir(IRT(IR_SUB, IRT_IGC), REF_BASE, fr); vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase, - lj_ir_kint(J, frofs-(8<L->base[idx-2-LJ_FR2-nvararg]); aref = emitir(IRT(IR_AREF, IRT_PGC), vbase, tridx); tr = lj_record_vload(J, aref, 0, t); diff --git a/src/3rdparty/luajit/src/lj_state.c b/src/3rdparty/luajit/src/lj_state.c index b45a2043..6efe189d 100644 --- a/src/3rdparty/luajit/src/lj_state.c +++ b/src/3rdparty/luajit/src/lj_state.c @@ -103,8 +103,17 @@ void lj_state_shrinkstack(lua_State *L, MSize used) void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need) { MSize n; - if (L->stacksize > LJ_STACK_MAXEX) /* Overflow while handling overflow? */ - lj_err_throw(L, LUA_ERRERR); + if (L->stacksize >= LJ_STACK_MAXEX) { + /* 4. Throw 'error in error handling' when we are _over_ the limit. */ + if (L->stacksize > LJ_STACK_MAXEX) + lj_err_throw(L, LUA_ERRERR); /* Does not invoke an error handler. */ + /* 1. We are _at_ the limit after the last growth. */ + if (L->status < LUA_ERRRUN) { /* 2. Throw 'stack overflow'. */ + L->status = LUA_ERRRUN; /* Prevent ending here again for pushed msg. */ + lj_err_msg(L, LJ_ERR_STKOV); /* May invoke an error handler. */ + } + /* 3. Add space (over the limit) for pushed message and error handler. */ + } n = L->stacksize + need; if (n > LJ_STACK_MAX) { n += 2*LUA_MINSTACK; @@ -114,8 +123,6 @@ void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need) n = LJ_STACK_MAX; } resizestack(L, n); - if (L->stacksize >= LJ_STACK_MAXEX) - lj_err_msg(L, LJ_ERR_STKOV); } void LJ_FASTCALL lj_state_growstack1(lua_State *L) @@ -123,6 +130,18 @@ void LJ_FASTCALL lj_state_growstack1(lua_State *L) lj_state_growstack(L, 1); } +static TValue *cpgrowstack(lua_State *co, lua_CFunction dummy, void *ud) +{ + UNUSED(dummy); + lj_state_growstack(co, *(MSize *)ud); + return NULL; +} + +int LJ_FASTCALL lj_state_cpgrowstack(lua_State *L, MSize need) +{ + return lj_vm_cpcall(L, NULL, &need, cpgrowstack); +} + /* Allocate basic stack for new state. */ static void stack_init(lua_State *L1, lua_State *L) { diff --git a/src/3rdparty/luajit/src/lj_state.h b/src/3rdparty/luajit/src/lj_state.h index db67f03b..3850e5a1 100644 --- a/src/3rdparty/luajit/src/lj_state.h +++ b/src/3rdparty/luajit/src/lj_state.h @@ -18,6 +18,7 @@ LJ_FUNC void lj_state_relimitstack(lua_State *L); LJ_FUNC void lj_state_shrinkstack(lua_State *L, MSize used); LJ_FUNCA void LJ_FASTCALL lj_state_growstack(lua_State *L, MSize need); LJ_FUNC void LJ_FASTCALL lj_state_growstack1(lua_State *L); +LJ_FUNC int LJ_FASTCALL lj_state_cpgrowstack(lua_State *L, MSize need); static LJ_AINLINE void lj_state_checkstack(lua_State *L, MSize need) { diff --git a/src/3rdparty/luajit/src/lj_target.h b/src/3rdparty/luajit/src/lj_target.h index 09d19bd9..e7322c07 100644 --- a/src/3rdparty/luajit/src/lj_target.h +++ b/src/3rdparty/luajit/src/lj_target.h @@ -58,9 +58,13 @@ typedef uint32_t RegSP; #if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 typedef uint64_t RegSet; #define RSET_BITS 6 +#define rset_picktop_(rs) ((Reg)lj_fls64(rs)) +#define rset_pickbot_(rs) ((Reg)lj_ffs64(rs)) #else typedef uint32_t RegSet; #define RSET_BITS 5 +#define rset_picktop_(rs) ((Reg)lj_fls(rs)) +#define rset_pickbot_(rs) ((Reg)lj_ffs(rs)) #endif #define RID2RSET(r) (((RegSet)1) << (r)) @@ -71,13 +75,6 @@ typedef uint32_t RegSet; #define rset_set(rs, r) (rs |= RID2RSET(r)) #define rset_clear(rs, r) (rs &= ~RID2RSET(r)) #define rset_exclude(rs, r) (rs & ~RID2RSET(r)) -#if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 -#define rset_picktop_(rs) ((Reg)(__builtin_clzll(rs)^63)) -#define rset_pickbot_(rs) ((Reg)__builtin_ctzll(rs)) -#else -#define rset_picktop_(rs) ((Reg)lj_fls(rs)) -#define rset_pickbot_(rs) ((Reg)lj_ffs(rs)) -#endif /* -- Register allocation cost -------------------------------------------- */ diff --git a/src/3rdparty/luajit/src/lj_target_arm64.h b/src/3rdparty/luajit/src/lj_target_arm64.h index 65a14307..c34f1e59 100644 --- a/src/3rdparty/luajit/src/lj_target_arm64.h +++ b/src/3rdparty/luajit/src/lj_target_arm64.h @@ -234,6 +234,8 @@ typedef enum A64Ins { A64I_MOVZx = 0xd2800000, A64I_MOVNw = 0x12800000, A64I_MOVNx = 0x92800000, + A64I_ADR = 0x10000000, + A64I_ADRP = 0x90000000, A64I_LDRB = 0x39400000, A64I_LDRH = 0x79400000, diff --git a/src/3rdparty/luajit/src/lj_trace.c b/src/3rdparty/luajit/src/lj_trace.c index f311d54b..fee78e2e 100644 --- a/src/3rdparty/luajit/src/lj_trace.c +++ b/src/3rdparty/luajit/src/lj_trace.c @@ -613,21 +613,27 @@ static int trace_abort(jit_State *J) J->cur.link = 0; J->cur.linktype = LJ_TRLINK_NONE; lj_vmevent_send(L, TRACE, - TValue *frame; + cTValue *bot = tvref(L->stack)+LJ_FR2; + cTValue *frame; const BCIns *pc; - GCfunc *fn; + BCPos pos = 0; setstrV(L, L->top++, lj_str_newlit(L, "abort")); setintV(L->top++, traceno); /* Find original Lua function call to generate a better error message. */ - frame = J->L->base-1; - pc = J->pc; - while (!isluafunc(frame_func(frame))) { - pc = (frame_iscont(frame) ? frame_contpc(frame) : frame_pc(frame)) - 1; - frame = frame_prev(frame); + for (frame = J->L->base-1, pc = J->pc; ; frame = frame_prev(frame)) { + if (isluafunc(frame_func(frame))) { + pos = proto_bcpos(funcproto(frame_func(frame)), pc); + break; + } else if (frame_prev(frame) <= bot) { + break; + } else if (frame_iscont(frame)) { + pc = frame_contpc(frame) - 1; + } else { + pc = frame_pc(frame) - 1; + } } - fn = frame_func(frame); - setfuncV(L, L->top++, fn); - setintV(L->top++, proto_bcpos(funcproto(fn), pc)); + setfuncV(L, L->top++, frame_func(frame)); + setintV(L->top++, pos); copyTV(L, L->top++, restorestack(L, errobj)); copyTV(L, L->top++, &J->errinfo); ); diff --git a/src/3rdparty/luajit/src/msvcbuild.bat b/src/3rdparty/luajit/src/msvcbuild.bat index f9bf2528..cd25beee 100644 --- a/src/3rdparty/luajit/src/msvcbuild.bat +++ b/src/3rdparty/luajit/src/msvcbuild.bat @@ -27,39 +27,52 @@ @set BUILDTYPE=release @set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c +@setlocal +@call :SETHOSTVARS %LJCOMPILE% host\minilua.c @if errorlevel 1 goto :BAD %LJLINK% /out:minilua.exe minilua.obj @if errorlevel 1 goto :BAD if exist minilua.exe.manifest^ %LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe +@endlocal -@set DASMFLAGS=-D WIN -D JIT -D FFI -D P64 +@set DASMFLAGS=-D WIN -D JIT -D FFI -D ENDIAN_LE -D FPU -D P64 @set LJARCH=x64 @minilua -@if errorlevel 8 goto :X64 +@if errorlevel 8 goto :NO32 @set DASC=vm_x86.dasc -@set DASMFLAGS=-D WIN -D JIT -D FFI +@set DASMFLAGS=-D WIN -D JIT -D FFI -D ENDIAN_LE -D FPU @set LJARCH=x86 @set LJCOMPILE=%LJCOMPILE% /arch:SSE2 +@goto :DA +:NO32 +@if "%VSCMD_ARG_TGT_ARCH%" neq "arm64" goto :X64 +@set DASC=vm_arm64.dasc +@set DASMTARGET=-D LUAJIT_TARGET=LUAJIT_ARCH_ARM64 +@set LJARCH=arm64 +@goto :DA :X64 -@if "%1" neq "nogc64" goto :GC64 +@if "%1" neq "nogc64" goto :DA @shift @set DASC=vm_x86.dasc @set LJCOMPILE=%LJCOMPILE% /DLUAJIT_DISABLE_GC64 -:GC64 +:DA minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h %DASC% @if errorlevel 1 goto :BAD if exist ..\.git ( git show -s --format=%%ct >luajit_relver.txt ) else ( type ..\.relver >luajit_relver.txt ) minilua host\genversion.lua -%LJCOMPILE% /I "." /I %DASMDIR% host\buildvm*.c +@setlocal +@call :SETHOSTVARS +%LJCOMPILE% /I "." /I %DASMDIR% %DASMTARGET% host\buildvm*.c @if errorlevel 1 goto :BAD %LJLINK% /out:buildvm.exe buildvm*.obj @if errorlevel 1 goto :BAD if exist buildvm.exe.manifest^ %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe +@endlocal buildvm -m peobj -o lj_vm.obj @if errorlevel 1 goto :BAD @@ -118,6 +131,12 @@ if exist luajit.exe.manifest^ @echo. @echo === Successfully built LuaJIT for Windows/%LJARCH% === +@goto :END +:SETHOSTVARS +@if "%VSCMD_ARG_HOST_ARCH%_%VSCMD_ARG_TGT_ARCH%" equ "x64_arm64" ( + call "%VSINSTALLDIR%Common7\Tools\VsDevCmd.bat" -arch=%VSCMD_ARG_HOST_ARCH% -no_logo + echo on +) @goto :END :BAD @echo. diff --git a/src/3rdparty/luajit/src/vm_arm64.dasc b/src/3rdparty/luajit/src/vm_arm64.dasc index 698b4210..2aaa64cb 100644 --- a/src/3rdparty/luajit/src/vm_arm64.dasc +++ b/src/3rdparty/luajit/src/vm_arm64.dasc @@ -113,13 +113,37 @@ | |.define TMPDofs, #24 | +|.if WIN +|// Windows unwind data is suited to r1 stored first. +|.macro stp_unwind, r1, r2, where +| stp r1, r2, where +|.endmacro +|.macro ldp_unwind, r1, r2, where +| ldp r1, r2, where +|.endmacro +|.macro ldp_unwind, r1, r2, where, post_index +| ldp r1, r2, where, post_index +|.endmacro +|.else +|// Otherwise store r2 first for compact unwind info (OSX). +|.macro stp_unwind, r1, r2, where +| stp r2, r1, where +|.endmacro +|.macro ldp_unwind, r1, r2, where +| ldp r2, r1, where +|.endmacro +|.macro ldp_unwind, r1, r2, where, post_index +| ldp r2, r1, where, post_index +|.endmacro +|.endif +| |.macro save_, gpr1, gpr2, fpr1, fpr2 -| stp d..fpr2, d..fpr1, [sp, # SAVE_FPR_+(14-fpr1)*8] -| stp x..gpr2, x..gpr1, [sp, # SAVE_GPR_+(27-gpr1)*8] +| stp_unwind d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(14-fpr1)*8] +| stp_unwind x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(27-gpr1)*8] |.endmacro |.macro rest_, gpr1, gpr2, fpr1, fpr2 -| ldp d..fpr2, d..fpr1, [sp, # SAVE_FPR_+(14-fpr1)*8] -| ldp x..gpr2, x..gpr1, [sp, # SAVE_GPR_+(27-gpr1)*8] +| ldp_unwind d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(14-fpr1)*8] +| ldp_unwind x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(27-gpr1)*8] |.endmacro | |.macro saveregs @@ -127,14 +151,14 @@ | sub sp, sp, # CFRAME_SPACE | stp fp, lr, [sp, # SAVE_FP_LR_] | add fp, sp, # SAVE_FP_LR_ -| stp x20, x19, [sp, # SAVE_GPR_+(27-19)*8] +| stp_unwind x19, x20, [sp, # SAVE_GPR_+(27-19)*8] | save_ 21, 22, 8, 9 | save_ 23, 24, 10, 11 | save_ 25, 26, 12, 13 | save_ 27, 28, 14, 15 |.endmacro |.macro restoreregs -| ldp x20, x19, [sp, # SAVE_GPR_+(27-19)*8] +| ldp_unwind x19, x20, [sp, # SAVE_GPR_+(27-19)*8] | rest_ 21, 22, 8, 9 | rest_ 23, 24, 10, 11 | rest_ 25, 26, 12, 13 @@ -267,8 +291,17 @@ | blo target |.endmacro | +|.macro init_constants +| movn TISNIL, #0 +| movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 +| movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 +|.endmacro +| |.macro mov_false, reg; movn reg, #0x8000, lsl #32; .endmacro |.macro mov_true, reg; movn reg, #0x0001, lsl #48; .endmacro +|.macro mov_nil, reg; mov reg, TISNIL; .endmacro +|.macro cmp_nil, reg; cmp reg, TISNIL; .endmacro +|.macro add_TISNUM, dst, src; add dst, src, TISNUM; .endmacro | #define GL_J(field) (GG_G2J + (int)offsetof(jit_State, field)) | @@ -406,26 +439,26 @@ static void build_subroutines(BuildCtx *ctx) | |->vm_unwind_c: // Unwind C stack, return from vm_pcall. | // (void *cframe, int errcode) + | add fp, CARG1, # SAVE_FP_LR_ | mov sp, CARG1 | mov CRET1, CARG2 - |->vm_unwind_c_eh: // Landing pad for external unwinder. | ldr L, SAVE_L - | mv_vmstate TMP0w, C | ldr GL, L->glref + |->vm_unwind_c_eh: // Landing pad for external unwinder. + | mv_vmstate TMP0w, C | st_vmstate TMP0w | b ->vm_leave_unw | |->vm_unwind_ff: // Unwind C stack, return from ff pcall. | // (void *cframe) - | and sp, CARG1, #CFRAME_RAWMASK - |->vm_unwind_ff_eh: // Landing pad for external unwinder. + | add fp, CARG1, # SAVE_FP_LR_ + | mov sp, CARG1 | ldr L, SAVE_L - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | movn TISNIL, #0 + | init_constants + | ldr GL, L->glref // Setup pointer to global state. + |->vm_unwind_ff_eh: // Landing pad for external unwinder. | mov RC, #16 // 2 results: false + error message. | ldr BASE, L->base - | ldr GL, L->glref // Setup pointer to global state. | mov_false TMP0 | sub RA, BASE, #8 // Results start at BASE-8. | ldr PC, [BASE, FRAME_PC] // Fetch PC of previous frame. @@ -486,11 +519,9 @@ static void build_subroutines(BuildCtx *ctx) | str L, GL->cur_L | mov RA, BASE | ldp BASE, CARG1, L->base - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 + | init_constants | ldr PC, [BASE, FRAME_PC] | strb wzr, L->status - | movn TISNIL, #0 | sub RC, CARG1, BASE | ands CARG1, PC, #FRAME_TYPE | add RC, RC, #8 @@ -526,10 +557,8 @@ static void build_subroutines(BuildCtx *ctx) |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype). | str L, GL->cur_L | ldp RB, CARG1, L->base // RB = old base (for vmeta_call). - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 | add PC, PC, BASE - | movn TISNIL, #0 + | init_constants | sub PC, PC, RB // PC = frame delta + frame type | sub NARGS8:RC, CARG1, BASE | st_vmstate ST_INTERP @@ -638,7 +667,7 @@ static void build_subroutines(BuildCtx *ctx) | b >1 | |->vmeta_tgetb: // RB = table, RC = index - | add RC, RC, TISNUM + | add_TISNUM RC, RC | add CARG2, BASE, RB, lsl #3 | add CARG3, sp, TMPDofs | str RC, TMPD @@ -673,7 +702,7 @@ static void build_subroutines(BuildCtx *ctx) | sxtw CARG2, TMP1w | bl extern lj_tab_getinth // (GCtab *t, int32_t key) | // Returns cTValue * or NULL. - | mov TMP0, TISNIL + | mov_nil TMP0 | cbz CRET1, ->BC_TGETR_Z | ldr TMP0, [CRET1] | b ->BC_TGETR_Z @@ -696,7 +725,7 @@ static void build_subroutines(BuildCtx *ctx) | b >1 | |->vmeta_tsetb: // RB = table, RC = index - | add RC, RC, TISNUM + | add_TISNUM RC, RC | add CARG2, BASE, RB, lsl #3 | add CARG3, sp, TMPDofs | str RC, TMPD @@ -1010,7 +1039,7 @@ static void build_subroutines(BuildCtx *ctx) |1: // Field metatable must be at same offset for GCtab and GCudata! | ldr TAB:RB, TAB:CARG1->metatable |2: - | mov CARG1, TISNIL + | mov_nil CARG1 | ldr STR:RC, GL->gcroot[GCROOT_MMNAME+MM_metatable] | cbz TAB:RB, ->fff_restv | ldr TMP1w, TAB:RB->hmask @@ -1032,7 +1061,7 @@ static void build_subroutines(BuildCtx *ctx) | movk CARG1, #(LJ_TTAB>>1)&0xffff, lsl #48 | b ->fff_restv |5: - | cmp TMP0, TISNIL + | cmp_nil TMP0 | bne ->fff_restv | b <4 | @@ -1132,8 +1161,8 @@ static void build_subroutines(BuildCtx *ctx) | cbnz TAB:CARG2, ->fff_fallback #endif | mov RC, #(3+1)*8 - | stp CARG1, TISNIL, [BASE, #-8] - | str CFUNC:CARG4, [BASE, #-16] + | stp CFUNC:CARG4, CARG1, [BASE, #-16] + | str TISNIL, [BASE] | b ->fff_res | |.ffunc_2 ipairs_aux @@ -1145,14 +1174,14 @@ static void build_subroutines(BuildCtx *ctx) | add CARG2w, CARG2w, #1 | cmp CARG2w, TMP1w | ldr PC, [BASE, FRAME_PC] - | add TMP2, CARG2, TISNUM + | add_TISNUM TMP2, CARG2 | mov RC, #(0+1)*8 | str TMP2, [BASE, #-16] | bhs >2 // Not in array part? | ldr TMP0, [CARG3, CARG2, lsl #3] |1: | mov TMP1, #(2+1)*8 - | cmp TMP0, TISNIL + | cmp_nil TMP0 | str TMP0, [BASE, #-8] | csel RC, RC, TMP1, eq | b ->fff_res @@ -1175,8 +1204,8 @@ static void build_subroutines(BuildCtx *ctx) | cbnz TAB:CARG2, ->fff_fallback #endif | mov RC, #(3+1)*8 - | stp CARG1, TISNUM, [BASE, #-8] - | str CFUNC:CARG4, [BASE, #-16] + | stp CFUNC:CARG4, CARG1, [BASE, #-16] + | str TISNUM, [BASE] | b ->fff_res | |//-- Base library: catch errors ---------------------------------------- @@ -1366,7 +1395,7 @@ static void build_subroutines(BuildCtx *ctx) | eor CARG2w, CARG1w, CARG1w, asr #31 | movz CARG3, #0x41e0, lsl #48 // 2^31. | subs CARG1w, CARG2w, CARG1w, asr #31 - | add CARG1, CARG1, TISNUM + | add_TISNUM CARG1, CARG1 | csel CARG1, CARG1, CARG3, pl | // Fallthrough. | @@ -1457,7 +1486,7 @@ static void build_subroutines(BuildCtx *ctx) | ldr PC, [BASE, FRAME_PC] | str d0, [BASE, #-16] | mov RC, #(2+1)*8 - | add CARG2, CARG2, TISNUM + | add_TISNUM CARG2, CARG2 | str CARG2, [BASE, #-8] | b ->fff_res | @@ -1523,7 +1552,7 @@ static void build_subroutines(BuildCtx *ctx) | bne ->fff_fallback | ldrb TMP0w, STR:CARG1[1] // Access is always ok (NUL at end). | ldr CARG3w, STR:CARG1->len - | add TMP0, TMP0, TISNUM + | add_TISNUM TMP0, TMP0 | str TMP0, [BASE, #-16] | mov RC, #(0+1)*8 | cbz CARG3, ->fff_res @@ -1669,17 +1698,17 @@ static void build_subroutines(BuildCtx *ctx) |.ffunc_bit tobit | mov TMP0w, CARG1w |9: // Label reused by .ffunc_bit_op users. - | add CARG1, TMP0, TISNUM + | add_TISNUM CARG1, TMP0 | b ->fff_restv | |.ffunc_bit bswap | rev TMP0w, CARG1w - | add CARG1, TMP0, TISNUM + | add_TISNUM CARG1, TMP0 | b ->fff_restv | |.ffunc_bit bnot | mvn TMP0w, CARG1w - | add CARG1, TMP0, TISNUM + | add_TISNUM CARG1, TMP0 | b ->fff_restv | |.macro .ffunc_bit_sh, name, ins, shmod @@ -1700,7 +1729,7 @@ static void build_subroutines(BuildCtx *ctx) | checkint CARG1, ->vm_tobit_fb |2: | ins TMP0w, CARG1w, TMP1w - | add CARG1, TMP0, TISNUM + | add_TISNUM CARG1, TMP0 | b ->fff_restv |.endmacro | @@ -1889,8 +1918,7 @@ static void build_subroutines(BuildCtx *ctx) | and CARG3, CARG3, #LJ_GCVMASK | beq >2 |1: // Move results down. - | ldr CARG1, [RA] - | add RA, RA, #8 + | ldr CARG1, [RA], #8 | subs RB, RB, #8 | str CARG1, [BASE, RC, lsl #3] | add RC, RC, #1 @@ -2005,13 +2033,11 @@ static void build_subroutines(BuildCtx *ctx) |.if JIT | ldr L, SAVE_L |1: + | init_constants | cmn CARG1w, #LUA_ERRERR | bhs >9 // Check for error from exit. - | lsl RC, CARG1, #3 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC] - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | movn TISNIL, #0 + | lsl RC, CARG1, #3 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK | str RCw, SAVE_MULTRES | str BASE, L->base @@ -2162,7 +2188,7 @@ static void build_subroutines(BuildCtx *ctx) |//----------------------------------------------------------------------- | |// Handler for callback functions. - |// Saveregs already performed. Callback slot number in [sp], g in r12. + |// Saveregs already performed. Callback slot number in w9, g in x10. |->vm_ffi_callback: |.if FFI |.type CTSTATE, CTState, PC @@ -2186,9 +2212,7 @@ static void build_subroutines(BuildCtx *ctx) | bl extern lj_ccallback_enter // (CTState *cts, void *cf) | // Returns lua_State *. | ldp BASE, RC, L:CRET1->base - | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48 - | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16 - | movn TISNIL, #0 + | init_constants | mov L, CRET1 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] | sub RC, RC, BASE @@ -2215,7 +2239,7 @@ static void build_subroutines(BuildCtx *ctx) |.if FFI | .type CCSTATE, CCallState, x19 | sp_auth - | stp x20, CCSTATE, [sp, #-32]! + | stp_unwind CCSTATE, x20, [sp, #-32]! | stp fp, lr, [sp, #16] | add fp, sp, #16 | mov CCSTATE, x0 @@ -2247,7 +2271,7 @@ static void build_subroutines(BuildCtx *ctx) | stp d0, d1, CCSTATE->fpr[0] | stp d2, d3, CCSTATE->fpr[2] | ldp fp, lr, [sp, #16] - | ldp x20, CCSTATE, [sp], #32 + | ldp_unwind CCSTATE, x20, [sp], #32 | ret_auth |.endif |// Note: vm_ffi_call must be the last function in this object file! @@ -2567,7 +2591,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | bne >5 | negs TMP0w, TMP0w | movz CARG3, #0x41e0, lsl #48 // 2^31. - | add TMP0, TMP0, TISNUM + | add_TISNUM TMP0, TMP0 | csel TMP0, TMP0, CARG3, vc |5: | str TMP0, [BASE, RA, lsl #3] @@ -2582,7 +2606,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | bne >2 | ldr CARG1w, STR:CARG1->len |1: - | add CARG1, CARG1, TISNUM + | add_TISNUM CARG1, CARG1 | str CARG1, [BASE, RA, lsl #3] | ins_next | @@ -2690,7 +2714,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | intins CARG1w, CARG1w, CARG2w | ins_arithfallback bvs |.endif - | add CARG1, CARG1, TISNUM + | add_TISNUM CARG1, CARG1 | str CARG1, [BASE, RA, lsl #3] |4: | ins_next @@ -2783,7 +2807,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) case BC_KSHORT: | // RA = dst, RC = int16_literal | sxth RCw, RCw - | add TMP0, RC, TISNUM + | add_TISNUM TMP0, RC | str TMP0, [BASE, RA, lsl #3] | ins_next break; @@ -3006,7 +3030,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | cmp TMP1w, CARG1w // In array part? | bhs ->vmeta_tgetv | ldr TMP0, [CARG3] - | cmp TMP0, TISNIL + | cmp_nil TMP0 | beq >5 |1: | str TMP0, [BASE, RA, lsl #3] @@ -3049,7 +3073,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | ldr NODE:CARG3, NODE:CARG3->next | cmp CARG1, CARG4 | bne >4 - | cmp TMP0, TISNIL + | cmp_nil TMP0 | beq >5 |3: | str TMP0, [BASE, RA, lsl #3] @@ -3058,7 +3082,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |4: // Follow hash chain. | cbnz NODE:CARG3, <1 | // End of hash chain: key not found, nil result. - | mov TMP0, TISNIL + | mov_nil TMP0 | |5: // Check for __index if table value is nil. | ldr TAB:CARG1, TAB:CARG2->metatable @@ -3079,7 +3103,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | cmp RCw, CARG1w // In array part? | bhs ->vmeta_tgetb | ldr TMP0, [CARG3] - | cmp TMP0, TISNIL + | cmp_nil TMP0 | beq >5 |1: | str TMP0, [BASE, RA, lsl #3] @@ -3126,7 +3150,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | ldr TMP1, [CARG3] | ldr TMP0, [BASE, RA, lsl #3] | ldrb TMP2w, TAB:CARG2->marked - | cmp TMP1, TISNIL // Previous value is nil? + | cmp_nil TMP1 // Previous value is nil? | beq >5 |1: | str TMP0, [CARG3] @@ -3178,7 +3202,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | cmp CARG1, CARG4 | bne >5 | ldr TMP0, [BASE, RA, lsl #3] - | cmp TMP1, TISNIL // Previous value is nil? + | cmp_nil TMP1 // Previous value is nil? | beq >4 |2: | str TMP0, NODE:CARG3->val @@ -3237,7 +3261,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | ldr TMP1, [CARG3] | ldr TMP0, [BASE, RA, lsl #3] | ldrb TMP2w, TAB:CARG2->marked - | cmp TMP1, TISNIL // Previous value is nil? + | cmp_nil TMP1 // Previous value is nil? | beq >5 |1: | str TMP0, [CARG3] @@ -3336,9 +3360,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |->BC_CALL_Z: | mov RB, BASE // Save old BASE for vmeta_call. | add BASE, BASE, RA, lsl #3 - | ldr CARG3, [BASE] + | ldr CARG3, [BASE], #16 | sub NARGS8:RC, NARGS8:RC, #8 - | add BASE, BASE, #16 | checkfunc CARG3, ->vmeta_call | ins_call break; @@ -3354,9 +3377,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | // RA = base, (RB = 0,) RC = (nargs+1)*8 |->BC_CALLT1_Z: | add RA, BASE, RA, lsl #3 - | ldr TMP1, [RA] + | ldr TMP1, [RA], #16 | sub NARGS8:RC, NARGS8:RC, #8 - | add RA, RA, #16 | checktp CARG3, TMP1, LJ_TFUNC, ->vmeta_callt | ldr PC, [BASE, FRAME_PC] |->BC_CALLT2_Z: @@ -3436,10 +3458,10 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | add CARG3, CARG2, CARG1, lsl #3 | bhs >5 // Index points after array part? | ldr TMP0, [CARG3] - | cmp TMP0, TISNIL + | cmp_nil TMP0 | cinc CARG1, CARG1, eq // Skip holes in array part. | beq <1 - | add CARG1, CARG1, TISNUM + | add_TISNUM CARG1, CARG1 | stp CARG1, TMP0, [RA] | add CARG1, CARG1, #1 |3: @@ -3457,7 +3479,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | add NODE:CARG3, NODE:RB, CARG1, lsl #3 // node = tab->node + idx*3*8 | bhi <4 | ldp TMP0, CARG1, NODE:CARG3->val - | cmp TMP0, TISNIL + | cmp_nil TMP0 | add RC, RC, #1 | beq <6 // Skip holes in hash part. | stp CARG1, TMP0, [RA] @@ -3475,8 +3497,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | checkfunc CFUNC:CARG1, >5 | asr TMP0, TAB:CARG3, #47 | ldrb TMP1w, CFUNC:CARG1->ffid - | cmn TMP0, #-LJ_TTAB - | ccmp CARG4, TISNIL, #0, eq + | cmp_nil CARG4 + | ccmn TMP0, #-LJ_TTAB, #0, eq | ccmp TMP1w, #FF_next_N, #0, eq | bne >5 | mov TMP0w, #0xfffe7fff // LJ_KEYINDEX @@ -3516,51 +3538,51 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | and RC, RC, #255 | // RA = base, RB = (nresults+1), RC = numparams | ldr TMP1, [BASE, FRAME_PC] - | add RC, BASE, RC, lsl #3 - | add RA, BASE, RA, lsl #3 - | add RC, RC, #FRAME_VARG - | add TMP2, RA, RB, lsl #3 - | sub RC, RC, TMP1 // RC = vbase - | // Note: RC may now be even _above_ BASE if nargs was < numparams. + | add TMP0, BASE, RC, lsl #3 + | add RC, BASE, RA, lsl #3 // RC = destination + | add TMP0, TMP0, #FRAME_VARG + | add TMP2, RC, RB, lsl #3 + | sub RA, TMP0, TMP1 // RA = vbase + | // Note: RA may now be even _above_ BASE if nargs was < numparams. | sub TMP3, BASE, #16 // TMP3 = vtop | cbz RB, >5 | sub TMP2, TMP2, #16 |1: // Copy vararg slots to destination slots. - | cmp RC, TMP3 - | ldr TMP0, [RC], #8 - | csel TMP0, TMP0, TISNIL, lo - | cmp RA, TMP2 - | str TMP0, [RA], #8 + | cmp RA, TMP3 + | ldr TMP0, [RA], #8 + | csinv TMP0, TMP0, xzr, lo // TISNIL = ~xzr + | cmp RC, TMP2 + | str TMP0, [RC], #8 | blo <1 |2: | ins_next | |5: // Copy all varargs. | ldr TMP0, L->maxstack - | subs TMP2, TMP3, RC + | subs TMP2, TMP3, RA | csel RB, xzr, TMP2, le // MULTRES = (max(vtop-vbase,0)+1)*8 | add RB, RB, #8 - | add TMP1, RA, TMP2 + | add TMP1, RC, TMP2 | str RBw, SAVE_MULTRES | ble <2 // Nothing to copy. | cmp TMP1, TMP0 | bhi >7 |6: - | ldr TMP0, [RC], #8 - | str TMP0, [RA], #8 - | cmp RC, TMP3 + | ldr TMP0, [RA], #8 + | str TMP0, [RC], #8 + | cmp RA, TMP3 | blo <6 | b <2 | |7: // Grow stack for varargs. | lsr CARG2, TMP2, #3 - | stp BASE, RA, L->base + | stp BASE, RC, L->base | mov CARG1, L - | sub RC, RC, BASE // Need delta, because BASE may change. + | sub RA, RA, BASE // Need delta, because BASE may change. | str PC, SAVE_PC | bl extern lj_state_growstack // (lua_State *L, int n) - | ldp BASE, RA, L->base - | add RC, BASE, RC + | ldp BASE, RC, L->base + | add RA, BASE, RA | sub TMP3, BASE, #16 | b <6 break; @@ -3704,7 +3726,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) } else { | adds CARG1w, CARG1w, CARG3w | bvs >2 - | add TMP0, CARG1, TISNUM + | add_TISNUM TMP0, CARG1 | tbnz CARG3w, #31, >4 | cmp CARG1w, CARG2w } @@ -3783,7 +3805,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | // RA = base, RC = target | ldr CARG1, [BASE, RA, lsl #3] | add TMP1, BASE, RA, lsl #3 - | cmp CARG1, TISNIL + | cmp_nil CARG1 | beq >1 // Stop if iterator returned nil. if (op == BC_JITERL) { | str CARG1, [TMP1, #-8] @@ -3816,9 +3838,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |.if JIT | // RA = base (ignored), RC = traceno | ldr CARG1, [GL, #GL_J(trace)] - | mov CARG2w, #0 // Traces on ARM64 don't store the trace #, so use 0. + | st_vmstate wzr // Traces on ARM64 don't store the trace #, so use 0. | ldr TRACE:RC, [CARG1, RC, lsl #3] - | st_vmstate CARG2w |.if PAUTH | ldr RA, TRACE:RC->mcauth |.else @@ -3893,6 +3914,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | add TMP2, BASE, RC | add LFUNC:CARG3, CARG3, TMP0, lsl #47 | add RA, RA, RC + | sub CARG1, CARG1, #8 | add TMP0, RC, #16+FRAME_VARG | str LFUNC:CARG3, [TMP2], #8 // Store (tagged) copy of LFUNC. | ldr KBASE, [PC, #-4+PC2PROTO(k)] diff --git a/src/3rdparty/luajit/src/vm_mips64.dasc b/src/3rdparty/luajit/src/vm_mips64.dasc index 6c215f2b..ef0d901d 100644 --- a/src/3rdparty/luajit/src/vm_mips64.dasc +++ b/src/3rdparty/luajit/src/vm_mips64.dasc @@ -5396,6 +5396,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | settp LFUNC:RB, TMP0 | daddu TMP0, RA, RC | sd LFUNC:RB, 0(TMP1) // Store (tagged) copy of LFUNC. + | daddiu TMP2, TMP2, -8 | daddiu TMP3, RC, 16+FRAME_VARG | sltu AT, TMP0, TMP2 | ld KBASE, -4+PC2PROTO(k)(PC) diff --git a/src/3rdparty/scintilla/src/lexers/LexBash.cxx b/src/3rdparty/scintilla/src/lexers/LexBash.cxx index d853ce68..157af818 100644 --- a/src/3rdparty/scintilla/src/lexers/LexBash.cxx +++ b/src/3rdparty/scintilla/src/lexers/LexBash.cxx @@ -56,15 +56,11 @@ enum class CmdState { Body, Start, Word, - Test, - Arithmetic, - Delimiter, -}; - -enum class TestExprType { Test, // test - DoubleBracket, // [[]] SingleBracket, // [] + DoubleBracket, // [[]] + Arithmetic, + Delimiter, }; enum class CommandSubstitution { @@ -474,7 +470,7 @@ const LexicalClass lexicalClasses[] = { 10, "SCE_SH_PARAM", "identifier", "Parameter", 11, "SCE_SH_BACKTICKS", "literal string", "Backtick quoted command", 12, "SCE_SH_HERE_DELIM", "operator", "Heredoc delimiter", - 13, "SCE_SH_HERE_Q", "literal string", "Heredoc quoted string", + 13, "SCE_SH_HERE_Q", "here-doc literal string", "Heredoc quoted string", }; } @@ -492,7 +488,7 @@ class LexerBash final : public DefaultLexer { SubStyles subStyles; public: LexerBash() : - DefaultLexer("bash", SCLEX_BASH, lexicalClasses, ELEMENTS(lexicalClasses)), + DefaultLexer("bash", SCLEX_BASH, lexicalClasses, std::size(lexicalClasses)), setParamStart(CharacterSet::setAlphaNum, "_" BASH_SPECIAL_PARAMETER), subStyles(styleSubable, 0x80, 0x40, 0) { cmdDelimiter.Set("| || |& & && ; ;; ( ) { }"); @@ -639,7 +635,6 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int int digit = 0; const Sci_PositionU endPos = startPos + length; CmdState cmdState = CmdState::Start; - TestExprType testExprType = TestExprType::Test; LexAccessor styler(pAccess); // Always backtracks to the start of a line that is not a continuation @@ -663,7 +658,9 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int if (sc.atLineStart) { CmdState state = CmdState::Body; // force backtrack while retaining cmdState if (!StyleForceBacktrack(MaskCommand(sc.state))) { - if (!QuoteStack.lineContinuation) { // retain last line's state + // retain last line's state + // arithmetic expression and double bracket test can span multiline without line continuation + if (!QuoteStack.lineContinuation && !AnyOf(cmdState, CmdState::DoubleBracket, CmdState::Arithmetic)) { cmdState = CmdState::Start; } if (QuoteStack.Empty()) { // force backtrack when nesting @@ -678,7 +675,7 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int // states Body|Test|Arithmetic persist until the end of a command segment // state Word persist, but ends with 'in' or 'do' construct keywords CmdState cmdStateNew = CmdState::Body; - if (cmdState == CmdState::Test || cmdState == CmdState::Arithmetic || cmdState == CmdState::Word) + if (cmdState >= CmdState::Word && cmdState <= CmdState::Arithmetic) cmdStateNew = cmdState; const int stylePrev = MaskCommand(sc.state); const int insideCommand = QuoteStack.insideCommand; @@ -694,7 +691,7 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int break; case SCE_SH_WORD: // "." never used in Bash variable names but used in file names - if (!setWord.Contains(sc.ch) || sc.Match('+', '=')) { + if (!setWord.Contains(sc.ch) || sc.Match('+', '=') || sc.Match('.', '.')) { char s[500]; sc.GetCurrent(s, sizeof(s)); int identifierStyle = SCE_SH_IDENTIFIER | insideCommand; @@ -722,7 +719,6 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int if (strcmp(s, "test") == 0) { if (cmdState == CmdState::Start && keywordEnds) { cmdStateNew = CmdState::Test; - testExprType = TestExprType::Test; } else sc.ChangeState(identifierStyle); } @@ -742,7 +738,8 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int } // disambiguate option items and file test operators else if (s[0] == '-') { - if (cmdState != CmdState::Test || !IsTestOperator(s, setSingleCharOp)) + if (!AnyOf(cmdState, CmdState::Test, CmdState::SingleBracket, CmdState::DoubleBracket) + || !keywordEnds || !IsTestOperator(s, setSingleCharOp)) sc.ChangeState(identifierStyle); } // disambiguate keywords and identifiers @@ -813,7 +810,8 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int #endif ) { sc.ChangeState(SCE_SH_ERROR | insideCommand); - } else if (digit < 62 || digit == 63 || (cmdState != CmdState::Arithmetic && AnyOf(sc.ch, '-', '.'))) { + } else if (digit < 62 || digit == 63 || (cmdState != CmdState::Arithmetic && + (sc.ch == '-' || (sc.ch == '.' && sc.chNext != '.')))) { // current character is alpha numeric, underscore, hyphen or dot sc.ChangeState(SCE_SH_IDENTIFIER | insideCommand); break; @@ -1093,10 +1091,12 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int } } else if (sc.ch == '-' && // test operator or short and long option cmdState != CmdState::Arithmetic && - (IsUpperOrLowerCase(sc.chNext) || sc.chNext == '-') && - (IsASpace(sc.chPrev) || setMetaCharacter.Contains(sc.chPrev))) { - sc.SetState(SCE_SH_WORD | insideCommand); - sc.Forward(); + sc.chPrev != '~' && !IsADigit(sc.chNext)) { + if (IsASpace(sc.chPrev) || setMetaCharacter.Contains(sc.chPrev)) { + sc.SetState(SCE_SH_WORD | insideCommand); + } else { + sc.SetState(SCE_SH_IDENTIFIER | insideCommand); + } } else if (setBashOperator.Contains(sc.ch)) { bool isCmdDelim = false; sc.SetState(SCE_SH_OPERATOR | insideCommand); @@ -1126,12 +1126,10 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int cmdState = CmdState::Arithmetic; sc.Forward(); } else if (sc.Match('[', '[') && IsASpace(sc.GetRelative(2))) { - cmdState = CmdState::Test; - testExprType = TestExprType::DoubleBracket; + cmdState = CmdState::DoubleBracket; sc.Forward(); } else if (sc.ch == '[' && IsASpace(sc.chNext)) { - cmdState = CmdState::Test; - testExprType = TestExprType::SingleBracket; + cmdState = CmdState::SingleBracket; } } // special state -- for ((x;y;z)) in ... looping @@ -1140,11 +1138,8 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int sc.Forward(2); continue; } - // handle command delimiters in command Start|Body|Word state, also Test if 'test' - if (cmdState == CmdState::Start - || cmdState == CmdState::Body - || cmdState == CmdState::Word - || (cmdState == CmdState::Test && testExprType == TestExprType::Test)) { + // handle command delimiters in command Start|Body|Word state, also Test if 'test' or '[]' + if (cmdState < CmdState::DoubleBracket) { char s[10]; s[0] = static_cast(sc.ch); if (setBashOperator.Contains(sc.chNext)) { @@ -1168,12 +1163,12 @@ void SCI_METHOD LexerBash::Lex(Sci_PositionU startPos, Sci_Position length, int if (cmdState == CmdState::Arithmetic && sc.Match(')', ')')) { cmdState = CmdState::Body; sc.Forward(); - } else if (cmdState == CmdState::Test && IsASpace(sc.chPrev)) { - if (sc.Match(']', ']') && testExprType == TestExprType::DoubleBracket) { - sc.Forward(); + } else if (sc.ch == ']' && IsASpace(sc.chPrev)) { + if (cmdState == CmdState::SingleBracket) { cmdState = CmdState::Body; - } else if (sc.ch == ']' && testExprType == TestExprType::SingleBracket) { + } else if (cmdState == CmdState::DoubleBracket && sc.chNext == ']') { cmdState = CmdState::Body; + sc.Forward(); } } } diff --git a/src/3rdparty/scintilla/src/lexers/LexCPP.cxx b/src/3rdparty/scintilla/src/lexers/LexCPP.cxx index 080ccd08..00494cd2 100644 --- a/src/3rdparty/scintilla/src/lexers/LexCPP.cxx +++ b/src/3rdparty/scintilla/src/lexers/LexCPP.cxx @@ -1664,8 +1664,9 @@ void LexerCPP::EvaluateTokens(Tokens &tokens, const SymbolTable &preprocessorDef // The insertion is done before the removal because there were failures with the opposite approach tokens.insert(bracketPair.itBracket, inBracket.begin(), inBracket.end()); - bracketPair = FindBracketPair(tokens); - tokens.erase(bracketPair.itBracket, bracketPair.itEndBracket + 1); + // insert invalidated bracketPair. Use a new variable to avoid warning from Coverity. + const BracketPair pairToErase = FindBracketPair(tokens); + tokens.erase(pairToErase.itBracket, pairToErase.itEndBracket + 1); bracketPair = FindBracketPair(tokens); } diff --git a/src/3rdparty/scintilla/src/lexers/LexPerl.cxx b/src/3rdparty/scintilla/src/lexers/LexPerl.cxx index 1ba426e1..4d29a19d 100644 --- a/src/3rdparty/scintilla/src/lexers/LexPerl.cxx +++ b/src/3rdparty/scintilla/src/lexers/LexPerl.cxx @@ -34,6 +34,8 @@ using namespace Scintilla; using namespace Lexilla; +namespace { + // Info for HERE document handling from perldata.pod (reformatted): // ---------------------------------------------------------------- // A line-oriented form of quoting is based on the shell ``here-doc'' syntax. @@ -91,7 +93,7 @@ using namespace Lexilla; // we also assume SCE_PL_STRING_VAR is the interpolated style with the smallest value #define INTERPOLATE_SHIFT (SCE_PL_STRING_VAR - SCE_PL_STRING) -static bool isPerlKeyword(Sci_PositionU start, Sci_PositionU end, WordList &keywords, LexAccessor &styler) { +bool isPerlKeyword(Sci_PositionU start, Sci_PositionU end, WordList &keywords, LexAccessor &styler) { // old-style keyword matcher; needed because GetCurrent() needs // current segment to be committed, but we may abandon early... char s[100]; @@ -102,7 +104,7 @@ static bool isPerlKeyword(Sci_PositionU start, Sci_PositionU end, WordList &keyw return keywords.InList(s); } -static int disambiguateBareword(LexAccessor &styler, Sci_PositionU bk, Sci_PositionU fw, +int disambiguateBareword(LexAccessor &styler, Sci_PositionU bk, Sci_PositionU fw, int backFlag, Sci_PositionU backPos, Sci_PositionU endPos) { // identifiers are recognized by Perl as barewords under some // conditions, the following attempts to do the disambiguation @@ -152,7 +154,7 @@ static int disambiguateBareword(LexAccessor &styler, Sci_PositionU bk, Sci_Posit return result; } -static void skipWhitespaceComment(LexAccessor &styler, Sci_PositionU &p) { +void skipWhitespaceComment(LexAccessor &styler, Sci_PositionU &p) { // when backtracking, we need to skip whitespace and comments while (p > 0) { const int style = styler.StyleAt(p); @@ -162,7 +164,7 @@ static void skipWhitespaceComment(LexAccessor &styler, Sci_PositionU &p) { } } -static int findPrevLexeme(LexAccessor &styler, Sci_PositionU &bk, int &style) { +int findPrevLexeme(LexAccessor &styler, Sci_PositionU &bk, int &style) { // scan backward past whitespace and comments to find a lexeme skipWhitespaceComment(styler, bk); if (bk == 0) @@ -178,7 +180,7 @@ static int findPrevLexeme(LexAccessor &styler, Sci_PositionU &bk, int &style) { return sz; } -static int styleBeforeBracePair(LexAccessor &styler, Sci_PositionU bk) { +int styleBeforeBracePair(LexAccessor &styler, Sci_PositionU bk) { // backtrack to find open '{' corresponding to a '}', balanced // return significant style to be tested for '/' disambiguation int braceCount = 1; @@ -205,7 +207,7 @@ static int styleBeforeBracePair(LexAccessor &styler, Sci_PositionU bk) { return SCE_PL_DEFAULT; } -static int styleCheckIdentifier(LexAccessor &styler, Sci_PositionU bk) { +int styleCheckIdentifier(LexAccessor &styler, Sci_PositionU bk) { // backtrack to classify sub-styles of identifier under test // return sub-style to be tested for '/' disambiguation if (styler.SafeGetCharAt(bk) == '>') // inputsymbol, like @@ -230,7 +232,7 @@ static int styleCheckIdentifier(LexAccessor &styler, Sci_PositionU bk) { return 0; } -static int podLineScan(LexAccessor &styler, Sci_PositionU &pos, Sci_PositionU endPos) { +int podLineScan(LexAccessor &styler, Sci_PositionU &pos, Sci_PositionU endPos) { // forward scan the current line to classify line for POD style int state = -1; while (pos < endPos) { @@ -254,7 +256,7 @@ static int podLineScan(LexAccessor &styler, Sci_PositionU &pos, Sci_PositionU en return state; } -static bool styleCheckSubPrototype(LexAccessor &styler, Sci_PositionU bk) { +bool styleCheckSubPrototype(LexAccessor &styler, Sci_PositionU bk) { // backtrack to identify if we're starting a subroutine prototype // we also need to ignore whitespace/comments, format is like: // sub abc::pqr :const :prototype(...) @@ -311,7 +313,7 @@ static bool styleCheckSubPrototype(LexAccessor &styler, Sci_PositionU bk) { return (state == SUB_HAS_SUB); } -static int actualNumStyle(int numberStyle) { +int actualNumStyle(int numberStyle) { if (numberStyle == PERLNUM_VECTOR || numberStyle == PERLNUM_V_VECTOR) { return SCE_PL_STRING; } else if (numberStyle == PERLNUM_BAD) { @@ -320,7 +322,7 @@ static int actualNumStyle(int numberStyle) { return SCE_PL_NUMBER; } -static int opposite(int ch) { +int opposite(int ch) { if (ch == '(') return ')'; if (ch == '[') return ']'; if (ch == '{') return '}'; @@ -328,7 +330,7 @@ static int opposite(int ch) { return ch; } -static bool IsCommentLine(Sci_Position line, LexAccessor &styler) { +bool IsCommentLine(Sci_Position line, LexAccessor &styler) { Sci_Position pos = styler.LineStart(line); Sci_Position eol_pos = styler.LineStart(line + 1) - 1; for (Sci_Position i = pos; i < eol_pos; i++) { @@ -342,7 +344,7 @@ static bool IsCommentLine(Sci_Position line, LexAccessor &styler) { return false; } -static bool IsPackageLine(Sci_Position line, LexAccessor &styler) { +bool IsPackageLine(Sci_Position line, LexAccessor &styler) { Sci_Position pos = styler.LineStart(line); int style = styler.StyleAt(pos); if (style == SCE_PL_WORD && styler.Match(pos, "package")) { @@ -351,7 +353,7 @@ static bool IsPackageLine(Sci_Position line, LexAccessor &styler) { return false; } -static int PodHeadingLevel(Sci_Position pos, LexAccessor &styler) { +int PodHeadingLevel(Sci_Position pos, LexAccessor &styler) { int lvl = static_cast(styler.SafeGetCharAt(pos + 5)); if (lvl >= '1' && lvl <= '4') { return lvl - '0'; @@ -387,7 +389,7 @@ struct OptionsPerl { } }; -static const char *const perlWordListDesc[] = { +const char *const perlWordListDesc[] = { "Keywords", 0 }; @@ -416,6 +418,55 @@ struct OptionSetPerl : public OptionSet { } }; +const LexicalClass lexicalClasses[] = { + // Lexer perl SCLEX_PERL SCE_PL_: + 0, "SCE_PL_DEFAULT", "default", "white space", + 1, "SCE_PL_ERROR", "error", "error", + 2, "SCE_PL_COMMENTLINE", "comment line", "comment", + 3, "SCE_PL_POD", "data", "pod: = at beginning of line", + 4, "SCE_PL_NUMBER", "literal numeric", "number", + 5, "SCE_PL_WORD", "keyword", "keyword", + 6, "SCE_PL_STRING", "literal string interpolated", "double quoted string", + 7, "SCE_PL_CHARACTER", "literal string", "single quoted string", + 8, "SCE_PL_PUNCTUATION", "operator", "symbols / punctuation. currently not used", + 9, "SCE_PL_PREPROCESSOR", "preprocessor unused", "preprocessor. currently not used", + 10, "SCE_PL_OPERATOR", "operator", "operators", + 11, "SCE_PL_IDENTIFIER", "identifier", "identifiers (functions, etc.)", + 12, "SCE_PL_SCALAR", "identifier", "scalars: $var", + 13, "SCE_PL_ARRAY", "identifier", "array: @var", + 14, "SCE_PL_HASH", "identifier", "hash: %var", + 15, "SCE_PL_SYMBOLTABLE", "identifier", "symbol table: *var", + 16, "SCE_PL_VARIABLE_INDEXER", "identifier unused", "sce_pl_variable_indexer allocated but unused", + 17, "SCE_PL_REGEX", "literal regex", "regex: /re/ or m{re}", + 18, "SCE_PL_REGSUBST", "literal regex", "substitution: s/re/ore/", + 19, "SCE_PL_LONGQUOTE", "literal string", "long quote (qq, qr, qw, qx) -- obsolete: replaced by qq, qx, qr, qw", + 20, "SCE_PL_BACKTICKS", "literal string interpolated", "back ticks", + 21, "SCE_PL_DATASECTION", "data", "data section: __data__ or __end__ at beginning of line", + 22, "SCE_PL_HERE_DELIM", "here-doc literal string", "here-doc (delimiter)", + 23, "SCE_PL_HERE_Q", "here-doc literal string", "here-doc (single quoted, q)", + 24, "SCE_PL_HERE_QQ", "here-doc literal string interpolated", "here-doc (double quoted, qq)", + 25, "SCE_PL_HERE_QX", "here-doc literal interpolated", "here-doc (back ticks, qx)", + 26, "SCE_PL_STRING_Q", "literal string", "single quoted string, generic", + 27, "SCE_PL_STRING_QQ", "literal string interpolated", "qq = double quoted string", + 28, "SCE_PL_STRING_QX", "literal string interpolated", "qx = back ticks", + 29, "SCE_PL_STRING_QR", "literal regex", "qr = regex", + 30, "SCE_PL_STRING_QW", "literal string interpolated", "qw = array", + 31, "SCE_PL_POD_VERB", "data", "pod: verbatim paragraphs", + 40, "SCE_PL_SUB_PROTOTYPE", "identifier", "subroutine prototype", + 41, "SCE_PL_FORMAT_IDENT", "identifier", "format identifier", + 42, "SCE_PL_FORMAT", "literal string", "format body", + 43, "SCE_PL_STRING_VAR", "identifier interpolated", "double quoted string (interpolated variable)", + 44, "SCE_PL_XLAT", "literal string", "translation: tr{}{} y{}{}", + 54, "SCE_PL_REGEX_VAR", "identifier interpolated", "regex: /re/ or m{re} (interpolated variable)", + 55, "SCE_PL_REGSUBST_VAR", "identifier interpolated", "substitution: s/re/ore/ (interpolated variable)", + 57, "SCE_PL_BACKTICKS_VAR", "identifier interpolated", "back ticks (interpolated variable)", + 61, "SCE_PL_HERE_QQ_VAR", "identifier interpolated", "here-doc (double quoted, qq) (interpolated variable)", + 62, "SCE_PL_HERE_QX_VAR", "identifier interpolated", "here-doc (back ticks, qx) (interpolated variable)", + 64, "SCE_PL_STRING_QQ_VAR", "identifier interpolated", "qq = double quoted string (interpolated variable)", + 65, "SCE_PL_STRING_QX_VAR", "identifier interpolated", "qx = back ticks (interpolated variable)", + 66, "SCE_PL_STRING_QR_VAR", "identifier interpolated", "qr = regex (interpolated variable)", +}; + class LexerPerl : public DefaultLexer { CharacterSet setWordStart; CharacterSet setWord; @@ -426,7 +477,7 @@ class LexerPerl : public DefaultLexer { OptionSetPerl osPerl; public: LexerPerl() : - DefaultLexer("perl", SCLEX_PERL), + DefaultLexer("perl", SCLEX_PERL, lexicalClasses, std::size(lexicalClasses)), setWordStart(CharacterSet::setAlpha, "_", 0x80, true), setWord(CharacterSet::setAlphaNum, "_", 0x80, true), setSpecialVar(CharacterSet::setNone, "\"$;<>&`'+,./\\%:=~!?@[]"), @@ -1848,4 +1899,6 @@ void SCI_METHOD LexerPerl::Fold(Sci_PositionU startPos, Sci_Position length, int styler.SetLevel(lineCurrent, levelPrev | flagsNext); } +} + LexerModule lmPerl(SCLEX_PERL, LexerPerl::LexerFactoryPerl, "perl", perlWordListDesc); diff --git a/src/3rdparty/scintilla/src/lexers/LexR.cxx b/src/3rdparty/scintilla/src/lexers/LexR.cxx index 7d8638d5..b3319760 100644 --- a/src/3rdparty/scintilla/src/lexers/LexR.cxx +++ b/src/3rdparty/scintilla/src/lexers/LexR.cxx @@ -124,7 +124,7 @@ void ColouriseRDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, W dashCount = lineState >> 8; } - for (; sc.More(); sc.Forward()) { + while (sc.More()) { // Determine if the current state should terminate. switch (sc.state) { case SCE_R_OPERATOR: @@ -272,6 +272,7 @@ void ColouriseRDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, W const int lineState = matchingDelimiter | (dashCount << 8); styler.SetLineState(sc.currentLine, lineState); } + sc.Forward(); } sc.Complete(); } diff --git a/src/3rdparty/scintilla/src/lexers/LexVerilog.cxx b/src/3rdparty/scintilla/src/lexers/LexVerilog.cxx index b2120d47..4a3fedff 100644 --- a/src/3rdparty/scintilla/src/lexers/LexVerilog.cxx +++ b/src/3rdparty/scintilla/src/lexers/LexVerilog.cxx @@ -47,7 +47,7 @@ struct PPDefinition { std::string value; bool isUndef; std::string arguments; - PPDefinition(Sci_Position line_, const std::string &key_, const std::string &value_, bool isUndef_ = false, std::string arguments_="") : + PPDefinition(Sci_Position line_, const std::string &key_, const std::string &value_, bool isUndef_ = false, const std::string &arguments_ = "") : line(line_), key(key_), value(value_), isUndef(isUndef_), arguments(arguments_) { } }; @@ -472,7 +472,7 @@ void SCI_METHOD LexerVerilog::Lex(Sci_PositionU startPos, Sci_Position length, i } } - if (sc.atLineEnd) { + if (sc.MatchLineEnd()) { curLine++; lineEndNext = styler.LineEnd(curLine); vlls.Add(curLine, preproc); @@ -513,7 +513,7 @@ void SCI_METHOD LexerVerilog::Lex(Sci_PositionU startPos, Sci_Position length, i sc.SetState(state|activitySet); } - const bool atLineEndBeforeSwitch = sc.atLineEnd; + const bool atLineEndBeforeSwitch = sc.MatchLineEnd(); // Determine if the current state should terminate. switch (MaskActive(sc.state)) { @@ -564,7 +564,7 @@ void SCI_METHOD LexerVerilog::Lex(Sci_PositionU startPos, Sci_Position length, i } break; case SCE_V_PREPROCESSOR: - if (!IsAWordChar(sc.ch) || sc.atLineEnd) { + if (!IsAWordChar(sc.ch) || sc.MatchLineEnd()) { sc.SetState(SCE_V_DEFAULT|activitySet); } break; @@ -593,14 +593,16 @@ void SCI_METHOD LexerVerilog::Lex(Sci_PositionU startPos, Sci_Position length, i } } else if (sc.ch == '\"') { sc.ForwardSetState(SCE_V_DEFAULT|activitySet); - } else if (sc.atLineEnd) { + } else if (sc.MatchLineEnd()) { sc.ChangeState(SCE_V_STRINGEOL|activitySet); + if (sc.Match('\r', '\n')) + sc.Forward(); sc.ForwardSetState(SCE_V_DEFAULT|activitySet); } break; } - if (sc.atLineEnd && !atLineEndBeforeSwitch) { + if (sc.MatchLineEnd() && !atLineEndBeforeSwitch) { // State exit processing consumed characters up to end of line. curLine++; lineEndNext = styler.LineEnd(curLine); @@ -618,7 +620,7 @@ void SCI_METHOD LexerVerilog::Lex(Sci_PositionU startPos, Sci_Position length, i do { sc.Forward(); } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More()); - if (sc.atLineEnd) { + if (sc.MatchLineEnd()) { sc.SetState(SCE_V_DEFAULT|activitySet); styler.SetLineState(curLine, lineState); } else { diff --git a/src/3rdparty/scintilla/src/lexlib/CharacterCategory.cxx b/src/3rdparty/scintilla/src/lexlib/CharacterCategory.cxx index e5d4f79f..ed97a485 100644 --- a/src/3rdparty/scintilla/src/lexlib/CharacterCategory.cxx +++ b/src/3rdparty/scintilla/src/lexlib/CharacterCategory.cxx @@ -20,7 +20,7 @@ namespace { const int catRanges[] = { //++Autogenerated -- start of section automatically generated -// Created with Python 3.11.0, Unicode 14.0.0 +// Created with Python 3.12.0, Unicode 15.0.0 25, 1046, 1073, @@ -1049,7 +1049,8 @@ const int catRanges[] = { 105672, 106013, 106020, -106109, +106086, +106141, 106501, 106566, 106628, @@ -1141,7 +1142,7 @@ const int catRanges[] = { 121027, 121085, 121093, -121309, +121341, 121352, 121693, 121732, @@ -3124,6 +3125,7 @@ const int catRanges[] = { 2217437, 2217476, 2217565, +2219941, 2220036, 2220970, 2221284, @@ -3222,7 +3224,9 @@ const int catRanges[] = { 2246341, 2246417, 2246597, -2246653, +2246628, +2246693, +2246749, 2248708, 2248957, 2248964, @@ -3436,6 +3440,8 @@ const int catRanges[] = { 2315389, 2315780, 2318141, +2318353, +2318685, 2326532, 2326845, 2326852, @@ -3502,6 +3508,22 @@ const int catRanges[] = { 2350758, 2350833, 2350909, +2351109, +2351172, +2351206, +2351236, +2351677, +2351684, +2352774, +2352837, +2353021, +2353094, +2353157, +2353190, +2353221, +2353265, +2353672, +2354013, 2356740, 2356797, 2357258, @@ -3522,9 +3544,11 @@ const int catRanges[] = { 2489905, 2489981, 2490372, -2524669, 2524698, -2524989, +2525189, +2525220, +2525413, +2525917, 2654212, 2672893, 2949124, @@ -3594,8 +3618,12 @@ const int catRanges[] = { 3538941, 3538948, 3548285, +3548740, +3548797, 3549700, 3549821, +3549860, +3549917, 3550340, 3550493, 3550724, @@ -3640,6 +3668,8 @@ const int catRanges[] = { 3819589, 3819701, 3819741, +3823626, +3824285, 3824650, 3825309, 3825685, @@ -3755,6 +3785,8 @@ const int catRanges[] = { 3924292, 3924321, 3924989, +3925153, +3925373, 3932165, 3932413, 3932421, @@ -3765,6 +3797,10 @@ const int catRanges[] = { 3933373, 3933381, 3933565, +3933699, +3935709, +3936741, +3936797, 3940356, 3941821, 3941893, @@ -3784,6 +3820,11 @@ const int catRanges[] = { 3956573, 3956723, 3956765, +3971588, +3972451, +3972485, +3972616, +3972957, 3996676, 3996925, 3996932, @@ -3913,14 +3954,14 @@ const int catRanges[] = { 4095860, 4096021, 4119325, -4119477, +4119445, 4119997, 4120085, 4120509, 4120597, -4124317, -4124693, -4127549, +4124413, +4124533, +4127581, 4127765, 4128157, 4128277, @@ -3942,23 +3983,19 @@ const int catRanges[] = { 4148245, 4148701, 4148757, -4148925, -4149013, 4149181, 4149269, -4149501, +4149565, 4149781, -4150717, -4150805, -4151165, -4151317, +4151261, +4151285, 4151517, -4151829, -4152157, +4151765, +4152221, 4152341, -4152605, +4152637, 4152853, -4153085, +4153149, 4153365, 4158077, 4158101, @@ -3968,7 +4005,7 @@ const int catRanges[] = { 4194308, 5561373, 5562372, -5695293, +5695325, 5695492, 5702621, 5702660, @@ -3979,6 +4016,8 @@ const int catRanges[] = { 6243293, 6291460, 6449533, +6449668, +6583837, 29360186, 29360221, 29361178, diff --git a/src/3rdparty/scintilla/src/lexlib/Lexilla.cxx b/src/3rdparty/scintilla/src/lexlib/Lexilla.cxx index cb3b8256..e807427d 100644 --- a/src/3rdparty/scintilla/src/lexlib/Lexilla.cxx +++ b/src/3rdparty/scintilla/src/lexlib/Lexilla.cxx @@ -330,7 +330,7 @@ extern "C" { EXPORT_FUNCTION int CALLING_CONVENTION GetLexerCount() { AddEachLexer(); - return (int)catalogueLexilla.Count(); + return static_cast(catalogueLexilla.Count()); } EXPORT_FUNCTION void CALLING_CONVENTION GetLexerName(unsigned int index, char *name, int buflength) { @@ -349,7 +349,7 @@ EXPORT_FUNCTION LexerFactoryFunction CALLING_CONVENTION GetLexerFactory(unsigned EXPORT_FUNCTION Scintilla::ILexer5 * CALLING_CONVENTION CreateLexer(const char *name) { AddEachLexer(); - for (unsigned int i = 0; i < catalogueLexilla.Count(); i++) { + for (size_t i = 0; i < catalogueLexilla.Count(); i++) { const char *lexerName = catalogueLexilla.Name(i); if (0 == strcmp(lexerName, name)) { return catalogueLexilla.Create(i); @@ -363,9 +363,8 @@ EXPORT_FUNCTION const char * CALLING_CONVENTION LexerNameFromID(int identifier) const LexerModule *pModule = catalogueLexilla.Find(identifier); if (pModule) { return pModule->languageName; - } else { - return nullptr; } + return nullptr; } EXPORT_FUNCTION const char * CALLING_CONVENTION GetLibraryPropertyNames() { diff --git a/src/3rdparty/scintilla/src/lexlib/SparseState.h b/src/3rdparty/scintilla/src/lexlib/SparseState.h index 592b333b..ff0a5954 100644 --- a/src/3rdparty/scintilla/src/lexlib/SparseState.h +++ b/src/3rdparty/scintilla/src/lexlib/SparseState.h @@ -17,7 +17,8 @@ class SparseState { struct State { Sci_Position position; T value; - constexpr State(Sci_Position position_, T value_) noexcept : position(position_), value(value_) { + constexpr State(Sci_Position position_, T value_) noexcept : + position(position_), value(std::move(value_)) { } inline bool operator<(const State &other) const noexcept { return position < other.position; diff --git a/src/3rdparty/scintilla/src/src/CallTip.cxx b/src/3rdparty/scintilla/src/src/CallTip.cxx index eea59248..87a2bab0 100644 --- a/src/3rdparty/scintilla/src/src/CallTip.cxx +++ b/src/3rdparty/scintilla/src/src/CallTip.cxx @@ -272,7 +272,7 @@ void CallTip::MouseClick(Point pt) noexcept { } PRectangle CallTip::CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn, - int codePage_, Surface *surfaceMeasure, std::shared_ptr font_) { + int codePage_, Surface *surfaceMeasure, const std::shared_ptr &font_) { clickPlace = 0; val = defn; codePage = codePage_; diff --git a/src/3rdparty/scintilla/src/src/CallTip.h b/src/3rdparty/scintilla/src/src/CallTip.h index f8d29465..bd02da7d 100644 --- a/src/3rdparty/scintilla/src/src/CallTip.h +++ b/src/3rdparty/scintilla/src/src/CallTip.h @@ -71,7 +71,7 @@ class CallTip { /// Setup the calltip and return a rectangle of the area required. PRectangle CallTipStart(Sci::Position pos, Point pt, int textHeight, const char *defn, - int codePage_, Surface *surfaceMeasure, std::shared_ptr font_); + int codePage_, Surface *surfaceMeasure, const std::shared_ptr &font_); void CallTipCancel() noexcept; diff --git a/src/3rdparty/scintilla/src/src/ChangeHistory.cxx b/src/3rdparty/scintilla/src/src/ChangeHistory.cxx index 7295f89a..394b37e2 100644 --- a/src/3rdparty/scintilla/src/src/ChangeHistory.cxx +++ b/src/3rdparty/scintilla/src/src/ChangeHistory.cxx @@ -30,44 +30,82 @@ namespace Scintilla::Internal { void ChangeStack::Clear() noexcept { steps.clear(); - insertions.clear(); + changes.clear(); } void ChangeStack::AddStep() { steps.push_back(0); } -void ChangeStack::PushDeletion(Sci::Position positionDeletion, int edition) { - steps.back()++; - insertions.push_back({ positionDeletion, 0, edition, InsertionSpan::Direction::deletion }); +namespace { + +constexpr bool InsertionSpanSameDeletion(const ChangeSpan &is, Sci::Position positionDeletion, int edition) { + // Equal except for count + return + is.direction == ChangeSpan::Direction::deletion && + is.start == positionDeletion && + is.length == 0 && + is.edition == edition; +}; + +} + +void ChangeStack::PushDeletion(Sci::Position positionDeletion, const EditionCount &ec) { + steps.back() += ec.count; + if (changes.empty() || !InsertionSpanSameDeletion(changes.back(), positionDeletion, ec.edition)) { + changes.push_back({ positionDeletion, 0, ec.edition, ec.count, ChangeSpan::Direction::deletion }); + } else { + changes.back().count += ec.count; + } } void ChangeStack::PushInsertion(Sci::Position positionInsertion, Sci::Position length, int edition) { steps.back()++; - insertions.push_back({ positionInsertion, length, edition, InsertionSpan::Direction::insertion }); + changes.push_back({ positionInsertion, length, edition, 1, ChangeSpan::Direction::insertion }); } -size_t ChangeStack::PopStep() noexcept { - const size_t spans = steps.back(); +int ChangeStack::PopStep() noexcept { + const int spans = steps.back(); steps.pop_back(); return spans; } -InsertionSpan ChangeStack::PopSpan() noexcept { - const InsertionSpan span = insertions.back(); - insertions.pop_back(); +ChangeSpan ChangeStack::PopSpan(int maxSteps) noexcept { + ChangeSpan span = changes.back(); + const int remove = std::min(maxSteps, span.count); + if (span.count == remove) { + changes.pop_back(); + } else { + changes.back().count -= remove; + span.count = remove; + } return span; } void ChangeStack::SetSavePoint() noexcept { // Switch changeUnsaved to changeSaved - for (InsertionSpan &x : insertions) { + for (ChangeSpan &x : changes) { if (x.edition == changeModified) { x.edition = changeSaved; } } } +void ChangeStack::Check() const noexcept { +#ifdef _DEBUG + // Ensure count in steps same as insertions; + int sizeSteps = 0; + for (const int c : steps) { + sizeSteps += c; + } + int sizeInsertions = 0; + for (const ChangeSpan &is: changes) { + sizeInsertions += is.count; + } + assert(sizeSteps == sizeInsertions); +#endif +} + void ChangeLog::Clear(Sci::Position length) { changeStack.Clear(); insertEdition.DeleteAll(); @@ -105,8 +143,8 @@ void ChangeLog::CollapseRange(Sci::Position position, Sci::Position deleteLength while (positionDeletion <= positionMax) { const EditionSetOwned &editions = deleteEdition.ValueAt(positionDeletion); if (editions) { - for (const int ed : *editions) { - PushDeletionAt(position, ed); + for (const EditionCount &ec : *editions) { + PushDeletionAt(position, ec); } EditionSetOwned empty; deleteEdition.SetValueAt(positionDeletion, std::move(empty)); @@ -115,19 +153,50 @@ void ChangeLog::CollapseRange(Sci::Position position, Sci::Position deleteLength } } -void ChangeLog::PushDeletionAt(Sci::Position position, int edition) { +namespace { + +// EditionSets have repeat counts on items so push and pop may just +// manipulate the count field or may push/pop items. + +void EditionSetPush(EditionSet &set, EditionCount ec) { + if (set.empty() || (set.back().edition != ec.edition)) { + set.push_back(ec); + } else { + set.back().count += ec.count; + } +} + +void EditionSetPop(EditionSet &set) noexcept { + if (set.back().count == 1) { + set.pop_back(); + } else { + set.back().count--; + } +} + +int EditionSetCount(const EditionSet &set) noexcept { + int count = 0; + for (const EditionCount &ec : set) { + count += ec.count; + } + return count; +} + +} + +void ChangeLog::PushDeletionAt(Sci::Position position, EditionCount ec) { if (!deleteEdition.ValueAt(position)) { deleteEdition.SetValueAt(position, std::make_unique()); } - deleteEdition.ValueAt(position)->push_back(edition); + EditionSetPush(*deleteEdition.ValueAt(position), ec); } -void ChangeLog::InsertFrontDeletionAt(Sci::Position position, int edition) { +void ChangeLog::InsertFrontDeletionAt(Sci::Position position, EditionCount ec) { if (!deleteEdition.ValueAt(position)) { deleteEdition.SetValueAt(position, std::make_unique()); } const EditionSetOwned &editions = deleteEdition.ValueAt(position); - editions->insert(editions->begin(), edition); + editions->insert(editions->begin(), ec); } void ChangeLog::SaveRange(Sci::Position position, Sci::Position length) { @@ -149,8 +218,8 @@ void ChangeLog::SaveRange(Sci::Position position, Sci::Position length) { while (positionDeletion <= positionMax) { const EditionSetOwned &editions = deleteEdition.ValueAt(positionDeletion); if (editions) { - for (const int ed : *editions) { - changeStack.PushDeletion(positionDeletion, ed); + for (const EditionCount &ec : *editions) { + changeStack.PushDeletion(positionDeletion, ec); } } positionDeletion = deleteEdition.PositionNext(positionDeletion); @@ -164,17 +233,25 @@ void ChangeLog::PopDeletion(Sci::Position position, Sci::Position deleteLength) deleteEdition.SetValueAt(position, std::move(eso)); const EditionSetOwned &editions = deleteEdition.ValueAt(position); assert(editions); - editions->pop_back(); - const size_t inserts = changeStack.PopStep(); - for (size_t i = 0; i < inserts; i++) { - const InsertionSpan span = changeStack.PopSpan(); - if (span.direction == InsertionSpan::Direction::insertion) { + EditionSetPop(*editions); + const int inserts = changeStack.PopStep(); + for (int i = 0; i < inserts;) { + const ChangeSpan span = changeStack.PopSpan(inserts); + if (span.direction == ChangeSpan::Direction::insertion) { + assert(span.count == 1); // Insertions are never compressed insertEdition.FillRange(span.start, span.edition, span.length); + i++; } else { assert(editions); - assert(editions->back() == span.edition); - editions->pop_back(); - InsertFrontDeletionAt(span.start, span.edition); + assert(editions->back().edition == span.edition); + for (int j = 0; j < span.count; j++) { + EditionSetPop(*editions); + } + // Iterating backwards (pop) through changeStack, reverse order of insertion + // and original deletion list. + // Therefore need to insert at front to recreate original order. + InsertFrontDeletionAt(span.start, { span.edition, span.count }); + i += span.count; } } @@ -213,9 +290,9 @@ void ChangeLog::SetSavePoint() { for (Sci::Position positionDeletion = 0; positionDeletion <= length;) { const EditionSetOwned &editions = deleteEdition.ValueAt(positionDeletion); if (editions) { - for (int &ed : *editions) { - if (ed == changeModified) { - ed = changeSaved; + for (EditionCount &ec : *editions) { + if (ec.edition == changeModified) { + ec.edition = changeSaved; } } } @@ -233,7 +310,7 @@ size_t ChangeLog::DeletionCount(Sci::Position start, Sci::Position length) const while (start <= end) { const EditionSetOwned &editions = deleteEdition.ValueAt(start); if (editions) { - count += editions->size(); + count += EditionSetCount(*editions); } start = deleteEdition.PositionNext(start); } @@ -242,6 +319,7 @@ size_t ChangeLog::DeletionCount(Sci::Position start, Sci::Position length) const void ChangeLog::Check() const noexcept { assert(insertEdition.Length() == deleteEdition.Length()); + changeStack.Check(); } ChangeHistory::ChangeHistory(Sci::Position length) { @@ -270,7 +348,7 @@ void ChangeHistory::DeleteRange(Sci::Position position, Sci::Position deleteLeng if (changeLogReversions) { changeLogReversions->DeleteRangeSavingHistory(position, deleteLength); if (reverting) { - changeLogReversions->PushDeletionAt(position, 1); + changeLogReversions->PushDeletionAt(position, { changeRevertedOriginal, 1 }); } } Check(); @@ -278,7 +356,7 @@ void ChangeHistory::DeleteRange(Sci::Position position, Sci::Position deleteLeng void ChangeHistory::DeleteRangeSavingHistory(Sci::Position position, Sci::Position deleteLength, bool beforeSave, bool isDetached) { changeLog.DeleteRangeSavingHistory(position, deleteLength); - changeLog.PushDeletionAt(position, beforeSave ? changeSaved : changeModified); + changeLog.PushDeletionAt(position, { beforeSave ? changeSaved : changeModified, 1 }); if (changeLogReversions) { if (isDetached) { changeLogReversions->SaveHistoryForDelete(position, deleteLength); @@ -332,7 +410,7 @@ void ChangeHistory::EditionCreateHistory(Sci::Position start, Sci::Position leng if (length) { changeLog.insertEdition.FillRange(start, historicEpoch, length); } else { - changeLog.PushDeletionAt(start, historicEpoch); + changeLog.PushDeletionAt(start, { historicEpoch, 1 }); } } } @@ -349,9 +427,9 @@ int ChangeHistory::EditionAt(Sci::Position pos) const noexcept { if (changeLogReversions) { const int editionReversion = changeLogReversions->insertEdition.ValueAt(pos); if (editionReversion) { - if (edition < 0) - return 1; - return edition ? 4 : 1; + if (edition < 0) // Historical revision + return changeRevertedOriginal; + return edition ? changeRevertedToChange : changeRevertedOriginal; } } return edition; @@ -372,8 +450,8 @@ unsigned int ChangeHistory::EditionDeletesAt(Sci::Position pos) const noexcept { unsigned int editionSet = 0; const EditionSetOwned &editionSetDeletions = changeLog.deleteEdition.ValueAt(pos); if (editionSetDeletions) { - for (const unsigned int ed : *editionSetDeletions) { - editionSet = editionSet | (1u << (ed-1)); + for (const EditionCount &ec : *editionSetDeletions) { + editionSet = editionSet | (1u << (ec.edition-1)); } } if (changeLogReversions) { diff --git a/src/3rdparty/scintilla/src/src/ChangeHistory.h b/src/3rdparty/scintilla/src/src/ChangeHistory.h index 8a6e745d..c3960367 100644 --- a/src/3rdparty/scintilla/src/src/ChangeHistory.h +++ b/src/3rdparty/scintilla/src/src/ChangeHistory.h @@ -22,27 +22,39 @@ constexpr unsigned int bitSaved = 2; constexpr unsigned int bitModified = 4; constexpr unsigned int bitRevertedToModified = 8; -struct InsertionSpan { +struct ChangeSpan { Sci::Position start; Sci::Position length; int edition; + int count; enum class Direction { insertion, deletion } direction; }; -using EditionSet = std::vector; +struct EditionCount { + int edition; + int count; + // Used in tests. + constexpr bool operator==(const EditionCount &other) const noexcept { + return (edition == other.edition) && (count == other.count); + } +}; + +// EditionSet is ordered from oldest to newest, its not really a set +using EditionSet = std::vector; using EditionSetOwned = std::unique_ptr; class ChangeStack { - std::vector steps; - std::vector insertions; + std::vector steps; + std::vector changes; public: void Clear() noexcept; void AddStep(); - void PushDeletion(Sci::Position positionDeletion, int edition); + void PushDeletion(Sci::Position positionDeletion, const EditionCount &ec); void PushInsertion(Sci::Position positionInsertion, Sci::Position length, int edition); - [[nodiscard]] size_t PopStep() noexcept; - [[nodiscard]] InsertionSpan PopSpan() noexcept; + [[nodiscard]] int PopStep() noexcept; + [[nodiscard]] ChangeSpan PopSpan(int maxSteps) noexcept; void SetSavePoint() noexcept; + void Check() const noexcept; }; struct ChangeLog { @@ -55,8 +67,8 @@ struct ChangeLog { void DeleteRange(Sci::Position position, Sci::Position deleteLength); void Insert(Sci::Position start, Sci::Position length, int edition); void CollapseRange(Sci::Position position, Sci::Position deleteLength); - void PushDeletionAt(Sci::Position position, int edition); - void InsertFrontDeletionAt(Sci::Position position, int edition); + void PushDeletionAt(Sci::Position position, EditionCount ec); + void InsertFrontDeletionAt(Sci::Position position, EditionCount ec); void SaveRange(Sci::Position position, Sci::Position length); void PopDeletion(Sci::Position position, Sci::Position deleteLength); void SaveHistoryForDelete(Sci::Position position, Sci::Position deleteLength); diff --git a/src/3rdparty/scintilla/src/src/CharacterCategoryMap.cxx b/src/3rdparty/scintilla/src/src/CharacterCategoryMap.cxx index 06a2dd23..b8b20fee 100644 --- a/src/3rdparty/scintilla/src/src/CharacterCategoryMap.cxx +++ b/src/3rdparty/scintilla/src/src/CharacterCategoryMap.cxx @@ -22,7 +22,7 @@ namespace { const int catRanges[] = { //++Autogenerated -- start of section automatically generated -// Created with Python 3.11.0, Unicode 14.0.0 +// Created with Python 3.12.0, Unicode 15.0.0 25, 1046, 1073, @@ -1051,7 +1051,8 @@ const int catRanges[] = { 105672, 106013, 106020, -106109, +106086, +106141, 106501, 106566, 106628, @@ -1143,7 +1144,7 @@ const int catRanges[] = { 121027, 121085, 121093, -121309, +121341, 121352, 121693, 121732, @@ -3126,6 +3127,7 @@ const int catRanges[] = { 2217437, 2217476, 2217565, +2219941, 2220036, 2220970, 2221284, @@ -3224,7 +3226,9 @@ const int catRanges[] = { 2246341, 2246417, 2246597, -2246653, +2246628, +2246693, +2246749, 2248708, 2248957, 2248964, @@ -3438,6 +3442,8 @@ const int catRanges[] = { 2315389, 2315780, 2318141, +2318353, +2318685, 2326532, 2326845, 2326852, @@ -3504,6 +3510,22 @@ const int catRanges[] = { 2350758, 2350833, 2350909, +2351109, +2351172, +2351206, +2351236, +2351677, +2351684, +2352774, +2352837, +2353021, +2353094, +2353157, +2353190, +2353221, +2353265, +2353672, +2354013, 2356740, 2356797, 2357258, @@ -3524,9 +3546,11 @@ const int catRanges[] = { 2489905, 2489981, 2490372, -2524669, 2524698, -2524989, +2525189, +2525220, +2525413, +2525917, 2654212, 2672893, 2949124, @@ -3596,8 +3620,12 @@ const int catRanges[] = { 3538941, 3538948, 3548285, +3548740, +3548797, 3549700, 3549821, +3549860, +3549917, 3550340, 3550493, 3550724, @@ -3642,6 +3670,8 @@ const int catRanges[] = { 3819589, 3819701, 3819741, +3823626, +3824285, 3824650, 3825309, 3825685, @@ -3757,6 +3787,8 @@ const int catRanges[] = { 3924292, 3924321, 3924989, +3925153, +3925373, 3932165, 3932413, 3932421, @@ -3767,6 +3799,10 @@ const int catRanges[] = { 3933373, 3933381, 3933565, +3933699, +3935709, +3936741, +3936797, 3940356, 3941821, 3941893, @@ -3786,6 +3822,11 @@ const int catRanges[] = { 3956573, 3956723, 3956765, +3971588, +3972451, +3972485, +3972616, +3972957, 3996676, 3996925, 3996932, @@ -3915,14 +3956,14 @@ const int catRanges[] = { 4095860, 4096021, 4119325, -4119477, +4119445, 4119997, 4120085, 4120509, 4120597, -4124317, -4124693, -4127549, +4124413, +4124533, +4127581, 4127765, 4128157, 4128277, @@ -3944,23 +3985,19 @@ const int catRanges[] = { 4148245, 4148701, 4148757, -4148925, -4149013, 4149181, 4149269, -4149501, +4149565, 4149781, -4150717, -4150805, -4151165, -4151317, +4151261, +4151285, 4151517, -4151829, -4152157, +4151765, +4152221, 4152341, -4152605, +4152637, 4152853, -4153085, +4153149, 4153365, 4158077, 4158101, @@ -3970,7 +4007,7 @@ const int catRanges[] = { 4194308, 5561373, 5562372, -5695293, +5695325, 5695492, 5702621, 5702660, @@ -3981,6 +4018,8 @@ const int catRanges[] = { 6243293, 6291460, 6449533, +6449668, +6583837, 29360186, 29360221, 29361178, diff --git a/src/3rdparty/scintilla/src/version.txt b/src/3rdparty/scintilla/src/version.txt index 1fc4946c..ff5f5b64 100644 --- a/src/3rdparty/scintilla/src/version.txt +++ b/src/3rdparty/scintilla/src/version.txt @@ -1 +1 @@ -536 +537 diff --git a/src/3rdparty/scintilla/src/win32/PlatWin.cxx b/src/3rdparty/scintilla/src/win32/PlatWin.cxx index 40302102..91af4a68 100644 --- a/src/3rdparty/scintilla/src/win32/PlatWin.cxx +++ b/src/3rdparty/scintilla/src/win32/PlatWin.cxx @@ -2671,7 +2671,7 @@ void SurfaceD2D::FlushDrawing() { } void SurfaceD2D::SetRenderingParams(std::shared_ptr renderingParams_) { - renderingParams = renderingParams_; + renderingParams = std::move(renderingParams_); } #endif diff --git a/src/3rdparty/sqlite3/src/sqlite3.c b/src/3rdparty/sqlite3/src/sqlite3.c index 310583f9..a1fbd604 100644 --- a/src/3rdparty/sqlite3/src/sqlite3.c +++ b/src/3rdparty/sqlite3/src/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.43.0. By combining all the individual C code files into this +** version 3.43.2. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** f80b798b3f4b81a7bb4233c58294edd0f11. +** 310099cce5a487035fa535dd3002c59ac7f. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 @@ -459,9 +459,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.43.0" -#define SQLITE_VERSION_NUMBER 3043000 -#define SQLITE_SOURCE_ID "2023-08-24 12:36:59 0f80b798b3f4b81a7bb4233c58294edd0f1156f36b6ecf5ab8e83631d468778c" +#define SQLITE_VERSION "3.43.2" +#define SQLITE_VERSION_NUMBER 3043002 +#define SQLITE_SOURCE_ID "2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -35185,29 +35185,29 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou double rr[2]; rr[0] = r; rr[1] = 0.0; - if( rr[0]>1.84e+19 ){ - while( rr[0]>1.84e+119 ){ + if( rr[0]>9.223372036854774784e+18 ){ + while( rr[0]>9.223372036854774784e+118 ){ exp += 100; dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); } - while( rr[0]>1.84e+29 ){ + while( rr[0]>9.223372036854774784e+28 ){ exp += 10; dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); } - while( rr[0]>1.84e+19 ){ + while( rr[0]>9.223372036854774784e+18 ){ exp += 1; dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); } }else{ - while( rr[0]<1.84e-82 ){ + while( rr[0]<9.223372036854774784e-83 ){ exp -= 100; dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); } - while( rr[0]<1.84e+08 ){ + while( rr[0]<9.223372036854774784e+07 ){ exp -= 10; dekkerMul2(rr, 1.0e+10, 0.0); } - while( rr[0]<1.84e+18 ){ + while( rr[0]<9.22337203685477478e+17 ){ exp -= 1; dekkerMul2(rr, 1.0e+01, 0.0); } @@ -77024,6 +77024,7 @@ static int rebuildPage( int k; /* Current slot in pCArray->apEnd[] */ u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */ + assert( nCell>0 ); assert( i(u32)usableSize) ){ j = 0; } @@ -77330,6 +77331,7 @@ static int editPage( return SQLITE_OK; editpage_fail: /* Unable to edit this page. Rebuild it from scratch instead. */ + if( nNew<1 ) return SQLITE_CORRUPT_BKPT; populateCellCache(pCArray, iNew, nNew); return rebuildPage(pCArray, iNew, nNew, pPg); } @@ -100833,8 +100835,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ /* Set the value of register r[1] in the SQL statement to integer iRow. ** This is done directly as a performance optimization */ - v->aMem[1].flags = MEM_Int; - v->aMem[1].u.i = iRow; + sqlite3VdbeMemSetInt64(&v->aMem[1], iRow); /* If the statement has been run before (and is paused at the OP_ResultRow) ** then back it up to the point where it does the OP_NotExists. This could @@ -128461,8 +128462,10 @@ static void sumFinalize(sqlite3_context *context){ if( p->approx ){ if( p->ovrfl ){ sqlite3_result_error(context,"integer overflow",-1); - }else{ + }else if( !sqlite3IsNaN(p->rErr) ){ sqlite3_result_double(context, p->rSum+p->rErr); + }else{ + sqlite3_result_double(context, p->rSum); } }else{ sqlite3_result_int64(context, p->iSum); @@ -128475,7 +128478,8 @@ static void avgFinalize(sqlite3_context *context){ if( p && p->cnt>0 ){ double r; if( p->approx ){ - r = p->rSum+p->rErr; + r = p->rSum; + if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } @@ -128488,7 +128492,8 @@ static void totalFinalize(sqlite3_context *context){ p = sqlite3_aggregate_context(context, 0); if( p ){ if( p->approx ){ - r = p->rSum+p->rErr; + r = p->rSum; + if( !sqlite3IsNaN(p->rErr) ) r += p->rErr; }else{ r = (double)(p->iSum); } @@ -145691,12 +145696,12 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){ assert( pItem->pSelect!=0 ); pSub = pItem->pSelect; assert( pSub->pEList->nExpr==pTab->nCol ); - if( (pSub->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ - testcase( pSub->selFlags & SF_Distinct ); - testcase( pSub->selFlags & SF_Aggregate ); - return 0; - } for(pX=pSub; pX; pX=pX->pPrior){ + if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ + testcase( pX->selFlags & SF_Distinct ); + testcase( pX->selFlags & SF_Aggregate ); + return 0; + } if( pX->pPrior && pX->op!=TK_ALL ){ /* This optimization does not work for compound subqueries that ** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */ @@ -198084,7 +198089,7 @@ static u64 fts3ChecksumIndex( int rc; u64 cksum = 0; - assert( *pRc==SQLITE_OK ); + if( *pRc ) return 0; memset(&filter, 0, sizeof(filter)); memset(&csr, 0, sizeof(csr)); @@ -203714,7 +203719,9 @@ static void jsonArrayLengthFunc( } if( pNode->eType==JSON_ARRAY ){ while( 1 /*exit-by-break*/ ){ - for(i=1; i<=pNode->n; n++){ + i = 1; + while( i<=pNode->n ){ + if( (pNode[i].jnFlags & JNODE_REMOVE)==0 ) n++; i += jsonNodeSize(&pNode[i]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; @@ -204130,6 +204137,7 @@ static void jsonReplaceFunc( } pParse = jsonParseCached(ctx, argv[0], ctx, argc>1); if( pParse==0 ) return; + pParse->nJPRef++; for(i=1; i<(u32)argc; i+=2){ zPath = (const char*)sqlite3_value_text(argv[i]); pParse->useMod = 1; @@ -204142,6 +204150,7 @@ static void jsonReplaceFunc( jsonReturnJson(pParse, pParse->aNode, ctx, 1); replace_err: jsonDebugPrintParse(pParse); + jsonParseFree(pParse); } @@ -204176,6 +204185,7 @@ static void jsonSetFunc( } pParse = jsonParseCached(ctx, argv[0], ctx, argc>1); if( pParse==0 ) return; + pParse->nJPRef++; for(i=1; i<(u32)argc; i+=2){ zPath = (const char*)sqlite3_value_text(argv[i]); bApnd = 0; @@ -204192,9 +204202,8 @@ static void jsonSetFunc( } jsonDebugPrintParse(pParse); jsonReturnJson(pParse, pParse->aNode, ctx, 1); - jsonSetDone: - /* no cleanup required */; + jsonParseFree(pParse); } /* @@ -222986,15 +222995,19 @@ static int sessionReadRecord( } } if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - sqlite3_int64 v = sessionGetI64(aVal); - if( eType==SQLITE_INTEGER ){ - sqlite3VdbeMemSetInt64(apOut[i], v); + if( (pIn->nData-pIn->iNext)<8 ){ + rc = SQLITE_CORRUPT_BKPT; }else{ - double d; - memcpy(&d, &v, 8); - sqlite3VdbeMemSetDouble(apOut[i], d); + sqlite3_int64 v = sessionGetI64(aVal); + if( eType==SQLITE_INTEGER ){ + sqlite3VdbeMemSetInt64(apOut[i], v); + }else{ + double d; + memcpy(&d, &v, 8); + sqlite3VdbeMemSetDouble(apOut[i], d); + } + pIn->iNext += 8; } - pIn->iNext += 8; } } } @@ -239679,7 +239692,6 @@ static void fts5DoSecureDelete( int iIdx = 0; int iStart = 0; int iKeyOff = 0; - int iPrevKeyOff = 0; int iDelKeyOff = 0; /* Offset of deleted key, if any */ nIdx = nPg-iPgIdx; @@ -239820,80 +239832,79 @@ static void fts5DoSecureDelete( } } }else if( iStart==4 ){ - int iPgno; - - assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno ); - /* The entry being removed may be the only position list in - ** its doclist. */ - for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){ - Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno)); - int bEmpty = (pPg && pPg->nn==4); - fts5DataRelease(pPg); - if( bEmpty==0 ) break; - } - - if( iPgno==pSeg->iTermLeafPgno ){ - i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno); - Fts5Data *pTerm = fts5DataRead(p, iId); - if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){ - u8 *aTermIdx = &pTerm->p[pTerm->szLeaf]; - int nTermIdx = pTerm->nn - pTerm->szLeaf; - int iTermIdx = 0; - int iTermOff = 0; - - while( 1 ){ - u32 iVal = 0; - int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal); - iTermOff += iVal; - if( (iTermIdx+nByte)>=nTermIdx ) break; - iTermIdx += nByte; - } - nTermIdx = iTermIdx; + int iPgno; + + assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno ); + /* The entry being removed may be the only position list in + ** its doclist. */ + for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){ + Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno)); + int bEmpty = (pPg && pPg->nn==4); + fts5DataRelease(pPg); + if( bEmpty==0 ) break; + } - memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx); - fts5PutU16(&pTerm->p[2], iTermOff); + if( iPgno==pSeg->iTermLeafPgno ){ + i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno); + Fts5Data *pTerm = fts5DataRead(p, iId); + if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){ + u8 *aTermIdx = &pTerm->p[pTerm->szLeaf]; + int nTermIdx = pTerm->nn - pTerm->szLeaf; + int iTermIdx = 0; + int iTermOff = 0; - fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx); - if( nTermIdx==0 ){ - fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno); - } + while( 1 ){ + u32 iVal = 0; + int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal); + iTermOff += iVal; + if( (iTermIdx+nByte)>=nTermIdx ) break; + iTermIdx += nByte; } - fts5DataRelease(pTerm); - } - } + nTermIdx = iTermIdx; - if( p->rc==SQLITE_OK ){ - const int nMove = nPg - iNextOff; - int nShift = 0; - - memmove(&aPg[iOff], &aPg[iNextOff], nMove); - iPgIdx -= (iNextOff - iOff); - nPg = iPgIdx; - fts5PutU16(&aPg[2], iPgIdx); - - nShift = iNextOff - iOff; - for(iIdx=0, iKeyOff=0, iPrevKeyOff=0; iIdxiOff ){ - iKeyOff -= nShift; - nShift = 0; - } - nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOff - iPrevKeyOff); - iPrevKeyOff = iKeyOff; + memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx); + fts5PutU16(&pTerm->p[2], iTermOff); + + fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx); + if( nTermIdx==0 ){ + fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno); } } + fts5DataRelease(pTerm); + } + } + + if( p->rc==SQLITE_OK ){ + const int nMove = nPg - iNextOff; /* Number of bytes to move */ + int nShift = iNextOff - iOff; /* Distance to move them */ + + int iPrevKeyOut = 0; + int iKeyIn = 0; + + memmove(&aPg[iOff], &aPg[iNextOff], nMove); + iPgIdx -= nShift; + nPg = iPgIdx; + fts5PutU16(&aPg[2], iPgIdx); - if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){ - fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno); + for(iIdx=0; iIdxiOff ? nShift : 0)); + nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOut - iPrevKeyOut); + iPrevKeyOut = iKeyOut; } + } - assert_nc( nPg>4 || fts5GetU16(aPg)==0 ); - fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg,nPg); + if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){ + fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno); } - sqlite3_free(aIdx); + + assert_nc( nPg>4 || fts5GetU16(aPg)==0 ); + fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg, nPg); + } + sqlite3_free(aIdx); } /* @@ -244242,6 +244253,9 @@ static int fts5FilterMethod( pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64); } + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); + if( rc!=SQLITE_OK ) goto filter_out; + if( pTab->pSortCsr ){ /* If pSortCsr is non-NULL, then this call is being made as part of ** processing for a "... MATCH ORDER BY rank" query (ePlan is @@ -244264,7 +244278,9 @@ static int fts5FilterMethod( pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); }else if( pCsr->pExpr ){ - rc = fts5CursorParseRank(pConfig, pCsr, pRank); + if( rc==SQLITE_OK ){ + rc = fts5CursorParseRank(pConfig, pCsr, pRank); + } if( rc==SQLITE_OK ){ if( bOrderByRank ){ pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; @@ -245745,7 +245761,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2023-08-24 12:36:59 0f80b798b3f4b81a7bb4233c58294edd0f1156f36b6ecf5ab8e83631d468778c", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790", -1, SQLITE_TRANSIENT); } /* diff --git a/src/3rdparty/sqlite3/src/sqlite3.h b/src/3rdparty/sqlite3/src/sqlite3.h index ec451a5c..03761134 100644 --- a/src/3rdparty/sqlite3/src/sqlite3.h +++ b/src/3rdparty/sqlite3/src/sqlite3.h @@ -146,9 +146,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.43.0" -#define SQLITE_VERSION_NUMBER 3043000 -#define SQLITE_SOURCE_ID "2023-08-24 12:36:59 0f80b798b3f4b81a7bb4233c58294edd0f1156f36b6ecf5ab8e83631d468778c" +#define SQLITE_VERSION "3.43.2" +#define SQLITE_VERSION_NUMBER 3043002 +#define SQLITE_SOURCE_ID "2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790" /* ** CAPI3REF: Run-Time Library Version Numbers diff --git a/src/Makefile b/src/Makefile index 210144a9..da182fc3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,11 +6,11 @@ CDEP = -I3rdparty\libcurl\include -I3rdparty\libopenssl\include -I3rdparty\l -I3rdparty\libmysql\include -I3rdparty\liboci\include -I3rdparty\libhiredis\include \ -I3rdparty\libiconv\include -I3rdparty\luajit\src -I3rdparty\nanosvg\include \ -I3rdparty\pcre\src -I3rdparty\sqlite3\src -I3rdparty\chardet\src \ - -I3rdparty\qrencode\src -I3rdparty\tinyexpr\src \ + -I3rdparty\qrencode\src -I3rdparty\tinyexpr\src -I3rdparty\expat\src \ -I3rdparty\scintilla\src\include CFLAGS = -W3 -WX- -wd4996 -wd4819 -Zi -D "_CRT_SECURE_NO_WARNINGS" -D "UNICODE" -D "_UNICODE" \ - -utf-8 -D "JSON_TRACK_SOURCE" -D "PCRE_STATIC" $(CFLAGS) $(CDEP) + -utf-8 -D "JSON_TRACK_SOURCE" -D "PCRE_STATIC" -D "XML_STATIC" $(CFLAGS) $(CDEP) !IF "$(ACTIONS_BUILDING)"=="1" CFLAGS = $(CFLAGS) -D "ACTIONS_BUILDING" @@ -38,7 +38,8 @@ WINLIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.l LIBS = $(LDEP) $(WINLIBS) API_LIBS = $(BIND)\libchardet.lib $(BIND)\qrencode.lib $(BIND)\sqlite3.lib $(BIND)\pcre.lib \ - $(BIND)\luajit.lib $(BIND)\iconv.lib $(BIND)\scilexer.lib $(BIND)\tinyexpr.lib + $(BIND)\luajit.lib $(BIND)\iconv.lib $(BIND)\scilexer.lib $(BIND)\tinyexpr.lib \ + $(BIND)\expat.lib API_DEPS = $(API_LIBS) -LIBPATH:$(BIND) $(WINLIBS) @@ -111,6 +112,7 @@ EUAPI_OBJS = \ $(OBJD)\eu_favorites.obj \ $(OBJD)\eu_settings.obj \ $(OBJD)\eu_hintctl.obj \ + $(OBJD)\eu_xmlist.obj \ SHARED_LIB = $(BIND)\euapi.dll @@ -214,6 +216,7 @@ $(OBJD)\eu_session.obj : eu_session.c eu_session.h framework $(OBJD)\eu_favorites.obj : eu_favorites.c eu_favorites.h framework.h $(OBJD)\eu_settings.obj : eu_settings.c eu_settings.h framework.h $(OBJD)\eu_hintctl.obj : eu_hintctl.c eu_hintctl.h framework.h +$(OBJD)\eu_xmlist.obj : eu_xmlist.c eu_xmlist.h framework.h $(OBJD)\eu_encoding_utf8.obj : eu_encoding_utf8.c eu_encoding_utf8.h framework.h $(CC) $(API_CLFGAS) -Fd$(BIND)\euapi.pdb -Fo$(OBJD)\ $(MAVX2) -c eu_encoding_utf8.c $(OBJD)\resource.res : skylark.rc targetver.h skylark.exe.manifest $(ROOT)\resources\*.bmp diff --git a/src/eu_api.c b/src/eu_api.c index b1f7b632..647db2c5 100644 --- a/src/eu_api.c +++ b/src/eu_api.c @@ -353,6 +353,40 @@ eu_touch(LPCTSTR path) return ret; } +int +eu_prepend_path(const TCHAR *dir) +{ + size_t bufsize; + TCHAR *path; + TCHAR *value = NULL; + int rc = -1; + if ((path = _tgetenv(_T("PATH"))) == NULL) + { + return (-1); + } + bufsize = _tcslen(dir) + _tcslen(path) + 8; + value = (TCHAR *)calloc(1, bufsize * sizeof(TCHAR)); + if (value && _sntprintf(value, bufsize, _T("PATH=%s;%s"), dir, path) > 0) + { + rc = _tputenv(value); + } + eu_safe_free(value); + return rc; +} + +bool +eu_gui_app(void) +{ + HMODULE hmodule = GetModuleHandle(NULL); + if(hmodule == NULL) + { + return false; + } + IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER *)hmodule; + IMAGE_NT_HEADERS* pe_header =(IMAGE_NT_HEADERS *)((uint8_t *)dos_header + dos_header->e_lfanew); + return pe_header->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI; +} + static bool do_rename_operation(const TCHAR *porig) { @@ -1811,7 +1845,7 @@ eu_free_toolbar(void) } void -eu_config_api_release(void) +eu_api_release(void) { eu_free_theme(); eu_free_config(); @@ -1991,6 +2025,12 @@ eu_save_config(void) " margin_right = %d,\n" " margin_bottom = %d\n" "}\n" + "-- titlebar default setting\n" + "titlebar = {\n" + " icon = %s,\n" + " name = %s,\n" + " path = %s\n" + "}\n" "-- hyperlink hotspot default setting\n" "hyperlink_detection = %s\n" "-- automatically cached file (size < 200MB)\n" @@ -2106,6 +2146,9 @@ eu_save_config(void) g_config->eu_print.rect.top, g_config->eu_print.rect.right, g_config->eu_print.rect.bottom, + g_config->eu_titlebar.icon?"true":"false", + g_config->eu_titlebar.name?"true":"false", + g_config->eu_titlebar.path?"true":"false", g_config->m_hyperlink?"true":"false", g_config->m_limit, g_config->upgrade.enable?"true":"false", @@ -2962,6 +3005,12 @@ eu_theme_index(void) return (const int)THEME_UNUSABLE; } +bool +eu_xml_pretty(void *ptr, struct opt_format *opt) +{ + return on_xml_pretty(ptr, opt); +} + double eu_te_eval(const te_expr *n) { diff --git a/src/eu_api.h b/src/eu_api.h index da9e0ef2..1e517593 100644 --- a/src/eu_api.h +++ b/src/eu_api.h @@ -349,6 +349,13 @@ typedef struct _print_set RECT rect; }print_set; +typedef struct _titlebar_set +{ + bool icon; + bool name; + bool path; +}titlebar_set; + typedef struct _caret_set { int blink; @@ -403,6 +410,17 @@ typedef struct _customize_set uintptr_t hbmp; }customize_set; +struct opt_format +{ + bool no_c; + bool no_p; + bool no_f; + bool no_x; + bool no_t; + bool no_d; + bool no_a; +}; + struct eu_config { int new_file_eol; @@ -467,6 +485,7 @@ struct eu_config calltip_set eu_calltip; complete_set eu_complete; print_set eu_print; + titlebar_set eu_titlebar; bool m_hyperlink; int m_limit; upgrade_set upgrade; @@ -597,7 +616,7 @@ EU_EXT_CLASS struct eu_theme *eu_get_theme(void); EU_EXT_CLASS struct eu_config *eu_get_config(void); EU_EXT_CLASS eue_accel *eu_get_accel(void); EU_EXT_CLASS eue_toolbar *eu_get_toolbar(void); -EU_EXT_CLASS void eu_config_api_release(void); +EU_EXT_CLASS void eu_api_release(void); EU_EXT_CLASS const int eu_theme_index(void); EU_EXT_CLASS const uint32_t eu_win10_or_later(void); @@ -836,6 +855,7 @@ EU_EXT_CLASS int on_doc_reload_list_reqular(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_reload_list_sh(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_reload_tree_xml(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_reload_tree_json(eu_tabpage *pnode); +EU_EXT_CLASS int on_doc_reload_tree_xml(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_reload_tree_sql(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_reload_tree_redis(eu_tabpage *pnode); @@ -843,6 +863,7 @@ EU_EXT_CLASS int on_doc_click_list_jmp(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_click_list_jump_sh(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_click_tree_sql(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_click_tree_json(eu_tabpage *pnode); +EU_EXT_CLASS int on_doc_click_tree_xml(eu_tabpage *pnode); EU_EXT_CLASS int on_doc_click_tree_redis(eu_tabpage *pnode); /* 脚本调用 */ @@ -864,6 +885,9 @@ EU_EXT_CLASS void on_doc_comment_light(eu_tabpage *pnode, int lex, intptr_t rgb) EU_EXT_CLASS void on_doc_commentblock_light(eu_tabpage *pnode, int lex, intptr_t rgb); EU_EXT_CLASS void on_doc_commentdoc_light(eu_tabpage *pnode, int lex, intptr_t rgb); +/* for eu_xmlist.c */ +EU_EXT_CLASS bool eu_xml_pretty(void *ptr, struct opt_format *opt); + #ifdef __cplusplus } #endif diff --git a/src/eu_complete.c b/src/eu_complete.c index 2c9d0f92..01094703 100644 --- a/src/eu_complete.c +++ b/src/eu_complete.c @@ -67,6 +67,12 @@ on_complete_zero_focus(void) _InterlockedExchange(&last_snippet_focus, 0); } +static inline bool +on_complete_is_space(uint8_t ch) +{ + return (ch == 0 || isspace(ch) || ispunct(ch)); +} + static inline bool on_complete_equal_value(eu_tabpage *pnode, complete_t *it, int j) { @@ -599,47 +605,52 @@ on_complete_do_replace(eu_tabpage *pnode, char *pstr) char *p = NULL; char *psrc = pstr; char res[VALUE_LEN] = {0}; - while (((p = strchr(psrc, '$')) && str_prev(p) != '\\') && - ((strlen(p) > 1 && UTIL_BASE10(p[1])) || - (strlen(p) > 3 && p[1] == '{' && UTIL_BASE10(p[2]) && p[3] == ':')) - ) + while ((p = strchr(psrc, '$'))) { - complete_t *oit = NULL; - cvector_for_each_and_cmp(pnode->ac_vec, on_complete_char_cmp, UTIL_BASE10(p[1]) ? p[1] : p[2], &oit); - if (!oit) + if ((strlen(p) > 1 && UTIL_BASE10(p[1]) && on_complete_is_space(p[2])) || (strlen(p) > 3 && p[1] == '{' && UTIL_BASE10(p[2]) && p[3] == ':')) { - if (p[1] == '{') - { // 语法错误 - on_complete_reset_focus(pnode); - break; + complete_t *oit = NULL; + cvector_for_each_and_cmp(pnode->ac_vec, on_complete_char_cmp, UTIL_BASE10(p[1]) ? p[1] : p[2], &oit); + if (!oit) + { + if (p[1] == '{') + { // 语法错误 + on_complete_reset_focus(pnode); + break; + } + else + { // 可能存在没匹配的占位符$0..$9, 写入vec数组 + complete_t data; + on_complete_vec_init(&data); + data.index = UTIL_NUMBER(p[1]); + cvector_push_back(pnode->ac_vec, data); + oit = &pnode->ac_vec[cvector_size(pnode->ac_vec) - 1]; + } } - else - { // 可能存在没匹配的占位符$0..$9, 写入vec数组 - complete_t data; - on_complete_vec_init(&data); - data.index = UTIL_NUMBER(p[1]); - cvector_push_back(pnode->ac_vec, data); - oit = &pnode->ac_vec[cvector_size(pnode->ac_vec) - 1]; + for (int j = 0; j < OVEC_LEN; ++j) + { + if (oit->pos[j].min < 0) + { + oit->pos[j].min = (p - pstr); + break; + } } - } - for (int j = 0; j < OVEC_LEN; ++j) - { - if (oit->pos[j].min < 0) + if (UTIL_BASE10(p[1])) { - oit->pos[j].min = (p - pstr); - break; + _snprintf(res, VALUE_LEN - 1, "%s", p + 2); } - } - if (UTIL_BASE10(p[1])) - { - _snprintf(res, VALUE_LEN - 1, "%s", p + 2); + else + { + _snprintf(res, VALUE_LEN - 1, "%s", p + strlen(oit->word)); + } + _snprintf(p, VALUE_LEN - (p - pstr) - 1, "%s%s", oit->value, res); + psrc = pstr; } else { - _snprintf(res, VALUE_LEN - 1, "%s", p + strlen(oit->word)); + psrc = p + 1; + continue; } - _snprintf(p, VALUE_LEN - (p - pstr) - 1, "%s%s", oit->value, res); - psrc = pstr; } } @@ -700,7 +711,9 @@ on_complete_replace(eu_tabpage *pnode, char *pstr, const char *space) char tmp[3] = {0}; complete_t *oit = NULL; on_complete_do_replace(pnode, pstr); + on_complete_vec_printer(pnode->ac_vec); on_complete_parser_value(pnode); + on_complete_vec_printer(pnode->ac_vec); on_complete_parser_postion(pnode); #ifdef APP_DEBUG printf("============ ac_vec start ===========\n"); diff --git a/src/eu_config.c b/src/eu_config.c index 97fc1e99..b35bb78f 100644 --- a/src/eu_config.c +++ b/src/eu_config.c @@ -280,6 +280,7 @@ on_config_sync_snippet(void) _T("text.snippets"), _T("verilog.snippets"), _T("pascal.snippets"), + _T("tcl.snippets"), NULL}; _sntprintf(p2, MAX_BUFFER, _T("%s\\snippets"), eu_config_path); if (!eu_exist_dir(p2)) diff --git a/src/eu_cvector.h b/src/eu_cvector.h index 6dd4440f..8070f8d5 100644 --- a/src/eu_cvector.h +++ b/src/eu_cvector.h @@ -51,7 +51,7 @@ /** * @brief cvector_vector_type - The vector type used in this library */ -#define cvector_vector_type(type) type * +#define cvector_vector_type(type_) type_ * /** * @brief cvector_capacity - gets the current capacity of the vector @@ -130,7 +130,7 @@ /** * @brief cvector_freep - frees all memory and assign null to_ the pointer - * @param_ pvec_ - the vector pointer + * @param_ pvec_ - the vector's pointer * @return void */ #define cvector_freep(pvec_) \ @@ -340,21 +340,22 @@ /* * @brief cvector_init - Initialize a vector. The vector must be NULL for this to_ do anything. - * @param_ vec_ - the vector - * @param_ capacity - vector capacity to_ reserve + * @param_ pvec_ - the vector's pointer + * @param_ count_ - the vector initialization size + * @param_ type_ - the vector type * @return void */ -#define cvector_init(vec_, count_) \ +#define cvector_init(pvec_, count_, type_) \ do \ { \ - const size_t cv_sz__ = (count_) * sizeof(*(vec_)) + (sizeof(size_t) * 2); \ - if (!(vec_)) \ + const size_t cv_sz__ = (count_) * sizeof(type_) + (sizeof(size_t) * 2); \ + if (!(*(pvec_))) \ { \ - size_t *cv_p__ = cvector_clib_calloc(cv_sz__); \ + size_t *cv_p__ = cvector_clib_calloc(1, cv_sz__); \ assert(cv_p__); \ - (vec_) = (void *) (&cv_p__[2]); \ - cvector_set_capacity((vec_), (count_) + 1); \ - cvector_set_size((vec_), ((count_))); \ + (*(pvec_)) = (void *) (&cv_p__[2]); \ + cvector_set_capacity((*(pvec_)), (count_)); \ + cvector_set_size((*(pvec_)), (0)); \ } \ } while (0) diff --git a/src/eu_doctype.c b/src/eu_doctype.c index c1b63646..5ae8628c 100644 --- a/src/eu_doctype.c +++ b/src/eu_doctype.c @@ -1110,6 +1110,10 @@ on_doc_init_after_xml(eu_tabpage *pnode) on_doc_number_light(pnode, SCE_H_NUMBER, 0); on_doc_commentblock_light(pnode, SCE_H_COMMENT, 0); on_doc_enable_foldline(pnode); + if (pnode->doc_ptr->fn_reload_symtree) + { + pnode->doc_ptr->fn_reload_symtree(pnode); + } return 0; } @@ -1847,6 +1851,12 @@ on_doc_reload_tree_json(eu_tabpage *pnode) return on_symtree_json(pnode); } +int +on_doc_reload_tree_xml(eu_tabpage *pnode) +{ + return on_xml_tree(pnode); +} + int on_doc_click_tree_sql(eu_tabpage *pnode) { @@ -1859,6 +1869,12 @@ on_doc_click_tree_json(eu_tabpage *pnode) return on_symtree_postion(pnode); } +int +on_doc_click_tree_xml(eu_tabpage *pnode) +{ + return on_symtree_postion(pnode); +} + int on_doc_click_tree_redis(eu_tabpage *pnode) { diff --git a/src/eu_doctype.h b/src/eu_doctype.h index 9a15394e..99300d0e 100644 --- a/src/eu_doctype.h +++ b/src/eu_doctype.h @@ -83,7 +83,8 @@ enum dctype DOCTYPE_VBS = 39, DOCTYPE_LATEX = 40, DOCTYPE_VERILOG = 41, - DOCTYPE_PASCAL = 42 + DOCTYPE_PASCAL = 42, + DOCTYPE_TCL = 43 }; typedef struct _doc_styles diff --git a/src/eu_document_map.c b/src/eu_document_map.c index 04a70b9c..49e0ac35 100644 --- a/src/eu_document_map.c +++ b/src/eu_document_map.c @@ -22,12 +22,12 @@ #define DLG_FROST (RGB(0xFF, 0xFF, 0xFF)) #define WINE_BACK_COLOR 0x1E1E1E +static volatile sptr_t canvas_default_proc = 0; HWND hwnd_document_map = NULL; HWND hwnd_document_static = NULL; volatile long document_map_initialized = 0; volatile long higher_y = 0; volatile long lower_y = 0; -static WNDPROC canvas_default_proc; typedef enum _move_mode { @@ -233,7 +233,7 @@ on_map_canvas_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) default : break; } - return canvas_default_proc(hwnd, message, wParam, lParam); + return ((WNDPROC)canvas_default_proc)(hwnd, message, wParam, lParam); } static intptr_t CALLBACK @@ -246,9 +246,15 @@ on_map_static_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) HWND hwnd_canvas = GetDlgItem(hwnd, IDC_VIEWZONE_CANVAS); if (NULL != hwnd_canvas) { - canvas_default_proc = (WNDPROC)SetWindowLongPtr(hwnd_canvas, GWLP_WNDPROC, (LONG_PTR)on_map_canvas_proc); - BringWindowToTop(hwnd); - util_transparent(hwnd, 50); + if (inter_atom_compare_exchange(&canvas_default_proc, SetWindowLongPtr(hwnd_canvas, GWLP_WNDPROC, (LONG_PTR)on_map_canvas_proc), 0)) + { + SetWindowLongPtr(hwnd_canvas, GWLP_WNDPROC, (LONG_PTR)on_map_canvas_proc); + } + if (canvas_default_proc) + { + BringWindowToTop(hwnd); + util_transparent(hwnd, 50); + } return 1; } break; diff --git a/src/eu_encoding.c b/src/eu_encoding.c index 420d09e9..a8c712de 100644 --- a/src/eu_encoding.c +++ b/src/eu_encoding.c @@ -18,6 +18,7 @@ #include "framework.h" +#define MAX_UTF_BITS 5 #define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) #define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) @@ -232,9 +233,8 @@ on_encoding_do_iconv(euconv_t *icv, char *src, size_t *src_len, char **dst, size size_t lsrc = *src_len; char *psrc = src; char *pdst = NULL; - size_t ldst = lsrc * 4; + size_t ldst = lsrc * MAX_UTF_BITS; int msg = IDOK; - int argument = 0; if (!init_conv_handle(icv)) { return (size_t) -1; @@ -262,14 +262,7 @@ on_encoding_do_iconv(euconv_t *icv, char *src, size_t *src_len, char **dst, size } } *plen = ldst; - if (eu_iconvctl(icv->cd, ICONV_SET_DISCARD_ILSEQ, &argument) != 0) - { - eu_logmsg("can't enable illegal feature!\n"); - close_conv_handle(icv); - return (size_t) -1; - } - *dst = (char *) malloc(ldst + 1); - if (*dst == NULL) + if ((*dst = (char *) malloc(ldst + 1)) == NULL) { close_conv_handle(icv); return (size_t) -1; @@ -280,14 +273,34 @@ on_encoding_do_iconv(euconv_t *icv, char *src, size_t *src_len, char **dst, size } ret = eu_iconv(icv->cd, &psrc, &lsrc, &pdst, &ldst); if (ret != (size_t) -1) - { - // 成功, 写入转换后的长度 + { // 成功, 写入转换后的长度 *plen -= ldst; } + else if (stricmp(icv->src_from, "gb18030") == 0) + { + eu_iconv_close(icv->cd); + icv->src_from = "cp936"; + if (init_conv_handle(icv)) + { + psrc = src; + lsrc = *src_len; + pdst = *dst; + ldst = lsrc * MAX_UTF_BITS; + ret = eu_iconv(icv->cd, &psrc, &lsrc, &pdst, &ldst); + } + if (ret != (size_t) -1) + { + *plen -= ldst; + } + else + { + eu_safe_free(*dst); + } + } else { eu_safe_free(*dst); - eu_logmsg("%s: [%s->%s] failed! lsrc = %zu, ldst = %zu, ret = %d\n", __FUNCTION__, icv->src_from, icv->dst_to, lsrc, ldst, (int)ret); + eu_logmsg("%s: [%s->%s] failed! lsrc = %zu, ldst = %zu, ret = %d, errno = %d\n", __FUNCTION__, icv->src_from, icv->dst_to, lsrc, ldst, (int)ret, errno); } close_conv_handle(icv); return ret; diff --git a/src/eu_format.c b/src/eu_format.c index 9575034d..f5b64f04 100644 --- a/src/eu_format.c +++ b/src/eu_format.c @@ -244,7 +244,7 @@ js_action(const uint8_t *ptext, size_t *in, uint8_t *pbuf, size_t *out, int d) } static void -init_stderr_redirect(FILE** pout, FILE **perr) +on_format_init_std(FILE** pout, FILE **perr) { if ((_fileno(stderr) != 2) && AllocConsole()) { @@ -255,13 +255,13 @@ init_stderr_redirect(FILE** pout, FILE **perr) } static char* -append_ext(eu_tabpage *pnode) +on_format_append_ext(eu_tabpage *pnode) { char *pname = NULL; if (pnode && pnode->doc_ptr) { TCHAR filename[MAX_BUFFER + 1] = {0}; - const TCHAR *tmp = pnode->filename[0] ? pnode->filename : _T("a"); + const TCHAR *tmp = pnode->pathfile[0] && !url_has_remote(pnode->pathfile) ? pnode->pathfile : _T("a"); switch (pnode->doc_ptr->doc_type) { case DOCTYPE_CPP: @@ -308,7 +308,7 @@ append_ext(eu_tabpage *pnode) } static bool -init_lib_format(const char *filename, const char *data, size_t size, char **pout) +on_format_init_dll(const char *filename, const char *data, size_t size, char **pout) { bool ret = false; HMODULE m_dll = np_load_plugin_library(FORMAT_DLL, false); @@ -318,7 +318,7 @@ init_lib_format(const char *filename, const char *data, size_t size, char **pout if (fn_lib_format) { FILE *out = NULL, *err = NULL; - init_stderr_redirect(&out, &err); + on_format_init_std(&out, &err); ret = fn_lib_format(filename, data, size, pout); eu_close_file(out); eu_close_console(err); @@ -466,6 +466,13 @@ on_format_json_callback(const uint8_t *text, uint8_t **pbuf) return SKYLARK_OK; } +int +on_format_xml_compress(eu_tabpage *pnode) +{ + on_search_do_space(pnode, ">[\\s\r\n]*<", "><", RE_REGXP); + return SKYLARK_OK; +} + void on_format_do_compress(eu_tabpage *pnode, format_back fn) { @@ -550,7 +557,7 @@ on_format_clang_file(eu_tabpage *p, const bool whole) { break; } - if (!(filename = append_ext(pnode))) + if (!(filename = on_format_append_ext(pnode))) { break; } @@ -576,7 +583,7 @@ on_format_clang_file(eu_tabpage *p, const bool whole) break; } eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); - if (init_lib_format(filename, text, whole ? text_len + 1 : text_len, &out) && strcmp(text, out)) + if (on_format_init_dll(filename, text, whole ? text_len + 1 : text_len, &out) && strcmp(text, out)) { if (whole) { @@ -609,9 +616,16 @@ on_format_clang_file(eu_tabpage *p, const bool whole) void on_format_file_style(eu_tabpage *pnode) { - if (pnode && !pnode->hex_mode && !pnode->pmod && pnode->doc_ptr && (pnode->doc_ptr->doc_type == DOCTYPE_JSON || pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT)) + if (pnode && !pnode->hex_mode && !pnode->pmod && pnode->doc_ptr) { - on_format_clang_file(pnode, true); + if (pnode->doc_ptr->doc_type == DOCTYPE_JSON || pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT) + { + on_format_clang_file(pnode, true); + } + else if (pnode->doc_ptr->doc_type == DOCTYPE_XML) + { + on_xml_format(pnode); + } } } diff --git a/src/eu_format.h b/src/eu_format.h index 30fccb2f..e7bc5f71 100644 --- a/src/eu_format.h +++ b/src/eu_format.h @@ -28,6 +28,7 @@ extern "C" int on_format_js_callback(const uint8_t *text, uint8_t **pbuf); int on_format_json_callback(const uint8_t *text, uint8_t **pbuf); +int on_format_xml_compress(eu_tabpage *pnode); void on_format_file_style(eu_tabpage *pnode); void on_format_do_compress(eu_tabpage *pnode, format_back fn); void on_format_clang_file(eu_tabpage *p, const bool whole); diff --git a/src/eu_hintctl.c b/src/eu_hintctl.c index 17d6c0cb..691bd2b4 100644 --- a/src/eu_hintctl.c +++ b/src/eu_hintctl.c @@ -22,7 +22,7 @@ static eu_tabpage *phint = NULL; static volatile long code_hint_initialized = 0; static void -on_hint_reload(const char **pbuf) +on_hint_reload(const char **pbuf, const int tab_width) { if (phint) { @@ -31,6 +31,8 @@ on_hint_reload(const char **pbuf) on_sci_set_margin(phint); // 回车符 eu_sci_call(phint, SCI_SETEOLMODE, phint->eol, 0); + // tab + eu_sci_call(phint, SCI_SETTABWIDTH, (sptr_t)tab_width, 0); // 不显示插入符 eu_sci_call(phint, SCI_SETCARETSTYLE, CARETSTYLE_INVISIBLE, 0); // 设置缩放级别 @@ -143,6 +145,7 @@ on_hint_launch(eu_tabpage *pnode, const RECT *prc, const char **pbuf, const int long r1 = 0; long r2 = 0; int flags = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_EX_RTLREADING; + const int tab_width = (const int)eu_sci_call(pnode, SCI_GETTABWIDTH, 0, 0); const sptr_t font_width = eu_sci_call(pnode, SCI_TEXTWIDTH, STYLE_DEFAULT, (sptr_t)"X"); const sptr_t font_hight = eu_sci_call(pnode, SCI_TEXTHEIGHT, 0, 0); memcpy(&phint->rect_sc, prc, sizeof(RECT)); @@ -152,13 +155,13 @@ on_hint_launch(eu_tabpage *pnode, const RECT *prc, const char **pbuf, const int { rc.left = prc->left; rc.top = prc->top + (long)font_hight * 2; - rc.right = (long)MIN((r1 = pnode->rect_sc.right - pnode->rect_sc.left - eu_dpi_scale_xy(0, 28)), (r2 = (long)(rc.left + (line_max + 3) * font_width))); + rc.right = (long)MIN((r1 = pnode->rect_sc.right - pnode->rect_sc.left - eu_dpi_scale_xy(0, 28)), (r2 = (long)(rc.left + (line_max + 2) * font_width))); rc.bottom = rc.top + (long)(line_count * font_hight); } else { rc.left = prc->left; - rc.right = (long)MIN((r1 = pnode->rect_sc.right - pnode->rect_sc.left - eu_dpi_scale_xy(0, 28)), (r2 = (long)(rc.left + (line_max + 3) * font_width))); + rc.right = (long)MIN((r1 = pnode->rect_sc.right - pnode->rect_sc.left - eu_dpi_scale_xy(0, 28)), (r2 = (long)(rc.left + (line_max + 2) * font_width))); rc.bottom = prc->top - (long)font_hight; rc.top = rc.bottom - (long)(line_count * font_hight); } @@ -169,7 +172,7 @@ on_hint_launch(eu_tabpage *pnode, const RECT *prc, const char **pbuf, const int if (on_sci_create(phint, (HWND)phint->reserved0, flags, on_hint_code_proc) == SKYLARK_OK) { on_dark_border(phint->hwnd_sc, true); - on_hint_reload(pbuf); + on_hint_reload(pbuf, tab_width); } return SetWindowPos((HWND)phint->reserved0, HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW); } diff --git a/src/eu_log.h b/src/eu_log.h index a65ae473..1f81510e 100644 --- a/src/eu_log.h +++ b/src/eu_log.h @@ -24,22 +24,22 @@ #endif #ifndef STRCMP -#define STRCMP(_a_,_C_,_b_) ( strcmp(_a_,_b_) _C_ 0 ) -#define STRNCMP(_a_,_C_,_b_,_n_) ( strncmp(_a_,_b_,_n_) _C_ 0 ) +#define STRCMP(_a_,_C_,_b_) (((_a_) && (_b_)) ? (strcmp(_a_,_b_) _C_ 0) : (false)) #endif -#ifndef STRICMP -#if ( defined _WIN32 ) -#define STRICMP(_a_,_C_,_b_) ( stricmp(_a_,_b_) _C_ 0 ) -#define STRNICMP(_a_,_C_,_b_,_n_) ( strnicmp(_a_,_b_,_n_) _C_ 0 ) -#elif ( defined __unix ) || ( defined _AIX ) || ( defined __linux__ ) || ( defined __hpux ) -#define STRICMP(_a_,_C_,_b_) ( strcasecmp(_a_,_b_) _C_ 0 ) -#define STRNICMP(_a_,_C_,_b_,_n_) ( strncasecmp(_a_,_b_,_n_) _C_ 0 ) +#if defined(_WIN32) +#ifndef WCSCMP +#define WCSCMP(_a_,_C_,_b_) (((_a_) && (_b_)) ? (wcscmp(_a_,_b_) _C_ 0) : (false)) +#define WCSICMP(_a_,_C_,_b_) (((_a_) && (_b_)) ? (wcsicmp(_a_,_b_) _C_ 0) : (false)) #endif #endif -#ifndef MEMCMP -#define MEMCMP(_a_,_C_,_b_,_n_) ( memcmp(_a_,_b_,_n_) _C_ 0 ) +#ifndef STRICMP +#if defined (_WIN32) +#define STRICMP(_a_,_C_,_b_) (((_a_) && (_b_)) ? (stricmp(_a_,_b_) _C_ 0) : (false)) +#elif (defined __unix) || (defined _AIX) || (defined __linux__) || (defined __hpux) +#define STRICMP(_a_,_C_,_b_) (((_a_) && (_b_)) ? (strcasecmp(_a_,_b_) _C_ 0) : (false)) +#endif #endif #if defined(_MSC_VER) diff --git a/src/eu_main.c b/src/eu_main.c index ed3144d6..918f7667 100644 --- a/src/eu_main.c +++ b/src/eu_main.c @@ -345,7 +345,7 @@ _tmain(int argc, TCHAR *argv[]) eu_font_release(); eu_dbase_release(); eu_logmsg("All cleanup, process exit code [%d]\n", (int) msg.wParam); - eu_config_api_release(); + eu_api_release(); eu_reset_config(); return (int) msg.wParam; } diff --git a/src/eu_menu.c b/src/eu_menu.c index 78be16cf..ab884253 100644 --- a/src/eu_menu.c +++ b/src/eu_menu.c @@ -544,6 +544,9 @@ menu_update_item(const HMENU menu, const bool init) util_update_menu_chars(menu, IDM_VIEW_TAB_WIDTH, eu_get_config()->tab_width); util_set_menu_item(menu, IDM_TAB_CONVERT_SPACES, eu_get_config()->tab2spaces); } + util_set_menu_item(GetSubMenu(menu, TAB_MENU_TITLEBAR_SUB), IDM_VIEW_TITLEBAR_ICON, eu_get_config()->eu_titlebar.icon); + util_set_menu_item(GetSubMenu(menu, TAB_MENU_TITLEBAR_SUB), IDM_VIEW_TITLEBAR_NAME, eu_get_config()->eu_titlebar.name); + util_set_menu_item(GetSubMenu(menu, TAB_MENU_TITLEBAR_SUB), IDM_VIEW_TITLEBAR_PATH, eu_get_config()->eu_titlebar.path); util_switch_menu_group(menu, TAB_HISTORY_SUB, IDM_VIEW_HISTORY_NONE, IDM_VIEW_HISTORY_ALL, eu_get_config()->history_mask); util_switch_menu_group(menu, TAB_MENU_TOOLBAR_SUB, IDB_SIZE_0, IDB_SIZE_128, eu_get_config()->m_toolbar); util_switch_menu_group(menu, TAB_MENU_ACTIVE_SUB, IDM_VIEW_LEFT_TAB, IDM_VIEW_FAR_RIGHT_TAB, eu_get_config()->m_tab_active); @@ -572,6 +575,7 @@ menu_update_item(const HMENU menu, const bool init) pnode->doc_ptr->doc_type == DOCTYPE_JAVA || pnode->doc_ptr->doc_type == DOCTYPE_JAVASCRIPT || pnode->doc_ptr->doc_type == DOCTYPE_JSON)))); + util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_XML, init ||(pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_XML)); util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_LUA, init ||(pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_LUA)); util_enable_menu_item(menu, IDM_EDIT_PLACEHOLDE_ICODE, init || (!pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode))); util_enable_menu_item(menu, IDM_FORMAT_PLACEHOLDE_PUNCTUATION, init || (!pnode->hex_mode && !pnode->plugin && TAB_NOT_NUL(pnode))); @@ -629,9 +633,11 @@ menu_update_item(const HMENU menu, const bool init) on_theme_update_item(); menu_switch_theme(); if (!init) - { + { // 盾牌图标 menu_shield_icons(menu, IDM_ENV_FILE_POPUPMENU, IDM_ENV_SET_ASSOCIATED_WITH); + // 定制命令图标 menu_setting_icons(menu); + // 定制命令菜单更新 on_setting_update_menu(menu); } break; diff --git a/src/eu_menu.h b/src/eu_menu.h index 2cbf2709..d5830658 100644 --- a/src/eu_menu.h +++ b/src/eu_menu.h @@ -27,15 +27,16 @@ /* 子菜单弹出菜单位置 */ #define TAB_MENU_PANELS_SUB 4 -#define TAB_MENU_TOOLBAR_SUB 5 -#define TAB_MENU_HILIGHT_SUB 12 -#define TAB_DISPLAY_SUB 15 -#define TAB_HISTORY_SUB 16 -#define TAB_MENU_ACTIVE_SUB 18 -#define TAB_MENU_CLOSE_SUB 19 -#define TAB_MENU_NEW_SUB 20 -#define TAB_MENU_CBUTTON_SUB 21 -#define TAB_MENU_SCROLLCURSOR 23 +#define TAB_MENU_TITLEBAR_SUB 5 +#define TAB_MENU_TOOLBAR_SUB 6 +#define TAB_MENU_HILIGHT_SUB 13 +#define TAB_DISPLAY_SUB 16 +#define TAB_HISTORY_SUB 17 +#define TAB_MENU_ACTIVE_SUB 19 +#define TAB_MENU_CLOSE_SUB 20 +#define TAB_MENU_NEW_SUB 21 +#define TAB_MENU_CBUTTON_SUB 22 +#define TAB_MENU_SCROLLCURSOR 24 #define PROGRAM_SNIPPET_SUB 15 #define CUSTOMIZED_CMD_SUB 14 diff --git a/src/eu_proc.c b/src/eu_proc.c index 41ed186b..b321cbec 100644 --- a/src/eu_proc.c +++ b/src/eu_proc.c @@ -721,10 +721,17 @@ eu_main_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PostQuitMessage(0); } - if (eu_get_config()->m_fullscreen) + if (eu_get_config()) { - eu_get_config()->m_statusbar = false; - on_view_setfullscreenimpl(hwnd); + if (eu_get_config()->m_fullscreen) + { + eu_get_config()->m_statusbar = false; + on_view_setfullscreenimpl(hwnd); + } + else + { + util_updateui_icon(hwnd, eu_get_config()->eu_titlebar.icon); + } } break; case WM_NCPAINT: @@ -1000,6 +1007,7 @@ eu_main_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } if (IDM_SET_LUAJIT_EXECUTE <= wm_id && wm_id <= IDM_SET_LUAJIT_EXECUTE + DW_SIZE - 1) { + eu_logmsg("Run custom menu, wm_id = %d\n", (int)wm_id); on_setting_execute(g_hwndmain, wm_id); break; } @@ -1532,6 +1540,22 @@ eu_main_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) on_sci_refresh_ui(pnode); } break; + case IDM_FORMAT_REFORMAT_XML: + if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_XML) + { + on_format_file_style(pnode); + on_xml_tree(pnode); + on_sci_refresh_ui(pnode); + } + break; + case IDM_FORMAT_COMPRESS_XML: + if (pnode->doc_ptr && !pnode->hex_mode && pnode->doc_ptr->doc_type == DOCTYPE_XML) + { + on_format_xml_compress(pnode); + on_xml_tree(pnode); + on_sci_refresh_ui(pnode); + } + break; case IDM_FORMAT_WHOLE_FILE: on_format_clang_file(pnode, true); on_sci_refresh_ui(pnode); @@ -1593,6 +1617,18 @@ eu_main_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VIEW_INDENTGUIDES_VISIABLE: on_view_indent_visiable(); break; + case IDM_VIEW_TITLEBAR_ICON: + eu_get_config()->eu_titlebar.icon ^= true; + util_updateui_icon(hwnd, eu_get_config()->eu_titlebar.icon); + break; + case IDM_VIEW_TITLEBAR_NAME: + eu_get_config()->eu_titlebar.name ^= true; + util_set_title(pnode); + break; + case IDM_VIEW_TITLEBAR_PATH: + eu_get_config()->eu_titlebar.path ^= true; + util_set_title(pnode); + break; case IDM_VIEW_HISTORY_NONE: case IDM_VIEW_HISTORY_MARGIN: case IDM_VIEW_HISTORY_DOCS: @@ -2203,19 +2239,14 @@ eu_main_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) static ATOM class_register(HINSTANCE instance) { - WNDCLASSEX wcex; - wcex.cbSize = sizeof(WNDCLASSEX); + WNDCLASSEX wcex = {sizeof(WNDCLASSEX)}; wcex.style = CS_BYTEALIGNWINDOW | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = eu_main_proc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; wcex.hInstance = instance; - wcex.hIcon = LoadIcon(instance, MAKEINTRESOURCE(IDI_SKYLARK)); + wcex.hIconSm = wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wcex.lpszMenuName = NULL; wcex.lpszClassName = APP_CLASS; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SKYLARK)); return RegisterClassEx(&wcex); } @@ -2253,9 +2284,8 @@ eu_create_main_window(HINSTANCE instance) CloseHandle((HANDLE) _beginthreadex(NULL, 0, do_calss_drop, NULL, 0, NULL)); if (class_register(instance)) { - INITCOMMONCONTROLSEX icex; uint32_t ac_flags = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + INITCOMMONCONTROLSEX icex = {sizeof(INITCOMMONCONTROLSEX)}; icex.dwICC = ICC_TAB_CLASSES | ICC_COOL_CLASSES | ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES | ICC_USEREX_CLASSES; if (InitCommonControlsEx(&icex)) { diff --git a/src/eu_scintilla.c b/src/eu_scintilla.c index abb91413..fb47945e 100644 --- a/src/eu_scintilla.c +++ b/src/eu_scintilla.c @@ -673,6 +673,7 @@ on_sci_parser_line(eu_tabpage *p, const sptr_t current_line, const sptr_t last_l size_t len = 0; const sptr_t end_y = (const sptr_t )(p->rect_sc.bottom - p->rect_sc.top); const sptr_t font_hight = eu_sci_call(p, SCI_TEXTHEIGHT, 0, 0); + const int tab_width = (const int)eu_sci_call(p, SCI_GETTABWIDTH, 0, 0); const int w_count = (const int)(last_line - current_line + 1); // 确认代码提示向上还是向下 if (w_count <= eu_int_cast((end_y - current_y)/font_hight - 1)) @@ -700,7 +701,13 @@ on_sci_parser_line(eu_tabpage *p, const sptr_t current_line, const sptr_t last_l { // clang, 整型指针转size_t指针导致__fastfail? char *buffer = util_strdup_line(p, i, &len); if (buffer) - { + { // 把tab键占用的字符数算进去 + int j = util_count_characters(buffer, '\t'); + if (j > 0 && tab_width > 0) + { + j *= (tab_width - 1); + len += (size_t)j; + } cvector_push_back(*vec_buf, buffer); } if (len > (size_t)*pmax) diff --git a/src/eu_script.c b/src/eu_script.c index eba50435..484298e4 100644 --- a/src/eu_script.c +++ b/src/eu_script.c @@ -678,7 +678,7 @@ do_lua_func(const char *fname, const char *func, const char *arg) return status; } -static int +int do_lua_point(const char *fname, const char *func, void *arg) { int status; diff --git a/src/eu_script.h b/src/eu_script.h index b095aabb..146b8ffb 100644 --- a/src/eu_script.h +++ b/src/eu_script.h @@ -26,6 +26,7 @@ extern "C" { int do_lua_func(const char *, const char *, const char *arg); int do_lua_code(const char *s); int do_byte_code(eu_tabpage *pnode); +int do_lua_point(const char *fname, const char *func, void *arg); int do_lua_parser_doctype(const char *fname, const char *func); void do_lua_parser_release(void); bool do_lua_setting_path(eu_tabpage *pnode); diff --git a/src/eu_search.c b/src/eu_search.c index 1169203e..a3da5711 100644 --- a/src/eu_search.c +++ b/src/eu_search.c @@ -3926,7 +3926,7 @@ on_search_orig_find_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return 0; } -static void +void on_search_do_space(eu_tabpage *pnode, const char *key, const char *str_replace, replace_event docase) { sptr_t fpos = -1; diff --git a/src/eu_search.h b/src/eu_search.h index 8e63d994..db17dc56 100644 --- a/src/eu_search.h +++ b/src/eu_search.h @@ -52,7 +52,8 @@ typedef enum _replace_event FULL_HALF = 0, HALF_FULL, TAB_SPACE, - SPACE_TAB + SPACE_TAB, + RE_REGXP }replace_event; typedef struct _btn_state @@ -131,8 +132,8 @@ void on_search_repalce_event(eu_tabpage *p, replace_event docase); void on_search_jmp_matching_brace(eu_tabpage *pnode, int *pres); void on_search_turn_select(eu_tabpage *pnode); void on_search_regxp_error(void); -void -on_search_jmp_next_history(eu_tabpage *pnode); +void on_search_jmp_next_history(eu_tabpage *pnode); +void on_search_do_space(eu_tabpage *pnode, const char *key, const char *str_replace, replace_event docase); #ifdef __cplusplus } diff --git a/src/eu_settings.c b/src/eu_settings.c index 3185244d..64ecb618 100644 --- a/src/eu_settings.c +++ b/src/eu_settings.c @@ -38,18 +38,18 @@ on_setting_lua_icon(const int resid) static HBITMAP on_setting_load_icon(const TCHAR *path) { - int nid; // ID of resource that best fits current screen - HINSTANCE hexe; // handle to loaded .EXE file - HRSRC hresource; // handle to FindResource - HRSRC hmem; // handle to LoadResource - BYTE *lpresource; // pointer to resource data + int nid; // ID of resource that best fits current screen + HRSRC hresource; // handle to FindResource + HRSRC hmem; // handle to LoadResource + BYTE *lpresource; // pointer to resource data HICON hicon = NULL; HBITMAP hmap = NULL; + HINSTANCE hexe = NULL; // handle to loaded .EXE file const uint32_t dpi = eu_get_dpi(NULL); const int scx = Scintilla_GetSystemMetricsForDpi(SM_CXSMICON, dpi); const int scy = Scintilla_GetSystemMetricsForDpi(SM_CYSMICON, dpi); // Load the file from which to copy the icon. - do + while (!_tcsicmp(util_path_ext(path), _T("exe"))) { // Note: LoadLibrary should have a fully explicit path. if ((hexe = (HINSTANCE)LoadLibrary(path)) == NULL) @@ -65,6 +65,10 @@ on_setting_load_icon(const TCHAR *path) break; } } + if (!hresource && WCSICMP(util_path_filename(path), ==, _T("calc.exe"))) + { + hresource = FindResource(hexe, _T("IDI_CALC_ICON"), RT_GROUP_ICON); + } // Load and lock the icon directory. if (!(hmem = hresource ? LoadResource(hexe, hresource): NULL)) { @@ -91,7 +95,8 @@ on_setting_load_icon(const TCHAR *path) lpresource = LockResource(hmem); // Create a handle to the icon. hicon = CreateIconFromResourceEx((PBYTE) lpresource, SizeofResource(hexe, hresource), TRUE, 0x00030000, scx, scy, LR_DEFAULTCOLOR); - } while(0); + break; + } if (hicon) { hmap = util_icon_bitmap(hicon, scx, scy); diff --git a/src/eu_symlistctl.c b/src/eu_symlistctl.c index 33477660..77e69219 100644 --- a/src/eu_symlistctl.c +++ b/src/eu_symlistctl.c @@ -18,7 +18,7 @@ #include "framework.h" -static WNDPROC symlist_wnd; +static volatile sptr_t symlist_wnd = 0; static int pcre_match_callback(pcre_conainer *pcre_info, void *param) @@ -180,13 +180,13 @@ on_symlist_update_theme(eu_tabpage *pnode) LRESULT CALLBACK symlist_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - eu_tabpage *pnode = NULL; switch (message) { case WM_COMMAND: { if (LOWORD(wParam) == IDM_RELOAD_SYMBOLLIST) { + eu_tabpage *pnode = NULL; if ((pnode = on_tabpage_focus_at()) && pnode->doc_ptr && pnode->doc_ptr->fn_reload_symlist) { pnode->doc_ptr->fn_reload_symlist(pnode); @@ -196,8 +196,7 @@ symlist_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } case WM_LBUTTONDBLCLK: { - pnode = (eu_tabpage *) GetWindowLongPtr(hwnd, GWLP_USERDATA); - on_tabpage_symlist_click(pnode); + on_tabpage_symlist_click((eu_tabpage *) GetWindowLongPtr(hwnd, GWLP_USERDATA)); return 1; } case WM_RBUTTONDOWN: @@ -206,8 +205,7 @@ symlist_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } case WM_DPICHANGED: { - pnode = (eu_tabpage *) GetWindowLongPtr(hwnd, GWLP_USERDATA); - on_symlist_update_theme(pnode); + on_symlist_update_theme((eu_tabpage *) GetWindowLongPtr(hwnd, GWLP_USERDATA)); break; } case WM_DESTROY: @@ -218,14 +216,13 @@ symlist_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) default: break; } - return CallWindowProc(symlist_wnd, hwnd, message, wParam, lParam); + return CallWindowProc((WNDPROC)symlist_wnd, hwnd, message, wParam, lParam); } int on_symlist_create(eu_tabpage *pnode) { - EU_VERIFY(pnode != NULL); - if (pnode->doc_ptr->reqular_exp) + if (pnode && pnode->doc_ptr && pnode->doc_ptr->reqular_exp) { if (pnode->hwnd_symlist) { @@ -247,7 +244,11 @@ on_symlist_create(eu_tabpage *pnode) MSG_BOX(IDC_MSG_SYMLIST_FAIL, IDC_MSG_ERROR, MB_ICONERROR | MB_OK); return 1; } - if (!(symlist_wnd = (WNDPROC) SetWindowLongPtr(pnode->hwnd_symlist, GWLP_WNDPROC, (LONG_PTR) symlist_proc))) + if (inter_atom_compare_exchange(&symlist_wnd, SetWindowLongPtr(pnode->hwnd_symlist, GWLP_WNDPROC, (LONG_PTR) symlist_proc), 0)) + { + SetWindowLongPtr(pnode->hwnd_symlist, GWLP_WNDPROC, (LONG_PTR) symlist_proc); + } + if (!symlist_wnd) { eu_logmsg("%s: SetWindowLongPtr(pnode->hwnd_symlist) failed\n", __FUNCTION__); return 1; diff --git a/src/eu_symtreectl.c b/src/eu_symtreectl.c index 47831e1b..d216099f 100644 --- a/src/eu_symtreectl.c +++ b/src/eu_symtreectl.c @@ -18,7 +18,7 @@ #include "framework.h" -static WNDPROC symtree_wnd; +static volatile sptr_t symtree_wnd = 0; static char * get_symtree_str(eu_tabpage *pnode, bool get_parent) @@ -964,8 +964,8 @@ on_symtree_query_redis(eu_tabpage *pnode) return 0; } -static HTREEITEM -tvi_insert_str(HWND hwnd, HTREEITEM parent, const char *str, int64_t pos) +HTREEITEM +on_symtree_insert_str(HWND hwnd, HTREEITEM parent, const char *str, int64_t pos) { HTREEITEM hti = NULL; TVITEM tvi = {0}; @@ -989,6 +989,18 @@ tvi_insert_str(HWND hwnd, HTREEITEM parent, const char *str, int64_t pos) return hti; } +void +on_symtree_expand_all(const HWND htree, const HTREEITEM hitem) +{ + HTREEITEM hchild = TreeView_GetChild(htree, hitem); + while (hchild) + { + TreeView_Expand(htree,hchild,TVE_EXPAND); + on_symtree_expand_all(htree, hchild); + hchild = TreeView_GetNextItem(htree, hchild, TVGN_NEXT); + } +} + static HTREEITEM tvi_inser_object(HWND dlg, HTREEITEM parent, const char *parent_str, const char *text, int64_t pos) { @@ -1025,18 +1037,6 @@ tvi_inser_object(HWND dlg, HTREEITEM parent, const char *parent_str, const char return hti; } -static void -expand_all_child(HWND htree, HTREEITEM hitem) -{ - HTREEITEM hchild = TreeView_GetChild(htree, hitem); - while (hchild) - { - TreeView_Expand(htree,hchild,TVE_EXPAND); - expand_all_child(htree, hchild); - hchild = TreeView_GetNextItem(htree, hchild, TVGN_NEXT); - } -} - static void process_value(eu_tabpage *pnode, HTREEITEM tree_root, json_value *value, int x); @@ -1053,11 +1053,11 @@ process_object(eu_tabpage *pnode, HTREEITEM tree_root, json_value *value, int x, if (value->parent != NULL && value->parent->type != json_array && value->parent->u.object.values[x].name) { - new_tvi = tvi_insert_str(pnode->hwnd_symtree, tree_root, value->parent->u.object.values[x].name, pos); + new_tvi = on_symtree_insert_str(pnode->hwnd_symtree, tree_root, value->parent->u.object.values[x].name, pos); } else { - new_tvi = tvi_insert_str(pnode->hwnd_symtree, tree_root, "(object)", pos); + new_tvi = on_symtree_insert_str(pnode->hwnd_symtree, tree_root, "(object)", pos); } for (int i = 0; i < length; i++) { @@ -1122,7 +1122,7 @@ process_value(eu_tabpage *pnode, HTREEITEM new_tvi, json_value *json_root, int x } else { - tvi_insert_str(pnode->hwnd_symtree, new_tvi, i2s, pos); + on_symtree_insert_str(pnode->hwnd_symtree, new_tvi, i2s, pos); } break; } @@ -1136,7 +1136,7 @@ process_value(eu_tabpage *pnode, HTREEITEM new_tvi, json_value *json_root, int x } else { - tvi_insert_str(pnode->hwnd_symtree, new_tvi, f2s, pos); + on_symtree_insert_str(pnode->hwnd_symtree, new_tvi, f2s, pos); } break; } @@ -1147,7 +1147,7 @@ process_value(eu_tabpage *pnode, HTREEITEM new_tvi, json_value *json_root, int x } else { - tvi_insert_str(pnode->hwnd_symtree, new_tvi, json_root->u.string.ptr, pos); + on_symtree_insert_str(pnode->hwnd_symtree, new_tvi, json_root->u.string.ptr, pos); } break; case json_boolean: @@ -1157,7 +1157,7 @@ process_value(eu_tabpage *pnode, HTREEITEM new_tvi, json_value *json_root, int x } else { - tvi_insert_str(pnode->hwnd_symtree, new_tvi, json_root->u.jbool ? "true" : "false", pos); + on_symtree_insert_str(pnode->hwnd_symtree, new_tvi, json_root->u.jbool ? "true" : "false", pos); } break; case json_null: @@ -1167,7 +1167,7 @@ process_value(eu_tabpage *pnode, HTREEITEM new_tvi, json_value *json_root, int x } else { - tvi_insert_str(pnode->hwnd_symtree, new_tvi, "null", pos); + on_symtree_insert_str(pnode->hwnd_symtree, new_tvi, "null", pos); } break; default: @@ -1192,9 +1192,9 @@ init_json_tree(eu_tabpage *pnode, const char *buffer, int64_t len) } else { - tvi_insert_str(pnode->hwnd_symtree, tree_root, NULL, 0); + on_symtree_insert_str(pnode->hwnd_symtree, tree_root, NULL, 0); } - expand_all_child(pnode->hwnd_symtree, tree_root); + on_symtree_expand_all(pnode->hwnd_symtree, tree_root); return ret; } @@ -1202,11 +1202,7 @@ static unsigned WINAPI cjson_thread(void *lp) { eu_tabpage *pnode = (eu_tabpage *) lp; - if (!pnode) - { - return 1; - } - if (pnode->hwnd_symtree) + if (pnode && pnode->hwnd_symtree) { char *text = NULL; size_t text_len = 0; @@ -1218,20 +1214,21 @@ cjson_thread(void *lp) } free(text); } + _InterlockedExchange(&pnode->json_id, 0); } - _InterlockedExchange(&pnode->json_id, 0); return 0; } int on_symtree_json(eu_tabpage *pnode) { - if (!pnode) + if (!pnode || !pnode->hwnd_symtree) { return 1; } if (pnode->raw_size > 0xA00000) - { // size > 10MB + { + eu_logmsg("Error: This json file is larger than 10MB\n"); if (pnode->hwnd_symtree) { DestroyWindow(pnode->hwnd_symtree); @@ -1239,7 +1236,10 @@ on_symtree_json(eu_tabpage *pnode) } return 1; } - CloseHandle((HANDLE) _beginthreadex(NULL, 0, &cjson_thread, pnode, 0, (uint32_t *)&pnode->json_id)); + if (!pnode->json_id) + { + CloseHandle((HANDLE) _beginthreadex(NULL, 0, &cjson_thread, pnode, 0, (uint32_t *)&pnode->json_id)); + } return 0; } @@ -1375,12 +1375,11 @@ symtree_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) ClientToScreen(hwnd, &pt); if (tvhti.flags & TVHT_ONITEM) { - if (!(pnode = (eu_tabpage *) GetWindowLongPtr(hwnd, GWLP_USERDATA))) + if (!(pnode = on_tabpage_focus_at())) { break; } - if ((pnode->db_ptr && pnode->db_ptr->connected) || - (pnode->redis_ptr && pnode->redis_ptr->connected) ) + if ((pnode->db_ptr && pnode->db_ptr->connected) || (pnode->redis_ptr && pnode->redis_ptr->connected)) { TreeView_SelectItem(hwnd, tvhti.hItem); if (TreeView_GetChild(hwnd, tvhti.hItem)) @@ -1401,8 +1400,7 @@ symtree_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } case WM_DPICHANGED: { - pnode = on_tabpage_focus_at(); - on_symtree_update_theme(pnode); + on_symtree_update_theme((eu_tabpage *) GetWindowLongPtr(hwnd, GWLP_USERDATA)); break; } case WM_DESTROY: @@ -1413,34 +1411,41 @@ symtree_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) default: break; } - return CallWindowProc(symtree_wnd, hwnd, message, wParam, lParam); + return CallWindowProc((WNDPROC)symtree_wnd, hwnd, message, wParam, lParam); } int on_symtree_create(eu_tabpage *pnode) { - if (pnode->hwnd_symtree) - { - DestroyWindow(pnode->hwnd_symtree); - } - const int style = WS_CHILD | WS_CLIPSIBLINGS | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | WS_TABSTOP; - pnode->hwnd_symtree = CreateWindow(WC_TREEVIEW, NULL, style, 0, 0, 0, 0, eu_module_hwnd(), NULL, eu_module_handle(), NULL); - if (pnode->hwnd_symtree == NULL) + if (pnode) { - MSG_BOX(IDC_MSG_SYMTREE_ERR1, IDC_MSG_ERROR, MB_ICONERROR | MB_OK); - return 1; - } - if (!(symtree_wnd = (WNDPROC) SetWindowLongPtr(pnode->hwnd_symtree, GWLP_WNDPROC, (LONG_PTR) symtree_proc))) - { - eu_logmsg("%s: SetWindowLongPtr(pnode->hwnd_symtree) failed\n", __FUNCTION__); - DestroyWindow(pnode->hwnd_symtree); - pnode->hwnd_symtree = NULL; - return 1; - } - else - { - SetWindowLongPtr(pnode->hwnd_symtree, GWLP_USERDATA, (intptr_t) pnode); - on_symtree_update_theme(pnode); + if (pnode->hwnd_symtree) + { + DestroyWindow(pnode->hwnd_symtree); + } + const int style = WS_CHILD | WS_CLIPSIBLINGS | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | WS_TABSTOP; + pnode->hwnd_symtree = CreateWindow(WC_TREEVIEW, NULL, style, 0, 0, 0, 0, eu_module_hwnd(), NULL, eu_module_handle(), NULL); + if (pnode->hwnd_symtree == NULL) + { + MSG_BOX(IDC_MSG_SYMTREE_ERR1, IDC_MSG_ERROR, MB_ICONERROR | MB_OK); + return 1; + } + if (inter_atom_compare_exchange(&symtree_wnd, SetWindowLongPtr(pnode->hwnd_symtree, GWLP_WNDPROC, (LONG_PTR) symtree_proc), 0)) + { + SetWindowLongPtr(pnode->hwnd_symtree, GWLP_WNDPROC, (LONG_PTR) symtree_proc); + } + if (!symtree_wnd) + { + eu_logmsg("%s: SetWindowLongPtr(pnode->hwnd_symtree) failed\n", __FUNCTION__); + DestroyWindow(pnode->hwnd_symtree); + pnode->hwnd_symtree = NULL; + return 1; + } + else + { + SetWindowLongPtr(pnode->hwnd_symtree, GWLP_USERDATA, (intptr_t) pnode); + on_symtree_update_theme(pnode); + } } return 0; } diff --git a/src/eu_symtreectl.h b/src/eu_symtreectl.h index e7479b9d..090b8f74 100644 --- a/src/eu_symtreectl.h +++ b/src/eu_symtreectl.h @@ -67,6 +67,8 @@ int on_symtree_postion(eu_tabpage *pnode); int on_symtree_create(eu_tabpage *pnode); int on_symtree_add_text(eu_tabpage *pnode); int on_symtree_update_theme(eu_tabpage *pnode); +void on_symtree_expand_all(const HWND htree, const HTREEITEM hitem); +HTREEITEM on_symtree_insert_str(HWND hwnd, HTREEITEM parent, const char *str, int64_t pos); #ifdef __cplusplus } diff --git a/src/eu_tabpage.c b/src/eu_tabpage.c index d0afb528..e2be134d 100644 --- a/src/eu_tabpage.c +++ b/src/eu_tabpage.c @@ -1533,16 +1533,17 @@ eu_tabpage * on_tabpage_get_handle(void *hwnd_sc) { eu_tabpage *p = NULL; - EU_VERIFY(g_tabpages != NULL); - for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) + if (g_tabpages && (HWND)hwnd_sc) { - p = on_tabpage_get_ptr(index); - if (p && p->hwnd_sc == hwnd_sc) + for (int index = 0, count = TabCtrl_GetItemCount(g_tabpages); index < count; ++index) { - return p; + if ((p = on_tabpage_get_ptr(index)) && p->hwnd_sc == (HWND)hwnd_sc) + { + break; + } } } - return NULL; + return p; } int diff --git a/src/eu_util.c b/src/eu_util.c index 7c332ed6..3dfc507a 100644 --- a/src/eu_util.c +++ b/src/eu_util.c @@ -1055,7 +1055,7 @@ util_set_title(const eu_tabpage *pnode) TCHAR *title = NULL; const TCHAR *filename = pnode->pathfile; bool admin = !util_under_wine() && on_reg_admin(); - if ((len = _tcslen(pnode->pathfile)) > FILESIZE && pnode->filename[0]) + if (((len = _tcslen(pnode->pathfile)) > FILESIZE && pnode->filename[0]) || !eu_get_config()->eu_titlebar.path) { filename = pnode->filename; } @@ -1065,11 +1065,25 @@ util_set_title(const eu_tabpage *pnode) LOAD_APP_RESSTR(IDS_APP_TITLE, app_title); if (!filename[0]) { - _sntprintf(title, len, admin ? _T("%s [Administrator]") : _T("%s"), app_title); + if (eu_get_config()->eu_titlebar.name) + { + _sntprintf(title, len, admin ? _T("%s [Administrator]") : _T("%s"), app_title); + } + else + { + _sntprintf(title, len, _T("%s"), _T("")); + } } else { - _sntprintf(title, len, admin ? _T("%s [Administrator] - %s") : _T("%s - %s"), app_title, filename); + if (eu_get_config()->eu_titlebar.name) + { + _sntprintf(title, len, admin ? _T("%s [Administrator] - %s") : _T("%s - %s"), app_title, filename); + } + else + { + _sntprintf(title, len, _T("%s"), filename); + } } } SetWindowText(eu_module_hwnd(), title); @@ -1320,17 +1334,43 @@ util_availed_char(int ch) return false; } +bool +util_has_space(uint8_t ch) +{ + if (ch == '\r' || ch == '\n' || ch == '\t' || ch == ' ') + { + return true; + } + return false; +} + /************************************************** - * 去除字符串右边的*号字符 + * 去除字符串左右两端的空白字符 + * 返回一个指针, 使用后需释放(free) *************************************************/ -void -util_trim_right_star(TCHAR *str) +char* +util_trim_sides_white(const uint8_t *str) { - size_t str_len = _tcslen(str); - if (str_len > 0 && str[str_len - 1] == _T('*')) + char *p = NULL; + if (STR_NOT_NUL(str)) { - str[str_len - 1] = 0; + int i = 0; + int j = (int)strlen((const char *)str) - 1; + while(util_has_space(str[i])) + { + ++i; + } + while(util_has_space(str[j])) + { + --j; + } + if (j > 0 && (p = malloc(j + 2))) + { + strncpy(p, (const char *)(str + i), j - i + 1); + p[j - i + 1] = '\0'; + } } + return p; } /************************************************** @@ -2089,6 +2129,21 @@ util_count_number(size_t number) return length; } +int +util_count_characters(const char *pstr, const int ch) +{ + int var; + int c = 0; + while ((var = *pstr++)) + { + if (var == ch) + { + ++c; + } + } + return c; +} + sptr_t util_select_characters(eu_tabpage *pnode, const sptr_t start, const sptr_t end) { @@ -2479,40 +2534,6 @@ util_which(const TCHAR *name) return NULL; } -int -eu_prepend_path(const TCHAR *dir) -{ - size_t bufsize; - TCHAR *path; - TCHAR *value = NULL; - int rc = -1; - if ((path = _tgetenv(_T("PATH"))) == NULL) - { - return (-1); - } - bufsize = _tcslen(dir) + _tcslen(path) + 8; - value = (TCHAR *)calloc(1, bufsize * sizeof(TCHAR)); - if (value && _sntprintf(value, bufsize, _T("PATH=%s;%s"), dir, path) > 0) - { - rc = _tputenv(value); - } - eu_safe_free(value); - return rc; -} - -bool -eu_gui_app(void) -{ - HMODULE hmodule = GetModuleHandle(NULL); - if(hmodule == NULL) - { - return false; - } - IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER *)hmodule; - IMAGE_NT_HEADERS* pe_header =(IMAGE_NT_HEADERS *)((uint8_t *)dos_header + dos_header->e_lfanew); - return pe_header->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI; -} - bool util_delete_file(LPCTSTR filepath) { @@ -2734,6 +2755,28 @@ util_path_ext(const TCHAR *path) return NULL; } +const TCHAR* +util_path_filename(const TCHAR *path) +{ + if (STR_NOT_NUL(path)) + { + TCHAR *p = _tcsrchr(path, _T('\\')); + if (!p) + { + p = _tcsrchr(path, _T('/')); + } + if (!p) + { + return path; + } + else if (_tcslen(p) > 1) + { + return (const TCHAR *)&p[1]; + } + } + return NULL; +} + void util_postion_xy(eu_tabpage *pnode, sptr_t pos, sptr_t *px, sptr_t *py) { @@ -3102,6 +3145,29 @@ util_shield_icon(HINSTANCE hinst, LPCTSTR name) return hmap; } +void +util_updateui_icon(const HWND hwnd, const bool fnshow) +{ + if (fnshow) + { + HICON hicon = LoadIcon(eu_module_handle(), MAKEINTRESOURCE(IDI_SKYLARK)); + SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hicon); + SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon); + DestroyIcon(hicon); + } + else + { + uint32_t ex = (uint32_t)GetWindowLongPtr(hwnd, GWL_EXSTYLE); + SetWindowLongPtr(hwnd, GWL_EXSTYLE, ex | WS_EX_DLGMODALFRAME); + SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + if ((HICON)SendMessage(hwnd, WM_GETICON, ICON_SMALL, 0)) + { + SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)0); + SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)0); + } + } +} + void util_updateui_msg(const eu_tabpage *pnode) { @@ -3220,3 +3286,27 @@ util_update_env(eu_tabpage *pnode) eu_safe_free(psel); } } + +char* +util_has_newline(const char *dst) +{ + char *p = strchr(dst, '\r'); + if (!p) + { + p = strchr(dst, '\n'); + } + return p; +} + +void +util_strcat(uint8_t **dst, const char* pstr) +{ + if (dst && pstr) + { + while (*pstr) + { + cvector_push_back(*dst, (uint8_t)(*pstr)); + ++pstr; + } + } +} diff --git a/src/eu_util.h b/src/eu_util.h index 791c5d36..139c05d5 100644 --- a/src/eu_util.h +++ b/src/eu_util.h @@ -91,6 +91,7 @@ int util_query_hostname(char *hostname, char *ip, int bufsize); int util_effect_line(eu_tabpage *pnode, sptr_t *, sptr_t *); int util_get_hex_byte(const char *p); int util_strnspace(const char *s1, const char *s2, int *plen); +int util_count_characters(const char *pstr, const int ch); char* util_unix_newline(const char *in, const size_t in_size); char* util_strdup_select(eu_tabpage *pnode, size_t *text_len, size_t multiple); @@ -126,6 +127,7 @@ bool util_try_path(LPCTSTR dir); bool util_shell_path(const GUID *folder, TCHAR *path, const int len); bool util_copy_file(LPCWSTR source, LPCWSTR dest, const bool fail_exist); bool util_isxdigit_string(LPCTSTR str, const int len); +bool util_has_space(uint8_t ch); time_t util_last_time(const TCHAR *path); uint64_t util_gen_tstamp(void); void util_switch_menu_group(HMENU hmenu, int pop_id, uint32_t first_id, uint32_t last_id, uint32_t select); @@ -134,6 +136,7 @@ TCHAR* util_make_u16(const char *utf8, TCHAR *utf16, int len); char* util_make_u8(const TCHAR *utf16, char *utf8, int len); char* util_string_match(const char *str, const char *pattern, bool incase, bool match_start, bool whole); char* util_str_replace(const char *in, const char *pattern, const char *by); +char* util_trim_sides_white(const uint8_t *str); HANDLE util_mk_temp(TCHAR *file_path, TCHAR *ext); HWND util_create_tips(HWND hwnd_stc, HWND hwnd, TCHAR* ptext); HWND util_get_hwnd(const uint32_t pid); @@ -146,6 +149,7 @@ sptr_t util_line_header(eu_tabpage *pnode, const sptr_t start, const sptr_t end, wchar_t* util_wstr_unquote(wchar_t *path, const int size); char* util_str_unquote(const char *path); char* util_url_escape(const char *url); +char* util_has_newline(const char *dst); const char* util_trim_left_white(const char *str, int *length); unsigned long util_compress_bound(unsigned long source_len); int util_uncompress(uint8_t *dest, unsigned long *dest_len, const uint8_t *source, unsigned long *source_len); @@ -154,6 +158,7 @@ int util_count_number(size_t number); int util_split_attr(const char *pstr, char (*pout)[MAX_PATH], int ch); int util_strim_end(char *pstr, int len); int util_num_cores(void); +void util_strcat(uint8_t **dst, const char* pstr); void util_split(const char *pstr, const char *sep, char ***ppvec, const bool out_vec); void util_transparent(HWND hwnd, int percent); void util_untransparent(HWND hwnd); @@ -162,6 +167,7 @@ void util_explorer_open(eu_tabpage *pnode); void util_redraw(const HWND hwnd, const bool force); void util_symlink_destroy(eu_tabpage *pnode); void util_updateui_msg(const eu_tabpage *pnode); +void util_updateui_icon(const HWND hwnd, const bool fnshow); void util_update_env(eu_tabpage *pnode); bool util_product_name(LPCWSTR filepath, LPWSTR out_string, size_t len); bool util_file_access(LPCTSTR filename, uint32_t *pgranted); @@ -169,6 +175,7 @@ bool util_get_unix_file_name(LPCWSTR path, wchar_t *out, const int len); wchar_t* util_get_nt_file_name(LPCWSTR path); const uint32_t util_os_version(void); const TCHAR* util_path_ext(const TCHAR *path); +const TCHAR* util_path_filename(const TCHAR *path); HFONT util_create_font(const char* name, const int font_size, const bool bold); sptr_t util_select_characters(eu_tabpage *pnode, const sptr_t start, const sptr_t end); HBITMAP util_icon_bitmap(HICON hicon, const int width, const int height); diff --git a/src/eu_view.c b/src/eu_view.c index b0c0e754..9f3f211f 100644 --- a/src/eu_view.c +++ b/src/eu_view.c @@ -733,6 +733,11 @@ on_view_setfullscreenimpl(HWND hwnd) SetWindowPlacement(hwnd, &wndpl); } } + if (!eu_get_config()->eu_titlebar.icon) + { + util_updateui_icon(hwnd, true); + eu_get_config()->eu_titlebar.icon = true; + } } SetForegroundWindow(hwnd); } diff --git a/src/eu_xmlist.c b/src/eu_xmlist.c new file mode 100644 index 00000000..0047d2bc --- /dev/null +++ b/src/eu_xmlist.c @@ -0,0 +1,569 @@ +/****************************************************************************** + * This file is part of Skylark project + * Copyright ©2023 Hua andy + + * 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 3 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, see . + *******************************************************************************/ + +#include "framework.h" + +#define EXPAT_START 0 +#define EXPAT_END 1 +#define EXPAT_PI 3 +#define EXPAT_COMMENT 4 +#define EXPAT_CHARACTER 5 +#define EXPAT_CDATA 6 + +typedef struct _ex_stack +{ + int done_start; + int done_end; + int done_pi; + int done_comment; + int done_character; + int done_cdata; +} ex_stack; + +typedef struct _ex_userdata +{ + int depth; + int lastoperation; + bool firsttime; + bool showattributes; + const char *eol; + const char *indent; + uint8_t **ppbuf; + ex_stack indentstack[FILESIZE]; +} ex_userdata; + +typedef struct _ex_context +{ + int depth; + HTREEITEM hitem; + XML_Parser parser; + eu_tabpage *ptab; +} ex_context; + +static int +count_depth(const HWND hwnd, const HTREEITEM hti) +{ + int count = 0; + HTREEITEM parent = hti; + while ((parent = TreeView_GetParent(hwnd, parent))) + { + ++count; + } + return count; +} + +static void XMLCALL +start_element(void *userdata, const XML_Char *name, const XML_Char **atts) +{ + ex_context *ctx = (ex_context *) userdata; + HWND hwnd = ctx->ptab->hwnd_symtree; + HTREEITEM parent = ctx->hitem; + const int count = count_depth(hwnd, ctx->hitem); + if (count && ctx->depth <= count) + { + for (int i = ctx->depth; i <= count; ++i) + { + parent = TreeView_GetParent(hwnd, parent); + } + } + ctx->hitem = on_symtree_insert_str(hwnd, parent, name, XML_GetCurrentByteIndex(ctx->parser)); + ctx->depth += 1; +} + +static void XMLCALL +end_element(void *userdata, const XML_Char *name) +{ + ex_context *ctx = (ex_context *) userdata; + ctx->depth -= 1; +} + +static void XMLCALL +start_cdata(void *userdata) +{ + ex_context *ctx = (ex_context *) userdata; + start_element(userdata, "[CDATA]", NULL); +} + +static void XMLCALL +end_cdata(void *userdata) +{ + end_element(userdata, NULL); +} + +static void +on_xml_parser(eu_tabpage *pnode, const char *pbuf, const int buf_len) +{ + if (pnode && pnode->hwnd_symtree && pbuf && buf_len > 0) + { + int done = 0; + ex_context ctx = { 0 }; + // 创建XML解析器 + XML_Parser parser = XML_ParserCreate("utf-8"); + if (parser) + { + ctx.ptab = pnode; + ctx.parser = parser; + XML_SetUserData(parser, &ctx); + XML_SetElementHandler(parser, start_element, end_element); + XML_SetCdataSectionHandler(parser, start_cdata, end_cdata); + if (XML_Parse(parser, pbuf, buf_len, done) == XML_STATUS_ERROR) + { + char err[MAX_PATH] = { 0 }; + _snprintf(err, MAX_PATH - 1, "(%s at line %Id)\n", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + start_element(&ctx, err, NULL); + } + // 释放解析器内存 + XML_ParserFree(parser); + } + } +} + +static unsigned WINAPI +on_xml_thread(void *lp) +{ + eu_tabpage *pnode = (eu_tabpage *) lp; + if (pnode && pnode->hwnd_symtree) + { + char *text = NULL; + size_t text_len = 0; + if ((text = util_strdup_content(pnode, &text_len)) != NULL) + { + TreeView_DeleteAllItems(pnode->hwnd_symtree); + on_xml_parser(pnode, text, (const int) text_len); + if (TreeView_GetRoot(pnode->hwnd_symtree)) + { + on_symtree_expand_all(pnode->hwnd_symtree, NULL); + } + free(text); + } + _InterlockedExchange(&pnode->json_id, 0); + } + return 0; +} + +static bool +on_xml_white_space(const uint8_t *s) +{ + while (*s) + { + if (!util_has_space(*s)) + { + return false; + } + s++; + } + return true; +} + +static void +on_xml_indent(ex_userdata *ud) +{ + if (ud) + { + if (ud->firsttime) + { + ud->firsttime = false; + } + else + { + util_strcat(ud->ppbuf, ud->eol); + for (int i = 0; i < ud->depth; i++) + { + util_strcat(ud->ppbuf, ud->indent); + } + } + } +} + +static void XMLCALL +on_xml_element_start(void *userdata, const XML_Char *el, const XML_Char **attr) +{ + ex_userdata *ud = (ex_userdata *) userdata; + if (ud->depth >= 0 && ud->depth < FILESIZE) + { + on_xml_indent(ud); + cvector_push_back(*(ud->ppbuf), '<'); + util_strcat(ud->ppbuf, el); + if (ud->showattributes) + { + for (int i = 0; attr[i]; i += 2) + { + cvector_push_back(*(ud->ppbuf), ' '); + util_strcat(ud->ppbuf, attr[i]); + cvector_push_back(*(ud->ppbuf), '='); + cvector_push_back(*(ud->ppbuf), '"'); + util_strcat(ud->ppbuf, attr[i + 1]); + cvector_push_back(*(ud->ppbuf), '"'); + } + } + cvector_push_back(*(ud->ppbuf), '>'); + ud->lastoperation = EXPAT_START; + ud->indentstack[ud->depth].done_start = 1; + } + ud->depth++; +} + +static void XMLCALL +on_xml_element_end(void *userdata, const XML_Char *el) +{ + ex_userdata *ud = (ex_userdata *) userdata; + ud->depth--; + if (ud->depth >= 0 && ud->depth < FILESIZE) + { + if (ud->lastoperation == EXPAT_END || ud->indentstack[ud->depth].done_pi || ud->indentstack[ud->depth].done_comment || + ud->indentstack[ud->depth].done_cdata) + { + on_xml_indent(ud); + } + util_strcat(ud->ppbuf, "ppbuf, el); + cvector_push_back(*(ud->ppbuf), '>'); + ud->lastoperation = EXPAT_END; + memset(&ud->indentstack[ud->depth], 0, sizeof(ex_stack)); + } +} + +static void XMLCALL +on_xml_data_handler(void *userdata, const XML_Char *txt, int txtlen) +{ + ex_userdata *ud = (ex_userdata *) userdata; + if (ud->depth >= 0 && ud->depth < FILESIZE) + { + // 指向文本头部 + uint8_t *s = (uint8_t *) txt; + // 指向文本尾部 + uint8_t *e = ((uint8_t *) txt) + txtlen - 1; + // 头部指针跳过空白 + while (util_has_space(*s) && txtlen > 0) + { + s++; + txtlen--; + } + // 尾部指针移过空白 + if (txtlen > 0) + { + while (util_has_space(*e) && txtlen > 0) + { + e--; + txtlen--; + } + } + // 去除头尾空白的文本数据 + if (txtlen > 0) + { + if (ud->lastoperation == EXPAT_COMMENT || ud->lastoperation == EXPAT_PI || ud->lastoperation == EXPAT_CDATA || + ud->lastoperation == EXPAT_END) + { + on_xml_indent(ud); + } + for (int i = 0; i < txtlen; i++) + { + cvector_push_back(*(ud->ppbuf), s[i]); + } + ud->lastoperation = EXPAT_CHARACTER; + if (ud->depth > 0) + { + ud->indentstack[ud->depth - 1].done_character = 1; + } + } + } +} + +static void XMLCALL +on_xml_doctype_handler(void *userdata, const XML_Char *name, const XML_Char *sysid, const XML_Char *pubid, int has_) +{ + ex_userdata *ud = (ex_userdata *) userdata; + on_xml_indent(ud); + util_strcat(ud->ppbuf, "ppbuf, name); + if (pubid && sysid) + { + util_strcat(ud->ppbuf, " PUBLIC \""); + util_strcat(ud->ppbuf, pubid); + util_strcat(ud->ppbuf, "\" \""); + util_strcat(ud->ppbuf, sysid); + cvector_push_back(*(ud->ppbuf), '"'); + } + else + { + if (pubid) + { + util_strcat(ud->ppbuf, " PUBLIC \""); + util_strcat(ud->ppbuf, pubid); + cvector_push_back(*(ud->ppbuf), '"'); + } + else if (sysid) + { + util_strcat(ud->ppbuf, " SYSTEM \""); + util_strcat(ud->ppbuf, sysid); + cvector_push_back(*(ud->ppbuf), '"'); + } + } + // 不支持其他的内部子集 + cvector_push_back(*(ud->ppbuf), '>'); +} + +static void XMLCALL +on_xml_pi_handler(void *userdata, const XML_Char *target, const XML_Char *pidata) +{ + ex_userdata *ud = (ex_userdata *) userdata; + if (ud->depth >= 0 && ud->depth < FILESIZE) + { + on_xml_indent(ud); + util_strcat(ud->ppbuf, "ppbuf, target); + cvector_push_back(*(ud->ppbuf), ' '); + util_strcat(ud->ppbuf, pidata); + util_strcat(ud->ppbuf, "?>"); + ud->lastoperation = EXPAT_PI; + if (ud->depth > 0) + { + ud->indentstack[ud->depth - 1].done_pi = true; + } + } +} + +static void XMLCALL +on_xml_comment_handler(void *userdata, const XML_Char *data) +{ + char *p = NULL; + ex_userdata *ud = (ex_userdata *) userdata; + if (ud->depth >= 0 && ud->depth < FILESIZE) + { + on_xml_indent(ud); + if (util_has_newline((const char *) data)) + { + // 如果注释中有换行符, 保留文件格式, 按换行符进行缩进 + char *s = (char *) data; + util_strcat(ud->ppbuf, ""); + } + else + { + p = util_trim_sides_white((const uint8_t *)data); + util_strcat(ud->ppbuf, ""); + eu_safe_free(p); + } + ud->lastoperation = EXPAT_COMMENT; + if (ud->depth > 0) + { + ud->indentstack[ud->depth - 1].done_comment = 1; + } + } +} + +static void XMLCALL +on_xml_cdata_start(void *userdata) +{ + ex_userdata *ud = (ex_userdata *) userdata; + on_xml_indent(ud); + util_strcat(ud->ppbuf, "ppbuf, "]]>"); + if (ud->depth > 0) + { + ud->indentstack[ud->depth - 1].done_cdata = 1; + } + ud->lastoperation = EXPAT_CDATA; +} + +static void XMLCALL +on_xml_declaration_handler(void *userdata, const XML_Char *version, const XML_Char *encoding, int standalone) +{ + ex_userdata *ud = (ex_userdata *) userdata; + if (ud->depth >= 0 && ud->depth < FILESIZE && version) + { + on_xml_indent(ud); + util_strcat(ud->ppbuf, "ppbuf, version); + cvector_push_back(*(ud->ppbuf), '"'); + if (encoding) + { + util_strcat(ud->ppbuf, " encoding=\""); + util_strcat(ud->ppbuf, encoding); + cvector_push_back(*(ud->ppbuf), '"'); + } + if (standalone == 0 || standalone == 1) + { + util_strcat(ud->ppbuf, " standalone=\""); + util_strcat(ud->ppbuf, (standalone == 0) ? "no" : "yes"); + cvector_push_back(*(ud->ppbuf), '"'); + } + util_strcat(ud->ppbuf, "?>"); + ud->lastoperation = EXPAT_PI; + if (ud->depth > 0) + { + ud->indentstack[ud->depth - 1].done_pi = true; + } + } +} + +bool +on_xml_pretty(void *ptr, struct opt_format *opt) +{ + bool ret = false; + char *text = NULL; + eu_tabpage *pnode = (eu_tabpage *) ptr; + cvector_vector_type(uint8_t) pout = NULL; + if (pnode && opt) + { + size_t text_len = 0; + ex_userdata ctx = { 0 }; + XML_Parser parser = NULL; + if ((text = util_strdup_content(pnode, &text_len)) && (parser = XML_ParserCreate("utf-8")) && text_len < INT_MAX) + { + int done = 0; + char indent[QW_SIZE] = { 0 }; + ctx.showattributes = !opt->no_a; + ctx.firsttime = true; + ctx.eol = on_encoding_get_eol(pnode); + if ((bool) eu_sci_call(pnode, SCI_GETUSETABS, 0, 0)) + { + indent[0] = '\t'; + indent[1] = 0; + } + else + { + int n = (int) eu_sci_call(pnode, SCI_GETTABWIDTH, 0, 0); + memset(indent, 0x20, (n > 0 && n < QW_SIZE) ? n : 4); + } + cvector_init(&pout, text_len, uint8_t); + ctx.indent = indent; + ctx.ppbuf = &pout; + XML_SetUserData(parser, &ctx); + XML_SetElementHandler(parser, on_xml_element_start, on_xml_element_end); + if (!opt->no_c) + { + XML_SetCommentHandler(parser, on_xml_comment_handler); + } + if (!opt->no_p) + { + XML_SetProcessingInstructionHandler(parser, on_xml_pi_handler); + } + if (!opt->no_f) + { + XML_SetCdataSectionHandler(parser, on_xml_cdata_start, on_xml_cdata_end); + } + if (!opt->no_x) + { + XML_SetXmlDeclHandler(parser, on_xml_declaration_handler); + } + if (!opt->no_t) + { + XML_SetStartDoctypeDeclHandler(parser, on_xml_doctype_handler); + } + if (!opt->no_d) + { + XML_SetCharacterDataHandler(parser, on_xml_data_handler); + } + if (XML_Parse(parser, text, (int) text_len, done) == XML_STATUS_ERROR) + { + eu_logmsg("error: %s at line %Id\n", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + } + else + { + ret = true; + } + cvector_push_back(pout, '\0'); + } + if (parser) + { + XML_ParserFree(parser); + } + } + if (ret && strcmp(text, (const char *)pout)) + { + eu_sci_call(pnode, SCI_BEGINUNDOACTION, 0, 0); + eu_sci_call(pnode, SCI_CLEARALL, 0, 0); + eu_sci_call(pnode, SCI_ADDTEXT, strlen((const char *)pout), (sptr_t)pout); + eu_sci_call(pnode, SCI_ENDUNDOACTION, 0, 0); + } + eu_safe_free(text); + cvector_free(pout); + return ret; +} + +int +on_xml_format(eu_tabpage *pnode) +{ + char *lua_path = NULL; + TCHAR path[MAX_BUFFER] = { 0 }; + int m = _sntprintf(path, MAX_BUFFER, _T("%s\\conf\\conf.d\\xmlformater.lua"), eu_module_path); + if (!(m > 0 && m < MAX_BUFFER) || ((lua_path = eu_utf16_utf8(path, NULL)) == NULL)) + { + eu_logmsg("%s: path unavailable\n", __FUNCTION__); + goto xml_fail; + } + if (do_lua_point(lua_path, "run", pnode)) + { + eu_logmsg("%s: xmlformater.lua failed\n", __FUNCTION__); + } +xml_fail: + eu_safe_free(lua_path); + return SKYLARK_OK; +} + +int +on_xml_tree(eu_tabpage *pnode) +{ + if (!pnode || !pnode->hwnd_symtree) + { + return 1; + } + if (pnode->raw_size > 0xA00000) + { + eu_logmsg("Error: This XML file is larger than 10MB\n"); + if (pnode->hwnd_symtree) + { + DestroyWindow(pnode->hwnd_symtree); + pnode->hwnd_symtree = NULL; + } + return 1; + } + if (!pnode->json_id) + { + CloseHandle((HANDLE) _beginthreadex(NULL, 0, &on_xml_thread, pnode, 0, (uint32_t *) &pnode->json_id)); + } + return 0; +} diff --git a/src/eu_xmlist.h b/src/eu_xmlist.h new file mode 100644 index 00000000..f7410c5f --- /dev/null +++ b/src/eu_xmlist.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * This file is part of Skylark project + * Copyright ©2023 Hua andy + + * 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 3 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, see . + *******************************************************************************/ + +#ifndef _EU_XMLIST_H_ +#define _EU_XMLIST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int on_xml_tree(eu_tabpage *pnode); +int on_xml_format(eu_tabpage *pnode); +bool on_xml_pretty(void *ptr, struct opt_format *opt); + +#ifdef __cplusplus +} +#endif + +#endif // _EU_XMLIST_H_ diff --git a/src/framework.h b/src/framework.h index 3e113f08..03f60c6a 100644 --- a/src/framework.h +++ b/src/framework.h @@ -104,6 +104,7 @@ #include "libpq-fe.h" #include "chardet.h" #include "tinyexpr.h" +#include "expat.h" // skylark 源目录下的头文件 #include "eu_cvector.h" @@ -168,5 +169,6 @@ #include "eu_favorites.h" #include "eu_settings.h" #include "eu_hintctl.h" +#include "eu_xmlist.h" #endif // _EU_FRAMEWORK_H_ diff --git a/src/targetver.h b/src/targetver.h index b5d15e33..5d142fd1 100644 --- a/src/targetver.h +++ b/src/targetver.h @@ -30,7 +30,7 @@ // 定义版本信息 #define __EU_INFO_VERSION 4 #define __EU_INFO_VERSION_MINOR 0 -#define __EU_INFO_VERSION_PATCHLEVEL 5 +#define __EU_INFO_VERSION_PATCHLEVEL 6 #define __ORIGINAL_NAME TEXT("skylark.exe") #if !__EU_INFO_VERSION_PATCHLEVEL @@ -1242,6 +1242,15 @@ #define IDM_VIEW_DISPLAY_PLACEHOLDE 44730 +#define IDM_VIEW_TITLEBAR_GROUP 44740 +#define IDM_VIEW_TITLEBAR_ICON 44741 +#define IDM_VIEW_TITLEBAR_NAME 44742 +#define IDM_VIEW_TITLEBAR_PATH 44743 + +#define IDM_EDIT_PLACEHOLDE_XML 44750 +#define IDM_FORMAT_REFORMAT_XML 44751 +#define IDM_FORMAT_COMPRESS_XML 44752 + // For MessageBox #define IDALWAYS 12 #define MB_YESNOALWAYS 0x0007 diff --git a/src/version_display.txt b/src/version_display.txt index 7636e756..d13e837c 100644 --- a/src/version_display.txt +++ b/src/version_display.txt @@ -1 +1 @@ -4.0.5 +4.0.6