summaryrefslogtreecommitdiff
path: root/expat
diff options
context:
space:
mode:
authorSebastian Pipping <sebastian@pipping.org>2022-11-01 23:51:46 +0100
committerGitHub <noreply@github.com>2022-11-01 23:51:46 +0100
commitd4373f337f69a0fefdb3e4bfc76668bdaa3e27d9 (patch)
treeb41895f292422a9edc2dbf38a1ecc2425729e536 /expat
parenta43efacb1b95b47801f28b6965847819fb58243b (diff)
parente924330f98ef454f5ce2e294c72dd814cb96b4d8 (diff)
downloadlibexpat-git-d4373f337f69a0fefdb3e4bfc76668bdaa3e27d9.tar.gz
Merge pull request #673 from libexpat/examples-element-declarations
examples: Add new example on element declarations
Diffstat (limited to 'expat')
-rw-r--r--expat/CMakeLists.txt6
-rw-r--r--expat/Changes4
-rw-r--r--expat/examples/Makefile.am9
-rw-r--r--expat/examples/element_declarations.c229
4 files changed, 241 insertions, 7 deletions
diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt
index 2b4c13c5..72cf0b01 100644
--- a/expat/CMakeLists.txt
+++ b/expat/CMakeLists.txt
@@ -579,10 +579,8 @@ endif()
# C code examples
#
if(EXPAT_BUILD_EXAMPLES)
- add_executable(elements examples/elements.c)
- add_executable(outline examples/outline.c)
-
- foreach(_target elements outline)
+ foreach(_target element_declarations elements outline)
+ add_executable(${_target} examples/${_target}.c)
set_property(TARGET ${_target} PROPERTY RUNTIME_OUTPUT_DIRECTORY examples)
target_link_libraries(${_target} expat)
endforeach()
diff --git a/expat/Changes b/expat/Changes
index e6717105..4032ef77 100644
--- a/expat/Changes
+++ b/expat/Changes
@@ -2,6 +2,10 @@ NOTE: We are looking for help with a few things:
https://github.com/libexpat/libexpat/labels/help%20wanted
If you can help, please get in touch. Thanks!
+Release 2.5.1 xxx xxxxxxx xx xxxx
+ Other changes:
+ #673 examples: Add new example "element_declarations.c"
+
Release 2.5.0 Tue October 25 2022
Security fixes:
#616 #649 #650 CVE-2022-43680 -- Fix heap use-after-free after overeager
diff --git a/expat/examples/Makefile.am b/expat/examples/Makefile.am
index d386b592..e2e22bce 100644
--- a/expat/examples/Makefile.am
+++ b/expat/examples/Makefile.am
@@ -6,8 +6,8 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
-# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
+# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -31,7 +31,10 @@
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
-noinst_PROGRAMS = elements outline
+noinst_PROGRAMS = element_declarations elements outline
+
+element_declarations_SOURCES = element_declarations.c
+element_declarations_LDADD = ../lib/libexpat.la
elements_SOURCES = elements.c
elements_LDADD = ../lib/libexpat.la
diff --git a/expat/examples/element_declarations.c b/expat/examples/element_declarations.c
new file mode 100644
index 00000000..437b0996
--- /dev/null
+++ b/expat/examples/element_declarations.c
@@ -0,0 +1,229 @@
+/* Read an XML document from standard input and print
+ element declarations (if any) to standard output.
+ It must be used with Expat compiled for UTF-8 output.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
+ Copyright (c) 2004-2006 Karl Waclawek <karl@waclawek.net>
+ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
+ Copyright (c) 2019 Zhongyuan Zhou <zhouzhongyuan@huawei.com>
+ 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 <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <expat.h>
+
+#ifdef XML_LARGE_SIZE
+# define XML_FMT_INT_MOD "ll"
+#else
+# define XML_FMT_INT_MOD "l"
+#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_STR "ls"
+#else
+# define XML_FMT_STR "s"
+#endif
+
+// While traversing the XML_Content tree, we avoid recursion
+// to not be vulnerable to a denial of service attack.
+typedef struct StackStruct {
+ const XML_Content *model;
+ unsigned level;
+ struct StackStruct *prev;
+} Stack;
+
+static Stack *
+stackPushMalloc(Stack *stackTop, const XML_Content *model, unsigned level) {
+ Stack *const newStackTop = malloc(sizeof(Stack));
+ if (! newStackTop) {
+ return NULL;
+ }
+ newStackTop->model = model;
+ newStackTop->level = level;
+ newStackTop->prev = stackTop;
+ return newStackTop;
+}
+
+static Stack *
+stackPopFree(Stack *stackTop) {
+ Stack *const newStackTop = stackTop->prev;
+ free(stackTop);
+ return newStackTop;
+}
+
+static char *
+contentTypeName(enum XML_Content_Type contentType) {
+ switch (contentType) {
+ case XML_CTYPE_EMPTY:
+ return "EMPTY";
+ case XML_CTYPE_ANY:
+ return "ANY";
+ case XML_CTYPE_MIXED:
+ return "MIXED";
+ case XML_CTYPE_NAME:
+ return "NAME";
+ case XML_CTYPE_CHOICE:
+ return "CHOICE";
+ case XML_CTYPE_SEQ:
+ return "SEQ";
+ default:
+ return "???";
+ }
+}
+
+static char *
+contentQuantName(enum XML_Content_Quant contentQuant) {
+ switch (contentQuant) {
+ case XML_CQUANT_NONE:
+ return "NONE";
+ case XML_CQUANT_OPT:
+ return "OPT";
+ case XML_CQUANT_REP:
+ return "REP";
+ case XML_CQUANT_PLUS:
+ return "PLUS";
+ default:
+ return "???";
+ }
+}
+
+static void
+dumpContentModelElement(const XML_Content *model, unsigned level,
+ const XML_Content *root) {
+ // Indent
+ unsigned u = 0;
+ for (; u < level; u++) {
+ printf(" ");
+ }
+
+ // Node
+ printf("[%u] type=%s(%d), quant=%s(%d)", (unsigned)(model - root),
+ contentTypeName(model->type), model->type,
+ contentQuantName(model->quant), model->quant);
+ if (model->name) {
+ printf(", name=\"%" XML_FMT_STR "\"", model->name);
+ } else {
+ printf(", name=NULL");
+ }
+ printf(", numchildren=%d", model->numchildren);
+ printf("\n");
+}
+
+static bool
+dumpContentModel(const XML_Char *name, const XML_Content *root) {
+ printf("Element \"%" XML_FMT_STR "\":\n", name);
+ Stack *stackTop = NULL;
+ stackTop = stackPushMalloc(stackTop, root, 1);
+ if (! stackTop) {
+ return false;
+ }
+
+ while (stackTop) {
+ const XML_Content *const model = stackTop->model;
+ const unsigned level = stackTop->level;
+
+ dumpContentModelElement(model, level, root);
+
+ stackTop = stackPopFree(stackTop);
+
+ for (size_t u = model->numchildren; u >= 1; u--) {
+ stackTop
+ = stackPushMalloc(stackTop, model->children + (u - 1), level + 1);
+ if (! stackTop) {
+ return false;
+ }
+ }
+ }
+
+ printf("\n");
+ return true;
+}
+
+static void XMLCALL
+handleElementDeclaration(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ XML_Parser parser = (XML_Parser)userData;
+ const bool success = dumpContentModel(name, model);
+ XML_FreeContentModel(parser, model);
+ if (! success) {
+ XML_StopParser(parser, /* resumable= */ XML_FALSE);
+ }
+}
+
+int
+main(void) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ int done;
+
+ if (! parser) {
+ fprintf(stderr, "Couldn't allocate memory for parser\n");
+ return 1;
+ }
+
+ XML_SetUserData(parser, parser);
+ XML_SetElementDeclHandler(parser, handleElementDeclaration);
+
+ do {
+ void *const buf = XML_GetBuffer(parser, BUFSIZ);
+ if (! buf) {
+ fprintf(stderr, "Couldn't allocate memory for buffer\n");
+ XML_ParserFree(parser);
+ return 1;
+ }
+
+ const size_t len = fread(buf, 1, BUFSIZ, stdin);
+
+ if (ferror(stdin)) {
+ fprintf(stderr, "Read error\n");
+ XML_ParserFree(parser);
+ return 1;
+ }
+
+ done = feof(stdin);
+
+ if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
+ enum XML_Error errorCode = XML_GetErrorCode(parser);
+ if (errorCode == XML_ERROR_ABORTED) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ }
+ fprintf(stderr,
+ "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber(parser), XML_ErrorString(errorCode));
+ XML_ParserFree(parser);
+ return 1;
+ }
+ } while (! done);
+
+ XML_ParserFree(parser);
+ return 0;
+}