diff -Nru erlang-p1-xml-0.2015.04.15/CHANGELOG.md erlang-p1-xml-1.1.2/CHANGELOG.md --- erlang-p1-xml-0.2015.04.15/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/CHANGELOG.md 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,20 @@ +# Version 1.1.1 + +* Support for both rebar and rebar3 (Mickaël Rémond) +* Huge performance and memory improvements (Paweł Chmielowski) +* Normalize namespace prefixed elements (Paweł Chmielowski) +* Document how to run tests (Mickaël Rémond) +* Architecture documentation in README.md (Mickaël Rémond) +* Introduce Elixir Quickcheck tests (Mickaël Rémond) +* Support C code coverage (Paweł Chmielowski) +* Better test case coverage (Evgeniy Khramtsov) +* Continuous integration with Travis CI and Coveralls (Paweł Chmielowski - Mickaël Rémond) +* Test refactoring (Evgeniy Khramtsov) +* Save cflags/ldflags passed to configure (Paweł Chmielowski) +* Move code for locating nif files to p1_utils package (Paweł Chmielowski) +* Improve code for locating .so part (Paweł Chmielowski) +* Do not check Expat presence via m4 macro (Evgeniy Khramtsov) + +# Version 1.1.0 + +* Initial release on Hex.pm (Mickaël Rémond) diff -Nru erlang-p1-xml-0.2015.04.15/configure erlang-p1-xml-1.1.2/configure --- erlang-p1-xml-0.2015.04.15/configure 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/configure 2016-01-23 17:21:53.000000000 +0000 @@ -619,9 +619,7 @@ #endif" ac_subst_vars='LTLIBOBJS -flash_hack -disable_nif -full_xml +gcov ERLCFLAGS ERLC ERL @@ -656,6 +654,7 @@ docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -678,9 +677,7 @@ ac_subst_files='' ac_user_opts=' enable_option_checking -enable_full_xml -enable_disable_nif -enable_flash_hack +enable_gcov ' ac_precious_vars='build_alias host_alias @@ -732,6 +729,7 @@ sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -984,6 +982,15 @@ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1121,7 +1128,7 @@ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1274,6 +1281,7 @@ --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1303,10 +1311,7 @@ --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-full-xml use XML features in XMPP stream (ex: CDATA) - (default: no, requires XML compliant clients) - --disable-nif (default: no) - --enable-flash-hack support Adobe Flash client XML (default: no) + --enable-gcov compile with gcov enabled (default: no) Some influential environment variables: CC C compiler command @@ -3747,13 +3752,28 @@ # AC_ERLANG_SUBST_ROOT_DIR # AC_ERLANG_SUBST_LIB_DIR -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XML_ParserCreate in -lexpat" >&5 -$as_echo_n "checking for XML_ParserCreate in -lexpat... " >&6; } -if ${ac_cv_lib_expat_XML_ParserCreate+:} false; then : +for ac_header in expat.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "expat.h" "ac_cv_header_expat_h" "$ac_includes_default" +if test "x$ac_cv_header_expat_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPAT_H 1 +_ACEOF + +else + + as_fn_error $? "libexpat header file expat.h was not found" "$LINENO" 5 +fi + +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing XML_ParserCreate" >&5 +$as_echo_n "checking for library containing XML_ParserCreate... " >&6; } +if ${ac_cv_search_XML_ParserCreate+:} false; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lexpat $LIBS" + ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -3772,78 +3792,59 @@ return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_expat_XML_ParserCreate=yes -else - ac_cv_lib_expat_XML_ParserCreate=no +for ac_lib in '' expat; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_XML_ParserCreate=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_expat_XML_ParserCreate" >&5 -$as_echo "$ac_cv_lib_expat_XML_ParserCreate" >&6; } -if test "x$ac_cv_lib_expat_XML_ParserCreate" = xyes; then : - EXPAT_LIB=yes -fi - -ac_fn_c_check_header_mongrel "$LINENO" "expat.h" "ac_cv_header_expat_h" "$ac_includes_default" -if test "x$ac_cv_header_expat_h" = xyes; then : - EXPAT_HEADER=yes + conftest$ac_exeext + if ${ac_cv_search_XML_ParserCreate+:} false; then : + break fi +done +if ${ac_cv_search_XML_ParserCreate+:} false; then : - - -if test "x$EXPAT_LIB" = "x"; then - as_fn_error $? "Expat library was not found" "$LINENO" 5 +else + ac_cv_search_XML_ParserCreate=no fi - -if test "x$EXPAT_HEADER" = "x"; then - as_fn_error $? "Expat header file \"expat.h\" was not found" "$LINENO" 5 +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_XML_ParserCreate" >&5 +$as_echo "$ac_cv_search_XML_ParserCreate" >&6; } +ac_res=$ac_cv_search_XML_ParserCreate +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" -# Check whether --enable-full_xml was given. -if test "${enable_full_xml+set}" = set; then : - enableval=$enable_full_xml; case "${enableval}" in - yes) full_xml=true ;; - no) full_xml=false ;; - *) as_fn_error $? "bad value ${enableval} for --enable-full-xml" "$LINENO" 5 ;; -esac else - full_xml=false -fi - - -# Check whether --enable-disable_nif was given. -if test "${enable_disable_nif+set}" = set; then : - enableval=$enable_disable_nif; case "${enableval}" in - yes) disable_nif=true ;; - no) disable_nif=false ;; - *) as_fn_error $? "bad value ${enableval} for --disable-nif" "$LINENO" 5 ;; -esac -else - disable_nif=false + as_fn_error $? "libexpat library was not found" "$LINENO" 5 fi - -# Check whether --enable-flash_hack was given. -if test "${enable_flash_hack+set}" = set; then : - enableval=$enable_flash_hack; case "${enableval}" in - yes) flash_hack=true ;; - no) flash_hack=false ;; - *) as_fn_error $? "bad value ${enableval} for --enable-flash-hack" "$LINENO" 5 ;; +# Check whether --enable-gcov was given. +if test "${enable_gcov+set}" = set; then : + enableval=$enable_gcov; case "${enableval}" in + yes) gcov=true ;; + no) gcov=false ;; + *) as_fn_error $? "bad value ${enableval} for --enable-gcov" "$LINENO" 5 ;; esac else - flash_hack=false + gcov=false fi -ac_config_files="$ac_config_files rebar.config.script" +ac_config_files="$ac_config_files vars.config" + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -4549,7 +4550,7 @@ for ac_config_target in $ac_config_targets do case $ac_config_target in - "rebar.config.script") CONFIG_FILES="$CONFIG_FILES rebar.config.script" ;; + "vars.config") CONFIG_FILES="$CONFIG_FILES vars.config" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff -Nru erlang-p1-xml-0.2015.04.15/configure.ac erlang-p1-xml-1.1.2/configure.ac --- erlang-p1-xml-0.2015.04.15/configure.ac 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/configure.ac 2016-01-23 17:21:53.000000000 +0000 @@ -28,44 +28,22 @@ # AC_ERLANG_SUBST_ROOT_DIR # AC_ERLANG_SUBST_LIB_DIR -AC_CHECK_LIB(expat, XML_ParserCreate, [EXPAT_LIB=yes], [], []) -AC_CHECK_HEADER(expat.h, [EXPAT_HEADER=yes], [], []) +AC_CHECK_HEADERS([expat.h], [], [ + AC_MSG_ERROR([libexpat header file expat.h was not found])]) -if test "x$EXPAT_LIB" = "x"; then - AC_MSG_ERROR([Expat library was not found]) -fi - -if test "x$EXPAT_HEADER" = "x"; then - AC_MSG_ERROR([Expat header file "expat.h" was not found]) -fi +AC_SEARCH_LIBS([XML_ParserCreate], [expat], [], [ + AC_MSG_ERROR([libexpat library was not found])]) -AC_ARG_ENABLE(full_xml, -[AC_HELP_STRING([--enable-full-xml], [use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients)])], +AC_ARG_ENABLE(gcov, +[AC_HELP_STRING([--enable-gcov], [compile with gcov enabled (default: no)])], [case "${enableval}" in - yes) full_xml=true ;; - no) full_xml=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-full-xml) ;; -esac],[full_xml=false]) -AC_SUBST(full_xml) + yes) gcov=true ;; + no) gcov=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-gcov) ;; +esac],[gcov=false]) -AC_ARG_ENABLE(disable_nif, -[AC_HELP_STRING([--disable-nif], [ (default: no)])], -[case "${enableval}" in - yes) disable_nif=true ;; - no) disable_nif=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-nif) ;; -esac],[disable_nif=false]) -AC_SUBST(disable_nif) - -AC_ARG_ENABLE(flash_hack, -[AC_HELP_STRING([--enable-flash-hack], [support Adobe Flash client XML (default: no)])], -[case "${enableval}" in - yes) flash_hack=true ;; - no) flash_hack=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-flash-hack) ;; -esac],[flash_hack=false]) -AC_SUBST(flash_hack) -AC_CONFIG_FILES([rebar.config.script]) +AC_SUBST(gcov) +AC_CONFIG_FILES([vars.config]) AC_OUTPUT diff -Nru erlang-p1-xml-0.2015.04.15/COPYING erlang-p1-xml-1.1.2/COPYING --- erlang-p1-xml-0.2015.04.15/COPYING 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/COPYING 1970-01-01 00:00:00.000000000 +0000 @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff -Nru erlang-p1-xml-0.2015.04.15/c_src/expat_erl.c erlang-p1-xml-1.1.2/c_src/expat_erl.c --- erlang-p1-xml-0.2015.04.15/c_src/expat_erl.c 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/c_src/expat_erl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2002-2015 ProcessOne - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include - - -#define XML_START 0 -#define XML_END 1 -#define XML_CDATA 2 -#define XML_ERROR 3 - -#define PARSE_COMMAND 0 -#define PARSE_FINAL_COMMAND 1 -#define PARSING_NOT_RESUMABLE XML_FALSE - -/* - * R15B changed several driver callbacks to use ErlDrvSizeT and - * ErlDrvSSizeT typedefs instead of int. - * This provides missing typedefs on older OTP versions. - */ -#if ERL_DRV_EXTENDED_MAJOR_VERSION < 2 -typedef int ErlDrvSizeT; -typedef int ErlDrvSSizeT; -#endif - -ei_x_buff event_buf; -ei_x_buff xmlns_buf; - -typedef struct { - ErlDrvPort port; - XML_Parser parser; -} expat_data; - -static XML_Memory_Handling_Suite ms; - -void encode_name(const XML_Char *name) -{ - char *name_start; - char *prefix_start; - char *buf; - int name_len, prefix_len, buf_len; - - if ((name_start = strchr(name, '\n'))) { - if ((prefix_start = strchr(name_start+1, '\n'))) { - name_len = prefix_start - name_start; - prefix_len = strlen(prefix_start+1); - buf_len = prefix_len + name_len; - buf = driver_alloc(buf_len); - memcpy(buf, prefix_start+1, prefix_len); - memcpy(buf+prefix_len, name_start, name_len); - buf[prefix_len] = ':'; - ei_x_encode_binary(&event_buf, buf, buf_len); - driver_free(buf); - } else { - ei_x_encode_binary(&event_buf, name_start+1, strlen(name_start+1)); - }; - } else { - ei_x_encode_binary(&event_buf, name, strlen(name)); - } -} - -void *erlXML_StartElementHandler(expat_data *d, - const XML_Char *name, - const XML_Char **atts) -{ - int i; - - ei_x_encode_list_header(&event_buf, 1); - ei_x_encode_tuple_header(&event_buf, 2); - ei_x_encode_long(&event_buf, XML_START); - ei_x_encode_tuple_header(&event_buf, 2); - encode_name(name); - ei_x_append(&event_buf, &xmlns_buf); - ei_x_free(&xmlns_buf); - ei_x_new(&xmlns_buf); - - for (i = 0; atts[i]; i += 2) {} - - if (i > 0) - { - ei_x_encode_list_header(&event_buf, i/2); - - for (i = 0; atts[i]; i += 2) - { - ei_x_encode_tuple_header(&event_buf, 2); - encode_name(atts[i]); - ei_x_encode_binary(&event_buf, atts[i+1], strlen(atts[i+1])); - } - } - - ei_x_encode_empty_list(&event_buf); - - return NULL; -} - -void *erlXML_EndElementHandler(expat_data *d, - const XML_Char *name) -{ - ei_x_encode_list_header(&event_buf, 1); - ei_x_encode_tuple_header(&event_buf, 2); - ei_x_encode_long(&event_buf, XML_END); - encode_name(name); - return NULL; -} - -void *erlXML_CharacterDataHandler(expat_data *d, - const XML_Char *s, - int len) -{ - ei_x_encode_list_header(&event_buf, 1); - ei_x_encode_tuple_header(&event_buf, 2); - ei_x_encode_long(&event_buf, XML_CDATA); - ei_x_encode_binary(&event_buf, s, len); - return NULL; -} - -void *erlXML_StartNamespaceDeclHandler(expat_data *d, - const XML_Char *prefix, - const XML_Char *uri) -{ - int prefix_len; - char *buf; - - /* From the expat documentation: - "For a default namespace declaration (xmlns='...'), - the prefix will be null ... - ... The URI will be null for the case where - the default namespace is being unset." - - FIXME: I'm not quite sure what all that means */ - if (uri == NULL) - return NULL; - - ei_x_encode_list_header(&xmlns_buf, 1); - ei_x_encode_tuple_header(&xmlns_buf, 2); - if (prefix) { - prefix_len = strlen(prefix); - buf = driver_alloc(7 + prefix_len); - strcpy(buf, "xmlns:"); - strcpy(buf+6, prefix); - ei_x_encode_binary(&xmlns_buf, buf, strlen(buf)); - driver_free(buf); - } else { - ei_x_encode_binary(&xmlns_buf, "xmlns", strlen("xmlns")); - }; - ei_x_encode_binary(&xmlns_buf, uri, strlen(uri)); - - return NULL; -} - -/* - * Prevent entity expansion attacks (CVE-2013-1664) by refusing - * to process any XML that contains a DTD. - */ -void *erlXML_StartDoctypeDeclHandler(expat_data *d, - const XML_Char *doctypeName, - const XML_Char *doctypeSysid, - const XML_Char *doctypePubid, - int hasInternalSubset) -{ - XML_StopParser(d->parser, PARSING_NOT_RESUMABLE); - return NULL; -} - -/* - * Prevent entity expansion attacks (CVE-2013-1664) by having an explicit - * default handler. According to the documentation, - * - * "Setting the handler with this call has the side effect of turning off - * expansion of references to internally defined general entities. Instead - * these references are passed to the default handler." - */ -void *erlXML_DefaultHandler(expat_data *d, - const XML_Char *s, - int len) -{ - return NULL; -} - -static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff) -{ - expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data)); - d->port = port; - d->parser = XML_ParserCreate_MM("UTF-8", &ms, "\n"); - XML_SetUserData(d->parser, d); - - set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); - - XML_SetStartElementHandler( - d->parser, (XML_StartElementHandler)erlXML_StartElementHandler); - XML_SetEndElementHandler( - d->parser, (XML_EndElementHandler)erlXML_EndElementHandler); - XML_SetCharacterDataHandler( - d->parser, (XML_CharacterDataHandler)erlXML_CharacterDataHandler); - - XML_SetStartNamespaceDeclHandler( - d->parser, (XML_StartNamespaceDeclHandler) erlXML_StartNamespaceDeclHandler); - XML_SetStartDoctypeDeclHandler( - d->parser, (XML_StartDoctypeDeclHandler) erlXML_StartDoctypeDeclHandler); - XML_SetReturnNSTriplet(d->parser, 1); - - XML_SetDefaultHandler( - d->parser, (XML_DefaultHandler) erlXML_DefaultHandler); - - return (ErlDrvData)d; -} - -static void expat_erl_stop(ErlDrvData handle) -{ - XML_ParserFree(((expat_data *)handle)->parser); - driver_free((char*)handle); -} - -static ErlDrvSSizeT expat_erl_control(ErlDrvData drv_data, - unsigned int command, - char *buf, ErlDrvSizeT len, - char **rbuf, ErlDrvSizeT rlen) -{ - expat_data* d = (expat_data*)drv_data; - int res, errcode; - char *errstring; - ErlDrvBinary *b; - size_t size; - - switch (command) - { - case PARSE_COMMAND: - case PARSE_FINAL_COMMAND: - ei_x_new_with_version(&event_buf); - ei_x_new(&xmlns_buf); -#ifdef ENABLE_FLASH_HACK - /* Flash hack - Flash clients send a null byte after the stanza. Remove that... */ - { - int i; - int found_null = 0; - - /* Maybe the Flash client sent many stanzas in one packet. - If so, there is a null byte between every stanza. */ - for (i = 0; i < len; i++) { - if (buf[i] == '\0') { - buf[i] = ' '; - found_null = 1; - } - } - - /* And also remove the closing slash if this is a - flash:stream element. Assume that flash:stream is the - last element in the packet, and entirely contained in - it. This requires that a null byte has been found. */ - if (found_null && strstr(buf, " - buf[len - 3] is / (maybe) - */ - if (buf[len - 3] == '/') - buf[len - 3] = ' '; - } -#endif /* ENABLE_FLASH_HACK */ - - res = XML_Parse(d->parser, buf, len, command == PARSE_FINAL_COMMAND); - - if(!res) - { - errcode = XML_GetErrorCode(d->parser); - if (errcode == XML_STATUS_SUSPENDED) - errstring = (char *)"DTDs are not allowed"; - else - errstring = (char *)XML_ErrorString(errcode); - - ei_x_encode_list_header(&event_buf, 1); - ei_x_encode_tuple_header(&event_buf, 2); - ei_x_encode_long(&event_buf, XML_ERROR); - ei_x_encode_tuple_header(&event_buf, 2); - ei_x_encode_long(&event_buf, errcode); - ei_x_encode_binary(&event_buf, errstring, strlen(errstring)); - } - - ei_x_encode_empty_list(&event_buf); - - size = event_buf.index; - - b = driver_alloc_binary(size); - memcpy(b->orig_bytes, event_buf.buff, size); - - ei_x_free(&event_buf); - ei_x_free(&xmlns_buf); - - *rbuf = (char *)b; - return size; - default: - return 0; - } -} - -ErlDrvEntry expat_driver_entry = { - NULL, /* F_PTR init, N/A */ - expat_erl_start, /* L_PTR start, called when port is opened */ - expat_erl_stop, /* F_PTR stop, called when port is closed */ - NULL, /* F_PTR output, called when erlang has sent */ - NULL, /* F_PTR ready_input, called when input descriptor ready */ - NULL, /* F_PTR ready_output, called when output descriptor ready */ - "expat_erl", /* char *driver_name, the argument to open_port */ - NULL, /* F_PTR finish, called when unloaded */ - NULL, /* handle */ - expat_erl_control, /* F_PTR control, port_command callback */ - NULL, /* F_PTR timeout, reserved */ - NULL, /* F_PTR outputv, reserved */ - /* Added in Erlang/OTP R15B: */ - NULL, /* ready_async */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, /* extended_marker */ - ERL_DRV_EXTENDED_MAJOR_VERSION, /* major_version */ - ERL_DRV_EXTENDED_MINOR_VERSION, /* minor_version */ - 0, /* driver_flags */ - NULL, /* handle2 */ - NULL, /* process_exit */ - NULL /* stop_select */ -}; - -DRIVER_INIT(expat_erl) /* must match name in driver_entry */ -{ - ms.malloc_fcn = driver_alloc; - ms.realloc_fcn = driver_realloc; - ms.free_fcn = driver_free; - return &expat_driver_entry; -} - - diff -Nru erlang-p1-xml-0.2015.04.15/c_src/xml.c erlang-p1-xml-1.1.2/c_src/xml.c --- erlang-p1-xml-0.2015.04.15/c_src/xml.c 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/c_src/xml.c 2016-01-23 17:21:53.000000000 +0000 @@ -1,20 +1,17 @@ /* - * ejabberd, Copyright (C) 2002-2015 ProcessOne + * Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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. + * http://www.apache.org/licenses/LICENSE-2.0 * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * */ @@ -75,7 +72,7 @@ }; } -inline void resize_buf(ErlNifEnv* env, struct buf *rbuf, int len_to_add) +static void resize_buf(ErlNifEnv* env, struct buf *rbuf, int len_to_add) { int new_len = rbuf->len + len_to_add; @@ -128,6 +125,40 @@ }; } +static void attr_encode(ErlNifEnv* env, struct buf *rbuf, unsigned char *data, int len) +{ + int i; + + for (i = 0; i < len; i++) { + switch (data[i]) { + case '&': + buf_add_str(env, rbuf, "&", 5); + break; + case '<': + buf_add_str(env, rbuf, "<", 4); + break; + case '"': + buf_add_str(env, rbuf, """, 6); + break; + case '\'': + buf_add_str(env, rbuf, "'", 6); + break; + case '\t': + buf_add_str(env, rbuf, " ", 5); + break; + case '\n': + buf_add_str(env, rbuf, " ", 5); + break; + case '\r': + buf_add_str(env, rbuf, " ", 5); + break; + default: + buf_add_char(env, rbuf, data[i]); + break; + }; + }; +} + static int make_elements(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM els) { ERL_NIF_TERM head, tail; @@ -160,7 +191,7 @@ buf_add_char(env, rbuf, ' '); buf_add_str(env, rbuf, (char *)name.data, name.size); buf_add_str(env, rbuf, "='", 2); - xml_encode(env, rbuf, data.data, data.size); + attr_encode(env, rbuf, data.data, data.size); buf_add_char(env, rbuf, '\''); attrs = tail; } else { @@ -253,14 +284,6 @@ return enif_make_badarg(env); } -#ifdef SSL40 -static ERL_NIF_TERM element_to_string(ErlNifEnv* env, int argc, - const ERL_NIF_TERM argv[]) -{ - return element_to(env, argc, argv, 1); -} -#endif - static ERL_NIF_TERM element_to_binary(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { @@ -269,12 +292,6 @@ static ErlNifFunc nif_funcs[] = { - /* Stupid Erlang bug with enif_make_string() is fixed - in R14A only (OTP-8685), so we can't use - element_to_string in Erlang < R14A.*/ -#ifdef SSL40 - {"element_to_string", 1, element_to_string}, -#endif {"element_to_binary", 1, element_to_binary} }; diff -Nru erlang-p1-xml-0.2015.04.15/c_src/xml_stream.c erlang-p1-xml-1.1.2/c_src/xml_stream.c --- erlang-p1-xml-0.2015.04.15/c_src/xml_stream.c 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/c_src/xml_stream.c 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,946 @@ +/* + * Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#define PARSING_NOT_RESUMABLE XML_FALSE + +#define ASSERT(x) if (!(x)) return 0 +#define PARSER_ASSERT(X, E) do { if (!(X)) { state->error = (E); XML_StopParser(state->parser, PARSING_NOT_RESUMABLE); return; } } while(0) +#define PARSER_MEM_ASSERT(x) PARSER_ASSERT((x), "enomem") + +typedef struct children_list_t { + union { + ERL_NIF_TERM term; + ErlNifBinary cdata; + }; + struct children_list_t *next; + char is_cdata; +} children_list_t; + +typedef struct attrs_list_t { + ErlNifBinary name; + ErlNifBinary value; + struct attrs_list_t *next; +} attrs_list_t; + +typedef struct xmlel_stack_t { + ERL_NIF_TERM name; + ERL_NIF_TERM attrs; + children_list_t *children; + struct xmlel_stack_t *next; + char *namespace; + int redefined_top_prefix; +} xmlel_stack_t; + + +typedef struct { + ErlNifEnv *env; + ErlNifEnv *send_env; + ErlNifPid *pid; + size_t depth; + size_t size; + size_t max_size; + XML_Parser parser; + xmlel_stack_t *elements_stack; + attrs_list_t *xmlns_attrs; + attrs_list_t *top_xmlns_attrs; + const char *error; + int normalize_ns; +} state_t; + +typedef enum xmlns_op { + OP_ERROR = 0, + OP_REMOVE_PREFIX, + OP_REMOVE_XMLNS, + OP_REPLACE_XMLNS, + OP_NOP +} xmlns_op; + +static XML_Memory_Handling_Suite ms = { + .malloc_fcn = enif_alloc, + .realloc_fcn = enif_realloc, + .free_fcn = enif_free +}; + +static ErlNifResourceType *parser_state_t = NULL; + +#define FAKE_BIN(STR) { sizeof(STR)-1, (unsigned char*)STR } + +static attrs_list_t stream_stream_ns_attr = { + FAKE_BIN("stream:stream"), + FAKE_BIN("http://etherx.jabber.org/streams") +}; + +static char *jabber_client_ns = "jabber:client"; + +static int same_str_buf(const char *str, const char *buf, size_t buf_len) +{ + if (strlen(str) != buf_len) + return 0; + return memcmp(str, buf, buf_len) == 0; +} + +static char *dup_buf(const char *buf, size_t buf_len) +{ + char *res = enif_alloc(buf_len+1); + if (!res) + return NULL; + + memcpy(res, buf, buf_len); + res[buf_len] = '\0'; + + return res; +} + +static char *dup_str(const char *str) +{ + return dup_buf(str, strlen(str)); +} + +static int dup_to_bin(ErlNifBinary *bin, const char *buf, size_t buf_len) +{ + if (!enif_alloc_binary(buf_len, bin)) + return 0; + + memcpy(bin->data, buf, buf_len); + + return 1; +} + +static ERL_NIF_TERM dup_to_term(ErlNifEnv *env, const char *buf, size_t buf_len) +{ + ERL_NIF_TERM term; + + unsigned char *str = enif_make_new_binary(env, buf_len, &term); + memcpy(str, buf, buf_len); + + return term; +} + +static int has_prefix_ns_from_list(attrs_list_t*list, const char *pfx, size_t pfx_len, + const char *ns, size_t ns_len) +{ + while (pfx_len && list) { + if ((pfx == NULL || + (list->name.size == pfx_len && memcmp(list->name.data, pfx, pfx_len) == 0)) && + (ns == NULL || + (list->value.size == ns_len && memcmp(list->value.data, ns, ns_len) == 0))) + { + return 1; + } + list = list->next; + } + return 0; +} + +static int has_prefix_ns_from_top(state_t *state, const char *pfx, size_t pfx_len, + const char *ns, size_t ns_len) +{ + if (state->elements_stack->redefined_top_prefix || !pfx_len) + return 0; + + return has_prefix_ns_from_list(state->top_xmlns_attrs, pfx, pfx_len, ns, ns_len); +} + +static xmlns_op encode_name(state_t *state, const char *xml_name, ErlNifBinary *buf, + char **ns_str, char **pfx_str, int top_element) +{ + const char *parts[3]; + int i, idx = 0; + + for (i = 0; ; i++) { + if (!xml_name[i] || xml_name[i] == '\n') { + parts[idx++] = xml_name + i; + if (!xml_name[i]) + break; + } + if (idx >= 3) + return OP_ERROR; + } + const char *ns = NULL, *name = NULL, *prefix = NULL; + size_t ns_len = 0, name_len = 0, prefix_len = 0; + + if (idx == 1) { + name = xml_name; + name_len = parts[0] - xml_name; + } else { + ns = xml_name; + ns_len = parts[0] - xml_name; + name = parts[0] + 1; + name_len = parts[1] - parts[0] - 1; + if (idx == 3) { + prefix = parts[1] + 1; + prefix_len = parts[2] - parts[1] - 1; + } + } + + int with_prefix = prefix_len && (top_element || !ns_str); + xmlns_op res = OP_REPLACE_XMLNS; + + if (state->normalize_ns && !top_element) { + if (ns_str) { + if (!state->elements_stack->redefined_top_prefix && prefix_len && + has_prefix_ns_from_top(state, prefix, prefix_len, ns, ns_len)) + { + res = OP_REMOVE_PREFIX; + with_prefix = 1; + } else if (same_str_buf(state->elements_stack->namespace, ns, ns_len)) { + res = OP_REMOVE_XMLNS; + with_prefix = 0; + } + } + } else + res = OP_NOP; + + if (with_prefix) { + ASSERT(enif_alloc_binary(name_len + prefix_len + 1, buf)); + memcpy(buf->data, prefix, prefix_len); + buf->data[prefix_len] = ':'; + memcpy(buf->data + prefix_len + 1, name, name_len); + } else { + ASSERT(dup_to_bin(buf, name, name_len)); + } + + if (ns_str) { + if (top_element && prefix_len > 0) + *ns_str = NULL; + else { + *ns_str = top_element ? dup_buf(ns, ns_len) : + res == OP_REMOVE_PREFIX ? + state->elements_stack->namespace : + dup_buf(ns, ns_len); + + if (!*ns_str) { + enif_release_binary(buf); + return OP_ERROR; + } + } + if (pfx_str) { + if (res == OP_REMOVE_PREFIX) { + *pfx_str = dup_buf(prefix, prefix_len); + if (!*pfx_str) { + enif_release_binary(buf); + if (ns_str && *ns_str) + enif_free(*ns_str); + return OP_ERROR; + } + } else + *pfx_str = NULL; + } + } + + return res; +} + +static ERL_NIF_TERM str2bin(ErlNifEnv *env, const char *s) +{ + return dup_to_term(env, s, strlen(s)); +} + +static void send_event(state_t *state, ERL_NIF_TERM el) +{ + state->size = 0; + enif_send(state->env, state->pid, state->send_env, + enif_make_tuple2(state->send_env, + enif_make_atom(state->send_env, "$gen_event"), + el)); + enif_clear_env(state->send_env); +} + +static void send_all_state_event(state_t *state, ERL_NIF_TERM el) +{ + state->size = 0; + enif_send(state->env, state->pid, state->send_env, + enif_make_tuple2(state->send_env, + enif_make_atom(state->send_env, "$gen_all_state_event"), + el)); + enif_clear_env(state->send_env); +} + +void erlXML_StartElementHandler(state_t *state, + const XML_Char *name, + const XML_Char **atts) +{ + int i = 0; + ErlNifEnv* env = state->send_env; + ERL_NIF_TERM attrs_term = enif_make_list(env, 0); + ErlNifBinary name_bin; + + if (state->error) + return; + + state->depth++; + + while (atts[i]) + i += 2; + + i -= 2; + + while (i >= 0) { + ErlNifBinary attr_name; + ERL_NIF_TERM val; + unsigned char *val_str; + + PARSER_MEM_ASSERT(encode_name(state, atts[i], &attr_name, NULL, NULL, 0)); + + size_t val_len = strlen(atts[i+1]); + val_str = enif_make_new_binary(env, val_len, &val); + PARSER_MEM_ASSERT(val_str); + memcpy(val_str, atts[i+1], val_len); + + ERL_NIF_TERM el = enif_make_tuple2(env, enif_make_binary(env, &attr_name), val); + attrs_term = enif_make_list_cell(env, el, attrs_term); + i -= 2; + } + + char *ns = NULL, *pfx = NULL; + int redefined_top_prefix = state->depth > 1 ? state->elements_stack->redefined_top_prefix : 0; + int xmlns_op; + + if (state->normalize_ns) + xmlns_op = encode_name(state, name, &name_bin, &ns, &pfx, state->depth == 1); + else + xmlns_op = encode_name(state, name, &name_bin, NULL, NULL, state->depth == 1); + + PARSER_MEM_ASSERT(xmlns_op); + + if (!state->normalize_ns) + xmlns_op = OP_NOP; + + int non_xmpp_ns = -1; + int had_stream_stream = 0; + + while (state->xmlns_attrs) { + ERL_NIF_TERM tuple = 0; + attrs_list_t *c = state->xmlns_attrs; + ErlNifBinary new_prefix, new_ns; + + state->xmlns_attrs = c->next; + + if (state->depth == 1 && state->normalize_ns && c->name.size > 6) { + if (non_xmpp_ns != 1 || !has_prefix_ns_from_list(&stream_stream_ns_attr, + (char*)c->name.data+6, c->name.size-6, + (char*)c->value.data, c->value.size)) + { + if (had_stream_stream) { + PARSER_MEM_ASSERT(dup_to_bin(&new_prefix, (char*)stream_stream_ns_attr.name.data, + stream_stream_ns_attr.name.size)); + PARSER_MEM_ASSERT(dup_to_bin(&new_ns, (char*)stream_stream_ns_attr.value.data, + stream_stream_ns_attr.value.size)); + c->name = new_prefix; + c->value = new_ns; + c->next = state->top_xmlns_attrs; + state->top_xmlns_attrs = c; + had_stream_stream = 0; + } + non_xmpp_ns = 1; + PARSER_MEM_ASSERT(dup_to_bin(&new_prefix, (char*)c->name.data+6, c->name.size-6)); + PARSER_MEM_ASSERT(dup_to_bin(&new_ns, (char*)c->value.data, c->value.size)); + } else { + had_stream_stream = 1; + non_xmpp_ns = 0; + } + } + + if (c->name.size == 5) { // xmlns + if (xmlns_op == OP_REMOVE_XMLNS) { + enif_release_binary(&c->name); + enif_release_binary(&c->value); + enif_free(c); + continue; + } else if (xmlns_op == OP_REPLACE_XMLNS) { + enif_release_binary(&c->value); + tuple = enif_make_tuple2(env, enif_make_binary(env, &c->name), + dup_to_term(env, ns, strlen(ns))); + xmlns_op = OP_NOP; + } + if (!ns && state->normalize_ns) + PARSER_MEM_ASSERT(ns = dup_buf((char *) c->value.data, c->value.size)); + } else if (xmlns_op == OP_REMOVE_PREFIX && + same_str_buf(pfx, (char*)c->name.data + 6, c->name.size - 6)) { + enif_release_binary(&c->name); + enif_release_binary(&c->value); + enif_free(c); + continue; + } else if (!redefined_top_prefix && state->depth > 1 && c->name.size > 6 && + has_prefix_ns_from_top(state, (char*)c->name.data + 6, c->name.size - 6, NULL, 0)) { + redefined_top_prefix = 1; + } + + if (!tuple) { + tuple = enif_make_tuple2(env, enif_make_binary(env, &c->name), + enif_make_binary(env, &c->value)); + } + attrs_term = enif_make_list_cell(env, tuple, attrs_term); + + if (non_xmpp_ns && state->depth == 1 && state->normalize_ns && c->name.size > 6) { + c->name = new_prefix; + c->value = new_ns; + c->next = state->top_xmlns_attrs; + state->top_xmlns_attrs = c; + } else + enif_free(c); + } + + if (!non_xmpp_ns && state->depth == 1 && state->normalize_ns) { + state->top_xmlns_attrs = &stream_stream_ns_attr; + } + + if (xmlns_op == OP_REPLACE_XMLNS) { + ERL_NIF_TERM tuple = enif_make_tuple2(env, dup_to_term(env, "xmlns", 5), + dup_to_term(env, ns, strlen(ns))); + attrs_term = enif_make_list_cell(env, tuple, attrs_term); + } else if (xmlns_op == OP_REMOVE_PREFIX) { + enif_free(pfx); + } + + if (!ns && state->normalize_ns) + PARSER_MEM_ASSERT(ns = dup_buf("", 0)); + + xmlel_stack_t *xmlel = enif_alloc(sizeof(xmlel_stack_t)); + PARSER_MEM_ASSERT(xmlel); + + xmlel->next = state->elements_stack; + xmlel->attrs = attrs_term; + xmlel->namespace = ns; + xmlel->children = NULL; + xmlel->redefined_top_prefix = redefined_top_prefix; + + state->elements_stack = xmlel; + + if (state->pid && state->depth == 1) { + send_event(state, + enif_make_tuple3(env, + enif_make_atom(env, "xmlstreamstart"), + enif_make_binary(env, &name_bin), + attrs_term)); + } else { + xmlel->name = enif_make_binary(env, &name_bin); + } +} + +void erlXML_CharacterDataHandler(state_t *state, const XML_Char *s, int len) +{ + ErlNifEnv *env = state->send_env; + + if (state->error) + return; + + if (state->depth == 0) + return; + + if (state->pid && state->depth == 1) { + ErlNifBinary cdata; + PARSER_MEM_ASSERT(enif_alloc_binary(len, &cdata)); + memcpy(cdata.data, s, len); + send_all_state_event(state, + enif_make_tuple2(env, + enif_make_atom(env, "xmlstreamcdata"), + enif_make_binary(env, &cdata))); + return; + } + + children_list_t *children = state->elements_stack->children; + + if (children && children->is_cdata) { + int old_size = children->cdata.size; + PARSER_MEM_ASSERT(enif_realloc_binary(&children->cdata, old_size + len)); + memcpy(children->cdata.data+old_size, s, len); + } else { + children = enif_alloc(sizeof(children_list_t)); + PARSER_MEM_ASSERT(children); + if (!enif_alloc_binary(len, &children->cdata)) { + enif_free(children); + PARSER_MEM_ASSERT(0); + } + children->is_cdata = 1; + memcpy(children->cdata.data, s, len); + children->next = state->elements_stack->children; + state->elements_stack->children = children; + } + + return; +} + +ERL_NIF_TERM +make_xmlel_children_list(ErlNifEnv *env, children_list_t *list) { + ERL_NIF_TERM children_list = enif_make_list(env, 0); + + while (list) { + if (list->is_cdata) + children_list = enif_make_list_cell(env, + enif_make_tuple2(env, + enif_make_atom(env, "xmlcdata"), + enif_make_binary(env, &list->cdata)), + children_list); + else + children_list = enif_make_list_cell(env, list->term, children_list); + + children_list_t *old_head = list; + list = list->next; + + enif_free(old_head); + } + + return children_list; +} + +void erlXML_EndElementHandler(state_t *state, const XML_Char *name) +{ + ErlNifEnv *env = state->send_env; + + if (state->error) + return; + + state->depth--; + + if (state->pid && state->depth == 0) { + ErlNifBinary name_bin; + + PARSER_MEM_ASSERT(encode_name(state, name, &name_bin, NULL, NULL, 0)); + + send_event(state, + enif_make_tuple2(env, + enif_make_atom(env, "xmlstreamend"), + enif_make_binary(env, &name_bin))); + return; + } + + ERL_NIF_TERM xmlel_term; + + xmlel_term = enif_make_tuple4(env, enif_make_atom(env, "xmlel"), + state->elements_stack->name, + state->elements_stack->attrs, + make_xmlel_children_list(env, state->elements_stack->children)); + + if (!state->pid || state->depth > 1) { + children_list_t *el; + xmlel_stack_t *cur_el = state->elements_stack; + + PARSER_MEM_ASSERT(el = enif_alloc(sizeof(children_list_t))); + + state->elements_stack = state->elements_stack->next; + + el->is_cdata = 0; + el->term = xmlel_term; + el->next = state->elements_stack->children; + state->elements_stack->children = el; + if (cur_el->namespace != state->elements_stack->namespace) + enif_free(cur_el->namespace); + enif_free(cur_el); + } else { + xmlel_stack_t *cur_el = state->elements_stack; + state->elements_stack = cur_el->next; + if (!state->elements_stack || cur_el->namespace != state->elements_stack->namespace) + enif_free(cur_el->namespace); + enif_free(cur_el); + send_event(state, + enif_make_tuple2(state->send_env, + enif_make_atom(state->send_env, "xmlstreamelement"), + xmlel_term)); + } + + return; +} + +void erlXML_StartNamespaceDeclHandler(state_t *state, + const XML_Char *prefix, + const XML_Char *uri) +{ + /* From the expat documentation: + "For a default namespace declaration (xmlns='...'), + the prefix will be null ... + ... The URI will be null for the case where + the default namespace is being unset." + + FIXME: I'm not quite sure what all that means */ + if (uri == NULL) + return; + + if (state->error) + return; + + attrs_list_t *c = enif_alloc(sizeof(attrs_list_t)); + PARSER_MEM_ASSERT(c); + + if (prefix) { + size_t len = strlen(prefix); + + if (!enif_alloc_binary(len + 6, &c->name)) { + enif_free(c); + PARSER_MEM_ASSERT(0); + } + memcpy(c->name.data, "xmlns:", 6); + memcpy(c->name.data + 6, prefix, len); + } else { + if (!enif_alloc_binary(5, &c->name)) { + enif_free(c); + PARSER_MEM_ASSERT(0); + } + memcpy(c->name.data, "xmlns", 5); + }; + + size_t len = strlen(uri); + if (!enif_alloc_binary(len, &c->value)) { + enif_release_binary(&c->name); + enif_free(c); + PARSER_MEM_ASSERT(0); + } + + memcpy(c->value.data, uri, len); + + c->next = state->xmlns_attrs; + state->xmlns_attrs = c; + + return; +} + +/* + * Prevent entity expansion attacks (CVE-2013-1664) by refusing + * to process any XML that contains a DTD. + */ +void erlXML_StartDoctypeDeclHandler(state_t *state, + const XML_Char *doctypeName, + const XML_Char *doctypeSysid, + const XML_Char *doctypePubid, + int hasInternalSubset) +{ + XML_StopParser(state->parser, PARSING_NOT_RESUMABLE); + return; +} + +/* + * Prevent entity expansion attacks (CVE-2013-1664) by having an explicit + * default handler. According to the documentation, + * + * "Setting the handler with this call has the side effect of turning off + * expansion of references to internally defined general entities. Instead + * these references are passed to the default handler." + */ +void erlXML_DefaultHandler(state_t *state, const XML_Char *s, int len) +{ + return; +} + +static void free_parser_allocated_structs(state_t *state) { + while (state->xmlns_attrs) { + attrs_list_t *c = state->xmlns_attrs; + state->xmlns_attrs = c->next; + + enif_release_binary(&c->name); + enif_release_binary(&c->value); + enif_free(c); + } + while (state->elements_stack) { + xmlel_stack_t *c = state->elements_stack; + while (c->children) { + children_list_t *cc = c->children; + if (cc->is_cdata) + enif_release_binary(&cc->cdata); + c->children = cc->next; + enif_free(cc); + } + if (!c->next || c->namespace != c->next->namespace) + enif_free(c->namespace); + state->elements_stack = c->next; + enif_free(c); + } + if (state->top_xmlns_attrs != &stream_stream_ns_attr) + while (state->top_xmlns_attrs) { + attrs_list_t *c = state->top_xmlns_attrs; + state->top_xmlns_attrs = c->next; + enif_release_binary(&c->name); + enif_release_binary(&c->value); + enif_free(c); + } +} + +static void destroy_parser_state(ErlNifEnv *env, void *data) +{ + state_t *state = (state_t *) data; + if (state) { + if (state->parser) XML_ParserFree(state->parser); + if (state->pid) enif_free(state->pid); + if (state->send_env) enif_free_env(state->send_env); + + free_parser_allocated_structs(state); + + memset(state, 0, sizeof(state_t)); + } +} + +static void setup_parser(state_t *state) +{ + XML_SetUserData(state->parser, state); + XML_SetStartElementHandler(state->parser, + (XML_StartElementHandler) erlXML_StartElementHandler); + XML_SetEndElementHandler(state->parser, + (XML_EndElementHandler) erlXML_EndElementHandler); + XML_SetCharacterDataHandler(state->parser, + (XML_CharacterDataHandler) erlXML_CharacterDataHandler); + XML_SetStartNamespaceDeclHandler(state->parser, + (XML_StartNamespaceDeclHandler) + erlXML_StartNamespaceDeclHandler); + XML_SetStartDoctypeDeclHandler(state->parser, + (XML_StartDoctypeDeclHandler) + erlXML_StartDoctypeDeclHandler); + XML_SetReturnNSTriplet(state->parser, 1); + XML_SetDefaultHandler(state->parser, (XML_DefaultHandler) erlXML_DefaultHandler); +} + +static state_t *init_parser_state(ErlNifPid *pid) +{ + state_t *state = enif_alloc_resource(parser_state_t, sizeof(state_t)); + ASSERT(state); + memset(state, 0, sizeof(state_t)); + if (pid) { + state->send_env = enif_alloc_env(); + ASSERT(state->send_env); + state->pid = enif_alloc(sizeof(ErlNifPid)); + ASSERT(state->pid); + memcpy(state->pid, pid, sizeof(ErlNifPid)); + } + state->parser = XML_ParserCreate_MM("UTF-8", &ms, "\n"); + setup_parser(state); + return state; +} + +static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info) +{ + ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER; + parser_state_t = enif_open_resource_type(env, NULL, "parser_state_t", + destroy_parser_state, + flags, NULL); + + return 0; +} + +static ERL_NIF_TERM make_parse_error(ErlNifEnv *env, XML_Parser parser) +{ + enum XML_Error errcode = XML_GetErrorCode(parser); + const char *errstring; + + if (errcode == XML_ERROR_EXTERNAL_ENTITY_HANDLING) + errstring = "DTDs are not allowed"; + else + errstring = XML_ErrorString(errcode); + + return enif_make_tuple2(env, enif_make_uint(env, errcode), + str2bin(env, errstring)); +} + +static ERL_NIF_TERM reset_nif(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) +{ + state_t *state = NULL; + + if (argc != 1) + return enif_make_badarg(env); + + if (!enif_get_resource(env, argv[0], parser_state_t, (void *) &state)) + return enif_make_badarg(env); + + ASSERT(XML_ParserReset(state->parser, "UTF-8")); + setup_parser(state); + + free_parser_allocated_structs(state); + + enif_clear_env(state->send_env); + + state->size = 0; + state->depth = 0; + state->error = NULL; + + return argv[0]; +} + +static ERL_NIF_TERM parse_element_nif(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM el; + ErlNifBinary bin; + + if (argc != 1) + return enif_make_badarg(env); + + if (!enif_inspect_binary(env, argv[0], &bin)) + return enif_make_badarg(env); + + state_t *state = init_parser_state(NULL); + if (!state) + return enif_make_badarg(env); + + state->send_env = env; + + xmlel_stack_t *xmlel = enif_alloc(sizeof(xmlel_stack_t)); + if (!xmlel) { + enif_release_resource(state); + return enif_make_badarg(env); + } + + memset(xmlel, 0, sizeof(xmlel_stack_t)); + + xmlel->next = state->elements_stack; + xmlel->children = NULL; + + state->elements_stack = xmlel; + + int res = XML_Parse(state->parser, (char *)bin.data, bin.size, 1); + if (res == XML_STATUS_OK && state->elements_stack->children && + !state->elements_stack->children->is_cdata) + el = state->elements_stack->children->term; + else if (state->error) + el = enif_make_tuple2(env, enif_make_atom(env, "error"), + enif_make_atom(env, state->error)); + else + el = enif_make_tuple2(env, enif_make_atom(env, "error"), + make_parse_error(env, state->parser)); + + state->send_env = NULL; + + enif_release_resource(state); + + return el; +} + +static ERL_NIF_TERM parse_nif(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) +{ + state_t *state = NULL; + ErlNifBinary bin; + + if (argc != 2) + return enif_make_badarg(env); + + if (!enif_get_resource(env, argv[0], parser_state_t, (void *) &state)) + return enif_make_badarg(env); + + if (!enif_inspect_binary(env, argv[1], &bin)) + return enif_make_badarg(env); + + if (!state->parser || !state->pid || !state->send_env) + return enif_make_badarg(env); + + state->size += bin.size; + state->env = env; + + if (state->size >= state->max_size) { + send_event(state, + enif_make_tuple2(state->send_env, + enif_make_atom(state->send_env, "xmlstreamerror"), + str2bin(state->send_env, "XML stanza is too big"))); + } else { + int res = XML_Parse(state->parser, (char *)bin.data, bin.size, 0); + if (!res) + send_event(state, + enif_make_tuple2(state->send_env, + enif_make_atom(state->send_env, "xmlstreamerror"), + state->error ? + str2bin(state->send_env, state->error) : + make_parse_error(state->send_env, state->parser))); + } + + return argv[0]; +} + +static ERL_NIF_TERM change_callback_pid_nif(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) +{ + state_t *state = NULL; + ErlNifPid pid; + + if (argc != 2) + return enif_make_badarg(env); + + if (!enif_get_resource(env, argv[0], parser_state_t, (void *) &state)) + return enif_make_badarg(env); + + if (!state->parser || !state->pid || !state->send_env) + return enif_make_badarg(env); + + if (!enif_get_local_pid(env, argv[1], &pid)) + return enif_make_badarg(env); + + memcpy(state->pid, &pid, sizeof(ErlNifPid)); + + return enif_make_resource(env, state); +} + +static ERL_NIF_TERM close_nif(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) +{ + state_t *state = NULL; + + if (argc != 1) + return enif_make_badarg(env); + + if (!enif_get_resource(env, argv[0], parser_state_t, (void *) &state)) + return enif_make_badarg(env); + + if (!state->parser || !state->pid) + return enif_make_badarg(env); + + destroy_parser_state(env, state); + + return enif_make_atom(env, "true"); +} + +static ERL_NIF_TERM new_nif(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) +{ + if (argc != 2) + return enif_make_badarg(env); + + ErlNifPid pid; + if (!enif_get_local_pid(env, argv[0], &pid)) + return enif_make_badarg(env); + + state_t *state = init_parser_state(&pid); + if (!state) + return enif_make_badarg(env); + + state->normalize_ns = 1; + + ERL_NIF_TERM result = enif_make_resource(env, state); + enif_release_resource(state); + + ErlNifUInt64 max_size; + if (enif_get_uint64(env, argv[1], &max_size)) + state->max_size = (size_t) max_size; + else if (!enif_compare(argv[1], enif_make_atom(env, "infinity"))) + state->max_size = (size_t) - 1; + else + return enif_make_badarg(env); + + return result; +} + +static ErlNifFunc nif_funcs[] = + { + {"new", 2, new_nif}, + {"parse", 2, parse_nif}, + {"parse_element", 1, parse_element_nif}, + {"reset", 1, reset_nif}, + {"close", 1, close_nif}, + {"change_callback_pid", 2, change_callback_pid_nif} + }; + +ERL_NIF_INIT(xml_stream, nif_funcs, load, NULL, NULL, NULL) diff -Nru erlang-p1-xml-0.2015.04.15/debian/changelog erlang-p1-xml-1.1.2/debian/changelog --- erlang-p1-xml-0.2015.04.15/debian/changelog 2016-03-12 06:38:58.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/changelog 2016-03-18 03:46:15.000000000 +0000 @@ -1,8 +1,59 @@ -erlang-p1-xml (0.2015.04.15-1~14.04.0) trusty; urgency=medium +erlang-p1-xml (1.1.2-1~14.04.0) trusty; urgency=medium * backport to trusty - -- Richard Hansen Sun, 06 Mar 2016 05:37:28 -0500 + -- Richard Hansen Thu, 17 Mar 2016 23:46:02 -0400 + +erlang-p1-xml (1.1.2-1) unstable; urgency=medium + + * Imported Upstream version 1.1.2 + * Updated Standards-Version: 3.9.7 (no changes needed) + * Updated Vcs-* fields in debian/control + + -- Philipp Huebner Wed, 03 Feb 2016 10:03:50 +0100 + +erlang-p1-xml (1.1.1-1) unstable; urgency=medium + + * Imported Upstream version 1.1.1 + * Updated debian/copyright + * Updated debian/watch + + -- Philipp Huebner Sat, 16 Jan 2016 12:32:54 +0100 + +erlang-p1-xml (0.2015.10.23-1) unstable; urgency=medium + + * Imported Upstream version 0.2015.10.23 + + -- Philipp Huebner Sat, 31 Oct 2015 16:49:31 +0100 + +erlang-p1-xml (0.2015.10.05-2) unstable; urgency=medium + + * Fix FTBFS on arm* and mips* + + -- Philipp Huebner Thu, 08 Oct 2015 13:57:27 +0200 + +erlang-p1-xml (0.2015.10.05-1) unstable; urgency=medium + + * Imported Upstream version 0.2015.10.05 + * Re-enabled eunit + + -- Philipp Huebner Mon, 05 Oct 2015 11:04:35 +0200 + +erlang-p1-xml (0.2015.10.01-1) unstable; urgency=medium + + * Imported Upstream version 0.2015.10.01 + * Disabled eunit because it's currently broken: + https://github.com/processone/xml/issues/16 + + -- Philipp Huebner Mon, 05 Oct 2015 09:37:52 +0200 + +erlang-p1-xml (0.2015.07.24-1) unstable; urgency=medium + + * Imported Upstream version 0.2015.07.24 + * Enabled eunit + * Fixed debian/copyright (make lintian happy) + + -- Philipp Huebner Mon, 17 Aug 2015 17:33:00 +0200 erlang-p1-xml (0.2015.04.15-1) unstable; urgency=medium diff -Nru erlang-p1-xml-0.2015.04.15/debian/control erlang-p1-xml-1.1.2/debian/control --- erlang-p1-xml-0.2015.04.15/debian/control 2016-03-12 06:38:58.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/control 2016-02-04 14:10:20.000000000 +0000 @@ -1,17 +1,17 @@ Source: erlang-p1-xml Priority: optional Maintainer: Philipp Huebner -Build-Depends: debhelper (>= 9), dh-rebar, erlang-syntax-tools, libexpat1-dev -Standards-Version: 3.9.6 +Build-Depends: debhelper (>= 9), dh-rebar, erlang-eunit, erlang-p1-utils (>= 1.0.3), erlang-syntax-tools, libexpat1-dev +Standards-Version: 3.9.7 Section: libs Homepage: https://github.com/processone/xml -Vcs-Git: git://anonscm.debian.org/users/debalance/erlang-p1-xml.git -Vcs-Browser: https://anonscm.debian.org/cgit/users/debalance/erlang-p1-xml.git +Vcs-Git: https://anonscm.debian.org/git/users/debalance/erlang-p1-xml.git +Vcs-Browser: https://anonscm.debian.org/git/users/debalance/erlang-p1-xml.git Package: erlang-p1-xml Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, erlang-base | ${erlang-abi:Depends}, - ${erlang:Depends} + ${erlang:Depends}, erlang-p1-utils (>= 1.0.3) Description: XML utilities for Erlang This library was written for ejabberd which still uses it. It was split off into it's own project to follow diff -Nru erlang-p1-xml-0.2015.04.15/debian/copyright erlang-p1-xml-1.1.2/debian/copyright --- erlang-p1-xml-0.2015.04.15/debian/copyright 2016-03-12 06:38:58.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/copyright 2016-02-04 14:10:20.000000000 +0000 @@ -3,9 +3,15 @@ Source: https://github.com/processone/xml Files: * -Copyright: 2002-2015 ProcessOne - 2002-2015 Alexey Shchepin - 2009-2015 Evgeniy Khramtsov +Copyright: 2002-2016 ProcessOne + 2002-2016 Alexey Shchepin + 2009-2016 Evgeniy Khramtsov +License: GPL-2+ + +Files: debian/* +Copyright: 2014-2016 Philipp Huebner +License: GPL-2+ + License: GPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -31,22 +37,3 @@ License: FSF This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. - -Files: debian/* -Copyright: 2014-2015 Philipp Huebner -License: GPL-2+ - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - . - This package 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 - . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". diff -Nru erlang-p1-xml-0.2015.04.15/debian/dh-rebar.conf erlang-p1-xml-1.1.2/debian/dh-rebar.conf --- erlang-p1-xml-0.2015.04.15/debian/dh-rebar.conf 2016-03-12 06:38:58.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/dh-rebar.conf 2016-02-04 14:10:20.000000000 +0000 @@ -1 +1 @@ -EXEC_REBAR_COMMANDS=compile +EXEC_REBAR_COMMANDS=compile eunit diff -Nru erlang-p1-xml-0.2015.04.15/debian/docs erlang-p1-xml-1.1.2/debian/docs --- erlang-p1-xml-0.2015.04.15/debian/docs 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/docs 2016-02-04 14:10:20.000000000 +0000 @@ -0,0 +1 @@ +README.md diff -Nru erlang-p1-xml-0.2015.04.15/debian/erlang-p1-xml.lintian-overrides erlang-p1-xml-1.1.2/debian/erlang-p1-xml.lintian-overrides --- erlang-p1-xml-0.2015.04.15/debian/erlang-p1-xml.lintian-overrides 2016-03-12 06:38:58.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/erlang-p1-xml.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -# there are no potentially unfortified functions called by any routines, -# the package was correctly built with the default Debian compiler flags -# defined by dpkg-buildflags -erlang-p1-xml: hardening-no-fortify-functions usr/lib/erlang/lib/p1_xml-0.2015.04.15/priv/lib/expat_erl.so diff -Nru erlang-p1-xml-0.2015.04.15/debian/patches/remove-deps.diff erlang-p1-xml-1.1.2/debian/patches/remove-deps.diff --- erlang-p1-xml-0.2015.04.15/debian/patches/remove-deps.diff 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/patches/remove-deps.diff 2016-02-04 14:10:20.000000000 +0000 @@ -0,0 +1,17 @@ +Description: remove deps in rebar.config + Without this patch, rebar would download and compile the listed deps + at compile time. +Author: Philipp Huebner + +Index: erlang-p1-xml/rebar.config +=================================================================== +--- erlang-p1-xml.orig/rebar.config ++++ erlang-p1-xml/rebar.config +@@ -12,7 +12,6 @@ + {port_specs, [{"priv/lib/xml.so", ["c_src/xml.c"]}, + {"priv/lib/xml_stream.so", ["c_src/xml_stream.c"]}]}. + +-{deps, [{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.3"}}}]}. + + {clean_files, ["c_src/xml.gcda", "c_src/xml.gcno", "c_src/xml_stream.gcda", "c_src/xml_stream.gcno"]}. + diff -Nru erlang-p1-xml-0.2015.04.15/debian/patches/series erlang-p1-xml-1.1.2/debian/patches/series --- erlang-p1-xml-0.2015.04.15/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/patches/series 2016-02-04 14:10:20.000000000 +0000 @@ -0,0 +1 @@ +remove-deps.diff diff -Nru erlang-p1-xml-0.2015.04.15/debian/rules erlang-p1-xml-1.1.2/debian/rules --- erlang-p1-xml-0.2015.04.15/debian/rules 2016-03-12 06:38:58.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/rules 2016-02-04 14:10:20.000000000 +0000 @@ -28,6 +28,6 @@ override_dh_auto_clean: - rm -f config.log config.status - rm -rf priv + rm -f config.log config.status vars.config + rm -rf priv ebin .rebar dh_auto_clean diff -Nru erlang-p1-xml-0.2015.04.15/debian/watch erlang-p1-xml-1.1.2/debian/watch --- erlang-p1-xml-0.2015.04.15/debian/watch 2016-03-12 06:38:58.000000000 +0000 +++ erlang-p1-xml-1.1.2/debian/watch 2016-02-04 14:10:20.000000000 +0000 @@ -1 +1,3 @@ -# There are no upstream releases yet to be tracked +version=3 +opts="filenamemangle=s/(?:.*)?v?(\d[\d\.]*)\.tar\.gz/erlang-p1-xml_$1.tar.gz/" \ + https://github.com/processone/xml/tags (?:.*/)?v?(\d[\d\.]*)\.tar\.gz diff -Nru erlang-p1-xml-0.2015.04.15/include/xml_gen.hrl erlang-p1-xml-1.1.2/include/xml_gen.hrl --- erlang-p1-xml-0.2015.04.15/include/xml_gen.hrl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/include/xml_gen.hrl 2016-01-23 17:21:53.000000000 +0000 @@ -1,3 +1,26 @@ +%%%---------------------------------------------------------------------- +%%% File : xml_gen.hrl +%%% Author : Evgeniy Khramtsov +%%% Purpose : XML utils +%%% Created : 1 May 2013 by Evgeniy Khramtsov +%%% +%%% +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. +%%% +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. +%%% +%%%---------------------------------------------------------------------- + -record(attr, {name, label, required = false, diff -Nru erlang-p1-xml-0.2015.04.15/include/xml.hrl erlang-p1-xml-1.1.2/include/xml.hrl --- erlang-p1-xml-0.2015.04.15/include/xml.hrl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/include/xml.hrl 2016-01-23 17:21:53.000000000 +0000 @@ -1,11 +1,26 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeniy Khramtsov -%%% @copyright (C) 2013, Evgeniy Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 1 May 2013 by Evgeniy Khramtsov -%%%------------------------------------------------------------------- +%%%---------------------------------------------------------------------- +%%% File : xml.hrl +%%% Author : Evgeniy Khramtsov +%%% Purpose : XML utils +%%% Created : 1 May 2013 by Evgeniy Khramtsov +%%% +%%% +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. +%%% +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. +%%% +%%%---------------------------------------------------------------------- + -record(xmlel, { name = <<"">> :: binary(), diff -Nru erlang-p1-xml-0.2015.04.15/LICENSE.txt erlang-p1-xml-1.1.2/LICENSE.txt --- erlang-p1-xml-0.2015.04.15/LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/LICENSE.txt 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff -Nru erlang-p1-xml-0.2015.04.15/Makefile erlang-p1-xml-1.1.2/Makefile --- erlang-p1-xml-0.2015.04.15/Makefile 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/Makefile 2016-01-23 17:21:53.000000000 +0000 @@ -1,12 +1,19 @@ all: src src: - rebar compile + rebar get-deps compile xref clean: rebar clean -test: - rebar eunit +test: all + rebar -v skip_deps=true eunit -.PHONY: clean src test +# We assume Elixir and Quviq Quickcheck are installed +exunit: + MIX_EXS=test/elixir/mix.exs mix test + +check-syntax: + gcc -o nul -S ${CHK_SOURCES} + +.PHONY: clean src test all diff -Nru erlang-p1-xml-0.2015.04.15/README.md erlang-p1-xml-1.1.2/README.md --- erlang-p1-xml-0.2015.04.15/README.md 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/README.md 2016-01-23 17:21:53.000000000 +0000 @@ -1,54 +1,172 @@ -# xml +# Erlang and Elixir XML Parsing [![Build Status](https://travis-ci.org/processone/xml.svg?branch=master)](https://travis-ci.org/processone/xml) [![Coverage Status](https://coveralls.io/repos/processone/xml/badge.svg?branch=master&service=github)](https://coveralls.io/github/processone/xml?branch=master) -Fast Expat based Erlang XML parsing library, with a strong focus on XML stream parsing from network. +Fast Expat based Erlang XML parsing and manipulation library, with a +strong focus on XML stream parsing from network. -Note: This module obsolete and supercede exmpp. +It supports: -XML streaming parser example: +- Full XML structure parsing: Suitable for small but complete XML chunks. +- XML stream parsing: Suitable for large XML document, or infinite + network XML stream like XMPP. + +This module can parse files much faster than built-in module `xmerl`. +Depending on file complexity and size `xml_stream:parse_element/1` can +be 8-18 times faster than calling `xmerl_scan:string/2`. + +This application is now called [fast_xml](https://github.com/processone/fast_xml) +and was renamed after major optimisations to put emphasis on the fact it is damn +fast. Development is now being done in [fast_xml](https://github.com/processone/fast_xml) +repository. This repository is kept to avoid breaking code that depend on it. + +## Building + +Erlang XML parser can be build as follow: + + ./configure && make + +Erlang XML parser is a rebar-compatible OTP +application. Alternatively, you can build it with rebar: + + rebar compile + +## Dependencies + +Erlang XML parser depends on Expat XML parser. You need development +headers for Expat library to build it. + +You can use `configure` options to pass custom path to Expat libraries and headers: + + --with-expat=[ARG] use Expat XML Parser from given prefix (ARG=path); + check standard prefixes (ARG=yes); disable (ARG=no) + --with-expat-inc=[DIR] path to Expat XML Parser headers + --with-expat-lib=[ARG] link options for Expat XML Parser libraries + +## xmlel record and types + +XML elements are provided as Erlang xmlel records. + +Format of the record allows defining a simple tree-like +structure. xmlel record has the following fields: + +- name :: binary() +- attrs :: [attr()] +- children :: [xmlel() | cdata()] + +cdata type is a tuple of the form: + + {xmlcdata, CData::binary()} + +attr type if a tuple of the form: + + {Name::binary(), Value::binary()} + +## XML full structure parsing + +You can definitely parse a complete XML structure with `p1_xml`: + +``` +$ erl -pa ebin +Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] + +Eshell V6.3 (abort with ^G) +1> application:start(p1_xml). +ok +2> xml_stream:parse_element(<<"content cdata">>). +{xmlel,<<"test">>,[],[{xmlcdata,<<"content cdata">>}]} +``` + +## XML Stream parsing example + +You can also parse continuous stream. Our design allows decoupling +very easily the process receiving the raw XML to parse from the +process receiving the parsed content. + +The workflow is as follow: + + state = new(CallbackPID); parse(state, data); parse(state, moredata); ... + +and the parsed XML fragments (stanzas) are send to CallbackPID. + +With that approach you can be very flexible on how you architect your +own application. + +Here is an example XML stream parsing: ``` -$ erl -pa ebin +$ erl -pa ebin Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] Eshell V6.3 (abort with ^G) % Start the application: -1> application:start(p1_xml). +1> application:start(p1_xml). ok % Create a new stream, using self PID to received XML parsing event: 2> S1 = xml_stream:new(self()). -{xml_stream_state,<0.32.0>,#Port<0.751>,[],0,infinity} +<<>> % Start feeding content to the XML parser. -3> S2 = xml_stream:parse(S1, <<"">>). -{xml_stream_state,<0.32.0>,#Port<0.751>, - [xmlstreamstart], - 0,infinity} +3> S2 = xml_stream:parse(S1, <<"">>). +<<>> % Receive Erlang message send to shell process: 4> flush(). -Shell got {'$gen_event',{xmlstreamstart,<<"test">>,[]}} +Shell got {'$gen_event',{xmlstreamstart,<<"root">>,[]}} ok % Feed more content: -5> S3 = xml_stream:parse(S2, <<"content cdata">>). -{xml_stream_state,<0.32.0>,#Port<0.751>, - [xmlstreamstart], - 0,infinity} +5> S3 = xml_stream:parse(S2, <<"content cdata>). +<<>> % Receive more messages: -6> flush(). -Shell got {'$gen_all_state_event',{xmlstreamcdata,<<"content cdata">>}} +6> flush(). +Shell got {'$gen_event', + {xmlstreamelement, + {xmlel,<<"xmlelement">>,[], + [{xmlcdata,<<"content cdata">>}]}}} ok % Feed more content: -7> S4 = xml_stream:parse(S3, <<"">>). -{xml_stream_state,<0.32.0>,#Port<0.751>,[],7,infinity} +7> S4 = xml_stream:parse(S3, <<"">>). +<<>> % Receive messages: 8> flush(). -Shell got {'$gen_event',{xmlstreamend,<<"test">>}} +Shell got {'$gen_event',{xmlstreamend,<<"root">>}} ok + +9> xml_stream:close(S4). +true ``` +Note how the root element is important. We expect to have the root +element serve as boundary with stream start and stream end +event. Then, lower level tags are passed as sub stream elements. + +## How does this module relate to exmpp ? + +This module is a low level fast XML parser. It is not an XMPP client +library like [exmpp](https://processone.github.io/exmpp/). + +## References + +This module is use at large scale for parsing massive XML content in +[ejabberd](https://www.ejabberd.im) XMPP server project. It is used in +production in thousands of real life deployments. + +## Development + +### Test + +#### Unit test + +You can run eunit test with the command: + + $ rebar eunit + +#### Elixir / Quickcheck test + +You can run test written with Elixir / Quickcheck thanks to the mix command: + + MIX_EXS=test/elixir/mix.exs mix test diff -Nru erlang-p1-xml-0.2015.04.15/rebar.config erlang-p1-xml-1.1.2/rebar.config --- erlang-p1-xml-0.2015.04.15/rebar.config 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/rebar.config 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,30 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeniy Khramtsov +%%% @copyright (C) 2013, Evgeniy Khramtsov +%%% @doc +%%% Rebar build script. Compliant with rebar and rebar3. +%%% @end +%%% Created : 8 May 2013 by Evgeniy Khramtsov +%%%------------------------------------------------------------------- + +{erl_opts, [debug_info, {src_dirs, ["src"]}]}. +{port_env, [{"CFLAGS", "$CFLAGS"}, {"LDFLAGS", "$LDFLAGS"}]}. +{port_specs, [{"priv/lib/xml.so", ["c_src/xml.c"]}, + {"priv/lib/xml_stream.so", ["c_src/xml_stream.c"]}]}. + +{deps, [{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.3"}}}]}. + +{clean_files, ["c_src/xml.gcda", "c_src/xml.gcno", "c_src/xml_stream.gcda", "c_src/xml_stream.gcno"]}. + +{cover_enabled, true}. +{cover_export_enabled, true}. + +{xref_checks, [undefined_function_calls, undefined_functions, deprecated_function_calls, deprecated_functions]}. + +{profiles, [{test, [{erl_opts, [{src_dirs, ["src", "test"]}]}]}]}. +{plugins, []}. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: diff -Nru erlang-p1-xml-0.2015.04.15/rebar.config.script erlang-p1-xml-1.1.2/rebar.config.script --- erlang-p1-xml-0.2015.04.15/rebar.config.script 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/rebar.config.script 2016-01-23 17:21:53.000000000 +0000 @@ -2,44 +2,88 @@ %%% @author Evgeniy Khramtsov %%% @copyright (C) 2013, Evgeniy Khramtsov %%% @doc -%%% +%%% Rebar build script. Compliant with rebar and rebar3. %%% @end %%% Created : 8 May 2013 by Evgeniy Khramtsov %%%------------------------------------------------------------------- -Cfg = [{full_xml, false}, - {flash_hack, false}, - {disable_nif, false}]. - -Macros = lists:flatmap( - fun({full_xml, true}) -> - [{d, 'FULL_XML_SUPPORT'}]; - ({disable_nif, true}) -> - [{d, 'DISABLE_NIF'}]; - ({flash_hack, true}) -> - [{d, 'ENABLE_FLASH_HACK'}]; - (_) -> - [] - end, Cfg), - -NIFPortSpec = case lists:keysearch(disable_nif, 1, Cfg) of - {value, {disable_nif, true}} -> - []; - _ -> - [{"priv/lib/xml.so", ["c_src/xml.c"]}] - end, - -FlashHackFlag = case lists:keysearch(flash_hack, 1, Cfg) of - {value, {flash_hack, true}} -> - " -DENABLE_FLASH_HACK"; - _ -> - "" - end, - -Config = [{erl_opts, [debug_info, {src_dirs, [src, specs]}|Macros]}, - {port_env, [{"CFLAGS", "$CFLAGS -g -O2 -Wall" ++ FlashHackFlag}, - {"LDFLAGS", "$LDFLAGS -lexpat"}]}, - {port_specs, [{"priv/lib/expat_erl.so", ["c_src/expat_erl.c"]} - | NIFPortSpec]}], + +Cfg = case file:consult("vars.config") of + {ok, Terms} -> + Terms; + _Err -> + [] + end ++ [{cflags, "-g -O2 -Wall"}, {ldflags, "-lexpat"}, {with_gcov, "false"}], +{cflags, CfgCFlags} = lists:keyfind(cflags, 1, Cfg), +{ldflags, CfgLDFlags} = lists:keyfind(ldflags, 1, Cfg), +{with_gcov, CfgWithGCov} = lists:keyfind(with_gcov, 1, Cfg), + + +ModCfg0 = fun(F, Cfg, [Key|Tail], Op, Default) -> + {OldVal,PartCfg} = case lists:keytake(Key, 1, Cfg) of + {value, {_, V1}, V2} -> {V1, V2}; + false -> {if Tail == [] -> Default; true -> [] end, Cfg} + end, + case Tail of + [] -> + [{Key, Op(OldVal)} | PartCfg]; + _ -> + [{Key, F(F, OldVal, Tail, Op, Default)} | PartCfg] + end + end, +ModCfg = fun(Cfg, Keys, Op, Default) -> ModCfg0(ModCfg0, Cfg, Keys, Op, Default) end. +ModCfgS = fun(Cfg, Keys, Val) -> ModCfg0(ModCfg0, Cfg, Keys, fun(_V) -> Val end, "") end. + +Cfg0 = ModCfg(CONFIG, [port_env, "CFLAGS"], fun(V) -> V ++ " " ++ CfgCFlags end, "$CFLAGS"), +Cfg00 = ModCfg(Cfg0, [port_env, "LDFLAGS"], fun(V) -> V ++ " " ++ CfgLDFlags end, "$LDFLAGS"), +Cfg1 = case CfgWithGCov of + "true" -> + V1 = ModCfg(Cfg00, [post_hooks], fun(V) -> V ++ [{eunit, "gcov -o c_src xml xml_stream"}, + {eunit, "mv *.gcov .eunit/"}] end, []), + V2 = ModCfg(V1, [port_env, "LDFLAGS"], fun(V) -> V ++ " --coverage" end, ""), + ModCfg(V2, [port_env, "CFLAGS"], fun(V) -> V ++ " --coverage" end, ""); + _ -> + Cfg00 + end, + +%% Rebar3 support for hex.pm support: +%% - Transform dependencies specification to use hex.pm packages: +%% deps of the form: {Name, _Vsn, {git, _URL, {tag, Version}}} +%% are expected to refer to package and are rewritten for rebar3 as: +%% {Name, Version} +%% - Add rebar3_hex plugin +IsRebar3 = case application:get_key(rebar, vsn) of + {ok, VSN} -> + [VSN1 | _] = string:tokens(VSN, "-"), + [Maj, Min, Patch] = string:tokens(VSN1, "."), + (list_to_integer(Maj) >= 3); + undefined -> + lists:keymember(mix, 1, application:loaded_applications()) + end, +Cfg2 = case IsRebar3 of + true -> + DepsFun = fun(DepsList) -> lists:map(fun({DepName,_, {git,_, {tag,Version}}}) -> + {DepName, Version}; + (Dep) -> + Dep + end, DepsList) + end, + RB1 = ModCfg(Cfg1, [deps], DepsFun, []), + ModCfg(RB1, [plugins], fun(V) -> V ++ [rebar3_hex] end, []); + false -> + Cfg1 + end, + +%% When running Travis test, upload test coverage result to coveralls: +Config = case os:getenv("TRAVIS") of + "true" -> + JobId = os:getenv("TRAVIS_JOB_ID"), + Cfg3 = ModCfg(Cfg2, [deps], fun(V) -> [{coveralls, ".*", {git, "https://github.com/markusn/coveralls-erl.git", "master"}}|V] end, []), + ModCfg(Cfg3, [post_hooks], fun(V) -> V ++ [{eunit, "echo '\n%%! -pa .eunit/ deps/coveralls/ebin\nmain(_)->{ok,F}=file:open(\"erlang.json\",[write]),io:fwrite(F,\"~s\",[coveralls:convert_file(\".eunit/cover.coverdata\", \""++JobId++"\", \"travis-ci\")]).' > getcover.erl"}, + {eunit, "escript ./getcover.erl"}] end, []); + _ -> + Cfg2 + end, + %%io:format("xml configuration:~n ~p~n", [Config]), Config. diff -Nru erlang-p1-xml-0.2015.04.15/rebar.config.script.in erlang-p1-xml-1.1.2/rebar.config.script.in --- erlang-p1-xml-0.2015.04.15/rebar.config.script.in 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/rebar.config.script.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeniy Khramtsov -%%% @copyright (C) 2013, Evgeniy Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 8 May 2013 by Evgeniy Khramtsov -%%%------------------------------------------------------------------- -Cfg = [{full_xml, @full_xml@}, - {flash_hack, @flash_hack@}, - {disable_nif, @disable_nif@}]. - -Macros = lists:flatmap( - fun({full_xml, true}) -> - [{d, 'FULL_XML_SUPPORT'}]; - ({disable_nif, true}) -> - [{d, 'DISABLE_NIF'}]; - ({flash_hack, true}) -> - [{d, 'ENABLE_FLASH_HACK'}]; - (_) -> - [] - end, Cfg), - -NIFPortSpec = case lists:keysearch(disable_nif, 1, Cfg) of - {value, {disable_nif, true}} -> - []; - _ -> - [{"priv/lib/xml.so", ["c_src/xml.c"]}] - end, - -FlashHackFlag = case lists:keysearch(flash_hack, 1, Cfg) of - {value, {flash_hack, true}} -> - " -DENABLE_FLASH_HACK"; - _ -> - "" - end, - -Config = [{erl_opts, [debug_info, {src_dirs, [src, specs]}|Macros]}, - {port_env, [{"CFLAGS", "$CFLAGS -g -O2 -Wall" ++ FlashHackFlag}, - {"LDFLAGS", "$LDFLAGS -lexpat"}]}, - {port_specs, [{"priv/lib/expat_erl.so", ["c_src/expat_erl.c"]} - | NIFPortSpec]}], -%%io:format("xml configuration:~n ~p~n", [Config]), -Config. - -%% Local Variables: -%% mode: erlang -%% End: -%% vim: set filetype=erlang tabstop=8: diff -Nru erlang-p1-xml-0.2015.04.15/spec/README.md erlang-p1-xml-1.1.2/spec/README.md --- erlang-p1-xml-0.2015.04.15/spec/README.md 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/spec/README.md 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,6 @@ +This file is used to generate `src/xmlrpc_codec.erl`. + +From repository root, you can regenerate the file with: + + erl -noinput +B -pa ebin -pa deps/*/ebin -eval \ + 'case xml_gen:compile("spec/xmlrpc_codec.spec") of ok -> halt(0); _ -> halt(1) end.' diff -Nru erlang-p1-xml-0.2015.04.15/spec/xmlrpc_codec.spec erlang-p1-xml-1.1.2/spec/xmlrpc_codec.spec --- erlang-p1-xml-0.2015.04.15/spec/xmlrpc_codec.spec 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/spec/xmlrpc_codec.spec 2016-01-23 17:21:53.000000000 +0000 @@ -66,16 +66,16 @@ xmlns = <<"xmlrpc">>, result = {i4, '$cdata'}, cdata = #cdata{required = true, - dec = {xml_util, binary_to_integer, []}, - enc = {xml_util, integer_to_binary, []}}}). + dec = {erlang, binary_to_integer, []}, + enc = {erlang, integer_to_binary, []}}}). -xml(int, #elem{name = <<"int">>, xmlns = <<"xmlrpc">>, result = {int, '$cdata'}, cdata = #cdata{required = true, - dec = {xml_util, binary_to_integer, []}, - enc = {xml_util, integer_to_binary, []}}}). + dec = {erlang, binary_to_integer, []}, + enc = {erlang, integer_to_binary, []}}}). -xml(string, #elem{name = <<"string">>, @@ -88,8 +88,8 @@ xmlns = <<"xmlrpc">>, result = {double, '$cdata'}, cdata = #cdata{required = true, - dec = {xml_util, binary_to_float, []}, - enc = {xml_util, float_to_binary, []}}}). + dec = {erlang, binary_to_float, []}, + enc = {erlang, float_to_binary, []}}}). -xml(base64, #elem{name = <<"base64">>, diff -Nru erlang-p1-xml-0.2015.04.15/src/p1_xml.app.src erlang-p1-xml-1.1.2/src/p1_xml.app.src --- erlang-p1-xml-0.2015.04.15/src/p1_xml.app.src 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/p1_xml.app.src 2016-01-23 17:21:53.000000000 +0000 @@ -1,18 +1,39 @@ -%%%------------------------------------------------------------------- -%%% @author Evgeniy Khramtsov -%%% @copyright (C) 2013, Evgeniy Khramtsov -%%% @doc -%%% -%%% @end -%%% Created : 4 Apr 2013 by Evgeniy Khramtsov -%%%------------------------------------------------------------------- +%%%---------------------------------------------------------------------- +%%% File : xml.erl +%%% Author : Evgeniy Khramtsov +%%% Purpose : XML utils +%%% Created : 4 Apr 2013 by Evgeniy Khramtsov +%%% +%%% +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. +%%% +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. +%%% +%%%---------------------------------------------------------------------- + {application, p1_xml, - [{description, "XML library"}, - {vsn, "0.1.0"}, + [{description, "Fast Expat based Erlang XML parsing library"}, + {vsn, "1.1.1"}, {modules, []}, {registered, []}, {applications, [kernel, stdlib]}, - {mod, {xml_app,[]}}]}. + {mod, {xml_app,[]}}, + + %% hex.pm packaging: + {files, ["src/", "c_src/xml.c", "c_src/xml_stream.c", "include/", "spec/", "rebar.config", "rebar.config.script", "README.md", "CHANGELOG.md", "LICENSE.txt"]}, + {licenses, ["Apache 2.0"]}, + {maintainers, ["ProcessOne"]}, + {links, [{"Github", "https://github.com/processone/xml"}]}]}. %% Local Variables: %% mode: erlang diff -Nru erlang-p1-xml-0.2015.04.15/src/p1_xmlrpc.erl erlang-p1-xml-1.1.2/src/p1_xmlrpc.erl --- erlang-p1-xml-0.2015.04.15/src/p1_xmlrpc.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/p1_xmlrpc.erl 2016-01-23 17:21:53.000000000 +0000 @@ -1,29 +1,25 @@ -%%%---------------------------------------------------------------------- +%%%------------------------------------------------------------------- %%% File : p1_xmlrpc.erl %%% Author : Evgeny Khramtsov %%% Purpose : XMLRPC encoder/decoder %%% Created : 3 Oct 2014 by Evgeny Khramtsov %%% %%% -%%% p1_xml, Copyright (C) 2002-2015 ProcessOne +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. %%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at %%% -%%%---------------------------------------------------------------------- - +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. +%%% +%%%------------------------------------------------------------------- -module(p1_xmlrpc). %% API @@ -134,114 +130,3 @@ {{date, Date}, undefined}; encode_param(nil) -> {nil, undefined}. - --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). - -fault_test() -> - Fault = {xmlel,<<"methodResponse">>,[], - [{xmlel,<<"fault">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"struct">>,[], - [{xmlel,<<"member">>,[], - [{xmlel,<<"name">>,[],[{xmlcdata,<<"faultCode">>}]}, - {xmlel,<<"value">>,[], - [{xmlel,<<"int">>,[],[{xmlcdata,<<"4">>}]}]}]}, - {xmlel,<<"member">>,[], - [{xmlel,<<"name">>,[],[{xmlcdata,<<"faultString">>}]}, - {xmlel,<<"value">>,[], - [{xmlel,<<"string">>,[], - [{xmlcdata,<<"Too many parameters.">>}]}]}]}]}]}]}]}, - Result = {response, {fault, 4, <<"Too many parameters.">>}}, - ?assertEqual({ok, Result}, ?MODULE:decode(Fault)), - ?assertEqual(Fault, ?MODULE:encode(Result)). - -call_test() -> - Call = {xmlel,<<"methodCall">>,[], - [{xmlel,<<"methodName">>,[],[{xmlcdata,<<"examples.getStateName">>}]}, - {xmlel,<<"params">>,[], - [{xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"int">>,[],[{xmlcdata,<<"40">>}]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"int">>,[],[{xmlcdata,<<"30">>}]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"boolean">>,[],[{xmlcdata,<<"0">>}]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"base64">>,[], - [{xmlcdata,<<"eW91IGNhbid0IHJlYWQgdGhpcyE=">>}]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"dateTime.iso8601">>,[], - [{xmlcdata,<<"19980717T14:08:55">>}]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"string">>,[], - [{xmlcdata,<<"Hello world!">>}]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[],[{xmlel,<<"nil">>,[],[]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"array">>,[], - [{xmlel,<<"data">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"int">>,[], - [{xmlcdata,<<"1404">>}]}]}, - {xmlel,<<"value">>,[], - [{xmlel,<<"string">>,[], - [{xmlcdata,<<"Something here">>}]}]}, - {xmlel,<<"value">>,[], - [{xmlel,<<"int">>,[], - [{xmlcdata,<<"1">>}]}]}]}]}]}]}, - {xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"struct">>,[], - [{xmlel,<<"member">>,[], - [{xmlel,<<"name">>,[],[{xmlcdata,<<"foo">>}]}, - {xmlel,<<"value">>,[], - [{xmlel,<<"int">>,[], - [{xmlcdata,<<"1">>}]}]}]}, - {xmlel,<<"member">>,[], - [{xmlel,<<"name">>,[],[{xmlcdata,<<"bar">>}]}, - {xmlel,<<"value">>,[], - [{xmlel,<<"int">>,[], - [{xmlcdata,<<"2">>}]}]}]}]}]}]}]}]}, - Result = {call,'examples.getStateName', - [40,30,false, - {base64,<<"eW91IGNhbid0IHJlYWQgdGhpcyE=">>}, - {date,<<"19980717T14:08:55">>}, - <<"Hello world!">>,nil, - {array,[1404,<<"Something here">>,1]}, - {struct,[{foo,1},{bar,2}]}]}, - ?assertEqual({ok, Result}, ?MODULE:decode(Call)), - ?assertEqual(Call, ?MODULE:encode(Result)). - -response_test() -> - Response = {xmlel,<<"methodResponse">>, [], - [{xmlel,<<"params">>,[], - [{xmlel,<<"param">>,[], - [{xmlel,<<"value">>,[], - [{xmlel,<<"string">>,[], - [{xmlcdata,<<"South Dakota">>}]}]}]}]}]}, - Result = {response,[<<"South Dakota">>]}, - ?assertEqual({ok, Result}, ?MODULE:decode(Response)), - ?assertEqual(Response, ?MODULE:encode(Result)). - -empty_call_test() -> - Call = {xmlel,<<"methodCall">>,[], - [{xmlel,<<"methodName">>,[], - [{xmlcdata,<<"some_method">>}]}]}, - Result = {call, some_method, []}, - ?assertEqual({ok, Result}, ?MODULE:decode(Call)), - ?assertEqual(Call, ?MODULE:encode(Result)). - -empty_response_test() -> - Response = {xmlel,<<"methodResponse">>, [], []}, - Result = {response, []}, - ?assertEqual({ok, Result}, ?MODULE:decode(Response)), - ?assertEqual(Response, ?MODULE:encode(Result)). - --endif. diff -Nru erlang-p1-xml-0.2015.04.15/src/xml_app.erl erlang-p1-xml-1.1.2/src/xml_app.erl --- erlang-p1-xml-0.2015.04.15/src/xml_app.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/xml_app.erl 2016-01-23 17:21:53.000000000 +0000 @@ -1,26 +1,23 @@ %%%---------------------------------------------------------------------- %%% File : xml_app.erl %%% Author : Evgeniy Khramtsov -%%% Purpose : p1_xml application +%%% Purpose : XML application %%% Created : 1 May 2013 by Evgeniy Khramtsov %%% %%% -%%% p1_xml, Copyright (C) 2002-2015 ProcessOne +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. %%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. %%% %%%---------------------------------------------------------------------- @@ -52,11 +49,13 @@ %% @end %%-------------------------------------------------------------------- start(_StartType, _StartArgs) -> - case xml_sup:start_link() of - {ok, Pid} -> - {ok, Pid}; - Error -> - Error + case {xml:load_nif(), xml_stream:load_nif()} of + {ok, ok} -> + xml_sup:start_link(); + {{error,_} = E1, _} -> + E1; + {_, {error,_} = E2} -> + E2 end. %%-------------------------------------------------------------------- diff -Nru erlang-p1-xml-0.2015.04.15/src/xml.erl erlang-p1-xml-1.1.2/src/xml.erl --- erlang-p1-xml-0.2015.04.15/src/xml.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/xml.erl 2016-01-23 17:21:53.000000000 +0000 @@ -5,22 +5,19 @@ %%% Created : 20 Nov 2002 by Alexey Shchepin %%% %%% -%%% p1_xml, Copyright (C) 2002-2015 ProcessOne +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. %%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at %%% -%%% 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. +%%% http://www.apache.org/licenses/LICENSE-2.0 %%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. %%% %%%---------------------------------------------------------------------- @@ -28,74 +25,27 @@ -author('alexey@process-one.net'). --behaviour(gen_server). - --export([element_to_binary/1, get_so_path/0, - crypt/1, make_text_node/1, remove_cdata/1, +-export([element_to_binary/1, + crypt/1, remove_cdata/1, remove_subtags/3, get_cdata/1, get_tag_cdata/1, get_attr/2, get_attr_s/2, get_tag_attr/2, get_tag_attr_s/2, get_subtag/2, get_subtags/2, get_subtag_cdata/2, get_subtag_with_xmlns/3, get_subtags_with_xmlns/3, append_subtags/2, get_path_s/2, - replace_tag_attr/3, to_xmlel/1]). + replace_tag_attr/3, replace_subtag/2, to_xmlel/1]). -%% Internal exports, call-back functions. --export([start_link/0, init/1, handle_call/3, handle_cast/2, - handle_info/2, code_change/3, terminate/2]). +-export([load_nif/0]). -include("xml.hrl"). -%% Select at compile time how to escape characters in binary text -%% nodes. -%% Can be choosen with ./configure --enable-full-xml --ifdef(FULL_XML_SUPPORT). - --define(ESCAPE_BINARY(CData), make_text_node(CData)). - --else. - --define(ESCAPE_BINARY(CData), crypt(CData)). - --endif. - -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], - []). - -%% Can be choosen with ./configure --disable-nif --ifdef(DISABLE_NIF). -init([]) -> - {ok, []}. --else. %% Replace element_to_binary/1 with NIF -%% Can be choosen with ./configure --disable-nif -init([]) -> - SOPath = filename:join(get_so_path(), "xml"), +load_nif() -> + SOPath = p1_nif_utils:get_so_path(?MODULE, [p1_xml, xml], "xml"), case catch erlang:load_nif(SOPath, 0) of ok -> ok; - Err -> error_logger:warning_msg("unable to load xml NIF: ~p~n", [Err]) - end, - {ok, []}. --endif. - -%%% -------------------------------------------------------- -%%% The call-back functions. -%%% -------------------------------------------------------- - -handle_call(_, _, State) -> {noreply, State}. - -handle_cast(_, State) -> {noreply, State}. - -handle_info({'EXIT', Port, Reason}, Port) -> - {stop, {port_died, Reason}, Port}; -handle_info({'EXIT', _Pid, _Reason}, Port) -> - {noreply, Port}; -handle_info(_, State) -> {noreply, State}. - -code_change(_OldVsn, State, _Extra) -> {ok, State}. - -terminate(_Reason, _State) -> - ok. + Err -> error_logger:warning_msg("unable to load xml NIF: ~p~n", [Err]), + {error, unable_to_load_nif} + end. %% -spec(element_to_binary/1 :: @@ -104,46 +54,8 @@ -> binary() ). -element_to_binary(El) -> - iolist_to_binary(element_to_string(El)). - -%% --spec(element_to_string/1 :: -( - El :: xmlel() | cdata()) - -> string() -). - -element_to_string(El) -> - case catch element_to_string_nocatch(El) of - {'EXIT', Reason} -> erlang:error({badxml, El, Reason}); - Result -> Result - end. - --spec(element_to_string_nocatch/1 :: -( - El :: xmlel() | cdata()) - -> iolist() -). - -element_to_string_nocatch(El) -> - case El of - #xmlel{name = Name, attrs = Attrs, children = Els} -> - if Els /= [] -> - [$<, Name, attrs_to_list(Attrs), $>, - [element_to_string_nocatch(E) || E <- Els], $<, $/, - Name, $>]; - true -> [$<, Name, attrs_to_list(Attrs), $/, $>] - end; - %% We do not crypt CDATA binary, but we enclose it in XML CDATA - {xmlcdata, CData} -> - ?ESCAPE_BINARY(CData) - end. - -attrs_to_list(Attrs) -> [attr_to_list(A) || A <- Attrs]. - -attr_to_list({Name, Value}) -> - [$\s, Name, $=, $', crypt(Value), $']. +element_to_binary(_El) -> + erlang:nif_error(nif_not_loaded). crypt(S) -> << <<(case C of @@ -157,70 +69,6 @@ || <> <= S >>. %% --spec(make_text_node/1 :: -( - CData :: binary()) - -> binary() -). - -make_text_node(CData) -> - case cdata_need_escape(CData) of - cdata -> - CDATA1 = <<">, - CDATA2 = <<"]]>">>, - iolist_to_binary([CDATA1, CData, CDATA2]); - none -> CData; - {cdata, EndTokens} -> - EscapedCData = escape_cdata(CData, EndTokens), - iolist_to_binary(EscapedCData) - end. - -cdata_need_escape(CData) -> - cdata_need_escape(CData, 0, false, []). - -cdata_need_escape(<<>>, _, false, _) -> none; -cdata_need_escape(<<>>, _, true, []) -> cdata; -cdata_need_escape(<<>>, _, true, CDataEndTokens) -> - {cdata, lists:reverse(CDataEndTokens)}; -cdata_need_escape(<<$], $], $>, Rest/binary>>, - CurrentPosition, _XMLEscape, CDataEndTokens) -> - NewPosition = CurrentPosition + 3, - cdata_need_escape(Rest, NewPosition, true, - [CurrentPosition + 1 | CDataEndTokens]); -%% Only <, & need to be escaped in XML text node -%% See reference: http://www.w3.org/TR/xml11/#syntax -cdata_need_escape(<<$<, Rest/binary>>, CurrentPosition, - _XMLEscape, CDataEndTokens) -> - cdata_need_escape(Rest, CurrentPosition + 1, true, - CDataEndTokens); -cdata_need_escape(<<$&, Rest/binary>>, CurrentPosition, - _XMLEscape, CDataEndTokens) -> - cdata_need_escape(Rest, CurrentPosition + 1, true, - CDataEndTokens); -cdata_need_escape(<<_:8, Rest/binary>>, CurrentPosition, - XMLEscape, CDataEndTokens) -> - cdata_need_escape(Rest, CurrentPosition + 1, XMLEscape, - CDataEndTokens). - -escape_cdata(CData, EndTokens) -> - escape_cdata(CData, 0, EndTokens, []). - -escape_cdata(<<>>, _CurrentPosition, [], Acc) -> - lists:reverse(Acc); -escape_cdata(Rest, CurrentPosition, [], Acc) -> - CDATA1 = <<">, - CDATA2 = <<"]]>">>, - escape_cdata(<<>>, CurrentPosition, [], - [CDATA2, Rest, CDATA1 | Acc]); -escape_cdata(CData, Index, [Pos | Positions], Acc) -> - CDATA1 = <<">, - CDATA2 = <<"]]>">>, - Split = Pos - Index, - {Part, Rest} = split_binary(CData, Split + 1), - escape_cdata(Rest, Pos + 1, Positions, - [CDATA2, Part, CDATA1 | Acc]). - -%% -spec(remove_cdata_p/1 :: ( El :: xmlel() | cdata()) @@ -239,6 +87,9 @@ remove_cdata(L) -> [E || E <- L, remove_cdata_p(E)]. +%% This function is intended to remove subtags based on a name and an +%% attribute, usually an xmlns attribute for a specific XMPP +%% extension. -spec(remove_subtags/3 :: ( Xmlel :: xmlel(), @@ -529,6 +380,23 @@ attrs = [{Name, Value} | lists:keydelete(Name, 1, Xmlel#xmlel.attrs)] }. + +-spec(replace_subtag/2 :: +( + Tag :: xmlel(), + Xmlel :: xmlel()) + -> Xmlel :: #xmlel{ + name :: binary(), + attrs :: [attr(),...], + children :: [xmlel() | cdata()] + } +). + +replace_subtag(#xmlel{name = Name} = Tag, Xmlel) -> + Xmlel#xmlel{ + children = [Tag | lists:keydelete(Name, #xmlel.name, Xmlel#xmlel.children)] + }. + to_xmlel({_, Name, Attrs, Els}) -> #xmlel{name = iolist_to_binary(Name), attrs = [{iolist_to_binary(K), iolist_to_binary(V)} @@ -536,8 +404,3 @@ children = [to_xmlel(El) || El <- Els]}; to_xmlel({xmlcdata, CData}) -> {xmlcdata, iolist_to_binary(CData)}. - -get_so_path() -> - EbinDir = filename:dirname(code:which(?MODULE)), - AppDir = filename:dirname(EbinDir), - filename:join([AppDir, "priv", "lib"]). diff -Nru erlang-p1-xml-0.2015.04.15/src/xml_gen.erl erlang-p1-xml-1.1.2/src/xml_gen.erl --- erlang-p1-xml-0.2015.04.15/src/xml_gen.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/xml_gen.erl 2016-01-23 17:21:53.000000000 +0000 @@ -5,22 +5,19 @@ %%% Created : 22 Jun 2009 by Evgeniy Khramtsov %%% %%% -%%% p1_xml, Copyright (C) 2002-2015 ProcessOne +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. %%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at %%% -%%% 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. +%%% http://www.apache.org/licenses/LICENSE-2.0 %%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. %%% %%%---------------------------------------------------------------------- @@ -1729,7 +1726,7 @@ term_is_record(Term) -> try - [H|T]= tuple_to_list(Term), + [H|_T]= tuple_to_list(Term), true = is_atom(H), false == is_label(H) catch _:_ -> @@ -1803,7 +1800,7 @@ case term_is_record(RefElem#elem.result) of true -> RecName = element(1, RefElem#elem.result), - [{{record, RecName}, [{0, []}]}]; + [{{record, RecName}, {0, [{0, []}]}}]; false -> [] end diff -Nru erlang-p1-xml-0.2015.04.15/src/xmlrpc_codec.erl erlang-p1-xml-1.1.2/src/xmlrpc_codec.erl --- erlang-p1-xml-0.2015.04.15/src/xmlrpc_codec.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/xmlrpc_codec.erl 2016-01-23 17:21:53.000000000 +0000 @@ -476,7 +476,7 @@ erlang:error({xmlrpc_codec, {missing_cdata, <<>>, <<"double">>, __TopXMLNS}}); decode_double_cdata(__TopXMLNS, _val) -> - case catch xml_util:binary_to_float(_val) of + case catch erlang:binary_to_float(_val) of {'EXIT', _} -> erlang:error({xmlrpc_codec, {bad_cdata_value, <<>>, <<"double">>, __TopXMLNS}}); @@ -484,7 +484,7 @@ end. encode_double_cdata(_val, _acc) -> - [{xmlcdata, xml_util:float_to_binary(_val)} | _acc]. + [{xmlcdata, erlang:float_to_binary(_val)} | _acc]. decode_string(__TopXMLNS, __IgnoreEls, {xmlel, <<"string">>, _attrs, _els}) -> @@ -539,7 +539,7 @@ erlang:error({xmlrpc_codec, {missing_cdata, <<>>, <<"int">>, __TopXMLNS}}); decode_int_cdata(__TopXMLNS, _val) -> - case catch xml_util:binary_to_integer(_val) of + case catch erlang:binary_to_integer(_val) of {'EXIT', _} -> erlang:error({xmlrpc_codec, {bad_cdata_value, <<>>, <<"int">>, __TopXMLNS}}); @@ -547,7 +547,7 @@ end. encode_int_cdata(_val, _acc) -> - [{xmlcdata, xml_util:integer_to_binary(_val)} | _acc]. + [{xmlcdata, erlang:integer_to_binary(_val)} | _acc]. decode_i4(__TopXMLNS, __IgnoreEls, {xmlel, <<"i4">>, _attrs, _els}) -> @@ -574,7 +574,7 @@ erlang:error({xmlrpc_codec, {missing_cdata, <<>>, <<"i4">>, __TopXMLNS}}); decode_i4_cdata(__TopXMLNS, _val) -> - case catch xml_util:binary_to_integer(_val) of + case catch erlang:binary_to_integer(_val) of {'EXIT', _} -> erlang:error({xmlrpc_codec, {bad_cdata_value, <<>>, <<"i4">>, __TopXMLNS}}); @@ -582,7 +582,7 @@ end. encode_i4_cdata(_val, _acc) -> - [{xmlcdata, xml_util:integer_to_binary(_val)} | _acc]. + [{xmlcdata, erlang:integer_to_binary(_val)} | _acc]. decode_value(__TopXMLNS, __IgnoreEls, {xmlel, <<"value">>, _attrs, _els}) -> diff -Nru erlang-p1-xml-0.2015.04.15/src/xml_stream.erl erlang-p1-xml-1.1.2/src/xml_stream.erl --- erlang-p1-xml-0.2015.04.15/src/xml_stream.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/xml_stream.erl 2016-01-23 17:21:53.000000000 +0000 @@ -5,22 +5,19 @@ %%% Created : 17 Nov 2002 by Alexey Shchepin %%% %%% -%%% p1_xml, Copyright (C) 2002-2015 ProcessOne +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. %%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. %%% %%%---------------------------------------------------------------------- @@ -28,26 +25,10 @@ -author('alexey@process-one.net'). --behaviour(gen_server). - --export([new/1, new/2, parse/2, close/1, +-export([new/1, new/2, parse/2, close/1, reset/1, change_callback_pid/2, parse_element/1]). -%% Internal exports, call-back functions. --export([start_link/0, init/1, handle_call/3, handle_cast/2, - handle_info/2, code_change/3, terminate/2]). - --define(XML_START, 0). - --define(XML_END, 1). - --define(XML_CDATA, 2). - --define(XML_ERROR, 3). - --define(PARSE_COMMAND, 0). - --define(PARSE_FINAL_COMMAND, 1). +-export([load_nif/0]). -include("xml.hrl"). @@ -67,234 +48,53 @@ -type xml_stream_state() :: #xml_stream_state{}. -type stack() :: [xmlel()]. --type event() :: {?XML_START, {binary(), [attr()]}} | - {?XML_END, binary()} | - {?XML_CDATA, binary()} | - {?XML_ERROR, binary()}. -export_type([xml_stream_state/0, xml_stream_el/0]). -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], - []). - -init([]) -> - case load_driver() of - ok -> - {ok, []}; - {error, Why} -> - {stop, Why} - end. - -%%% -------------------------------------------------------- -%%% The call-back functions. -%%% -------------------------------------------------------- - -handle_call(_, _, State) -> {noreply, State}. - -handle_cast(_, State) -> {noreply, State}. - -handle_info({'EXIT', Port, Reason}, Port) -> - {stop, {port_died, Reason}, Port}; -handle_info({'EXIT', _Pid, _Reason}, Port) -> - {noreply, Port}; -handle_info(_, State) -> {noreply, State}. - -code_change(_OldVsn, State, _Extra) -> {ok, State}. - -terminate(_Reason, _State) -> - ok. - -process_data(CallbackPid, Stack, Data) -> - case Data of - {?XML_START, {Name, Attrs}} -> - if - Stack == [] -> - catch gen_fsm:send_event(CallbackPid, - {xmlstreamstart, Name, Attrs}), - %% There is no need to store name or attributes of - %% stream opening element as it is not used - %% anymore. - [xmlstreamstart]; - true -> - [#xmlel{name = Name, attrs = Attrs, children = []} - | Stack] - end; - {?XML_END, EndName} -> - case Stack of - [xmlstreamstart] -> - catch gen_fsm:send_event(CallbackPid, - {xmlstreamend, EndName}), - []; - [#xmlel{name = Name, attrs = Attrs, children = Els}, - xmlstreamstart] -> - NewEl = #xmlel{name = Name, attrs = Attrs, - children = lists:reverse(Els)}, - catch gen_fsm:send_event(CallbackPid, - {xmlstreamelement, NewEl}), - [xmlstreamstart]; - [#xmlel{name = Name, attrs = Attrs, children = Els}, - #xmlel{name = Name1, attrs = Attrs1, children = Els1} - | Tail] -> - NewEl = #xmlel{name = Name, attrs = Attrs, - children = lists:reverse(Els)}, - [{xmlel, Name1, Attrs1, [NewEl | Els1]} | Tail] - end; - {?XML_CDATA, CData} -> - case Stack of - [xmlstreamstart] -> - catch gen_fsm:send_all_state_event(CallbackPid, - {xmlstreamcdata, CData}), - [xmlstreamstart]; - %% Merge CDATA nodes if they are contiguous - %% This does not change the semantic: the split in - %% several CDATA nodes depends on the TCP/IP packet - %% fragmentation - [#xmlel{name = Name, attrs = Attrs, - children = [{xmlcdata, PreviousCData} | Els]} - | Tail] -> - [#xmlel{name = Name, attrs = Attrs, - children = - [{xmlcdata, - iolist_to_binary([PreviousCData, CData])} - | Els]} - | Tail]; - %% No previous CDATA - [#xmlel{name = Name, attrs = Attrs, children = Els} - | Tail] -> - [#xmlel{name = Name, attrs = Attrs, - children = [{xmlcdata, CData} | Els]} - | Tail]; - [] -> [] - end; - {?XML_ERROR, Err} -> - catch gen_fsm:send_event(CallbackPid, - {xmlstreamerror, Err}) +load_nif() -> + NifFile = p1_nif_utils:get_so_path(?MODULE, [p1_xml, xml], "xml_stream"), + case erlang:load_nif(NifFile, 0) of + ok -> + ok; + {error, {Reason, Txt}} -> + error_logger:error_msg("failed to load NIF ~s: ~s", + [NifFile, Txt]), + {error, Reason} end. -spec new(pid()) -> xml_stream_state(). -new(CallbackPid) -> new(CallbackPid, infinity). +new(CallbackPid) -> + new(CallbackPid, infinity). -spec new(pid(), non_neg_integer() | infinity) -> xml_stream_state(). -new(CallbackPid, MaxSize) -> - Port = open_port({spawn, "expat_erl"}, [binary]), - #xml_stream_state{callback_pid = CallbackPid, - port = Port, stack = [], size = 0, maxsize = MaxSize}. +new(_CallbackPid, _MaxSize) -> + erlang:nif_error(nif_not_loaded). + +-spec reset(xml_stream_state()) -> xml_stream_state(). + +reset(_State) -> + erlang:nif_error(nif_not_loaded). -spec change_callback_pid(xml_stream_state(), pid()) -> xml_stream_state(). -change_callback_pid(State, CallbackPid) -> - State#xml_stream_state{callback_pid = CallbackPid}. +change_callback_pid(_State, _CallbackPid) -> + erlang:nif_error(nif_not_loaded). --spec parse(xml_stream_state(), iodata()) -> xml_stream_state(). +-spec parse(xml_stream_state(), binary()) -> xml_stream_state(). -parse(#xml_stream_state{callback_pid = CallbackPid, - port = Port, stack = Stack, size = Size, - maxsize = MaxSize} = - State, - Str) -> - StrSize = byte_size(Str), - Res = port_control(Port, ?PARSE_COMMAND, Str), - {NewStack, NewSize} = lists:foldl(fun (Data, - {St, Sz}) -> - NewSt = process_data(CallbackPid, - St, Data), - case NewSt of - [_] -> {NewSt, 0}; - _ -> {NewSt, Sz} - end - end, - {Stack, Size + StrSize}, - binary_to_term(Res)), - if NewSize > MaxSize -> - catch gen_fsm:send_event(CallbackPid, - {xmlstreamerror, - <<"XML stanza is too big">>}); - true -> ok - end, - State#xml_stream_state{stack = NewStack, - size = NewSize}. +parse(_State, _Data) -> + erlang:nif_error(nif_not_loaded). -spec close(xml_stream_state()) -> true. -close(#xml_stream_state{port = Port}) -> - port_close(Port). +close(_State) -> + erlang:nif_error(nif_not_loaded). --spec parse_element(iodata()) -> xmlel() | +-spec parse_element(binary()) -> xmlel() | {error, parse_error} | {error, binary()}. -parse_element(Str) -> - Port = open_port({spawn, "expat_erl"}, [binary]), - Res = port_control(Port, ?PARSE_FINAL_COMMAND, Str), - port_close(Port), - process_element_events(binary_to_term(Res)). - -process_element_events(Events) -> - process_element_events(Events, []). - --spec process_element_events([event()], stack()) -> xmlel() | - {error, parse_error} | - {error, binary()}. - -process_element_events([], _Stack) -> - {error, parse_error}; -process_element_events([Event | Events], Stack) -> - case Event of - {?XML_START, {Name, Attrs}} -> - process_element_events(Events, - [#xmlel{name = Name, attrs = Attrs, - children = []} - | Stack]); - {?XML_END, _EndName} -> - case Stack of - [#xmlel{name = Name, attrs = Attrs, children = Els} - | Tail] -> - NewEl = #xmlel{name = Name, attrs = Attrs, - children = lists:reverse(Els)}, - case Tail of - [] -> - if Events == [] -> NewEl; - true -> {error, parse_error} - end; - [#xmlel{name = Name1, attrs = Attrs1, children = Els1} - | Tail1] -> - process_element_events(Events, - [#xmlel{name = Name1, - attrs = Attrs1, - children = [NewEl | Els1]} - | Tail1]) - end - end; - {?XML_CDATA, CData} -> - case Stack of - [#xmlel{name = Name, attrs = Attrs, children = Els} - | Tail] -> - process_element_events(Events, - [#xmlel{name = Name, attrs = Attrs, - children = - [{xmlcdata, CData} | Els]} - | Tail]); - [] -> process_element_events(Events, []) - end; - {?XML_ERROR, Err} -> {error, Err} - end. - -get_so_path() -> - EbinDir = filename:dirname(code:which(?MODULE)), - AppDir = filename:dirname(EbinDir), - filename:join([AppDir, "priv", "lib"]). - -load_driver() -> - case erl_ddll:load_driver(get_so_path(), expat_erl) of - ok -> - ok; - {error, already_loaded} -> - ok; - {error, ErrorDesc} = Err -> - error_logger:error_msg("failed to load Expat driver: ~s~n", - [erl_ddll:format_error(ErrorDesc)]), - Err - end. +parse_element(_Str) -> + erlang:nif_error(nif_not_loaded). diff -Nru erlang-p1-xml-0.2015.04.15/src/xml_sup.erl erlang-p1-xml-1.1.2/src/xml_sup.erl --- erlang-p1-xml-0.2015.04.15/src/xml_sup.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/xml_sup.erl 2016-01-23 17:21:53.000000000 +0000 @@ -1,26 +1,23 @@ %%%---------------------------------------------------------------------- %%% File : xml_sup.erl %%% Author : Evgeniy Khramtsov -%%% Purpose : p1_xml supervisor +%%% Purpose : XML supervisor %%% Created : 1 May 2013 by Evgeniy Khramtsov %%% %%% -%%% p1_xml, Copyright (C) 2002-2015 ProcessOne +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. %%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. %%% %%%---------------------------------------------------------------------- @@ -68,11 +65,7 @@ %% @end %%-------------------------------------------------------------------- init([]) -> - XML = {xml, {xml, start_link, []}, - permanent, brutal_kill, worker, [xml]}, - XMLStream = {xml_stream, {xml_stream, start_link, []}, - permanent, brutal_kill, worker, [xml_stream]}, - {ok, {{one_for_one, 10, 1}, [XML, XMLStream]}}. + {ok, {{one_for_one, 10, 1}, []}}. %%%=================================================================== %%% Internal functions diff -Nru erlang-p1-xml-0.2015.04.15/src/xml_util.erl erlang-p1-xml-1.1.2/src/xml_util.erl --- erlang-p1-xml-0.2015.04.15/src/xml_util.erl 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/src/xml_util.erl 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : xml_util.erl -%%% Author : Holger Weiss -%%% Purpose : Provide replacements for newer Erlang functions -%%% Created : 23 Dec 2014 by Holger Weiss -%%% -%%% -%%% p1_xml, Copyright (C) 2014-2015 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%---------------------------------------------------------------------- - --module(xml_util). --author('holger@zedat.fu-berlin.de'). - --export([binary_to_float/1, binary_to_integer/1, binary_to_integer/2, - float_to_binary/1, integer_to_binary/1, integer_to_binary/2]). - --spec(binary_to_float/1 :: -( - Binary :: binary()) - -> float() -). - -binary_to_float(Binary) -> - list_to_float(binary_to_list(Binary)). - --spec(binary_to_integer/1 :: -( - Binary :: binary()) - -> integer() -). - -binary_to_integer(Binary) -> - list_to_integer(binary_to_list(Binary)). - --spec(binary_to_integer/2 :: -( - Binary :: binary(), - Base :: 2..36) - -> integer() -). - -binary_to_integer(Binary, Base) -> - list_to_integer(binary_to_list(Binary), Base). - --spec(float_to_binary/1 :: -( - Float :: float()) - -> binary() -). - -float_to_binary(Float) -> - list_to_binary(float_to_list(Float)). - --spec(integer_to_binary/1 :: -( - Integer :: integer()) - -> binary() -). - -integer_to_binary(Integer) -> - list_to_binary(integer_to_list(Integer)). - --spec(integer_to_binary/2 :: -( - Integer :: integer(), - Base :: 2..36) - -> binary() -). - -integer_to_binary(Integer, Base) -> - list_to_binary(integer_to_list(Integer, Base)). diff -Nru erlang-p1-xml-0.2015.04.15/test/elixir/mix.exs erlang-p1-xml-1.1.2/test/elixir/mix.exs --- erlang-p1-xml-0.2015.04.15/test/elixir/mix.exs 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/test/elixir/mix.exs 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,45 @@ +# Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This mix module is used to configure project to run Elixir tests +# Elixir test can be run from project root using command: +# make exunit + +defmodule P1Xml.Mixfile do + use Mix.Project + + def project do + [app: :p1_xml, + version: "1.1.0", + elixir: "~> 1.1", + build_embedded: Mix.env == :prod, + start_permanent: Mix.env == :prod, + test_paths: ["test/elixir"], + deps: deps] + end + + def application do + [applications: [:logger], + mod: {:xml_app, []}] + end + + defp deps do + [{:p1_utils, + ~r//, # project is not semantically versioned + github: "processone/p1_utils", + compile: "rebar compile" + }, + {:eqc_ex, "~> 1.2.3"}] + end +end diff -Nru erlang-p1-xml-0.2015.04.15/test/elixir/test_helper.exs erlang-p1-xml-1.1.2/test/elixir/test_helper.exs --- erlang-p1-xml-0.2015.04.15/test/elixir/test_helper.exs 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/test/elixir/test_helper.exs 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,2 @@ +ExUnit.start() +# Mix is starting application p1_xml automatically diff -Nru erlang-p1-xml-0.2015.04.15/test/elixir/xml_test.exs erlang-p1-xml-1.1.2/test/elixir/xml_test.exs --- erlang-p1-xml-0.2015.04.15/test/elixir/xml_test.exs 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/test/elixir/xml_test.exs 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,104 @@ +# +# Test XML module with Quviq Quickcheck +# +# Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import :erlang, only: [list_to_binary: 1] + +defmodule XmlTest do + use ExUnit.Case + use EQC.ExUnit + require Record + +# MR: I do not think this is need as mix is starting p1_xml app automatically +# @on_load :nifs +# +# def nifs() do +# IO.puts "loading NIFs" +# :ok = :xml.load_nif() +# :ok = :xml_stream.load_nif() +# end + + Record.defrecord :xmlel, Record.extract(:xmlel, from: "include/xml.hrl") + + property "Can serialize arbitrary XML packets" do + forall xml_chunk <- xml_el do + is_binary(:xml.element_to_binary(xml_chunk)) + end + end + + property "Serialize and parse same XML packet" do + forall xml_chunk <- xml_el do + :xml_stream.parse_element(:xml.element_to_binary(xml_chunk)) == xml_chunk + end + end + + # Generators + # ========== + # + # Random small XML packets generator + # ---------------------------------- + + # TODO: We need to weight lowercase char much more that the rest + # An XML name cannot start with number of punctuation char + def xml_name do + [letter|list(letter_figure)] + end + + def letter do + oneof([choose(?A, ?Z), choose(?a, ?z)]) + end + + def letter_figure do + oneof([choose(?A, ?Z),choose(?a, ?z), choose(?0, ?9)]) + end + + def xml_attr do + let {key, val} <- {xml_name, xml_name} do + {list_to_binary(key), list_to_binary(val)} + end + end + + def xml_children(0) do + [] + end + + def xml_children(size) do + let name <- xml_name do + oneof([xml_children(0), + oneof([[{:xmlcdata, list_to_binary(name)}], + list(xml_child(div size, 3))])]) + end + end + + def xml_child(size) do + let {name, attrs} <- {xml_name, list(xml_attr)} do + xmlel(name: list_to_binary(name), + attrs: :lists.ukeysort(1, attrs), + children: xml_children(size)) + end + end + + def xml_el do + sized size do + let {tagname, attrs} <- {xml_name, list(xml_attr)} do + xmlel(name: list_to_binary(tagname), + attrs: :lists.ukeysort(1, attrs), + children: xml_children(size)) + end + end + end + +end diff -Nru erlang-p1-xml-0.2015.04.15/test/xml_test.erl erlang-p1-xml-1.1.2/test/xml_test.erl --- erlang-p1-xml-0.2015.04.15/test/xml_test.erl 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/test/xml_test.erl 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,865 @@ +%%%---------------------------------------------------------------------- +%%% File : xml_test.erl +%%% Author : Evgeniy Khramtsov +%%% Purpose : xml module testing +%%% Created : 17 Dec 2013 by Evgeny Khramtsov +%%% +%%% +%%% Copyright (C) 2002-2015 ProcessOne, SARL. All Rights Reserved. +%%% +%%% Licensed under the Apache License, Version 2.0 (the "License"); +%%% you may not use this file except in compliance with the License. +%%% You may obtain a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, software +%%% distributed under the License is distributed on an "AS IS" BASIS, +%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%%% See the License for the specific language governing permissions and +%%% limitations under the License. +%%% +%%%---------------------------------------------------------------------- + +-module(xml_test). + +-compile(export_all). + +-include_lib("eunit/include/eunit.hrl"). +-include("xml.hrl"). + +new() -> + new(self()). +new(Pid) -> + new(Pid, infinity). +new(Pid, MaxSize) -> + xml_stream:new(Pid, MaxSize). + +close(State) -> + ?assertEqual(true, xml_stream:close(State)). + +start_test() -> + ?assertEqual(ok, application:start(p1_xml)). + +tag_test() -> + ?assertEqual(#xmlel{name = <<"root">>}, + xml_stream:parse_element(<<"">>)). + +empty_tag_test() -> + ?assertEqual(#xmlel{name = <<"root">>}, + xml_stream:parse_element(<<"">>)). + +empty_tag_with_ns_test() -> + ?assertEqual(#xmlel{name = <<"root">>, attrs = [{<<"xmlns">>, <<"ns">>}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_cdata_test() -> + ?assertEqual(#xmlel{name = <<"root">>, + children = [{xmlcdata, <<"cdata">>}]}, + xml_stream:parse_element(<<"cdata">>)). + +tag_with_attrs_test() -> + ?assertEqual(#xmlel{name = <<"root">>, + attrs = [{<<"a">>, <<"1">>}, {<<"b">>, <<"2">>}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_empty_attr_test() -> + ?assertEqual(#xmlel{name = <<"root">>, attrs = [{<<"a">>, <<>>}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_prefix_test() -> + ?assertEqual(#xmlel{name = <<"prefix:root">>, + attrs = [{<<"xmlns:prefix">>, <<"ns">>}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_prefix_children1_test() -> + ?assertEqual(#xmlel{name = <<"prefix:root">>, + attrs = [{<<"xmlns:prefix">>, <<"ns">>}], + children = [#xmlel{name = <<"prefix:a">>}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_prefix_children2_test() -> + ?assertEqual(#xmlel{name = <<"prefix:root">>, + attrs = [{<<"xmlns:prefix">>, <<"ns">>}], + children = [#xmlel{name = <<"a">>, attrs=[{<<"xmlns">>, <<"ns2">>}]}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_prefix_children3_test() -> + ?assertEqual(#xmlel{name = <<"prefix:root">>, + attrs = [{<<"xmlns:prefix">>, <<"ns">>}], + children = [#xmlel{name = <<"zed:a">>, attrs=[{<<"xmlns:zed">>, <<"ns2">>}]}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_prefix_children4_test() -> + ?assertEqual(#xmlel{name = <<"prefix:root">>, + attrs = [{<<"xmlns:prefix">>, <<"ns">>}], + children = [#xmlel{name = <<"a">>, attrs=[{<<"xmlns">>, <<"ns">>}]}]}, + xml_stream:parse_element(<<"">>)). + +tag_with_attr_with_prefix_test() -> + ?assertEqual(#xmlel{name = <<"root">>, + attrs = [{<<"xmlns:prefix1">>, <<"ns1">>}, + {<<"xmlns:prefix2">>, <<"ns2">>}, + {<<"prefix1:a">>, <<"1">>}, + {<<"prefix2:b">>, <<"2">>}]}, + xml_stream:parse_element(<< + "">>)). + +tag_with_tags_test() -> + ?assertEqual(#xmlel{name = <<"root">>, + children = [#xmlel{name = <<"a">>}, + {xmlcdata, <<"cdata1">>}, + #xmlel{name = <<"b">>}, + {xmlcdata, <<"cdata2">>}]}, + xml_stream:parse_element(<<"cdata1cdata2">>)). + +receiver(Acc) -> + receive + {'$gen_event', Msg} -> + receiver([Msg|Acc]); + {get, Parent} -> + Parent ! lists:reverse(Acc), + receiver([]) + end. + +collect_events(Pid) -> + Pid ! {get, self()}, + receive + Events -> + Events + end. + +stream_test() -> + CallbackPid = spawn_link(fun() -> receiver([]) end), + Stream0 = new(CallbackPid), + Data = [<<"">>, + <<"junk1">>, <<"">>, <<"junk2">>, <<"cdata">>, + <<"junk3">>, <<"">>], + StreamN = lists:foldl( + fun(Chunk, Stream) -> + xml_stream:parse(Stream, Chunk) + end, Stream0, Data), + close(StreamN), + ?assertEqual( + [{xmlstreamstart, <<"prefix:root">>, [{<<"xmlns:prefix">>, <<"ns">>}, + {<<"prefix:r">>, <<"1">>}]}, + {xmlstreamelement, #xmlel{name = <<"a">>}}, + {xmlstreamelement, #xmlel{name = <<"b">>, + children = [{xmlcdata, <<"cdata">>}]}}, + {xmlstreamend, <<"prefix:root">>}], + collect_events(CallbackPid)). + +stream_normalized_ns_test() -> + CallbackPid = spawn_link(fun() -> receiver([]) end), + Stream0 = new(CallbackPid), + Data = [<<"">>, + <<"junk1">>, <<"">>, + <<"">>, + <<"">>, <<"">>, + <<"">>, <<"">>, + <<"">>, <<"">>, + <<"">>, + <<"junk2">>, <<"cdata">>, + <<"junk3">>, <<"">>], + StreamN = lists:foldl( + fun(Chunk, Stream) -> + xml_stream:parse(Stream, Chunk) + end, Stream0, Data), + close(StreamN), + ?assertEqual( + [{xmlstreamstart, <<"prefix:root">>, [{<<"xmlns">>, <<"ns0">>}, + {<<"xmlns:t">>, <<"ns1">>}, + {<<"xmlns:prefix">>, <<"ns">>}, + {<<"prefix:r">>, <<"1">>}]}, + {xmlstreamelement, #xmlel{name = <<"a">>}}, + {xmlstreamelement, #xmlel{name = <<"t:a">>, + children=[#xmlel{name = <<"b">>, + attrs=[{<<"xmlns">>, <<"ns2">>}, {<<"xmlns:s">>, <<"ns2">>}], + children=[#xmlel{name = <<"c">>, + attrs=[{<<"xmlns">>, <<"ns0">>}]}]}]}}, + {xmlstreamelement, #xmlel{name = <<"prefix:n1">>}}, + {xmlstreamelement, #xmlel{name = <<"prefix:n1">>}}, + {xmlstreamelement, #xmlel{name = <<"a">>, attrs=[{<<"xmlns">>, <<"ns5">>}], + children=[#xmlel{name = <<"b">>}, #xmlel{name = <<"t:c">>}]}}, + {xmlstreamelement, #xmlel{name = <<"n2">>, attrs=[{<<"xmlns">>, <<"2">>}]}}, + {xmlstreamelement, #xmlel{name = <<"t:n3">>}}, + {xmlstreamelement, #xmlel{name = <<"n4">>, attrs=[{<<"xmlns">>, <<"3">>}, {<<"xmlns:v">>, <<"3">>}]}}, + {xmlstreamelement, #xmlel{name = <<"n5">>, attrs=[{<<"xmlns">>, <<"n4">>}, {<<"xmlns:prefix">>, <<"n4">>}], + children=[#xmlel{name = <<"e1">>, attrs=[{<<"xmlns">>, <<"ns0">>}]}, + #xmlel{name = <<"e2">>}]}}, + {xmlstreamelement, #xmlel{name = <<"b">>, + children = [{xmlcdata, <<"cdata">>}]}}, + {xmlstreamend, <<"prefix:root">>}], + collect_events(CallbackPid)). + +stream_reset_test() -> + CallbackPid = spawn_link(fun() -> receiver([]) end), + S0 = new(CallbackPid), + S1 = xml_stream:parse(S0, <<"">>), + S2 = xml_stream:reset(S1), + S3 = xml_stream:parse(S2, <<"">>), + close(S3), + ?assertEqual( + [{xmlstreamstart, <<"a">>, [{<<"xmlns">>, <<"ns1">>}]}, + {xmlstreamelement, #xmlel{name = <<"b">>}}, + {xmlstreamstart, <<"a">>, []}, + {xmlstreamelement, #xmlel{name = <<"b">>}}, + {xmlstreamend, <<"a">>}], + collect_events(CallbackPid)). +stream_error_test() -> + CallbackPid = spawn_link(fun() -> receiver([]) end), + S0 = new(CallbackPid), + S1 = xml_stream:parse(S0, <<"a">>), + close(S1), + ?assertEqual( + [{xmlstreamstart, <<"a">>, []}, + {xmlstreamerror, {7, <<"mismatched tag">>}}], + collect_events(CallbackPid)). + +stream_with_joined_cdata_test() -> + CallbackPid = spawn_link(fun() -> receiver([]) end), + Stream0 = new(CallbackPid), + Data = [<<"">>, <<"">>, <<"1">>, <<"2">>, <<"3">>, + <<"">>, <<"">>], + StreamN = lists:foldl( + fun(Chunk, Stream) -> + xml_stream:parse(Stream, Chunk) + end, Stream0, Data), + close(StreamN), + ?assertEqual( + [{xmlstreamstart, <<"root">>, []}, + {xmlstreamelement, #xmlel{name = <<"a">>, + children = [{xmlcdata, <<"123">>}]}}, + {xmlstreamend, <<"root">>}], + collect_events(CallbackPid)). + +splitted_stream_test() -> + CallbackPid = spawn_link(fun() -> receiver([]) end), + Stream0 = new(CallbackPid), + Stream1 = xml_stream:parse(Stream0, <<">), + ?assertEqual([], collect_events(CallbackPid)), + Stream2 = xml_stream:parse(Stream1, <<">">>), + ?assertEqual([{xmlstreamstart, <<"root">>, []}], + collect_events(CallbackPid)), + Stream3 = xml_stream:parse(Stream2, <<">}}, + {xmlstreamelement, #xmlel{name = <<"b">>}}], + collect_events(CallbackPid)), + Stream4 = xml_stream:parse(Stream3, <<"'1'>">>), + ?assertEqual([{xmlstreamelement, #xmlel{name = <<"c">>, + attrs = [{<<"attr">>, <<"1">>}]}}], + collect_events(CallbackPid)), + Stream5 = xml_stream:parse(Stream4, <<"">>), + ?assertEqual([], collect_events(CallbackPid)), + Stream6 = xml_stream:parse(Stream5, <<"">>), + ?assertEqual([{xmlstreamend, <<"root">>}], collect_events(CallbackPid)), + close(Stream6). + +too_big_test() -> + CallbackPid = spawn_link(fun() -> receiver([]) end), + Stream0 = new(CallbackPid, 5), + Stream1 = xml_stream:parse(Stream0, <<"">>), + Stream2 = xml_stream:parse(Stream1, <<"">>), + Stream3 = xml_stream:parse(Stream2, <<"">>), + Stream4 = xml_stream:parse(Stream3, <<"">>), + ?assertEqual([{xmlstreamstart, <<"a">>, []}, + {xmlstreamelement, #xmlel{name = <<"b">>}}, + {xmlstreamelement, #xmlel{name = <<"c">>}}, + {xmlstreamerror, <<"XML stanza is too big">>}], + collect_events(CallbackPid)), + close(Stream4). + +close_close_test() -> + Stream = new(), + close(Stream), + ?assertError(badarg, xml_stream:close(Stream)). + +close_parse_test() -> + Stream = new(), + close(Stream), + ?assertError(badarg, xml_stream:parse(Stream, <<"junk">>)). + +close_change_callback_pid_test() -> + Stream = new(), + close(Stream), + ?assertError(badarg, xml_stream:change_callback_pid(Stream, self())). + +change_callback_pid_test() -> + Pid1 = spawn_link(fun() -> receiver([]) end), + Pid2 = spawn_link(fun() -> receiver([]) end), + Stream0 = new(Pid1), + Stream1 = xml_stream:parse(Stream0, <<"">>), + ?assertEqual([{xmlstreamstart, <<"root">>, []}], + collect_events(Pid1)), + Stream2 = xml_stream:change_callback_pid(Stream1, Pid2), + Stream3 = xml_stream:parse(Stream2, <<"">>), + ?assertEqual([{xmlstreamend, <<"root">>}], + collect_events(Pid2)), + close(Stream3). + +badarg_new_test() -> + ?assertError(badarg, xml_stream:new(1)), + ?assertError(badarg, xml_stream:new(self(), unlimited)), + ?assertError(badarg, xml_stream:new(foo, fun() -> ok end)). + +badarg_parse_test() -> + Stream = new(), + ?assertError(badarg, xml_stream:parse(1, <<"">>)), + ?assertError(badarg, xml_stream:parse(<<>>, "")), + ?assertError(badarg, xml_stream:parse(Stream, blah)), + ?assertError(badarg, xml_stream:parse(foo, fun() -> ok end)), + close(Stream). + +badarg_change_callback_pid_test() -> + Stream = new(), + ?assertError(badarg, xml_stream:change_callback_pid(1, self())), + ?assertError(badarg, xml_stream:change_callback_pid(<<>>, self())), + ?assertError(badarg, xml_stream:change_callback_pid(Stream, foo)), + ?assertError(badarg, xml_stream:change_callback_pid(foo, fun() -> ok end)), + close(Stream). + +badarg_close_test() -> + Stream = new(), + ?assertError(badarg, xml_stream:close(1)), + ?assertError(badarg, xml_stream:close(<<>>)), + close(Stream). + +badarg_parse_element_test() -> + ?assertError(badarg, xml_stream:parse_element(1)). + +parse_error_test() -> + L = ["<", "<>", "", "", "/>", + "", "x/>", "junk", + "", "", "", + "", ""], + lists:foreach( + fun(S) -> + ?assertMatch({error, _}, xml_stream:parse_element(list_to_binary(S))) + end, L). + +dead_pid_test() -> + CallbackPid = spawn(fun() -> receiver([]) end), + ?assertEqual(true, exit(CallbackPid, kill)), + ?assertEqual(false, is_process_alive(CallbackPid)), + Stream0 = new(CallbackPid), + Stream1 = xml_stream:parse(Stream0, <<"">>), + close(Stream1). + +huge_element_test_() -> + {timeout, 60, + fun() -> + Tags = [list_to_binary(["a", integer_to_list(I)]) + || I <- lists:seq(1, 100000)], + Data = ["", [[$<, Tag, "/>"] || Tag <- Tags], ""], + Els = #xmlel{name = <<"root">>, + children = [#xmlel{name = Tag} || Tag <- Tags]}, + ?assertEqual(Els, xml_stream:parse_element(iolist_to_binary(Data))) + end}. + +many_stream_elements_test_() -> + {timeout, 60, + fun() -> + CallbackPid = spawn(fun() -> receiver([]) end), + Stream0 = new(CallbackPid), + Stream1 = xml_stream:parse(Stream0, <<"">>), + ?assertEqual([{xmlstreamstart, <<"root">>, []}], + collect_events(CallbackPid)), + Stream2 = lists:foldl( + fun(I, Stream) -> + Tag = list_to_binary(["a", integer_to_list(I)]), + NewStream = xml_stream:parse(Stream, iolist_to_binary([$<, Tag, "/>"])), + ?assertEqual([{xmlstreamelement, #xmlel{name = Tag}}], + collect_events(CallbackPid)), + NewStream + end, Stream1, lists:seq(1, 100000)), + close(Stream2) + end}. + +billionlaughs_test() -> + Data = << + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "] >\n">>, + CallbackPid = spawn_link(fun() -> receiver([]) end), + Stream0 = new(CallbackPid), + Stream1 = xml_stream:parse(Stream0, Data), + close(Stream1), + ?assertMatch([{xmlstreamerror, _}], collect_events(CallbackPid)). + +element_to_binary_test() -> + ?assertEqual( + <<"" + "">>, + xml:element_to_binary( + #xmlel{name = <<"iq">>, + attrs = [{<<"from">>,<<"hag66@shakespeare.lit/pda">>}, + {<<"id">>,<<"ik3vs715">>}, + {<<"to">>,<<"coven@chat.shakespeare.lit">>}, + {<<"type">>,<<"get">>}], + children = [#xmlel{name = <<"query">>, + attrs = [{<<"xmlns">>, + <<"http://jabber.org/protocol/disco#info">>}], + children = []}]})). + +crypt_test() -> + ?assertEqual( + <<"a&b<c>d"e'f">>, + xml:crypt(<<"a&bd\"e\'f">>)). + +remove_cdata_test() -> + ?assertEqual( + [#xmlel{name = <<"b">>}], + xml:remove_cdata( + [{xmlcdata, <<"x">>}, + {xmlcdata, <<"y">>}, + #xmlel{name = <<"b">>}, + {xmlcdata, <<"z">>}])). + +remove_subtags_test() -> + ?assertMatch( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"2">>, + attrs = [{<<"n1">>, <<"v1">>}]}, + #xmlel{name = <<"1">>, + attrs = [{<<"n1">>, <<"v2">>}]}, + #xmlel{name = <<"1">>, + attrs = [{<<"n2">>, <<"v1">>}]}, + #xmlel{name = <<"3">>}]}, + xml:remove_subtags( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>, + attrs = [{<<"n1">>, <<"v1">>}]}, + #xmlel{name = <<"2">>, + attrs = [{<<"n1">>, <<"v1">>}]}, + #xmlel{name = <<"1">>, + attrs = [{<<"n1">>, <<"v2">>}]}, + #xmlel{name = <<"1">>, + attrs = [{<<"n2">>, <<"v1">>}]}, + #xmlel{name = <<"1">>, + attrs = [{<<"n1">>, <<"v1">>}]}, + #xmlel{name = <<"3">>}]}, + <<"1">>, {<<"n1">>, <<"v1">>})). + +get_cdata_test() -> + ?assertEqual( + <<"xyz">>, + xml:get_cdata( + [{xmlcdata, <<"x">>}, + {xmlcdata, <<"y">>}, + #xmlel{name = <<"b">>}, + {xmlcdata, <<"z">>}])). + +get_tag_cdata_test() -> + ?assertEqual( + <<"xyz">>, + xml:get_tag_cdata( + #xmlel{name = <<"a">>, + children = [{xmlcdata, <<"x">>}, + {xmlcdata, <<"y">>}, + #xmlel{name = <<"b">>}, + {xmlcdata, <<"z">>}]})). + +get_attr_test() -> + ?assertEqual( + {value, <<"2">>}, + xml:get_attr( + <<"y">>, + [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}])). + +get_attr_empty_test() -> + ?assertEqual( + false, + xml:get_attr( + <<"a">>, + [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}])). + +get_attr_s_test() -> + ?assertEqual( + <<"2">>, + xml:get_attr_s( + <<"y">>, + [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}])). + +get_attr_s_empty_test() -> + ?assertEqual( + <<"">>, + xml:get_attr_s( + <<"a">>, + [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}])). + +get_tag_attr_test() -> + ?assertEqual( + {value, <<"2">>}, + xml:get_tag_attr( + <<"y">>, + #xmlel{name = <<"foo">>, + attrs = [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}]})). + +get_tag_attr_empty_test() -> + ?assertEqual( + false, + xml:get_tag_attr( + <<"a">>, + #xmlel{name = <<"foo">>, + attrs = [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}]})). + +get_tag_attr_s_test() -> + ?assertEqual( + <<"2">>, + xml:get_tag_attr_s( + <<"y">>, + #xmlel{name = <<"foo">>, + attrs = [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}]})). + +get_tag_attr_s_empty_test() -> + ?assertEqual( + <<"">>, + xml:get_tag_attr_s( + <<"a">>, + #xmlel{name = <<"foo">>, + attrs = [{<<"x">>, <<"1">>}, + {<<"y">>, <<"2">>}, + {<<"z">>, <<"3">>}]})). + +get_subtag_test() -> + ?assertMatch( + #xmlel{name = <<"2">>}, + xml:get_subtag( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>}, + #xmlel{name = <<"3">>}]}, + <<"2">>)). + +get_subtag_false_test() -> + ?assertMatch( + false, + xml:get_subtag( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>}, + #xmlel{name = <<"3">>}]}, + <<"4">>)). + +get_subtags_test() -> + ?assertMatch( + [#xmlel{name = <<"1">>, attrs = [{<<"a">>, <<"b">>}]}, + #xmlel{name = <<"1">>, attrs = [{<<"x">>, <<"y">>}]}], + xml:get_subtags( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>, + attrs = [{<<"a">>, <<"b">>}]}, + #xmlel{name = <<"2">>}, + #xmlel{name = <<"3">>}, + #xmlel{name = <<"1">>, + attrs = [{<<"x">>, <<"y">>}]}]}, + <<"1">>)). + +get_subtags_empty_test() -> + ?assertEqual( + [], + xml:get_subtags( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>}, + #xmlel{name = <<"3">>}]}, + <<"4">>)). + +get_subtag_with_xmlns_test() -> + ?assertMatch( + #xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + xml:get_subtag_with_xmlns( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>, + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + #xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns2">>}]}, + #xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + #xmlel{name = <<"3">>, + attrs = [{<<"xmlns">>, <<"ns2">>}]}]}, + <<"2">>, <<"ns1">>)). + +get_subtag_with_xmlns_empty_test() -> + ?assertMatch( + false, + xml:get_subtag_with_xmlns( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>, + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + #xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns2">>}]}, + #xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + #xmlel{name = <<"3">>, + attrs = [{<<"xmlns">>, <<"ns2">>}]}]}, + <<"4">>, <<"ns2">>)). + +get_subtags_with_xmlns_test() -> + ?assertMatch( + [#xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns1">>}], + children = [{xmlcdata, <<"foo">>}]}, + #xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns1">>}], + children = [{xmlcdata, <<"bar">>}]}], + xml:get_subtags_with_xmlns( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>, + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + #xmlel{name = <<"2">>, + children = [{xmlcdata, <<"foo">>}], + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + #xmlel{name = <<"2">>, + attrs = [{<<"xmlns">>, <<"ns2">>}]}, + #xmlel{name = <<"2">>, + children = [{xmlcdata, <<"bar">>}], + attrs = [{<<"xmlns">>, <<"ns1">>}]}, + #xmlel{name = <<"3">>, + attrs = [{<<"xmlns">>, <<"ns2">>}]}]}, + <<"2">>, <<"ns1">>)). + +get_subtag_cdata_test() -> + ?assertEqual( + <<"ab">>, + xml:get_subtag_cdata( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>, + children = [{xmlcdata, <<"a">>}, + #xmlel{name = <<"3">>}, + {xmlcdata, <<"b">>}]}, + #xmlel{name = <<"2">>}]}, + <<"1">>)). + +get_subtag_cdata_empty_test() -> + ?assertEqual( + <<"">>, + xml:get_subtag_cdata( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"2">>}]}, + <<"1">>)). + +append_subtags_test() -> + ?assertMatch( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>}, + #xmlel{name = <<"3">>}]}, + xml:append_subtags( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}]}, + [#xmlel{name = <<"2">>}, #xmlel{name = <<"3">>}])). + +get_path_s_tag_test() -> + ?assertMatch( + #xmlel{name = <<"2">>}, + xml:get_path_s( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>}]}, + [{elem, <<"2">>}])). + +get_path_s_empty_tag_test() -> + ?assertEqual( + <<"">>, + xml:get_path_s( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>}]}, + [{elem, <<"3">>}])). + +get_path_s_attr_test() -> + ?assertEqual( + <<"v1">>, + xml:get_path_s( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"a">>, + children = + [#xmlel{name = <<"a1">>, + attrs = [{<<"x">>, <<"y">>}, + {<<"n1">>, <<"v1">>}]}, + #xmlel{name = <<"b">>}]}, + #xmlel{name = <<"b">>}]}, + [{elem, <<"a">>}, {elem, <<"a1">>}, {attr, <<"n1">>}])). + +get_path_s_cdata_test() -> + ?assertEqual( + <<"d1">>, + xml:get_path_s( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"a">>, + children = [#xmlel{name = <<"a1">>}, + {xmlcdata, <<"d1">>}]}, + #xmlel{name = <<"b">>}]}, + [{elem, <<"a">>}, cdata])). + +replace_tag_attr_test() -> + ?assertMatch( + #xmlel{name = <<"foo">>, + attrs = [{<<"2">>, <<"d">>}, + {<<"1">>, <<"a">>}, + {<<"2">>, <<"c">>}]}, + xml:replace_tag_attr( + <<"2">>, <<"d">>, + #xmlel{name = <<"foo">>, + attrs = [{<<"1">>, <<"a">>}, + {<<"2">>, <<"b">>}, + {<<"2">>, <<"c">>}]})). + +replace_subtag_test() -> + ?assertMatch( + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"2">>, children = []}, + #xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>, + children = [{xmlcdata, <<"b">>}]}]}, + xml:replace_subtag( + #xmlel{name = <<"2">>}, + #xmlel{name = <<"root">>, + children = [#xmlel{name = <<"1">>}, + #xmlel{name = <<"2">>, + children = [{xmlcdata, <<"a">>}]}, + #xmlel{name = <<"2">>, + children =[{xmlcdata, <<"b">>}]}]})). + +to_xmlel_test() -> + ?assertEqual( + #xmlel{name = <<"foo">>, + attrs = [{<<"a">>, <<"b">>}], + children = [{xmlcdata, <<"xyz">>}]}, + xml:to_xmlel({xmlelement, "foo", [{"a", "b"}], [{xmlcdata, "xyz"}]})). + +rpc_fault_test() -> + Fault = {xmlel,<<"methodResponse">>,[], + [{xmlel,<<"fault">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"struct">>,[], + [{xmlel,<<"member">>,[], + [{xmlel,<<"name">>,[],[{xmlcdata,<<"faultCode">>}]}, + {xmlel,<<"value">>,[], + [{xmlel,<<"int">>,[],[{xmlcdata,<<"4">>}]}]}]}, + {xmlel,<<"member">>,[], + [{xmlel,<<"name">>,[],[{xmlcdata,<<"faultString">>}]}, + {xmlel,<<"value">>,[], + [{xmlel,<<"string">>,[], + [{xmlcdata,<<"Too many parameters.">>}]}]}]}]}]}]}]}, + Result = {response, {fault, 4, <<"Too many parameters.">>}}, + ?assertEqual({ok, Result}, p1_xmlrpc:decode(Fault)), + ?assertEqual(Fault, p1_xmlrpc:encode(Result)). + +rpc_call_test() -> + Call = {xmlel,<<"methodCall">>,[], + [{xmlel,<<"methodName">>,[],[{xmlcdata,<<"examples.getStateName">>}]}, + {xmlel,<<"params">>,[], + [{xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"int">>,[],[{xmlcdata,<<"40">>}]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"int">>,[],[{xmlcdata,<<"30">>}]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"boolean">>,[],[{xmlcdata,<<"0">>}]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"base64">>,[], + [{xmlcdata,<<"eW91IGNhbid0IHJlYWQgdGhpcyE=">>}]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"dateTime.iso8601">>,[], + [{xmlcdata,<<"19980717T14:08:55">>}]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"string">>,[], + [{xmlcdata,<<"Hello world!">>}]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[],[{xmlel,<<"nil">>,[],[]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"array">>,[], + [{xmlel,<<"data">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"int">>,[], + [{xmlcdata,<<"1404">>}]}]}, + {xmlel,<<"value">>,[], + [{xmlel,<<"string">>,[], + [{xmlcdata,<<"Something here">>}]}]}, + {xmlel,<<"value">>,[], + [{xmlel,<<"int">>,[], + [{xmlcdata,<<"1">>}]}]}]}]}]}]}, + {xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"struct">>,[], + [{xmlel,<<"member">>,[], + [{xmlel,<<"name">>,[],[{xmlcdata,<<"foo">>}]}, + {xmlel,<<"value">>,[], + [{xmlel,<<"int">>,[], + [{xmlcdata,<<"1">>}]}]}]}, + {xmlel,<<"member">>,[], + [{xmlel,<<"name">>,[],[{xmlcdata,<<"bar">>}]}, + {xmlel,<<"value">>,[], + [{xmlel,<<"int">>,[], + [{xmlcdata,<<"2">>}]}]}]}]}]}]}]}]}, + Result = {call,'examples.getStateName', + [40,30,false, + {base64,<<"eW91IGNhbid0IHJlYWQgdGhpcyE=">>}, + {date,<<"19980717T14:08:55">>}, + <<"Hello world!">>,nil, + {array,[1404,<<"Something here">>,1]}, + {struct,[{foo,1},{bar,2}]}]}, + ?assertEqual({ok, Result}, p1_xmlrpc:decode(Call)), + ?assertEqual(Call, p1_xmlrpc:encode(Result)). + +response_test() -> + Response = {xmlel,<<"methodResponse">>, [], + [{xmlel,<<"params">>,[], + [{xmlel,<<"param">>,[], + [{xmlel,<<"value">>,[], + [{xmlel,<<"string">>,[], + [{xmlcdata,<<"South Dakota">>}]}]}]}]}]}, + Result = {response,[<<"South Dakota">>]}, + ?assertEqual({ok, Result}, p1_xmlrpc:decode(Response)), + ?assertEqual(Response, p1_xmlrpc:encode(Result)). + +rpc_empty_call_test() -> + Call = {xmlel,<<"methodCall">>,[], + [{xmlel,<<"methodName">>,[], + [{xmlcdata,<<"some_method">>}]}]}, + Result = {call, some_method, []}, + ?assertEqual({ok, Result}, p1_xmlrpc:decode(Call)), + ?assertEqual(Call, p1_xmlrpc:encode(Result)). + +rpc_empty_response_test() -> + Response = {xmlel,<<"methodResponse">>, [], []}, + Result = {response, []}, + ?assertEqual({ok, Result}, p1_xmlrpc:decode(Response)), + ?assertEqual(Response, p1_xmlrpc:encode(Result)). + +application_stop_test() -> + ?assertEqual(ok, application:stop(p1_xml)). diff -Nru erlang-p1-xml-0.2015.04.15/tests/billionlaughs.py erlang-p1-xml-1.1.2/tests/billionlaughs.py --- erlang-p1-xml-0.2015.04.15/tests/billionlaughs.py 2015-05-02 16:49:03.000000000 +0000 +++ erlang-p1-xml-1.1.2/tests/billionlaughs.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -import socket -import time - -host = 'localhost' -port = 5223 - -payload = ''' ] >''' - -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - -s.connect((host, port)) - -ssl_sock = socket.ssl(s) - -print "Payload:\n" + payload + "\n" - -print "Sending XML billion laughs payload:\n" - -ssl_sock.write(payload) - -start = time.time() -data = ssl_sock.read() -end=time.time() - -print "\nOutput:\n"+data -print "\n\nTotal time taken: "+str(end-start)+" seconds" - -# Note that you need to close the underlying socket, not the SSL object. -del ssl_sock -s.close() diff -Nru erlang-p1-xml-0.2015.04.15/.travis.yml erlang-p1-xml-1.1.2/.travis.yml --- erlang-p1-xml-0.2015.04.15/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/.travis.yml 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,21 @@ +sudo: false + +language: erlang + +before_install: + - pip install --user cpp-coveralls coveralls-merge + +install: + - ./configure --enable-gcov + - rebar get-deps + +script: rebar compile xref && rebar skip_deps=true eunit + +after_success: + - coveralls --exclude lib --exclude tests --gcov-options '\-lp' --dump c.json + - coveralls-merge c.json erlang.json + +otp_release: + - 17.1 + - 17.5 + - 18.0 diff -Nru erlang-p1-xml-0.2015.04.15/vars.config.in erlang-p1-xml-1.1.2/vars.config.in --- erlang-p1-xml-0.2015.04.15/vars.config.in 1970-01-01 00:00:00.000000000 +0000 +++ erlang-p1-xml-1.1.2/vars.config.in 2016-01-23 17:21:53.000000000 +0000 @@ -0,0 +1,8 @@ +{cflags, "@CFLAGS@"}. +{ldflags, "@LDFLAGS@ @LIBS@"}. +{with_gcov, "@gcov@"}. + +%% Local Variables: +%% mode: erlang +%% End: +%% vim: set filetype=erlang tabstop=8: