This is an automated email from the ASF dual-hosted git repository. jinterrante pushed a commit to branch runtime2-2202 in repository https://gitbox.apache.org/repos/asf/daffodil.git
commit 5bc9cb0e23c6be68bb99abf509249b2677e5c132 Author: John Interrante <[email protected]> AuthorDate: Wed Apr 14 11:57:37 2021 -0400 Make more changes in response to reviewer requests In BUILD.md, copy build requirements and setup instructions here from README.md with some reordering and edits for better clarity. In README.md, restore Daffodil website full url, remove build setup instructions, and turn getting started instructions into bullet items for less vertical space and better readability. In build.sbt, allow environment variables CC and AR to override cCompiler and ccArchiveCommand's default values. In ElementBase.scala, ElementDeclMixin.scala, and ElementRef.scala, add hasFixedValue, fixedValueAsString, and fixedValue getters. In .clang-format, increase column limit to 110 (default had been 80). Reformat C files accordingly. In xml_reader.c, make xmlNumberElem define error_erd in block inside switch statement and make all cases call return. In xml_writer.c, use LIMIT_XML_NESTING constant from errors.h. In errors.c, add assert to default case in error_message, rename need_diagnostics to get_diagnostics, and make add_diagnostic check LIMIT_DIAGNOSTICS and return false if array is full. In errors.h, define limit constants inside enum Limits and use LIMIT_DIAGNOSTICS constant in Diagnostics. Rename member field of PState/UState from validati to diagnostics, rename need_diagnostics to get_diagnostics, and make add_diagnostic return bool. In infoset.c, use LIMIT_NAME_LENGTH constant from errors.h. In BinaryAbstractCodeGenerator.scala, use DSOM fixed getters instead of reading e.xml.attribute("fixed") directly to ensure fixed is a valid primitive data value before using it. In CodeGeneratorState.scala, make addImplementation count both parserStatements and unparserStatements, not only parserStatements. --- BUILD.md | 63 ++++++++++ README.md | 101 ++++------------ build.sbt | 4 +- .../org/apache/daffodil/dsom/ElementBase.scala | 43 ++++++- .../apache/daffodil/dsom/ElementDeclMixin.scala | 9 ++ .../org/apache/daffodil/dsom/ElementRef.scala | 2 + daffodil-runtime2/src/main/resources/.clang-format | 2 + .../src/main/resources/c/libcli/daffodil_argp.c | 69 +++++------ .../src/main/resources/c/libcli/daffodil_main.c | 22 ++-- .../src/main/resources/c/libcli/stack.h | 3 +- .../src/main/resources/c/libcli/xml_reader.c | 65 ++++------ .../src/main/resources/c/libcli/xml_writer.c | 13 +- .../src/main/resources/c/libruntime/errors.c | 35 +++--- .../src/main/resources/c/libruntime/errors.h | 36 +++--- .../src/main/resources/c/libruntime/infoset.c | 11 +- .../src/main/resources/c/libruntime/infoset.h | 15 +-- .../src/main/resources/c/libruntime/parsers.c | 131 ++++++++++----------- .../src/main/resources/c/libruntime/parsers.h | 21 ++-- .../src/main/resources/c/libruntime/unparsers.c | 99 ++++++++-------- .../generators/BinaryAbstractCodeGenerator.scala | 5 +- .../runtime2/generators/CodeGeneratorState.scala | 5 +- 21 files changed, 386 insertions(+), 368 deletions(-) diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000..b95e3e3 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,63 @@ +# Build Requirements + +Daffodil's build requirements include: + +* JDK 8 or higher +* SBT 0.13.8 or higher +* C compiler C99 or higher +* Mini-XML Version 3.2 or higher + +You will need the Java Software Development Kit ([JDK]) and the Scala +Build Tool ([SBT]) to build Daffodil, run all tests, create packages, +and more. The recommended way is to install the latest [Java 11 +LTS][JDK] version and the latest [SBT] version directly from their +websites. A package manager on your operating system may be a more +convenient way, but it may install an older version than what you'd +prefer. + +Since Daffodil now has a C backend as well as a Scala backend, you +will need a C compiler ([gcc] or [clang]), the [Mini-XML] library, and +possibly the GNU [argp] library if your system's C library doesn't +include it already. The recommended way is to install them using your +operating system's package manager (for example, `apt` on Debian or +Ubuntu): + + sudo apt install build-essential curl git libmxml-dev + # Just listing other packages you might need too + +Some operating systems don't package the [Mini-XML] library, so you +may have to build and install it from source on those operating +systems. See the Windows commands below for how to do so. + +You can set your environment variable "CC" to the appropriate driver +command (or set it to `true` to disable C compilation altogether) if +you don't want `sbt compile` to call your C compiler with `cc` as the +driver command. + +On Windows, the easiest way to install gcc and libargp is to install +[MSYS2]'s collection of free tools and libraries although MSYS2 has no +package for libmxml which you'll need to build from source. First +install [MSYS2] following its website's installation instructions, +then run the following commands in a "MSYS2 MSYS" window: + + pacman -S gcc git libargp-devel make pkgconf + git clone https://github.com/michaelrsweet/mxml.git + cd mxml + ./configure --prefix=/usr --disable-shared --disable-threads + make + make install + +You'll also need to define an environment variable using Windows' +control panel for editing environment variables. Define an +environment variable with the name `MSYS2_PATH_TYPE` and the value +`inherit`. Now when you open a new "MSYS2 MSYS" window from the Start +Menu, you will be able to type sbt and daffodil commands in the MSYS2 +window and both sbt and daffodil will be able to call the C compiler. + +[JDK]: https://adoptopenjdk.net/ +[Mini-XML]: https://www.msweet.org/mxml/ +[MSYS2]: https://www.msys2.org/ +[SBT]: https://www.scala-sbt.org/ +[argp]: https://packages.msys2.org/package/libargp-devel +[clang]: https://clang.llvm.org/get_started.html +[gcc]: https://linuxize.com/post/how-to-install-gcc-on-ubuntu-20-04/ diff --git a/README.md b/README.md index 3b3ad76..9f110f2 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ existing solutions. Daffodil is also capable of serializing or can also be converted directly to/from the data structures carried by data processing frameworks so as to bypass any XML/JSON overheads. -For more information about Daffodil, see the [Website]. +For more information about Daffodil, see <https://daffodil.apache.org/>. ## Build Requirements @@ -45,94 +45,46 @@ For more information about Daffodil, see the [Website]. * C compiler C99 or higher * Mini-XML Version 3.2 or higher -Since Daffodil has a DFDL to C backend, you will need a C compiler -([gcc] or [clang]), the [Mini-XML] library, and possibly the GNU -[argp] library if your system's C library doesn't include it. You can -install gcc and libmxml as system packages on most Unix based -platforms with distribution-specific packager commands such as (Debian -and Ubuntu): - - # Just mentioning all other packages you might need too - sudo apt install build-essential curl git libmxml-dev - -You will need the Java Software Development Kit ([JDK]) and the Scala -Build Tool ([SBT]) to build Daffodil, run all tests, create packages, -and more. [SDK] offers an easy and uniform way to install both java -and sbt on any Unix based platform: - - curl -s "https://get.sdkman.io" | bash - sdk install java - sdk install sbt - -You can edit the Compile / cCompiler setting in build.sbt if you don't -want sbt to call your C compiler with "cc" as the driver command. - -On Windows, the easiest way to install gcc and libargp is to install -[MSYS2]'s collection of free tools and libraries although MSYS2 has no -package for libmxml which you'll need to build from source. First -install [MSYS2] following its website's installation instructions, -then run the following commands in a "MSYS2 MSYS" window: - - pacman -S gcc git libargp-devel make pkgconf - git clone https://github.com/michaelrsweet/mxml.git - cd mxml - ./configure --prefix=/usr --disable-shared --disable-threads - make - make install - -You also need to install [JDK} and [SBT] from their Windows -installation packages and define an environment variable using -Windows' control panel for editing environment variables. Define an -environment variable with the name `MSYS2_PATH_TYPE` and the value -`inherit`. Now when you open a new "MSYS2 MSYS" window from the Start -Menu, you will be able to type your sbt commands in the MSYS2 window -and both sbt and daffodil will be able to call the C compiler. +See [BUILD.md](BUILD.md) for more details. ## Getting Started -Below are some of the more common commands used for Daffodil development. +[SBT] is the officially supported tool to build Daffodil. Here are +some of the more commonly used commands for Daffodil development. -### Compile +* Compile source code: - sbt compile + sbt compile -### Tests +* Run unit tests: -Run all unit tests: + sbt test - sbt test +* Run command line interface tests: -Run all command line interface tests: + sbt IntegrationTest/test - sbt it:test +* Build the command line interface (Linux and Windows shell scripts in +`daffodil-cli/target/universal/stage/bin/`; see the [Command Line +Interface] documentation for details on their usage): -### Command Line Interface + sbt daffodil-cli/stage -Create Linux and Windows shell scripts in -`daffodil-cli/target/universal/stage/bin/`. See the [Command Line -Interface] documentation for details on its usage: +* Run [Apache RAT] (license audit report in `target/rat.txt` and error +if any unapproved licenses are found): - sbt daffodil-cli/stage + sbt ratCheck -### License Check +* Run [sbt-scoverage] (test coverage report in +`target/scala-ver/scoverage-report/`): -Generate an [Apache RAT] license check report located in -``target/rat.txt`` and error if any unapproved licenses are found: - - sbt ratCheck - -### Test Coverage Report - -Generate an [sbt-scoverage] test coverage report located in -``target/scala-ver/scoverage-report/``: - - sbt clean coverage test it:test - sbt coverageAggregate + sbt clean coverage test IntegrationTest/test + sbt coverageAggregate ## Getting Help -For questions, we can be reached at the [email protected] or [email protected] mailing lists. Bugs can be reported via the +You can ask questions on the [email protected] or [email protected] mailing lists. You can report bugs via the [Daffodil JIRA]. ## License @@ -146,14 +98,7 @@ Apache Daffodil is licensed under the [Apache License, v2.0]. [DFDL specification]: https://daffodil.apache.org/docs/dfdl/ [Daffodil JIRA]: https://issues.apache.org/jira/projects/DAFFODIL/ [Github Actions]: https://github.com/apache/daffodil/actions?query=branch%3Amaster+ -[JDK]: https://adoptopenjdk.net/ -[Mini-XML]: https://www.msweet.org/mxml/ -[MSYS2]: https://www.msys2.org/ [Releases]: http://daffodil.apache.org/releases/ [SBT]: https://www.scala-sbt.org/ -[SDK]: https://sdkman.io/ [Website]: https://daffodil.apache.org/ -[argp]: https://packages.msys2.org/package/libargp-devel -[clang]: https://clang.llvm.org/get_started.html -[gcc]: https://linuxize.com/post/how-to-install-gcc-on-ubuntu-20-04/ [sbt-scoverage]: https://github.com/scoverage/sbt-scoverage/ diff --git a/build.sbt b/build.sbt index 2828483..666286a 100644 --- a/build.sbt +++ b/build.sbt @@ -68,8 +68,8 @@ lazy val runtime2 = Project("daffodil-runtime2", file("daffodil-runtime2 .settings(commonSettings) .settings(publishArtifact in (Compile, packageDoc) := false) .settings( - Compile / cCompiler := "cc", - Compile / ccArchiveCommand := "ar", + Compile / cCompiler := sys.env.getOrElse("CC", "cc"), + Compile / ccArchiveCommand := sys.env.getOrElse("AR", "ar"), Compile / ccTargets := ListSet(runtime2CFiles), Compile / cSources := Map( runtime2CFiles -> ( diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala index 58d2b46..267f705 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementBase.scala @@ -36,6 +36,7 @@ import java.lang.{ Integer => JInt } import org.apache.daffodil.dsom.walker.ElementBaseView import org.apache.daffodil.infoset.DataValue +import org.apache.daffodil.infoset.DataValue.DataValuePrimitiveNullable import org.apache.daffodil.infoset.DataValue.DataValuePrimitiveOrUseNilForDefaultOrNull /** @@ -323,9 +324,9 @@ trait ElementBase * The value will always be of the matching primitive types for the element, and * directly usable as the value of a simple-type element. * - * When a value is used, it is created from the XSD default or fixed attribute of the + * When a value is used, it is created from the XSD default attribute of the * element declaration, and that string cannot contain DFDL entities of any kind, - * nor any PUA-remapped characters. This insures the default/fixed value can still be + * nor any PUA-remapped characters. This insures the default value can still be * used for ordinary XML-schema validation outside of Daffodil/DFDL. */ final lazy val defaultValue: DataValuePrimitiveOrUseNilForDefaultOrNull = { @@ -352,6 +353,38 @@ trait ElementBase } else DataValue.NoValue } + /** + * Is either None or Some(primTypeValue). + * + * The value will always be of the matching primitive types for the element, and + * directly usable as the value of a simple-type element. + * + * When a value is used, it is created from the XSD fixed attribute of the + * element declaration, and that string cannot contain DFDL entities of any kind, + * nor any PUA-remapped characters. This insures the fixed value can still be + * used for ordinary XML-schema validation outside of Daffodil/DFDL. + */ + final lazy val fixedValue: DataValuePrimitiveNullable = { + if (hasFixedValue && (isScalar || isArrayWithAtLeastOneRequiredArrayElement)) { + val dv = { + // + // Note: no remapping PUA chars or otherwise messing with the text of the fixed value + // because this must be a regular XSD fixed value so that Xerces validation + // will work. + // + val str = fixedValueAsString + val value = try { + primType.fromXMLString(str) + } catch { + case ipd: InvalidPrimitiveDataException => + SDE("Invalid fixed value: %s", ipd.getMessage) + } + value + } + dv + } else DataValue.NoValue + } + lazy val unparserInfosetElementDefaultingBehavior: UnparserInfo.InfosetEventBehavior = { import UnparserInfo._ if (!isRepresented) MustExist @@ -991,6 +1024,12 @@ trait ElementBase def hasDefaultValue: Boolean /** + * Does the element have a fixed value? + */ + def fixedValueAsString: String + def hasFixedValue: Boolean + + /** * We require that there be a concept of empty if we're going to be able to default something * and we are going to require that we can tell this statically. I.e., we're not going to defer this to runtime * just in case the delimiters are being determined at runtime. diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala index 40598d0..99da373 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementDeclMixin.scala @@ -54,6 +54,8 @@ trait ElementDeclMixin final def hasDefaultValue: Boolean = defaultAttr.isDefined + final def hasFixedValue: Boolean = fixedAttr.isDefined + override final def simpleType: SimpleTypeBase = optSimpleType.get override final def complexType: ComplexTypeBase = optComplexType.get @@ -141,6 +143,8 @@ trait ElementDeclMixin final lazy val defaultAttr = xml.attribute("default") + final lazy val fixedAttr = xml.attribute("fixed") + final lazy val defaultValueAsString = { Assert.usage(hasDefaultValue) val dv = defaultAttr.get.text @@ -151,6 +155,11 @@ trait ElementDeclMixin dv } + final lazy val fixedValueAsString = { + Assert.usage(hasFixedValue) + fixedAttr.get.text + } + final lazy val isNillable = (xml \ "@nillable").text == "true" } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementRef.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementRef.scala index 735f300..d709869 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementRef.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ElementRef.scala @@ -43,7 +43,9 @@ abstract class AbstractElementRef( def complexType: ComplexTypeBase = this.referencedElement.complexType def defaultValueAsString: String = this.referencedElement.defaultValueAsString + def fixedValueAsString: String = this.referencedElement.fixedValueAsString def hasDefaultValue: Boolean = this.referencedElement.hasDefaultValue + def hasFixedValue: Boolean = this.referencedElement.hasFixedValue def isComplexType: Boolean = this.referencedElement.isComplexType def isNillable: Boolean = this.referencedElement.isNillable def isSimpleType: Boolean = this.referencedElement.isSimpleType diff --git a/daffodil-runtime2/src/main/resources/.clang-format b/daffodil-runtime2/src/main/resources/.clang-format index 57fbb91..908818d 100644 --- a/daffodil-runtime2/src/main/resources/.clang-format +++ b/daffodil-runtime2/src/main/resources/.clang-format @@ -15,8 +15,10 @@ AlignConsecutiveDeclarations: true AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: true AlwaysBreakAfterReturnType: TopLevelDefinitions BasedOnStyle: llvm BreakBeforeBraces: Allman +ColumnLimit: 110 IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: false diff --git a/daffodil-runtime2/src/main/resources/c/libcli/daffodil_argp.c b/daffodil-runtime2/src/main/resources/c/libcli/daffodil_argp.c index cbe33d4..fa65c4b 100644 --- a/daffodil-runtime2/src/main/resources/c/libcli/daffodil_argp.c +++ b/daffodil-runtime2/src/main/resources/c/libcli/daffodil_argp.c @@ -30,8 +30,7 @@ struct daffodil_parse_cli daffodil_parse = { }; static const struct argp_option parse_options[] = { - {"infoset-type", 'I', "<infoset_type>", 0, - "Infoset type to output. Must be one of 'xml' or 'null'", 0}, + {"infoset-type", 'I', "<infoset_type>", 0, "Infoset type to output. Must be one of 'xml' or 'null'", 0}, {"output", 'o', "<file>", 0, "Write output to a given file. If not given or is -, output is written to " @@ -44,15 +43,14 @@ static error_t parse_handler(int key, char *arg, struct argp_state *state); static const char parse_args_doc[] = "[infile]"; -static const char parse_doc[] = - "\n" - "Parse a file using a DFDL schema\n" - "\n" - "Parse Options:" - "\v" - " Trailing arguments:\n" - " infile (not required) input file to parse. " - "If not specified, or a value of -, reads from stdin"; +static const char parse_doc[] = "\n" + "Parse a file using a DFDL schema\n" + "\n" + "Parse Options:" + "\v" + " Trailing arguments:\n" + " infile (not required) input file to parse. " + "If not specified, or a value of -, reads from stdin"; static const struct argp parse_argp = { parse_options, // array of CLI options @@ -109,8 +107,7 @@ parse_daffodil_parse_cli(struct argp_state *state) sprintf(new_cmd, "%s parse", state->name); argv[0] = new_cmd; - error_t status = argp_parse(&parse_argp, argc, argv, ARGP_IN_ORDER, &argc, - &daffodil_parse); + error_t status = argp_parse(&parse_argp, argc, argv, ARGP_IN_ORDER, &argc, &daffodil_parse); argv[0] = old_cmd; state->next += argc - 1; @@ -127,8 +124,7 @@ struct daffodil_unparse_cli daffodil_unparse = { }; static const struct argp_option unparse_options[] = { - {"infoset-type", 'I', "<infoset_type>", 0, - "Infoset type to unparse. Must be 'xml'", 0}, + {"infoset-type", 'I', "<infoset_type>", 0, "Infoset type to unparse. Must be 'xml'", 0}, {"output", 'o', "<file>", 0, "Write output to file. If not given or is -, output is written to " @@ -141,15 +137,14 @@ static error_t unparse_handler(int key, char *arg, struct argp_state *state); static const char unparse_args_doc[] = "[infile]"; -static const char unparse_doc[] = - "\n" - "Unparse an infoset file using a DFDL schema\n" - "\n" - "Unparse Options:" - "\v" - " Trailing arguments:\n" - " infile (not required) input file to unparse. If not specified, or " - "a value of -, reads from stdin"; +static const char unparse_doc[] = "\n" + "Unparse an infoset file using a DFDL schema\n" + "\n" + "Unparse Options:" + "\v" + " Trailing arguments:\n" + " infile (not required) input file to unparse. If not specified, or " + "a value of -, reads from stdin"; static const struct argp unparse_argp = { unparse_options, // array of CLI options @@ -206,8 +201,7 @@ parse_daffodil_unparse_cli(struct argp_state *state) sprintf(new_cmd, "%s unparse", state->name); argv[0] = new_cmd; - error_t status = argp_parse(&unparse_argp, argc, argv, ARGP_IN_ORDER, &argc, - &daffodil_unparse); + error_t status = argp_parse(&unparse_argp, argc, argv, ARGP_IN_ORDER, &argc, &daffodil_unparse); argv[0] = old_cmd; state->next += argc - 1; @@ -223,8 +217,7 @@ struct daffodil_cli daffodil_cli = { }; static const struct argp_option daffodil_options[] = { - {"verbose", 'v', 0, 0, "Increment verbosity level, one level for each -v", - -1}, + {"verbose", 'v', 0, 0, "Increment verbosity level, one level for each -v", -1}, {0}}; @@ -232,15 +225,14 @@ static error_t daffodil_handler(int key, char *arg, struct argp_state *state); static const char daffodil_args_doc[] = "<subcommand> [SUBCOMMAND_OPTION...]"; -static const char daffodil_doc[] = - "\n" - "Global Options:" - "\v" - "Subcommands:\n" - " parse Parse data to a DFDL infoset\n" - " unparse Unparse a DFDL infoset\n" - "\n" - "Run 'daffodil <subcommand> --help' for subcommand specific options"; +static const char daffodil_doc[] = "\n" + "Global Options:" + "\v" + "Subcommands:\n" + " parse Parse data to a DFDL infoset\n" + " unparse Unparse a DFDL infoset\n" + "\n" + "Run 'daffodil <subcommand> --help' for subcommand specific options"; static const struct argp daffodil_argp = { daffodil_options, // array of CLI options @@ -304,6 +296,5 @@ parse_daffodil_cli(int argc, char **argv) { static char *argp_help_fmt = "ARGP_HELP_FMT=no-dup-args-note"; putenv(argp_help_fmt); // Do not pass an automatic variable to putenv - return argp_parse(&daffodil_argp, argc, argv, ARGP_IN_ORDER, NULL, - &daffodil_cli); + return argp_parse(&daffodil_argp, argc, argv, ARGP_IN_ORDER, NULL, &daffodil_cli); } diff --git a/daffodil-runtime2/src/main/resources/c/libcli/daffodil_main.c b/daffodil-runtime2/src/main/resources/c/libcli/daffodil_main.c index 03b1324..af9aee4 100644 --- a/daffodil-runtime2/src/main/resources/c/libcli/daffodil_main.c +++ b/daffodil-runtime2/src/main/resources/c/libcli/daffodil_main.c @@ -95,22 +95,19 @@ main(int argc, char *argv[]) // Parse the input file into our infoset. PState pstate = {input, 0, NULL, NULL}; root->erd->parseSelf(root, &pstate); - print_diagnostics(pstate.validati); + print_diagnostics(pstate.diagnostics); continue_or_exit(pstate.error); if (strcmp(daffodil_parse.infoset_converter, "xml") == 0) { // Visit the infoset and print XML from it. - XMLWriter xmlWriter = { - xmlWriterMethods, output, {NULL, NULL, 0}}; - const Error *error = - walkInfoset((VisitEventHandler *)&xmlWriter, root); + XMLWriter xmlWriter = {xmlWriterMethods, output, {NULL, NULL, 0}}; + const Error *error = walkInfoset((VisitEventHandler *)&xmlWriter, root); fflush_continue_or_exit(output, error); } else { - const Error error = {ERR_INFOSET_WRITE, - {daffodil_parse.infoset_converter}}; + const Error error = {ERR_INFOSET_WRITE, {daffodil_parse.infoset_converter}}; continue_or_exit(&error); } } @@ -123,23 +120,20 @@ main(int argc, char *argv[]) if (strcmp(daffodil_unparse.infoset_converter, "xml") == 0) { // Initialize our infoset's values from the XML data. - XMLReader xmlReader = {xmlReaderMethods, input, root, NULL, - NULL}; - const Error *error = - walkInfoset((VisitEventHandler *)&xmlReader, root); + XMLReader xmlReader = {xmlReaderMethods, input, root, NULL, NULL}; + const Error *error = walkInfoset((VisitEventHandler *)&xmlReader, root); continue_or_exit(error); } else { - const Error error = {ERR_INFOSET_READ, - {daffodil_unparse.infoset_converter}}; + const Error error = {ERR_INFOSET_READ, {daffodil_unparse.infoset_converter}}; continue_or_exit(&error); } // Unparse our infoset to the output file. UState ustate = {output, 0, NULL, NULL}; root->erd->unparseSelf(root, &ustate); - print_diagnostics(ustate.validati); + print_diagnostics(ustate.diagnostics); continue_or_exit(ustate.error); } diff --git a/daffodil-runtime2/src/main/resources/c/libcli/stack.h b/daffodil-runtime2/src/main/resources/c/libcli/stack.h index 0db5c32..c63a24e 100644 --- a/daffodil-runtime2/src/main/resources/c/libcli/stack.h +++ b/daffodil-runtime2/src/main/resources/c/libcli/stack.h @@ -37,8 +37,7 @@ typedef struct // Initialize stack with preallocated array -extern void stack_init(stack_t *p_stack, stack_item_t *p_array, - ptrdiff_t capacity); +extern void stack_init(stack_t *p_stack, stack_item_t *p_array, ptrdiff_t capacity); // Check whether stack is empty diff --git a/daffodil-runtime2/src/main/resources/c/libcli/xml_reader.c b/daffodil-runtime2/src/main/resources/c/libcli/xml_reader.c index 57deee2..c39804f 100644 --- a/daffodil-runtime2/src/main/resources/c/libcli/xml_reader.c +++ b/daffodil-runtime2/src/main/resources/c/libcli/xml_reader.c @@ -136,8 +136,7 @@ strtofnum(const char *numptr, const Error **errorptr) // with our own error checking) static intmax_t -strtonum(const char *numptr, intmax_t minval, intmax_t maxval, - const Error **errorptr) +strtonum(const char *numptr, intmax_t minval, intmax_t maxval, const Error **errorptr) { char *endptr = NULL; assert(minval < maxval); @@ -236,8 +235,7 @@ xmlStartDocument(XMLReader *reader) { do { - reader->node = - mxmlWalkNext(reader->node, reader->xml, MXML_DESCEND); + reader->node = mxmlWalkNext(reader->node, reader->xml, MXML_DESCEND); } while (mxmlGetType(reader->node) == MXML_OPAQUE); name = mxmlGetElement(reader->node); } @@ -247,8 +245,7 @@ xmlStartDocument(XMLReader *reader) { do { - reader->node = - mxmlWalkNext(reader->node, reader->xml, MXML_DESCEND); + reader->node = mxmlWalkNext(reader->node, reader->xml, MXML_DESCEND); } while (mxmlGetType(reader->node) == MXML_OPAQUE); } @@ -346,8 +343,6 @@ xmlNumberElem(XMLReader *reader, const ERD *erd, void *number) { if (strcmp(name_from_xml, name_from_erd) == 0) { - static Error error_erd = {ERR_XML_ERD, {NULL}}; - // Check for any errors getting the number const Error *error = NULL; @@ -357,52 +352,44 @@ xmlNumberElem(XMLReader *reader, const ERD *erd, void *number) { case PRIMITIVE_BOOLEAN: *(bool *)number = strtobool(number_from_xml, &error); - break; + return error; case PRIMITIVE_FLOAT: *(float *)number = strtofnum(number_from_xml, &error); - break; + return error; case PRIMITIVE_DOUBLE: *(double *)number = strtodnum(number_from_xml, &error); - break; + return error; case PRIMITIVE_INT16: - *(int16_t *)number = (int16_t)strtonum( - number_from_xml, INT16_MIN, INT16_MAX, &error); - break; + *(int16_t *)number = (int16_t)strtonum(number_from_xml, INT16_MIN, INT16_MAX, &error); + return error; case PRIMITIVE_INT32: - *(int32_t *)number = (int32_t)strtonum( - number_from_xml, INT32_MIN, INT32_MAX, &error); - break; + *(int32_t *)number = (int32_t)strtonum(number_from_xml, INT32_MIN, INT32_MAX, &error); + return error; case PRIMITIVE_INT64: - *(int64_t *)number = (int64_t)strtonum( - number_from_xml, INT64_MIN, INT64_MAX, &error); - break; + *(int64_t *)number = (int64_t)strtonum(number_from_xml, INT64_MIN, INT64_MAX, &error); + return error; case PRIMITIVE_INT8: - *(int8_t *)number = (int8_t)strtonum(number_from_xml, INT8_MIN, - INT8_MAX, &error); - break; + *(int8_t *)number = (int8_t)strtonum(number_from_xml, INT8_MIN, INT8_MAX, &error); + return error; case PRIMITIVE_UINT16: - *(uint16_t *)number = - (uint16_t)strtounum(number_from_xml, UINT16_MAX, &error); - break; + *(uint16_t *)number = (uint16_t)strtounum(number_from_xml, UINT16_MAX, &error); + return error; case PRIMITIVE_UINT32: - *(uint32_t *)number = - (uint32_t)strtounum(number_from_xml, UINT32_MAX, &error); - break; + *(uint32_t *)number = (uint32_t)strtounum(number_from_xml, UINT32_MAX, &error); + return error; case PRIMITIVE_UINT64: - *(uint64_t *)number = - (uint64_t)strtounum(number_from_xml, UINT64_MAX, &error); - break; + *(uint64_t *)number = (uint64_t)strtounum(number_from_xml, UINT64_MAX, &error); + return error; case PRIMITIVE_UINT8: - *(uint8_t *)number = - (uint8_t)strtounum(number_from_xml, UINT8_MAX, &error); - break; + *(uint8_t *)number = (uint8_t)strtounum(number_from_xml, UINT8_MAX, &error); + return error; default: + { + static Error error_erd = {ERR_XML_ERD, {NULL}}; error_erd.d64 = typeCode; - error = &error_erd; - break; + return &error_erd; + } } - - return error; } else { diff --git a/daffodil-runtime2/src/main/resources/c/libcli/xml_writer.c b/daffodil-runtime2/src/main/resources/c/libcli/xml_writer.c index 11d36ba..bfb336a 100644 --- a/daffodil-runtime2/src/main/resources/c/libcli/xml_writer.c +++ b/daffodil-runtime2/src/main/resources/c/libcli/xml_writer.c @@ -22,7 +22,7 @@ #include <stdint.h> // for int16_t, int32_t, int64_t, int8_t, uint16_t, uint32_t, uint64_t, uint8_t #include <stdio.h> // for NULL #include <string.h> // for strcmp -#include "errors.h" // for Error, ERR_XML_DECL, ERR_XML_ELEMENT, ERR_XML_WRITE, Error::(anonymous) +#include "errors.h" // for Error, ERR_XML_DECL, ERR_XML_ELEMENT, ERR_XML_WRITE, LIMIT_XML_NESTING, Error::(anonymous) #include "stack.h" // for stack_is_empty, stack_pop, stack_push, stack_top, stack_init // Push new XML document on stack (note the stack is stored in a @@ -32,12 +32,8 @@ static const Error * xmlStartDocument(XMLWriter *writer) { - enum - { - MAX_DEPTH = 100 - }; - static mxml_node_t *array[MAX_DEPTH]; - stack_init(&writer->stack, array, MAX_DEPTH); + static mxml_node_t *array[LIMIT_XML_NESTING]; + stack_init(&writer->stack, array, LIMIT_XML_NESTING); mxml_node_t *xml = mxmlNewXML("1.0"); if (xml) @@ -146,8 +142,7 @@ xmlNumberElem(XMLWriter *writer, const ERD *erd, const void *number) switch (typeCode) { case PRIMITIVE_BOOLEAN: - text = mxmlNewOpaquef(simple, "%s", - *(const bool *)number ? "true" : "false"); + text = mxmlNewOpaquef(simple, "%s", *(const bool *)number ? "true" : "false"); break; case PRIMITIVE_FLOAT: // Round-trippable float, shortest possible diff --git a/daffodil-runtime2/src/main/resources/c/libruntime/errors.c b/daffodil-runtime2/src/main/resources/c/libruntime/errors.c index 868b364..4bd657c 100644 --- a/daffodil-runtime2/src/main/resources/c/libruntime/errors.c +++ b/daffodil-runtime2/src/main/resources/c/libruntime/errors.c @@ -16,8 +16,10 @@ */ #include "errors.h" +#include <assert.h> // for assert #include <error.h> // for error #include <inttypes.h> // for PRId64 +#include <stdbool.h> // for bool, false, true #include <stdio.h> // for NULL, feof, ferror, FILE, size_t #include <stdlib.h> // for EXIT_FAILURE @@ -29,8 +31,7 @@ error_message(enum ErrorCode code) switch (code) { case ERR_CHOICE_KEY: - return "no match between choice dispatch key %" PRId64 - " and any branch key"; + return "no match between choice dispatch key %" PRId64 " and any branch key"; case ERR_FILE_CLOSE: return "error closing file"; case ERR_FILE_FLUSH: @@ -85,6 +86,7 @@ error_message(enum ErrorCode code) case ERR_XML_WRITE: return "error writing XML document"; default: + assert("invalid code" && 0); return "unrecognized error code, shouldn't happen"; } } @@ -126,42 +128,43 @@ print_maybe_stop(const Error *err, int status) } } -// need_diagnostics - return pointer to validation diagnostics +// get_diagnostics - get pointer to validation diagnostics Diagnostics * -need_diagnostics(void) +get_diagnostics(void) { - static Diagnostics validati; - return &validati; + static Diagnostics diagnostics; + return &diagnostics; } // add_diagnostic - add a new error to validation diagnostics -void -add_diagnostic(Diagnostics *validati, const Error *error) +bool +add_diagnostic(Diagnostics *diagnostics, const Error *error) { - if (validati && error) + if (diagnostics && error) { - if (validati->length < - sizeof(validati->array) / sizeof(*validati->array)) + if (diagnostics->length < LIMIT_DIAGNOSTICS) { - Error *err = &validati->array[validati->length++]; + Error *err = &diagnostics->array[diagnostics->length++]; err->code = error->code; err->s = error->s; + return true; } } + return false; } // print_diagnostics - print any validation diagnostics void -print_diagnostics(const Diagnostics *validati) +print_diagnostics(const Diagnostics *diagnostics) { - if (validati) + if (diagnostics) { - for (size_t i = 0; i < validati->length; i++) + for (size_t i = 0; i < diagnostics->length; i++) { - const Error *error = &validati->array[i]; + const Error *error = &diagnostics->array[i]; print_maybe_stop(error, 0); } } diff --git a/daffodil-runtime2/src/main/resources/c/libruntime/errors.h b/daffodil-runtime2/src/main/resources/c/libruntime/errors.h index f3153c7..c654181 100644 --- a/daffodil-runtime2/src/main/resources/c/libruntime/errors.h +++ b/daffodil-runtime2/src/main/resources/c/libruntime/errors.h @@ -18,8 +18,16 @@ #ifndef ERRORS_H #define ERRORS_H -#include <stdio.h> // for FILE, size_t +#include <stdbool.h> // for bool #include <stdint.h> // for int64_t +#include <stdio.h> // for FILE, size_t + +enum Limits +{ + LIMIT_DIAGNOSTICS = 100, // limits how many diagnostics can accumulate + LIMIT_NAME_LENGTH = 9999, // limits how long infoset names can become + LIMIT_XML_NESTING = 100 // limits how deep infoset elements can nest +}; // ErrorCode - types of errors which could occur @@ -70,7 +78,7 @@ typedef struct Error typedef struct Diagnostics { - Error array[100]; + Error array[LIMIT_DIAGNOSTICS]; size_t length; } Diagnostics; @@ -78,33 +86,33 @@ typedef struct Diagnostics typedef struct PState { - FILE * stream; // input to read data from - size_t position; // 0-based position in stream - Diagnostics *validati; // any validation diagnostics - const Error *error; // any error which stops program + FILE * stream; // input to read data from + size_t position; // 0-based position in stream + Diagnostics *diagnostics; // any validation diagnostics + const Error *error; // any error which stops program } PState; // UState - mutable state while unparsing infoset typedef struct UState { - FILE * stream; // output to write data to - size_t position; // 0-based position in stream - Diagnostics *validati; // any validation diagnostics - const Error *error; // any error which stops program + FILE * stream; // output to write data to + size_t position; // 0-based position in stream + Diagnostics *diagnostics; // any validation diagnostics + const Error *error; // any error which stops program } UState; -// need_diagnostics - return pointer to validation diagnostics +// get_diagnostics - get pointer to validation diagnostics -extern Diagnostics *need_diagnostics(void); +extern Diagnostics *get_diagnostics(void); // add_diagnostic - add a new error to validation diagnostics -extern void add_diagnostic(Diagnostics *validati, const Error *error); +extern bool add_diagnostic(Diagnostics *diagnostics, const Error *error); // print_diagnostics - print any validation diagnostics -extern void print_diagnostics(const Diagnostics *validati); +extern void print_diagnostics(const Diagnostics *diagnostics); // continue_or_exit - print and exit if an error occurred or continue otherwise diff --git a/daffodil-runtime2/src/main/resources/c/libruntime/infoset.c b/daffodil-runtime2/src/main/resources/c/libruntime/infoset.c index 8c52eb2..107aa55 100644 --- a/daffodil-runtime2/src/main/resources/c/libruntime/infoset.c +++ b/daffodil-runtime2/src/main/resources/c/libruntime/infoset.c @@ -17,7 +17,7 @@ #include "infoset.h" #include <string.h> // for memccpy -#include "errors.h" // for Error, ERR_WALK_KEY +#include "errors.h" // for Error, LIMIT_NAME_LENGTH // get_erd_name, get_erd_xmlns, get_erd_ns - get name and xmlns // attribute/value from ERD to use on XML element @@ -25,7 +25,7 @@ const char * get_erd_name(const ERD *erd) { - static char name[9999]; + static char name[LIMIT_NAME_LENGTH]; char * next = name; char * last = name + sizeof(name) - 1; @@ -66,7 +66,7 @@ get_erd_xmlns(const ERD *erd) { if (erd->namedQName.ns) { - static char xmlns[9999]; + static char xmlns[LIMIT_NAME_LENGTH]; char * next = xmlns; char * last = xmlns + sizeof(xmlns) - 1; @@ -135,9 +135,8 @@ walkInfosetNode(const VisitEventHandler *handler, const InfosetBase *infoNode) const size_t offset = offsets[i]; const ERD * childERD = childrenERDs[i]; // We use only one of these variables below depending on typeCode - const InfosetBase *childNode = - (const InfosetBase *)((const char *)infoNode + offset); - const void *number = (const void *)((const char *)infoNode + offset); + const InfosetBase *childNode = (const InfosetBase *)((const char *)infoNode + offset); + const void * number = (const void *)((const char *)infoNode + offset); // Will need to handle more element types const enum TypeCode typeCode = childERD->typeCode; diff --git a/daffodil-runtime2/src/main/resources/c/libruntime/infoset.h b/daffodil-runtime2/src/main/resources/c/libruntime/infoset.h index 77bc57f..50281b9 100644 --- a/daffodil-runtime2/src/main/resources/c/libruntime/infoset.h +++ b/daffodil-runtime2/src/main/resources/c/libruntime/infoset.h @@ -30,17 +30,13 @@ typedef struct VisitEventHandler VisitEventHandler; typedef void (*ERDInitSelf)(InfosetBase *infoNode); typedef void (*ERDParseSelf)(InfosetBase *infoNode, PState *pstate); typedef void (*ERDUnparseSelf)(const InfosetBase *infoNode, UState *ustate); -typedef const Error *(*InitChoiceRD)(const InfosetBase *infoNode, - const InfosetBase *rootElement); +typedef const Error *(*InitChoiceRD)(const InfosetBase *infoNode, const InfosetBase *rootElement); typedef const Error *(*VisitStartDocument)(const VisitEventHandler *handler); typedef const Error *(*VisitEndDocument)(const VisitEventHandler *handler); -typedef const Error *(*VisitStartComplex)(const VisitEventHandler *handler, - const InfosetBase * base); -typedef const Error *(*VisitEndComplex)(const VisitEventHandler *handler, - const InfosetBase * base); -typedef const Error *(*VisitNumberElem)(const VisitEventHandler *handler, - const ERD *erd, const void *number); +typedef const Error *(*VisitStartComplex)(const VisitEventHandler *handler, const InfosetBase *base); +typedef const Error *(*VisitEndComplex)(const VisitEventHandler *handler, const InfosetBase *base); +typedef const Error *(*VisitNumberElem)(const VisitEventHandler *handler, const ERD *erd, const void *number); // NamedQName - name of an infoset element @@ -119,7 +115,6 @@ extern InfosetBase *rootElement(void); // walkInfoset - walk an infoset and call VisitEventHandler methods -extern const Error *walkInfoset(const VisitEventHandler *handler, - const InfosetBase * infoset); +extern const Error *walkInfoset(const VisitEventHandler *handler, const InfosetBase *infoset); #endif // INFOSET_H diff --git a/daffodil-runtime2/src/main/resources/c/libruntime/parsers.c b/daffodil-runtime2/src/main/resources/c/libruntime/parsers.c index e10a22d..81b2b69 100644 --- a/daffodil-runtime2/src/main/resources/c/libruntime/parsers.c +++ b/daffodil-runtime2/src/main/resources/c/libruntime/parsers.c @@ -19,7 +19,7 @@ #include <endian.h> // for be32toh, le32toh, be16toh, be64toh, le16toh, le64toh #include <stdbool.h> // for bool, false, true #include <stdio.h> // for fread -#include "errors.h" // for PState, eof_or_error, Error, ERR_PARSE_BOOL, Error::(anonymous), add_diagnostic, need_diagnostics, ERR_FIXED_VALUE, Diagnostics +#include "errors.h" // for PState, eof_or_error, Error, ERR_PARSE_BOOL, Error::(anonymous), add_diagnostic, get_diagnostics, ERR_FIXED_VALUE, Diagnostics // Macros not defined by <endian.h> which we need for uniformity @@ -29,75 +29,74 @@ // Helper macro to reduce duplication of C code reading stream, // updating position, and checking for errors -#define read_stream_update_position \ - size_t count = fread(&buffer.c_val, 1, sizeof(buffer), pstate->stream); \ - pstate->position += count; \ - if (count < sizeof(buffer)) \ - { \ - pstate->error = eof_or_error(pstate->stream); \ - if (pstate->error) return; \ +#define read_stream_update_position \ + size_t count = fread(&buffer.c_val, 1, sizeof(buffer), pstate->stream); \ + pstate->position += count; \ + if (count < sizeof(buffer)) \ + { \ + pstate->error = eof_or_error(pstate->stream); \ + if (pstate->error) return; \ } // Macros to define parse_<endian>_<type> functions -#define define_parse_endian_bool(endian, bits) \ - void parse_##endian##_bool##bits(bool *number, int64_t true_rep, \ - uint32_t false_rep, PState *pstate) \ - { \ - union \ - { \ - char c_val[sizeof(uint##bits##_t)]; \ - uint##bits##_t i_val; \ - } buffer; \ - \ - read_stream_update_position; \ - buffer.i_val = endian##bits##toh(buffer.i_val); \ - if (true_rep < 0) \ - { \ - *number = (buffer.i_val != false_rep); \ - } \ - else if (buffer.i_val == (uint32_t)true_rep) \ - { \ - *number = true; \ - } \ - else if (buffer.i_val == false_rep) \ - { \ - *number = false; \ - } \ - else \ - { \ - static Error error = {ERR_PARSE_BOOL, {NULL}}; \ - error.d64 = (int64_t)buffer.i_val; \ - pstate->error = &error; \ - } \ +#define define_parse_endian_bool(endian, bits) \ + void parse_##endian##_bool##bits(bool *number, int64_t true_rep, uint32_t false_rep, PState *pstate) \ + { \ + union \ + { \ + char c_val[sizeof(uint##bits##_t)]; \ + uint##bits##_t i_val; \ + } buffer; \ + \ + read_stream_update_position; \ + buffer.i_val = endian##bits##toh(buffer.i_val); \ + if (true_rep < 0) \ + { \ + *number = (buffer.i_val != false_rep); \ + } \ + else if (buffer.i_val == (uint32_t)true_rep) \ + { \ + *number = true; \ + } \ + else if (buffer.i_val == false_rep) \ + { \ + *number = false; \ + } \ + else \ + { \ + static Error error = {ERR_PARSE_BOOL, {NULL}}; \ + error.d64 = (int64_t)buffer.i_val; \ + pstate->error = &error; \ + } \ } -#define define_parse_endian_real(endian, type, bits) \ - void parse_##endian##_##type(type *number, PState *pstate) \ - { \ - union \ - { \ - char c_val[sizeof(type)]; \ - type f_val; \ - uint##bits##_t i_val; \ - } buffer; \ - \ - read_stream_update_position; \ - buffer.i_val = endian##bits##toh(buffer.i_val); \ - *number = buffer.f_val; \ +#define define_parse_endian_real(endian, type, bits) \ + void parse_##endian##_##type(type *number, PState *pstate) \ + { \ + union \ + { \ + char c_val[sizeof(type)]; \ + type f_val; \ + uint##bits##_t i_val; \ + } buffer; \ + \ + read_stream_update_position; \ + buffer.i_val = endian##bits##toh(buffer.i_val); \ + *number = buffer.f_val; \ } -#define define_parse_endian_integer(endian, type, bits) \ - void parse_##endian##_##type##bits(type##bits##_t *number, PState *pstate) \ - { \ - union \ - { \ - char c_val[sizeof(type##bits##_t)]; \ - type##bits##_t i_val; \ - } buffer; \ - \ - read_stream_update_position; \ - *number = endian##bits##toh(buffer.i_val); \ +#define define_parse_endian_integer(endian, type, bits) \ + void parse_##endian##_##type##bits(type##bits##_t *number, PState *pstate) \ + { \ + union \ + { \ + char c_val[sizeof(type##bits##_t)]; \ + type##bits##_t i_val; \ + } buffer; \ + \ + read_stream_update_position; \ + *number = endian##bits##toh(buffer.i_val); \ } // Parse binary booleans, real numbers, and integers @@ -159,10 +158,10 @@ parse_validate_fixed(bool same, const char *element, PState *pstate) { if (!same) { - Diagnostics *validati = need_diagnostics(); - const Error error = {ERR_FIXED_VALUE, {element}}; + Diagnostics *diagnostics = get_diagnostics(); + const Error error = {ERR_FIXED_VALUE, {element}}; - add_diagnostic(validati, &error); - pstate->validati = validati; + add_diagnostic(diagnostics, &error); + pstate->diagnostics = diagnostics; } } diff --git a/daffodil-runtime2/src/main/resources/c/libruntime/parsers.h b/daffodil-runtime2/src/main/resources/c/libruntime/parsers.h index c005d94..0de7de7 100644 --- a/daffodil-runtime2/src/main/resources/c/libruntime/parsers.h +++ b/daffodil-runtime2/src/main/resources/c/libruntime/parsers.h @@ -25,12 +25,9 @@ // Parse binary booleans, real numbers, and integers -extern void parse_be_bool16(bool *number, int64_t true_rep, uint32_t false_rep, - PState *pstate); -extern void parse_be_bool32(bool *number, int64_t true_rep, uint32_t false_rep, - PState *pstate); -extern void parse_be_bool8(bool *number, int64_t true_rep, uint32_t false_rep, - PState *pstate); +extern void parse_be_bool16(bool *number, int64_t true_rep, uint32_t false_rep, PState *pstate); +extern void parse_be_bool32(bool *number, int64_t true_rep, uint32_t false_rep, PState *pstate); +extern void parse_be_bool8(bool *number, int64_t true_rep, uint32_t false_rep, PState *pstate); extern void parse_be_double(double *number, PState *pstate); extern void parse_be_float(float *number, PState *pstate); @@ -45,12 +42,9 @@ extern void parse_be_uint32(uint32_t *number, PState *pstate); extern void parse_be_uint64(uint64_t *number, PState *pstate); extern void parse_be_uint8(uint8_t *number, PState *pstate); -extern void parse_le_bool16(bool *number, int64_t true_rep, uint32_t false_rep, - PState *pstate); -extern void parse_le_bool32(bool *number, int64_t true_rep, uint32_t false_rep, - PState *pstate); -extern void parse_le_bool8(bool *number, int64_t true_rep, uint32_t false_rep, - PState *pstate); +extern void parse_le_bool16(bool *number, int64_t true_rep, uint32_t false_rep, PState *pstate); +extern void parse_le_bool32(bool *number, int64_t true_rep, uint32_t false_rep, PState *pstate); +extern void parse_le_bool8(bool *number, int64_t true_rep, uint32_t false_rep, PState *pstate); extern void parse_le_double(double *number, PState *pstate); extern void parse_le_float(float *number, PState *pstate); @@ -71,7 +65,6 @@ extern void parse_fill_bytes(size_t end_position, PState *pstate); // Validate parsed number is same as fixed value -extern void parse_validate_fixed(bool same, const char *element, - PState *pstate); +extern void parse_validate_fixed(bool same, const char *element, PState *pstate); #endif // PARSERS_H diff --git a/daffodil-runtime2/src/main/resources/c/libruntime/unparsers.c b/daffodil-runtime2/src/main/resources/c/libruntime/unparsers.c index 22555ab..d64b785 100644 --- a/daffodil-runtime2/src/main/resources/c/libruntime/unparsers.c +++ b/daffodil-runtime2/src/main/resources/c/libruntime/unparsers.c @@ -19,7 +19,7 @@ #include <endian.h> // for htobe32, htole32, htobe16, htobe64, htole16, htole64 #include <stdbool.h> // for bool #include <stdio.h> // for fwrite -#include "errors.h" // for UState, eof_or_error, add_diagnostic, need_diagnostics, ERR_FIXED_VALUE, Diagnostics, Error +#include "errors.h" // for UState, eof_or_error, add_diagnostic, get_diagnostics, ERR_FIXED_VALUE, Diagnostics, Error // Macros not defined by <endian.h> which we need for uniformity @@ -29,58 +29,56 @@ // Helper macro to reduce duplication of C code writing stream, // updating position, and checking for errors -#define write_stream_update_position \ - size_t count = fwrite(buffer.c_val, 1, sizeof(buffer), ustate->stream); \ - ustate->position += count; \ - if (count < sizeof(buffer)) \ - { \ - ustate->error = eof_or_error(ustate->stream); \ - if (ustate->error) return; \ +#define write_stream_update_position \ + size_t count = fwrite(buffer.c_val, 1, sizeof(buffer), ustate->stream); \ + ustate->position += count; \ + if (count < sizeof(buffer)) \ + { \ + ustate->error = eof_or_error(ustate->stream); \ + if (ustate->error) return; \ } // Macros to define unparse_<endian>_<type> functions -#define define_unparse_endian_bool(endian, bits) \ - void unparse_##endian##_bool##bits(bool number, uint32_t true_rep, \ - uint32_t false_rep, UState *ustate) \ - { \ - union \ - { \ - char c_val[sizeof(uint##bits##_t)]; \ - uint##bits##_t i_val; \ - } buffer; \ - \ - buffer.i_val = hto##endian##bits(number ? true_rep : false_rep); \ - write_stream_update_position; \ +#define define_unparse_endian_bool(endian, bits) \ + void unparse_##endian##_bool##bits(bool number, uint32_t true_rep, uint32_t false_rep, UState *ustate) \ + { \ + union \ + { \ + char c_val[sizeof(uint##bits##_t)]; \ + uint##bits##_t i_val; \ + } buffer; \ + \ + buffer.i_val = hto##endian##bits(number ? true_rep : false_rep); \ + write_stream_update_position; \ } -#define define_unparse_endian_real(endian, type, bits) \ - void unparse_##endian##_##type(type number, UState *ustate) \ - { \ - union \ - { \ - char c_val[sizeof(type)]; \ - type f_val; \ - uint##bits##_t i_val; \ - } buffer; \ - \ - buffer.f_val = number; \ - buffer.i_val = hto##endian##bits(buffer.i_val); \ - write_stream_update_position; \ +#define define_unparse_endian_real(endian, type, bits) \ + void unparse_##endian##_##type(type number, UState *ustate) \ + { \ + union \ + { \ + char c_val[sizeof(type)]; \ + type f_val; \ + uint##bits##_t i_val; \ + } buffer; \ + \ + buffer.f_val = number; \ + buffer.i_val = hto##endian##bits(buffer.i_val); \ + write_stream_update_position; \ } -#define define_unparse_endian_integer(endian, type, bits) \ - void unparse_##endian##_##type##bits(type##bits##_t number, \ - UState * ustate) \ - { \ - union \ - { \ - char c_val[sizeof(type##bits##_t)]; \ - type##bits##_t i_val; \ - } buffer; \ - \ - buffer.i_val = hto##endian##bits(number); \ - write_stream_update_position; \ +#define define_unparse_endian_integer(endian, type, bits) \ + void unparse_##endian##_##type##bits(type##bits##_t number, UState *ustate) \ + { \ + union \ + { \ + char c_val[sizeof(type##bits##_t)]; \ + type##bits##_t i_val; \ + } buffer; \ + \ + buffer.i_val = hto##endian##bits(number); \ + write_stream_update_position; \ } // Unparse binary booleans, real numbers, and integers @@ -122,8 +120,7 @@ define_unparse_endian_integer(le, uint, 8) // Unparse fill bytes until end position is reached void -unparse_fill_bytes(size_t end_position, const char fill_byte, - UState *ustate) +unparse_fill_bytes(size_t end_position, const char fill_byte, UState *ustate) { union { @@ -145,10 +142,10 @@ unparse_validate_fixed(bool same, const char *element, UState *ustate) { if (!same) { - Diagnostics *validati = need_diagnostics(); - const Error error = {ERR_FIXED_VALUE, {element}}; + Diagnostics *diagnostics = get_diagnostics(); + const Error error = {ERR_FIXED_VALUE, {element}}; - add_diagnostic(validati, &error); - ustate->validati = validati; + add_diagnostic(diagnostics, &error); + ustate->diagnostics = diagnostics; } } diff --git a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/BinaryAbstractCodeGenerator.scala b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/BinaryAbstractCodeGenerator.scala index f5aa79b..772a3b5 100644 --- a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/BinaryAbstractCodeGenerator.scala +++ b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/BinaryAbstractCodeGenerator.scala @@ -37,8 +37,6 @@ trait BinaryAbstractCodeGenerator { val byteOrder = e.byteOrderEv.constValue val conv = if (byteOrder eq ByteOrder.BigEndian) "be" else "le" val arraySize = if (e.occursCountKind == OccursCountKind.Fixed) e.maxOccurs else 0 - val fixed = e.xml.attribute("fixed") - val fixedValue = if (fixed.isDefined) fixed.get.text else "" def addStatements(deref: String): Unit = { val initStatement = s" instance->$fieldName$deref = $initialValue;" @@ -50,7 +48,8 @@ trait BinaryAbstractCodeGenerator { | if (ustate->error) return;""".stripMargin cgState.addSimpleTypeStatements(initStatement, parseStatement, unparseStatement) - if (fixedValue.nonEmpty) { + if (e.hasFixedValue) { + val fixedValue = e.fixedValue.value.toString val init2 = "" val parse2 = s""" parse_validate_fixed(instance->$fieldName$deref == $fixedValue, "$fieldName", pstate); diff --git a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala index 577a542..f045f03 100644 --- a/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala +++ b/daffodil-runtime2/src/main/scala/org/apache/daffodil/runtime2/generators/CodeGeneratorState.scala @@ -67,15 +67,14 @@ class CodeGeneratorState { val C = localName(context) val initStatements = structs.top.initStatements.mkString("\n") val initChoiceStatements = structs.top.initChoiceStatements.mkString("\n") - val hasStatements = structs.top.parserStatements.nonEmpty - val parserStatements = if (hasStatements) + val parserStatements = if (structs.top.parserStatements.nonEmpty) structs.top.parserStatements.mkString("\n") else s""" // Empty struct, but need to prevent compiler warnings | UNUSED(${C}_compute_offsets); | UNUSED(instance); | UNUSED(pstate);""".stripMargin - val unparserStatements = if (hasStatements) + val unparserStatements = if (structs.top.unparserStatements.nonEmpty) structs.top.unparserStatements.mkString("\n") else s""" // Empty struct, but need to prevent compiler warnings
