diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..dc441ebb --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/dcap_source"] + path = external/dcap_source + url = git@github.com:intel/SGXDataCenterAttestationPrimitives.git diff --git a/License.txt b/License.txt index 700ae075..5703798c 100644 --- a/License.txt +++ b/License.txt @@ -1,6 +1,6 @@ BSD License -Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +Copyright (C) 2011-2019 Intel Corporation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -1051,9 +1051,9 @@ http://www.stlport.org/doc/license.html -13. TinyXML +13. TinyXML-2 -http://www.grinninglizard.com/tinyxml/ +http://www.grinninglizard.com/tinyxml2/ The zlib/libpng License @@ -1440,3 +1440,242 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +19. C++ Micro Services + +The software is licensed under the liberal and commercially friendly Apache 2.0 License. + + http://cppmicroservices.org/ + + + 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. + + + +20. safecrt +safecrt is part of Microsoft CharkraCore, under MIT License. + + https://github.com/Microsoft/ChakraCore + +The MIT License (MIT) + +Copyright (c) Microsoft Corporation +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c++/sgx_t.mk b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c++/sgx_t.mk index 56fc95e0..46b947f2 100644 --- a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c++/sgx_t.mk +++ b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c++/sgx_t.mk @@ -125,4 +125,4 @@ $(enclaveName).signed.so: $(enclaveName).so @$(SGX_ENCLAVE_SIGNER) sign -key $(TRUSTED_DIR)/$(enclaveName)_private.pem -enclave $(enclaveName).so -out $@ -config $(TRUSTED_DIR)/$(enclaveName).config.xml @echo "SIGN => $@" clean: - @rm -f $(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_Cpp_Objects) $($(EnclaveName)_C_Objects) + @rm -f $(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_Cpp_Objects) $($(EnclaveName)_C_Objects) \ No newline at end of file diff --git a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_t.mk b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_t.mk index 8085fbfa..1634f6fe 100644 --- a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_t.mk +++ b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_t.mk @@ -113,4 +113,4 @@ $(enclaveName).signed.so: $(enclaveName).so @$(SGX_ENCLAVE_SIGNER) sign -key $(TRUSTED_DIR)/$(enclaveName)_private.pem -enclave $(enclaveName).so -out $@ -config $(TRUSTED_DIR)/$(enclaveName).config.xml @echo "SIGN => $@" clean: - @rm -f $(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_C_Objects) + @rm -f $(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_C_Objects) \ No newline at end of file diff --git a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_u.mk b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_u.mk index 500da4bd..c10e5361 100644 --- a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_u.mk +++ b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXEnclave/makefiles/c/sgx_u.mk @@ -124,4 +124,4 @@ sample: $(UNTRUSTED_DIR)/$(enclaveName)_u.o $(App_C_Objects) .PHONY: clean clean: - @rm -f sample $(App_C_Objects) $(UNTRUSTED_DIR)/$(enclaveName)_u.* + @rm -f sample $(App_C_Objects) $(UNTRUSTED_DIR)/$(enclaveName)_u.* \ No newline at end of file diff --git a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c++/sgx_t_static.mk b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c++/sgx_t_static.mk index 548eaac9..d3d485fd 100644 --- a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c++/sgx_t_static.mk +++ b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c++/sgx_t_static.mk @@ -103,4 +103,4 @@ lib$(enclaveName).sgx.static.lib.a: $(TRUSTED_DIR)/$(enclaveName)_t.h $($(Enclav @echo "LINK => $@" clean: - @rm -f lib$(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_Cpp_Objects) $($(EnclaveName)_C_Objects) + @rm -f lib$(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_Cpp_Objects) $($(EnclaveName)_C_Objects) \ No newline at end of file diff --git a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c/sgx_t_static.mk b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c/sgx_t_static.mk index d91c0e38..b49932ac 100644 --- a/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c/sgx_t_static.mk +++ b/Linux_SGXEclipsePlugin/build_directory/plugins/com.intel.sgx/templates/sgx/SGXTrustedStaticLibrary/makefiles/c/sgx_t_static.mk @@ -93,4 +93,4 @@ lib$(enclaveName).sgx.static.lib.a: $(TRUSTED_DIR)/$(enclaveName)_t.h $($(Enclav @echo "LINK => $@" clean: - @rm -f lib$(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_C_Objects) + @rm -f lib$(enclaveName).* $(TRUSTED_DIR)/$(enclaveName)_t.* $($(EnclaveName)_C_Objects) \ No newline at end of file diff --git a/Makefile b/Makefile index 1cf41f12..94fc47d8 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -30,14 +30,18 @@ # include buildenv.mk -.PHONY: all psw sdk clean rebuild sdk_install_pkg psw_install_pkg +.PHONY: all dcap_source psw sdk clean rebuild sdk_install_pkg psw_install_pkg +.NOTPARALLEL: dcap_source sdk psw -all: sdk psw +all: dcap_source sdk psw -psw: sdk +dcap_source: + git submodule update --init --recursive + +psw: dcap_source sdk $(MAKE) -C psw/ USE_OPT_LIBS=$(USE_OPT_LIBS) -sdk: +sdk: dcap_source $(MAKE) -C sdk/ USE_OPT_LIBS=$(USE_OPT_LIBS) # Generate SE SDK Install package @@ -65,8 +69,27 @@ clean: @$(MAKE) -C psw/ clean @$(RM) -r $(ROOT_DIR)/build @$(RM) -r linux/installer/bin/sgx_linux*.bin + @$(RM) -r linux/installer/deb/libsgx-enclave-common/libsgx-enclave-common-dbgsym_* + @$(RM) -r linux/installer/deb/libsgx-enclave-common/libsgx-enclave-common_*.tar.* + @$(RM) -r linux/installer/deb/libsgx-enclave-common/libsgx-enclave-common_*_amd64.* + @$(RM) -r linux/installer/deb/libsgx-enclave-common/libsgx-enclave-common_*.dsc + @$(RM) -r linux/installer/deb/libsgx-enclave-common-dev/libsgx-enclave-common-dev*.deb + @$(RM) -r linux/installer/deb/libsgx-enclave-common-dev/libsgx-enclave-common_*.tar.* + @$(RM) -r linux/installer/deb/libsgx-enclave-common-dev/libsgx-enclave-common_*_amd64.* + @$(RM) -r linux/installer/deb/libsgx-enclave-common-dev/libsgx-enclave-common_*.dsc + @$(RM) -r linux/installer/deb/libsgx-urts/libsgx-enclave-common_*.tar.* + @$(RM) -r linux/installer/deb/libsgx-urts/libsgx-enclave-common_*_amd64.* + @$(RM) -r linux/installer/deb/libsgx-urts/libsgx-urts_*.deb + @$(RM) -r linux/installer/deb/*.deb + @$(RM) -r linux/installer/deb/*.ddeb @$(RM) -rf linux/installer/common/psw/output @$(RM) -rf linux/installer/common/psw/gen_source.py + @$(RM) -rf linux/installer/common/libsgx-enclave-common/output + @$(RM) -rf linux/installer/common/libsgx-enclave-common/gen_source.py + @$(RM) -rf linux/installer/common/libsgx-enclave-common-dev/output + @$(RM) -rf linux/installer/common/libsgx-enclave-common-dev/gen_source.py + @$(RM) -rf linux/installer/common/libsgx-urts/output + @$(RM) -rf linux/installer/common/libsgx-urts/gen_source.py @$(RM) -rf linux/installer/common/sdk/output @$(RM) -rf linux/installer/common/sdk/pkgconfig/x64 @$(RM) -rf linux/installer/common/sdk/pkgconfig/x86 diff --git a/README.md b/README.md index 262a10fe..bfe3861a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + Intel(R) Software Guard Extensions for Linux\* OS ================================================ @@ -70,15 +71,15 @@ Build the Intel(R) SGX SDK and Intel(R) SGX PSW Package - Use the following command to install additional required tools to build the Intel(R) SGX PSW: * On Ubuntu 16.04 and Ubuntu 18.04: ``` - $ sudo apt-get install libssl-dev libcurl4-openssl-dev protobuf-compiler libprotobuf-dev debhelper + $ sudo apt-get install libssl-dev libcurl4-openssl-dev protobuf-compiler libprotobuf-dev debhelper cmake ``` * On Red Hat Enterprise Linux 7.4, CentOS 7.5 and Fedora 27: ``` - $ sudo yum install openssl-devel libcurl-devel protobuf-devel + $ sudo yum install openssl-devel libcurl-devel protobuf-devel cmake ``` * On SUSE Linux Enterprise Server 12: ``` - $ sudo zypper install libopenssl-devel libcurl-devel protobuf-devel + $ sudo zypper install libopenssl-devel libcurl-devel protobuf-devel cmake ``` - Use the script ``download_prebuilt.sh`` inside source code package to download prebuilt binaries to prebuilt folder You may need set an https proxy for the `wget` tool used by the script (such as ``export https_proxy=http://test-proxy:test-port``) @@ -312,6 +313,15 @@ To install the Intel(R) SGX PSW, invoke the installer with root privilege: $ cd linux/installer/bin $ sudo ./sgx_linux_x64_psw_${version}.bin ``` +### ECDSA attestation +To enable ECDSA attestation +- Ensure that you have the following required hardware: + * 8th Generation Intel(R) Core(TM) Processor or newer with **Flexible Launch Control** support* + * Intel(R) Atom(TM) Processor with **Flexible Launch Control** support* +- Ensure the PCS caching service is setup correctly by local administrator or data center administrator. Also make sure that if the PCS server is not on local machine, the configure file (/etc/sgx_default_qcnl.conf) needs to be consistent with the real environment, for example: +PCS_URL=https://your_pcs_server:8081/sgx/certification/v1/ +- For how to install and configure PCK Caching Service, please go to https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/master/QuoteGeneration + ### Start or Stop aesmd Service The Intel(R) SGX PSW installer installs an aesmd service in your machine, which is running in a special linux account `aesmd`. To stop the service: `$ sudo service aesmd stop` @@ -323,3 +333,4 @@ The aesmd service uses the HTTP protocol to initialize some services. If a proxy is required for the HTTP protocol, you may need to manually set up the proxy for the aesmd service. You should manually edit the file `/etc/aesmd.conf` (refer to the comments in the file) to set the proxy for the aesmd service. After you configure the proxy, you need to restart the service to enable the proxy. + diff --git a/SampleCode/Cxx11SGXDemo/App/App.cpp b/SampleCode/Cxx11SGXDemo/App/App.cpp index 8d0bafe8..baf4f04f 100644 --- a/SampleCode/Cxx11SGXDemo/App/App.cpp +++ b/SampleCode/Cxx11SGXDemo/App/App.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/App/App.h b/SampleCode/Cxx11SGXDemo/App/App.h index 3e3b94bc..3b049748 100644 --- a/SampleCode/Cxx11SGXDemo/App/App.h +++ b/SampleCode/Cxx11SGXDemo/App/App.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/App/TrustedLibrary/Libcxx.cpp b/SampleCode/Cxx11SGXDemo/App/TrustedLibrary/Libcxx.cpp index 016fbab7..dbcfbe98 100644 --- a/SampleCode/Cxx11SGXDemo/App/TrustedLibrary/Libcxx.cpp +++ b/SampleCode/Cxx11SGXDemo/App/TrustedLibrary/Libcxx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/Enclave/Enclave.cpp b/SampleCode/Cxx11SGXDemo/Enclave/Enclave.cpp index 7982f49e..8492c281 100644 --- a/SampleCode/Cxx11SGXDemo/Enclave/Enclave.cpp +++ b/SampleCode/Cxx11SGXDemo/Enclave/Enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/Enclave/Enclave.edl b/SampleCode/Cxx11SGXDemo/Enclave/Enclave.edl index e20994e3..9cc2b2a3 100644 --- a/SampleCode/Cxx11SGXDemo/Enclave/Enclave.edl +++ b/SampleCode/Cxx11SGXDemo/Enclave/Enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/Enclave/Enclave.h b/SampleCode/Cxx11SGXDemo/Enclave/Enclave.h index 20f8f897..5a41305e 100644 --- a/SampleCode/Cxx11SGXDemo/Enclave/Enclave.h +++ b/SampleCode/Cxx11SGXDemo/Enclave/Enclave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.cpp b/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.cpp index 2da47854..10f465c6 100644 --- a/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.cpp +++ b/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.edl b/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.edl index a7f3ab27..6a2021a4 100644 --- a/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.edl +++ b/SampleCode/Cxx11SGXDemo/Enclave/TrustedLibrary/Libcxx.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Cxx11SGXDemo/Makefile b/SampleCode/Cxx11SGXDemo/Makefile index d1491ab2..b8acc15d 100644 --- a/SampleCode/Cxx11SGXDemo/Makefile +++ b/SampleCode/Cxx11SGXDemo/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -138,6 +138,9 @@ Enclave_Include_Paths := -IEnclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/lib Enclave_C_Flags := -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++ +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -145,7 +148,8 @@ Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++ # Use `--start-group' and `--end-group' to link these libraries. # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. # Otherwise, you may get some undesirable errors. -Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/Cxx11SGXDemo/README.txt b/SampleCode/Cxx11SGXDemo/README.txt index 0acdaee9..13a921a1 100644 --- a/SampleCode/Cxx11SGXDemo/README.txt +++ b/SampleCode/Cxx11SGXDemo/README.txt @@ -44,3 +44,11 @@ How to Build/Execute the C++11 sample program 4. Execute the binary directly: $ ./app 5. Remember to "make clean" before switching build mode + +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/SampleCode/LocalAttestation/App/App.cpp b/SampleCode/LocalAttestation/App/App.cpp index 9a9a0a5c..a3e22fb9 100644 --- a/SampleCode/LocalAttestation/App/App.cpp +++ b/SampleCode/LocalAttestation/App/App.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave1/Enclave1.cpp b/SampleCode/LocalAttestation/Enclave1/Enclave1.cpp index 043f43bc..b7b5347e 100644 --- a/SampleCode/LocalAttestation/Enclave1/Enclave1.cpp +++ b/SampleCode/LocalAttestation/Enclave1/Enclave1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave1/Enclave1.edl b/SampleCode/LocalAttestation/Enclave1/Enclave1.edl index b986919d..1efea10e 100644 --- a/SampleCode/LocalAttestation/Enclave1/Enclave1.edl +++ b/SampleCode/LocalAttestation/Enclave1/Enclave1.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave1/Utility_E1.cpp b/SampleCode/LocalAttestation/Enclave1/Utility_E1.cpp index 6b6aea6b..6a2f7bc4 100644 --- a/SampleCode/LocalAttestation/Enclave1/Utility_E1.cpp +++ b/SampleCode/LocalAttestation/Enclave1/Utility_E1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave1/Utility_E1.h b/SampleCode/LocalAttestation/Enclave1/Utility_E1.h index c0d6373a..0cf61d23 100644 --- a/SampleCode/LocalAttestation/Enclave1/Utility_E1.h +++ b/SampleCode/LocalAttestation/Enclave1/Utility_E1.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave2/Enclave2.cpp b/SampleCode/LocalAttestation/Enclave2/Enclave2.cpp index bce517d8..874afa73 100644 --- a/SampleCode/LocalAttestation/Enclave2/Enclave2.cpp +++ b/SampleCode/LocalAttestation/Enclave2/Enclave2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave2/Enclave2.edl b/SampleCode/LocalAttestation/Enclave2/Enclave2.edl index 4e0c0094..18b263ef 100644 --- a/SampleCode/LocalAttestation/Enclave2/Enclave2.edl +++ b/SampleCode/LocalAttestation/Enclave2/Enclave2.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave2/Utility_E2.cpp b/SampleCode/LocalAttestation/Enclave2/Utility_E2.cpp index b580758a..210e08d2 100644 --- a/SampleCode/LocalAttestation/Enclave2/Utility_E2.cpp +++ b/SampleCode/LocalAttestation/Enclave2/Utility_E2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave2/Utility_E2.h b/SampleCode/LocalAttestation/Enclave2/Utility_E2.h index e8b4aefc..28f1b740 100644 --- a/SampleCode/LocalAttestation/Enclave2/Utility_E2.h +++ b/SampleCode/LocalAttestation/Enclave2/Utility_E2.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave3/Enclave3.cpp b/SampleCode/LocalAttestation/Enclave3/Enclave3.cpp index ddced88b..65298f75 100644 --- a/SampleCode/LocalAttestation/Enclave3/Enclave3.cpp +++ b/SampleCode/LocalAttestation/Enclave3/Enclave3.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave3/Enclave3.edl b/SampleCode/LocalAttestation/Enclave3/Enclave3.edl index a1e83a9d..ddc046c4 100644 --- a/SampleCode/LocalAttestation/Enclave3/Enclave3.edl +++ b/SampleCode/LocalAttestation/Enclave3/Enclave3.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave3/Utility_E3.cpp b/SampleCode/LocalAttestation/Enclave3/Utility_E3.cpp index 0533cd5b..57565750 100644 --- a/SampleCode/LocalAttestation/Enclave3/Utility_E3.cpp +++ b/SampleCode/LocalAttestation/Enclave3/Utility_E3.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Enclave3/Utility_E3.h b/SampleCode/LocalAttestation/Enclave3/Utility_E3.h index 69327b44..63e51878 100644 --- a/SampleCode/LocalAttestation/Enclave3/Utility_E3.h +++ b/SampleCode/LocalAttestation/Enclave3/Utility_E3.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Include/dh_session_protocol.h b/SampleCode/LocalAttestation/Include/dh_session_protocol.h index 7257b1f1..b625f75d 100644 --- a/SampleCode/LocalAttestation/Include/dh_session_protocol.h +++ b/SampleCode/LocalAttestation/Include/dh_session_protocol.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.cpp b/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.cpp index 5a1978f9..d36d7fe5 100644 --- a/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.cpp +++ b/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.h b/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.h index 1d8a56cd..95c77e1b 100644 --- a/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.h +++ b/SampleCode/LocalAttestation/LocalAttestationCode/EnclaveMessageExchange.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/LocalAttestationCode/LocalAttestationCode.edl b/SampleCode/LocalAttestation/LocalAttestationCode/LocalAttestationCode.edl index 82e76345..5fdbea05 100644 --- a/SampleCode/LocalAttestation/LocalAttestationCode/LocalAttestationCode.edl +++ b/SampleCode/LocalAttestation/LocalAttestationCode/LocalAttestationCode.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/LocalAttestationCode/datatypes.h b/SampleCode/LocalAttestation/LocalAttestationCode/datatypes.h index 6382ea15..25b93242 100644 --- a/SampleCode/LocalAttestation/LocalAttestationCode/datatypes.h +++ b/SampleCode/LocalAttestation/LocalAttestationCode/datatypes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/LocalAttestationCode/error_codes.h b/SampleCode/LocalAttestation/LocalAttestationCode/error_codes.h index 0bca4c01..84357516 100644 --- a/SampleCode/LocalAttestation/LocalAttestationCode/error_codes.h +++ b/SampleCode/LocalAttestation/LocalAttestationCode/error_codes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Makefile b/SampleCode/LocalAttestation/Makefile index 50130d8b..e51123d8 100644 --- a/SampleCode/LocalAttestation/Makefile +++ b/SampleCode/LocalAttestation/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -158,6 +158,9 @@ Enclave_C_Flags += $(Enclave_Include_Paths) Enclave_Cxx_Flags := $(Enclave_C_Flags) $(SGX_COMMON_CXXFLAGS) -nostdinc++ Enclave_C_Flasg += $(SGX_COMMON_CFLAGS) +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -165,7 +168,8 @@ Enclave_C_Flasg += $(SGX_COMMON_CFLAGS) # Use `--start-group' and `--end-group' to link these libraries. # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. # Otherwise, you may get some undesirable errors. -Common_Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Common_Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -L. -lLocalAttestation_Trusted -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/LocalAttestation/README.txt b/SampleCode/LocalAttestation/README.txt index 14277097..9b5b5126 100644 --- a/SampleCode/LocalAttestation/README.txt +++ b/SampleCode/LocalAttestation/README.txt @@ -30,3 +30,11 @@ How to Build/Execute the Sample Code 4. Execute the binary directly: $ ./app 5. Remember to "make clean" before switching build mode + +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.cpp b/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.cpp index 33601713..3d4e2196 100644 --- a/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.cpp +++ b/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.h b/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.h index 88476505..ad05d348 100644 --- a/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.h +++ b/SampleCode/LocalAttestation/Untrusted_LocalAttestation/UntrustedEnclaveMessageExchange.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/App/App.cpp b/SampleCode/PowerTransition/App/App.cpp index 75bb43b2..1a812232 100644 --- a/SampleCode/PowerTransition/App/App.cpp +++ b/SampleCode/PowerTransition/App/App.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -74,7 +74,7 @@ sgx_status_t load_and_initialize_enclave(sgx_enclave_id_t *eid, struct sealed_bu for( ; ; ) { // Step 1: check whether the loading and initialization operations are caused by power transition. - // If the loading and initialization operations are caused by power transition, we need to call sgx_destory_enclave() first. + // If the loading and initialization operations are caused by power transition, we need to call sgx_destroy_enclave() first. if(*eid != 0) { sgx_destroy_enclave(*eid); diff --git a/SampleCode/PowerTransition/App/ErrorSupport.cpp b/SampleCode/PowerTransition/App/ErrorSupport.cpp index d7be4bfa..9392cd63 100644 --- a/SampleCode/PowerTransition/App/ErrorSupport.cpp +++ b/SampleCode/PowerTransition/App/ErrorSupport.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/App/ErrorSupport.h b/SampleCode/PowerTransition/App/ErrorSupport.h index 1e716227..1edddbb7 100644 --- a/SampleCode/PowerTransition/App/ErrorSupport.h +++ b/SampleCode/PowerTransition/App/ErrorSupport.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/App/rwlock.cpp b/SampleCode/PowerTransition/App/rwlock.cpp index 34833663..3a7a45d7 100644 --- a/SampleCode/PowerTransition/App/rwlock.cpp +++ b/SampleCode/PowerTransition/App/rwlock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/App/rwlock.h b/SampleCode/PowerTransition/App/rwlock.h index efd3a79f..1602318f 100644 --- a/SampleCode/PowerTransition/App/rwlock.h +++ b/SampleCode/PowerTransition/App/rwlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/Common/types.h b/SampleCode/PowerTransition/Common/types.h index 676c93f4..cb690da9 100644 --- a/SampleCode/PowerTransition/Common/types.h +++ b/SampleCode/PowerTransition/Common/types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/Enclave/Enclave.cpp b/SampleCode/PowerTransition/Enclave/Enclave.cpp index 8b5daea5..7e45103d 100644 --- a/SampleCode/PowerTransition/Enclave/Enclave.cpp +++ b/SampleCode/PowerTransition/Enclave/Enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/Enclave/Enclave.edl b/SampleCode/PowerTransition/Enclave/Enclave.edl index 28dc48f0..1bf839f4 100644 --- a/SampleCode/PowerTransition/Enclave/Enclave.edl +++ b/SampleCode/PowerTransition/Enclave/Enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/PowerTransition/Makefile b/SampleCode/PowerTransition/Makefile index bc82d728..8115730a 100644 --- a/SampleCode/PowerTransition/Makefile +++ b/SampleCode/PowerTransition/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -138,6 +138,9 @@ endif Enclave_Compile_CFlags += -nostdinc -ffreestanding -fvisibility=hidden -fpie -ffunction-sections -fdata-sections $(Enclave_Include_Paths) Enclave_Compile_CXXFlags := -nostdinc++ $(Enclave_Compile_CFlags) +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -145,7 +148,8 @@ Enclave_Compile_CXXFlags := -nostdinc++ $(Enclave_Compile_CFlags) # Use `--start-group' and `--end-group' to link these libraries. # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. # Otherwise, you may get some undesirable errors. -Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,--version-script=Enclave/Enclave.lds -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/PowerTransition/README.txt b/SampleCode/PowerTransition/README.txt index fe2c4b93..643b132e 100644 --- a/SampleCode/PowerTransition/README.txt +++ b/SampleCode/PowerTransition/README.txt @@ -26,3 +26,11 @@ How to Build/Execute the Sample Code 4. Execute the binary directly: $ ./app 5. Remember to "make clean" before switching build mode + +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/SampleCode/RemoteAttestation/Makefile b/SampleCode/RemoteAttestation/Makefile index b8b95200..56947fbb 100644 --- a/SampleCode/RemoteAttestation/Makefile +++ b/SampleCode/RemoteAttestation/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -149,6 +149,9 @@ else endif Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++ +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -156,7 +159,8 @@ Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++ # Use `--start-group' and `--end-group' to link these libraries. # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. # Otherwise, you may get some undesirable errors. -Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_tkey_exchange -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/RemoteAttestation/README.txt b/SampleCode/RemoteAttestation/README.txt index f9176ade..ab415675 100644 --- a/SampleCode/RemoteAttestation/README.txt +++ b/SampleCode/RemoteAttestation/README.txt @@ -27,3 +27,11 @@ How to Build/Execute the Sample Code 4. Execute the binary directly: $ LD_LIBRARY_PATH=sample_libcrypto ./app 5. Remember to "make clean" before switching build mode + +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/SampleCode/RemoteAttestation/isv_app/isv_app.cpp b/SampleCode/RemoteAttestation/isv_app/isv_app.cpp index b05617c6..0fa30be3 100644 --- a/SampleCode/RemoteAttestation/isv_app/isv_app.cpp +++ b/SampleCode/RemoteAttestation/isv_app/isv_app.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/isv_app/sample_messages.h b/SampleCode/RemoteAttestation/isv_app/sample_messages.h index e2a80f68..981db950 100644 --- a/SampleCode/RemoteAttestation/isv_app/sample_messages.h +++ b/SampleCode/RemoteAttestation/isv_app/sample_messages.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.cpp b/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.cpp index be9423ab..197ab24d 100644 --- a/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.cpp +++ b/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.edl b/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.edl index ad0af58e..21c233a1 100644 --- a/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.edl +++ b/SampleCode/RemoteAttestation/isv_enclave/isv_enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/ecp.cpp b/SampleCode/RemoteAttestation/service_provider/ecp.cpp index d074c487..af6d723d 100644 --- a/SampleCode/RemoteAttestation/service_provider/ecp.cpp +++ b/SampleCode/RemoteAttestation/service_provider/ecp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/ecp.h b/SampleCode/RemoteAttestation/service_provider/ecp.h index 7dee6057..545c5da4 100644 --- a/SampleCode/RemoteAttestation/service_provider/ecp.h +++ b/SampleCode/RemoteAttestation/service_provider/ecp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/ias_ra.cpp b/SampleCode/RemoteAttestation/service_provider/ias_ra.cpp index 6867b4bc..da256c7c 100644 --- a/SampleCode/RemoteAttestation/service_provider/ias_ra.cpp +++ b/SampleCode/RemoteAttestation/service_provider/ias_ra.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/ias_ra.h b/SampleCode/RemoteAttestation/service_provider/ias_ra.h index fd228973..f253bf7a 100644 --- a/SampleCode/RemoteAttestation/service_provider/ias_ra.h +++ b/SampleCode/RemoteAttestation/service_provider/ias_ra.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/network_ra.cpp b/SampleCode/RemoteAttestation/service_provider/network_ra.cpp index 75cbc802..a11cf183 100644 --- a/SampleCode/RemoteAttestation/service_provider/network_ra.cpp +++ b/SampleCode/RemoteAttestation/service_provider/network_ra.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/network_ra.h b/SampleCode/RemoteAttestation/service_provider/network_ra.h index dc4c6d54..d7b55a7c 100644 --- a/SampleCode/RemoteAttestation/service_provider/network_ra.h +++ b/SampleCode/RemoteAttestation/service_provider/network_ra.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/remote_attestation_result.h b/SampleCode/RemoteAttestation/service_provider/remote_attestation_result.h index 2883a66b..5f243b2e 100644 --- a/SampleCode/RemoteAttestation/service_provider/remote_attestation_result.h +++ b/SampleCode/RemoteAttestation/service_provider/remote_attestation_result.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/service_provider.cpp b/SampleCode/RemoteAttestation/service_provider/service_provider.cpp index 30241edf..3915600f 100644 --- a/SampleCode/RemoteAttestation/service_provider/service_provider.cpp +++ b/SampleCode/RemoteAttestation/service_provider/service_provider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/RemoteAttestation/service_provider/service_provider.h b/SampleCode/RemoteAttestation/service_provider/service_provider.h index b34fded1..9f79a3b0 100644 --- a/SampleCode/RemoteAttestation/service_provider/service_provider.h +++ b/SampleCode/RemoteAttestation/service_provider/service_provider.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleCommonLoader/App/enclave_entry.S b/SampleCode/SampleCommonLoader/App/enclave_entry.S index 26e53d4f..029695c5 100644 --- a/SampleCode/SampleCommonLoader/App/enclave_entry.S +++ b/SampleCode/SampleCommonLoader/App/enclave_entry.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleCommonLoader/App/sample.cpp b/SampleCode/SampleCommonLoader/App/sample.cpp index 6c8789cf..4c4fb270 100644 --- a/SampleCode/SampleCommonLoader/App/sample.cpp +++ b/SampleCode/SampleCommonLoader/App/sample.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleCommonLoader/Include/enclave_entry.h b/SampleCode/SampleCommonLoader/Include/enclave_entry.h index d9d0df97..ef016324 100644 --- a/SampleCode/SampleCommonLoader/Include/enclave_entry.h +++ b/SampleCode/SampleCommonLoader/Include/enclave_entry.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleCommonLoader/Include/linux-regs.h b/SampleCode/SampleCommonLoader/Include/linux-regs.h index df066d8c..c01281bb 100644 --- a/SampleCode/SampleCommonLoader/Include/linux-regs.h +++ b/SampleCode/SampleCommonLoader/Include/linux-regs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleCommonLoader/Include/sgx_enclave_blob.h b/SampleCode/SampleCommonLoader/Include/sgx_enclave_blob.h index 2272a589..e7379b73 100644 --- a/SampleCode/SampleCommonLoader/Include/sgx_enclave_blob.h +++ b/SampleCode/SampleCommonLoader/Include/sgx_enclave_blob.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleCommonLoader/Include/sgx_enclave_ss.h b/SampleCode/SampleCommonLoader/Include/sgx_enclave_ss.h index 8277800d..fc501bfd 100644 --- a/SampleCode/SampleCommonLoader/Include/sgx_enclave_ss.h +++ b/SampleCode/SampleCommonLoader/Include/sgx_enclave_ss.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleCommonLoader/Makefile b/SampleCode/SampleCommonLoader/Makefile index 3892a078..04f7cbe2 100644 --- a/SampleCode/SampleCommonLoader/Makefile +++ b/SampleCode/SampleCommonLoader/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/App.cpp b/SampleCode/SampleEnclave/App/App.cpp index 7774c098..51dc4bbd 100644 --- a/SampleCode/SampleEnclave/App/App.cpp +++ b/SampleCode/SampleEnclave/App/App.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/App.h b/SampleCode/SampleEnclave/App/App.h index ab1262b2..00db8716 100644 --- a/SampleCode/SampleEnclave/App/App.h +++ b/SampleCode/SampleEnclave/App/App.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/Edger8rSyntax/Arrays.cpp b/SampleCode/SampleEnclave/App/Edger8rSyntax/Arrays.cpp index 9904948f..53963ca1 100644 --- a/SampleCode/SampleEnclave/App/Edger8rSyntax/Arrays.cpp +++ b/SampleCode/SampleEnclave/App/Edger8rSyntax/Arrays.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/Edger8rSyntax/Functions.cpp b/SampleCode/SampleEnclave/App/Edger8rSyntax/Functions.cpp index 0826c634..1067818e 100644 --- a/SampleCode/SampleEnclave/App/Edger8rSyntax/Functions.cpp +++ b/SampleCode/SampleEnclave/App/Edger8rSyntax/Functions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/Edger8rSyntax/Pointers.cpp b/SampleCode/SampleEnclave/App/Edger8rSyntax/Pointers.cpp index f2e18ef2..f6395efc 100644 --- a/SampleCode/SampleEnclave/App/Edger8rSyntax/Pointers.cpp +++ b/SampleCode/SampleEnclave/App/Edger8rSyntax/Pointers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/Edger8rSyntax/Types.cpp b/SampleCode/SampleEnclave/App/Edger8rSyntax/Types.cpp index e56e2299..710914b6 100644 --- a/SampleCode/SampleEnclave/App/Edger8rSyntax/Types.cpp +++ b/SampleCode/SampleEnclave/App/Edger8rSyntax/Types.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/TrustedLibrary/Libc.cpp b/SampleCode/SampleEnclave/App/TrustedLibrary/Libc.cpp index 54fb84da..de9e753a 100644 --- a/SampleCode/SampleEnclave/App/TrustedLibrary/Libc.cpp +++ b/SampleCode/SampleEnclave/App/TrustedLibrary/Libc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/TrustedLibrary/Libcxx.cpp b/SampleCode/SampleEnclave/App/TrustedLibrary/Libcxx.cpp index 223ef486..ab279df0 100644 --- a/SampleCode/SampleEnclave/App/TrustedLibrary/Libcxx.cpp +++ b/SampleCode/SampleEnclave/App/TrustedLibrary/Libcxx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/App/TrustedLibrary/Thread.cpp b/SampleCode/SampleEnclave/App/TrustedLibrary/Thread.cpp index 1a059729..4095fe67 100644 --- a/SampleCode/SampleEnclave/App/TrustedLibrary/Thread.cpp +++ b/SampleCode/SampleEnclave/App/TrustedLibrary/Thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.cpp b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.cpp index e1fbae1a..93c8cc7e 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.cpp +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.edl b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.edl index 3b35d681..2ce550ae 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.edl +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Arrays.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.cpp b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.cpp index a2e6ef9f..bd3540cb 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.cpp +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.edl b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.edl index 5e8520a2..947c82e7 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.edl +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Functions.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.cpp b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.cpp index 0624d0c5..56036890 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.cpp +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.edl b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.edl index 2072a5cf..e12eea35 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.edl +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Pointers.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.cpp b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.cpp index 8554a65e..44075d21 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.cpp +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.edl b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.edl index 55c61d03..a68b5b97 100644 --- a/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.edl +++ b/SampleCode/SampleEnclave/Enclave/Edger8rSyntax/Types.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Enclave.cpp b/SampleCode/SampleEnclave/Enclave/Enclave.cpp index 962cd479..f55b5d87 100644 --- a/SampleCode/SampleEnclave/Enclave/Enclave.cpp +++ b/SampleCode/SampleEnclave/Enclave/Enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Enclave.edl b/SampleCode/SampleEnclave/Enclave/Enclave.edl index a3de4438..4c7fcd40 100644 --- a/SampleCode/SampleEnclave/Enclave/Enclave.edl +++ b/SampleCode/SampleEnclave/Enclave/Enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/Enclave.h b/SampleCode/SampleEnclave/Enclave/Enclave.h index f7513e89..94478a53 100644 --- a/SampleCode/SampleEnclave/Enclave/Enclave.h +++ b/SampleCode/SampleEnclave/Enclave/Enclave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.cpp b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.cpp index fa50118e..373af973 100644 --- a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.cpp +++ b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.edl b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.edl index 47d05c3c..d83fdcfd 100644 --- a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.edl +++ b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libc.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.cpp b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.cpp index 2b06ed00..d898fece 100644 --- a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.cpp +++ b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.edl b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.edl index 9bcddb86..bf34effc 100644 --- a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.edl +++ b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Libcxx.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.cpp b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.cpp index 22f43464..d0c52164 100644 --- a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.cpp +++ b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.edl b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.edl index 7e9af63f..6482fbee 100644 --- a/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.edl +++ b/SampleCode/SampleEnclave/Enclave/TrustedLibrary/Thread.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Include/user_types.h b/SampleCode/SampleEnclave/Include/user_types.h index 478af7cf..f718e086 100644 --- a/SampleCode/SampleEnclave/Include/user_types.h +++ b/SampleCode/SampleEnclave/Include/user_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclave/Makefile b/SampleCode/SampleEnclave/Makefile index dd658ade..1be7a62f 100644 --- a/SampleCode/SampleEnclave/Makefile +++ b/SampleCode/SampleEnclave/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -135,6 +135,9 @@ endif Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++ +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -142,7 +145,8 @@ Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++ # Use `--start-group' and `--end-group' to link these libraries. # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. # Otherwise, you may get some undesirable errors. -Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/SampleEnclave/README.txt b/SampleCode/SampleEnclave/README.txt index 055a950c..f06a9483 100644 --- a/SampleCode/SampleEnclave/README.txt +++ b/SampleCode/SampleEnclave/README.txt @@ -67,3 +67,11 @@ config.01.xml: There is no dynamic thread, no dynamic heap expansion. config.02.xml: There is no dynamic thread. But dynamic heap expansion can happen. config.03.xml: There are dynamic threads. For a dynamic thread, there's no stack expansion. config.04.xml: There are dynamic threads. For a dynamic thread, stack will expanded as necessary. + +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/SampleCode/SampleEnclavePCL/App/App.cpp b/SampleCode/SampleEnclavePCL/App/App.cpp index 40545422..356ba0cb 100644 --- a/SampleCode/SampleEnclavePCL/App/App.cpp +++ b/SampleCode/SampleEnclavePCL/App/App.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/App.h b/SampleCode/SampleEnclavePCL/App/App.h index 36c45b0e..43b842ed 100644 --- a/SampleCode/SampleEnclavePCL/App/App.h +++ b/SampleCode/SampleEnclavePCL/App/App.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Arrays.cpp b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Arrays.cpp index 9904948f..53963ca1 100644 --- a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Arrays.cpp +++ b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Arrays.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Functions.cpp b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Functions.cpp index 0826c634..1067818e 100644 --- a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Functions.cpp +++ b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Functions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Pointers.cpp b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Pointers.cpp index a7c22f3d..241cded1 100644 --- a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Pointers.cpp +++ b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Pointers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Types.cpp b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Types.cpp index e56e2299..710914b6 100644 --- a/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Types.cpp +++ b/SampleCode/SampleEnclavePCL/App/Edger8rSyntax/Types.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libc.cpp b/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libc.cpp index 0d2b5dd6..d64a3254 100644 --- a/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libc.cpp +++ b/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libcxx.cpp b/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libcxx.cpp index 223ef486..ab279df0 100644 --- a/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libcxx.cpp +++ b/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Libcxx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Thread.cpp b/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Thread.cpp index c4d21c4c..af651606 100644 --- a/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Thread.cpp +++ b/SampleCode/SampleEnclavePCL/App/TrustedLibrary/Thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.cpp b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.cpp index e1fbae1a..93c8cc7e 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.edl b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.edl index 3b35d681..2ce550ae 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Arrays.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.cpp b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.cpp index a2e6ef9f..bd3540cb 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.edl b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.edl index 5e8520a2..947c82e7 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Functions.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.cpp b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.cpp index a4bb2917..c571c57b 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.edl b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.edl index 2072a5cf..e12eea35 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Pointers.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.cpp b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.cpp index 8554a65e..44075d21 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.edl b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.edl index 55c61d03..a68b5b97 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/Edger8rSyntax/Types.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Enclave.cpp b/SampleCode/SampleEnclavePCL/Enclave/Enclave.cpp index f0b9db0f..1dfd4643 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Enclave.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/Enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Enclave.edl b/SampleCode/SampleEnclavePCL/Enclave/Enclave.edl index a3de4438..4c7fcd40 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Enclave.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/Enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/Enclave.h b/SampleCode/SampleEnclavePCL/Enclave/Enclave.h index ed83970d..226b0279 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/Enclave.h +++ b/SampleCode/SampleEnclavePCL/Enclave/Enclave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.cpp b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.cpp index fa50118e..373af973 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.edl b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.edl index 0fb71cb3..67d5bcfd 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libc.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.cpp b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.cpp index 2b06ed00..d898fece 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.edl b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.edl index 9bcddb86..bf34effc 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Libcxx.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.cpp b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.cpp index 22f43464..d0c52164 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.cpp +++ b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.edl b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.edl index 7e9af63f..6482fbee 100644 --- a/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.edl +++ b/SampleCode/SampleEnclavePCL/Enclave/TrustedLibrary/Thread.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Include/user_types.h b/SampleCode/SampleEnclavePCL/Include/user_types.h index 478af7cf..f718e086 100644 --- a/SampleCode/SampleEnclavePCL/Include/user_types.h +++ b/SampleCode/SampleEnclavePCL/Include/user_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Makefile b/SampleCode/SampleEnclavePCL/Makefile index 04481629..c9c0a409 100644 --- a/SampleCode/SampleEnclavePCL/Makefile +++ b/SampleCode/SampleEnclavePCL/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -148,6 +148,9 @@ Enclave_C_Flags += $(Enclave_Include_Paths) Enclave_Cpp_Flags := $(Enclave_C_Flags) $(SGX_COMMON_CXXFLAGS) -nostdinc++ Enclave_C_Flags += $(SGX_COMMON_CFLAGS) +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -155,7 +158,8 @@ Enclave_C_Flags += $(SGX_COMMON_CFLAGS) # Use `--start-group' and `--end-group' to link these libraries. # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. # Otherwise, you may get some undesirable errors. -Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/SampleEnclavePCL/README.md b/SampleCode/SampleEnclavePCL/README.md index b2ccc9ff..cbb8fe1b 100644 --- a/SampleCode/SampleEnclavePCL/README.md +++ b/SampleCode/SampleEnclavePCL/README.md @@ -32,3 +32,11 @@ Build and test the Intel(R) SGX PCL with the sample code $ make $ ./app ``` + +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/SampleCode/SampleEnclavePCL/Seal/Seal.cpp b/SampleCode/SampleEnclavePCL/Seal/Seal.cpp index 301386e8..8506fa30 100644 --- a/SampleCode/SampleEnclavePCL/Seal/Seal.cpp +++ b/SampleCode/SampleEnclavePCL/Seal/Seal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SampleEnclavePCL/Seal/Seal.edl b/SampleCode/SampleEnclavePCL/Seal/Seal.edl index 662d5664..04911751 100644 --- a/SampleCode/SampleEnclavePCL/Seal/Seal.edl +++ b/SampleCode/SampleEnclavePCL/Seal/Seal.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/DRM_app/DRM_app.cpp b/SampleCode/SealedData/DRM_app/DRM_app.cpp index 8dc097e6..e9a03f29 100644 --- a/SampleCode/SealedData/DRM_app/DRM_app.cpp +++ b/SampleCode/SealedData/DRM_app/DRM_app.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.cpp b/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.cpp index df96587b..c934f855 100644 --- a/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.cpp +++ b/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.h b/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.h index 3824043f..7315ccff 100644 --- a/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.h +++ b/SampleCode/SealedData/DRM_app/ReplayProtectedDRM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/DRM_app/TimeBasedDRM.cpp b/SampleCode/SealedData/DRM_app/TimeBasedDRM.cpp index a9f400a2..d8ee3770 100644 --- a/SampleCode/SealedData/DRM_app/TimeBasedDRM.cpp +++ b/SampleCode/SealedData/DRM_app/TimeBasedDRM.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/DRM_app/TimeBasedDRM.h b/SampleCode/SealedData/DRM_app/TimeBasedDRM.h index 32cf4b98..11ab0885 100644 --- a/SampleCode/SealedData/DRM_app/TimeBasedDRM.h +++ b/SampleCode/SealedData/DRM_app/TimeBasedDRM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/DRM_enclave/DRM_enclave.cpp b/SampleCode/SealedData/DRM_enclave/DRM_enclave.cpp index 102dbbfa..e21eb932 100644 --- a/SampleCode/SealedData/DRM_enclave/DRM_enclave.cpp +++ b/SampleCode/SealedData/DRM_enclave/DRM_enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/DRM_enclave/DRM_enclave.edl b/SampleCode/SealedData/DRM_enclave/DRM_enclave.edl index 1955e591..b7736adf 100644 --- a/SampleCode/SealedData/DRM_enclave/DRM_enclave.edl +++ b/SampleCode/SealedData/DRM_enclave/DRM_enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/SealedData/Makefile b/SampleCode/SealedData/Makefile index 34dd1136..cf940c8c 100644 --- a/SampleCode/SealedData/Makefile +++ b/SampleCode/SealedData/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -137,6 +137,9 @@ Enclave_C_Flags += $(Enclave_Include_Paths) Enclave_Cpp_Flags := $(Enclave_C_Flags) $(SGX_COMMON_CXXFLAGS) -nostdinc++ Enclave_C_Flags += $(SGX_COMMON_CFLAGS) +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -144,7 +147,8 @@ Enclave_C_Flags += $(SGX_COMMON_CFLAGS) # Use `--start-group' and `--end-group' to link these libraries. # Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options. # Otherwise, you may get some undesirable errors. -Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/SealedData/README.txt b/SampleCode/SealedData/README.txt index 3a3a3c26..4a3b110a 100644 --- a/SampleCode/SealedData/README.txt +++ b/SampleCode/SealedData/README.txt @@ -29,3 +29,11 @@ How to Build/Execute the Sample Code 4. Execute the binary directly: $ ./app 5. Remember to "make clean" before switching build mode + +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/SampleCode/SealedData/include/sealed_data_defines.h b/SampleCode/SealedData/include/sealed_data_defines.h index 24e6727e..1082f259 100644 --- a/SampleCode/SealedData/include/sealed_data_defines.h +++ b/SampleCode/SealedData/include/sealed_data_defines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Switchless/App/App.cpp b/SampleCode/Switchless/App/App.cpp index 345b1a82..1265a235 100644 --- a/SampleCode/Switchless/App/App.cpp +++ b/SampleCode/Switchless/App/App.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Switchless/App/App.h b/SampleCode/Switchless/App/App.h index bb0ef20f..2df80c58 100644 --- a/SampleCode/Switchless/App/App.h +++ b/SampleCode/Switchless/App/App.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Switchless/Enclave/Enclave.cpp b/SampleCode/Switchless/Enclave/Enclave.cpp index 32bc4fbf..94f7d33b 100644 --- a/SampleCode/Switchless/Enclave/Enclave.cpp +++ b/SampleCode/Switchless/Enclave/Enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Switchless/Enclave/Enclave.edl b/SampleCode/Switchless/Enclave/Enclave.edl index 43455711..1917754a 100644 --- a/SampleCode/Switchless/Enclave/Enclave.edl +++ b/SampleCode/Switchless/Enclave/Enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Switchless/Enclave/Enclave.h b/SampleCode/Switchless/Enclave/Enclave.h index be0c0dd7..d3ed50cd 100644 --- a/SampleCode/Switchless/Enclave/Enclave.h +++ b/SampleCode/Switchless/Enclave/Enclave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/SampleCode/Switchless/Makefile b/SampleCode/Switchless/Makefile index c4574403..4d5606c3 100644 --- a/SampleCode/Switchless/Makefile +++ b/SampleCode/Switchless/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -130,6 +130,9 @@ Enclave_C_Flags := -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Encla Enclave_Cpp_Flags := $(Enclave_C_Flags) $(SGX_COMMON_CXXFLAGS) -nostdinc++ Enclave_C_Flags += $(SGX_COMMON_CFLAGS) +# Enable the security flags +Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack + # To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries: # 1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options, # so that the whole content of trts is included in the enclave. @@ -144,7 +147,8 @@ Enclave_C_Flags += $(SGX_COMMON_CFLAGS) # -lsgx_tswitchless option must be put between -Wl,--whole-archive and # -Wl,--no-whole-archive with -l$(TRTS_LIBRARY) and before the linker options # for other libraries (e.g., -lsgx_tstdc). -Enclave_Link_Flags := -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ +Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \ + -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) \ -Wl,--whole-archive -lsgx_tswitchless -l$(Trts_Library_Name) -Wl,--no-whole-archive \ -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l$(Crypto_Library_Name) -l$(Service_Library_Name) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ diff --git a/SampleCode/Switchless/README.txt b/SampleCode/Switchless/README.txt index 965a71a1..fee0510f 100644 --- a/SampleCode/Switchless/README.txt +++ b/SampleCode/Switchless/README.txt @@ -17,3 +17,10 @@ How to Build/Execute the Sample Code 3. Execute the binary directly: $ ./app +------------------------------------------------- +Launch token initialization +------------------------------------------------- +If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example, + +sgx_launch_token_t launch_token = {0}; +sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL); diff --git a/buildenv.mk b/buildenv.mk index 1d32d277..7a49ec12 100644 --- a/buildenv.mk +++ b/buildenv.mk @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -51,6 +51,7 @@ LINUX_EXTERNAL_DIR := $(ROOT_DIR)/external LINUX_PSW_DIR := $(ROOT_DIR)/psw LINUX_SDK_DIR := $(ROOT_DIR)/sdk LINUX_UNITTESTS := $(ROOT_DIR)/unittests +DCAP_DIR := $(LINUX_EXTERNAL_DIR)/dcap_source CP := /bin/cp -f diff --git a/common/inc/internal/ae_ipp.h b/common/inc/internal/ae_ipp.h index 948a0eba..4e9044d1 100644 --- a/common/inc/internal/ae_ipp.h +++ b/common/inc/internal/ae_ipp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/arch.h b/common/inc/internal/arch.h index f145e04a..98022011 100644 --- a/common/inc/internal/arch.h +++ b/common/inc/internal/arch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/cpprt_internal.h b/common/inc/internal/cpprt_internal.h index 47fb8499..28106674 100644 --- a/common/inc/internal/cpprt_internal.h +++ b/common/inc/internal/cpprt_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/cpputil.h b/common/inc/internal/cpputil.h index dc909d0c..4c01ee7e 100644 --- a/common/inc/internal/cpputil.h +++ b/common/inc/internal/cpputil.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/cpuid.h b/common/inc/internal/cpuid.h index 67c61707..0dbdbe2d 100644 --- a/common/inc/internal/cpuid.h +++ b/common/inc/internal/cpuid.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/crypto_wrapper.h b/common/inc/internal/crypto_wrapper.h index 0dedf29c..0c5a28f0 100644 --- a/common/inc/internal/crypto_wrapper.h +++ b/common/inc/internal/crypto_wrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/dh.h b/common/inc/internal/dh.h index 222898cc..8bbcf486 100644 --- a/common/inc/internal/dh.h +++ b/common/inc/internal/dh.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/driver_api.h b/common/inc/internal/driver_api.h index 50edbd8b..88d711df 100644 --- a/common/inc/internal/driver_api.h +++ b/common/inc/internal/driver_api.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/ecp_interface.h b/common/inc/internal/ecp_interface.h index 4530984b..81b95ec5 100644 --- a/common/inc/internal/ecp_interface.h +++ b/common/inc/internal/ecp_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/elf_util.h b/common/inc/internal/elf_util.h index 3bfbef9f..4fb0561e 100644 --- a/common/inc/internal/elf_util.h +++ b/common/inc/internal/elf_util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/enclave_creator.h b/common/inc/internal/enclave_creator.h index cff4bd13..0bd06c30 100644 --- a/common/inc/internal/enclave_creator.h +++ b/common/inc/internal/enclave_creator.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/global_data.h b/common/inc/internal/global_data.h index 2073bcab..4216a30b 100644 --- a/common/inc/internal/global_data.h +++ b/common/inc/internal/global_data.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/global_init.h b/common/inc/internal/global_init.h index 2b53667e..a508ca01 100644 --- a/common/inc/internal/global_init.h +++ b/common/inc/internal/global_init.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/inst.h b/common/inc/internal/inst.h index ad735aed..7e053b99 100644 --- a/common/inc/internal/inst.h +++ b/common/inc/internal/inst.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/ipp_wrapper.h b/common/inc/internal/ipp_wrapper.h index 9519be00..863ac6c2 100644 --- a/common/inc/internal/ipp_wrapper.h +++ b/common/inc/internal/ipp_wrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/linux/cpuid_gnu.h b/common/inc/internal/linux/cpuid_gnu.h index 02883e9b..8f3de574 100644 --- a/common/inc/internal/linux/cpuid_gnu.h +++ b/common/inc/internal/linux/cpuid_gnu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/linux/linux-regs.h b/common/inc/internal/linux/linux-regs.h index cebe07eb..4d5a634b 100644 --- a/common/inc/internal/linux/linux-regs.h +++ b/common/inc/internal/linux/linux-regs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/metadata.h b/common/inc/internal/metadata.h index df072d92..da769f1e 100644 --- a/common/inc/internal/metadata.h +++ b/common/inc/internal/metadata.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/mini_snprintf.h b/common/inc/internal/mini_snprintf.h index bdcc7df6..1d7a3dfc 100644 --- a/common/inc/internal/mini_snprintf.h +++ b/common/inc/internal/mini_snprintf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/oal/uae_oal_api.h b/common/inc/internal/oal/uae_oal_api.h index 682df1e1..4717984f 100644 --- a/common/inc/internal/oal/uae_oal_api.h +++ b/common/inc/internal/oal/uae_oal_api.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +32,7 @@ #define _UAE_OAL_H #include "sgx_quote.h" +#include "sgx_ql_quote.h" #include "sgx_error.h" #include "sgx_urts.h" #include @@ -147,6 +148,28 @@ uae_oal_status_t oal_register_common( uint32_t timeout_usec, aesm_error_t *result); +uae_oal_status_t oal_init_quote_ex(const sgx_ql_att_key_id_t *att_key_id, + uint32_t certification_key_type, + sgx_target_info_t *target_info, + bool refresh_att_key, + size_t *pub_key_id_size, size_t buf_size, uint8_t *pub_key_id, + uint32_t timeout_usec, aesm_error_t *result); + +uae_oal_status_t oal_get_quote_size_ex( + const sgx_ql_att_key_id_t *att_key_id, + uint32_t certification_key_type, + uint32_t *quote_size, + uint32_t timeout_usec, aesm_error_t *result); + +uae_oal_status_t oal_get_quote_ex( + const sgx_report_t *p_report, + const sgx_ql_att_key_id_t *att_key_id, + sgx_ql_qe_report_info_t *qe_report_info, + uint32_t quote_size, uint8_t *p_quote, + uint32_t timeout_usec, + aesm_error_t *result); + + sgx_status_t oal_map_status(uae_oal_status_t status); sgx_status_t oal_map_result(aesm_error_t result); diff --git a/common/inc/internal/pcl_common.h b/common/inc/internal/pcl_common.h index ed001d35..f69150a5 100644 --- a/common/inc/internal/pcl_common.h +++ b/common/inc/internal/pcl_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/routine.h b/common/inc/internal/routine.h index 38b3b520..d5a3b5c0 100644 --- a/common/inc/internal/routine.h +++ b/common/inc/internal/routine.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/rts.h b/common/inc/internal/rts.h index 36d224cd..9b41c87b 100644 --- a/common/inc/internal/rts.h +++ b/common/inc/internal/rts.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/rts_cmd.h b/common/inc/internal/rts_cmd.h index 4a3fe938..23fda78f 100644 --- a/common/inc/internal/rts_cmd.h +++ b/common/inc/internal/rts_cmd.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_atomic.h b/common/inc/internal/se_atomic.h index 13ca1d22..2299b665 100644 --- a/common/inc/internal/se_atomic.h +++ b/common/inc/internal/se_atomic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_cdefs.h b/common/inc/internal/se_cdefs.h index 88c7d091..f1affda8 100644 --- a/common/inc/internal/se_cdefs.h +++ b/common/inc/internal/se_cdefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_cpu_feature.h b/common/inc/internal/se_cpu_feature.h index 7bbb0f54..9025f650 100644 --- a/common/inc/internal/se_cpu_feature.h +++ b/common/inc/internal/se_cpu_feature.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_cpu_feature_defs.h b/common/inc/internal/se_cpu_feature_defs.h index 77e6f50f..76b49434 100644 --- a/common/inc/internal/se_cpu_feature_defs.h +++ b/common/inc/internal/se_cpu_feature_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_debugger_lib.h b/common/inc/internal/se_debugger_lib.h index f83210df..fac11760 100644 --- a/common/inc/internal/se_debugger_lib.h +++ b/common/inc/internal/se_debugger_lib.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_enclave_type.h b/common/inc/internal/se_enclave_type.h index 68da74ab..da86f91e 100644 --- a/common/inc/internal/se_enclave_type.h +++ b/common/inc/internal/se_enclave_type.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_error_internal.h b/common/inc/internal/se_error_internal.h index 20943843..fa01c6b3 100644 --- a/common/inc/internal/se_error_internal.h +++ b/common/inc/internal/se_error_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_event.h b/common/inc/internal/se_event.h index 81387770..5ed02976 100644 --- a/common/inc/internal/se_event.h +++ b/common/inc/internal/se_event.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_lock.hpp b/common/inc/internal/se_lock.hpp index 885e3dfb..90a8fd36 100644 --- a/common/inc/internal/se_lock.hpp +++ b/common/inc/internal/se_lock.hpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_macro.h b/common/inc/internal/se_macro.h index 57bb6b27..e451b51d 100644 --- a/common/inc/internal/se_macro.h +++ b/common/inc/internal/se_macro.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_map.h b/common/inc/internal/se_map.h index ccb69570..71d0469e 100644 --- a/common/inc/internal/se_map.h +++ b/common/inc/internal/se_map.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_memcpy.h b/common/inc/internal/se_memcpy.h index dc74f0fb..4639e5eb 100644 --- a/common/inc/internal/se_memcpy.h +++ b/common/inc/internal/se_memcpy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_memory.h b/common/inc/internal/se_memory.h index 63280fce..61198576 100644 --- a/common/inc/internal/se_memory.h +++ b/common/inc/internal/se_memory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_page_attr.h b/common/inc/internal/se_page_attr.h index 859ef2fb..b3cd2031 100644 --- a/common/inc/internal/se_page_attr.h +++ b/common/inc/internal/se_page_attr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_quote_internal.h b/common/inc/internal/se_quote_internal.h index c7dd91ea..ddcee206 100644 --- a/common/inc/internal/se_quote_internal.h +++ b/common/inc/internal/se_quote_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_rwlock.h b/common/inc/internal/se_rwlock.h index 76b6313d..402c8494 100644 --- a/common/inc/internal/se_rwlock.h +++ b/common/inc/internal/se_rwlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_stdio.h b/common/inc/internal/se_stdio.h index 5fd656d9..8d04a1cd 100644 --- a/common/inc/internal/se_stdio.h +++ b/common/inc/internal/se_stdio.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_string.h b/common/inc/internal/se_string.h index 17202daa..dccb66e9 100644 --- a/common/inc/internal/se_string.h +++ b/common/inc/internal/se_string.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_tcrypto_common.h b/common/inc/internal/se_tcrypto_common.h index a40ca592..2db7beaf 100644 --- a/common/inc/internal/se_tcrypto_common.h +++ b/common/inc/internal/se_tcrypto_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_thread.h b/common/inc/internal/se_thread.h index b241331c..69facbaf 100644 --- a/common/inc/internal/se_thread.h +++ b/common/inc/internal/se_thread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_time.h b/common/inc/internal/se_time.h index 3fec3a56..322a3e2c 100644 --- a/common/inc/internal/se_time.h +++ b/common/inc/internal/se_time.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_trace.h b/common/inc/internal/se_trace.h index 36e05680..1089ba27 100644 --- a/common/inc/internal/se_trace.h +++ b/common/inc/internal/se_trace.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_types.h b/common/inc/internal/se_types.h index 56ab1610..8c8b358c 100644 --- a/common/inc/internal/se_types.h +++ b/common/inc/internal/se_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_vendor.h b/common/inc/internal/se_vendor.h index 4ba853b6..382c08fe 100644 --- a/common/inc/internal/se_vendor.h +++ b/common/inc/internal/se_vendor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/se_version.h b/common/inc/internal/se_version.h index 2a8b5dd0..26d1287a 100644 --- a/common/inc/internal/se_version.h +++ b/common/inc/internal/se_version.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,9 +28,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#define STRFILEVER "2.4.100.48163" -#define COPYRIGHT "Copyright (C) 2018 Intel Corporation" +#define STRFILEVER "2.5.100.49891" +#define COPYRIGHT "Copyright (C) 2019 Intel Corporation" -#define UAE_SERVICE_VERSION "1.0.102.0" -#define URTS_VERSION "1.0.102.0" -#define ENCLAVE_COMMON_VERSION "1.0.102.0" +#define UAE_SERVICE_VERSION "1.1.100.0" +#define URTS_VERSION "1.1.100.0" +#define ENCLAVE_COMMON_VERSION "1.0.103.0" diff --git a/common/inc/internal/se_wrapper.h b/common/inc/internal/se_wrapper.h index 22b58182..cf78de2b 100644 --- a/common/inc/internal/se_wrapper.h +++ b/common/inc/internal/se_wrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sgx_ecc256_internal.h b/common/inc/internal/sgx_ecc256_internal.h index 3583690e..c0a8be61 100644 --- a/common/inc/internal/sgx_ecc256_internal.h +++ b/common/inc/internal/sgx_ecc256_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sgx_memset_s.h b/common/inc/internal/sgx_memset_s.h index 607c080f..34d43d52 100644 --- a/common/inc/internal/sgx_memset_s.h +++ b/common/inc/internal/sgx_memset_s.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sgx_profile.h b/common/inc/internal/sgx_profile.h index 4dc500d9..dfe6cb26 100644 --- a/common/inc/internal/sgx_profile.h +++ b/common/inc/internal/sgx_profile.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sgx_read_rand.h b/common/inc/internal/sgx_read_rand.h index f29a7d53..8a031dff 100644 --- a/common/inc/internal/sgx_read_rand.h +++ b/common/inc/internal/sgx_read_rand.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sgx_sha256_128.h b/common/inc/internal/sgx_sha256_128.h index 74854a10..754f36dd 100644 --- a/common/inc/internal/sgx_sha256_128.h +++ b/common/inc/internal/sgx_sha256_128.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_atomic.h b/common/inc/internal/sl_atomic.h index f1353f07..2a30eca4 100644 --- a/common/inc/internal/sl_atomic.h +++ b/common/inc/internal/sl_atomic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_bitops.h b/common/inc/internal/sl_bitops.h index 58db8df6..45305629 100644 --- a/common/inc/internal/sl_bitops.h +++ b/common/inc/internal/sl_bitops.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_compiler.h b/common/inc/internal/sl_compiler.h index c13971aa..8999a786 100644 --- a/common/inc/internal/sl_compiler.h +++ b/common/inc/internal/sl_compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_debug.h b/common/inc/internal/sl_debug.h index 97253920..9917d56d 100644 --- a/common/inc/internal/sl_debug.h +++ b/common/inc/internal/sl_debug.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_fcall_mngr.h b/common/inc/internal/sl_fcall_mngr.h index dac2944b..f62beae1 100644 --- a/common/inc/internal/sl_fcall_mngr.h +++ b/common/inc/internal/sl_fcall_mngr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_fcall_mngr_common.h b/common/inc/internal/sl_fcall_mngr_common.h index ffcdab61..45a73e09 100644 --- a/common/inc/internal/sl_fcall_mngr_common.h +++ b/common/inc/internal/sl_fcall_mngr_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_init.h b/common/inc/internal/sl_init.h index de4ea82b..2892f22b 100644 --- a/common/inc/internal/sl_init.h +++ b/common/inc/internal/sl_init.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_memlog.h b/common/inc/internal/sl_memlog.h index 073b78db..0ab063a6 100644 --- a/common/inc/internal/sl_memlog.h +++ b/common/inc/internal/sl_memlog.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_once.h b/common/inc/internal/sl_once.h index 4c709866..e9d178d0 100644 --- a/common/inc/internal/sl_once.h +++ b/common/inc/internal/sl_once.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_printk.h b/common/inc/internal/sl_printk.h index 9f3a4594..164af792 100644 --- a/common/inc/internal/sl_printk.h +++ b/common/inc/internal/sl_printk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_siglines.h b/common/inc/internal/sl_siglines.h index 811ca68c..9a5b5d19 100644 --- a/common/inc/internal/sl_siglines.h +++ b/common/inc/internal/sl_siglines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_spinlock.h b/common/inc/internal/sl_spinlock.h index b8e5339e..c8b1a6f1 100644 --- a/common/inc/internal/sl_spinlock.h +++ b/common/inc/internal/sl_spinlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_types.h b/common/inc/internal/sl_types.h index e188ccdd..b79492e7 100644 --- a/common/inc/internal/sl_types.h +++ b/common/inc/internal/sl_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_uswitchless.h b/common/inc/internal/sl_uswitchless.h index b0747c57..147ef1a9 100644 --- a/common/inc/internal/sl_uswitchless.h +++ b/common/inc/internal/sl_uswitchless.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_util.h b/common/inc/internal/sl_util.h index 5663f7ed..b8d15a81 100644 --- a/common/inc/internal/sl_util.h +++ b/common/inc/internal/sl_util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/sl_workers.h b/common/inc/internal/sl_workers.h index c47c83ee..6498898e 100644 --- a/common/inc/internal/sl_workers.h +++ b/common/inc/internal/sl_workers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/ssl_wrapper.h b/common/inc/internal/ssl_wrapper.h index 6688c151..ad72e6ad 100644 --- a/common/inc/internal/ssl_wrapper.h +++ b/common/inc/internal/ssl_wrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/tae_service_internal.h b/common/inc/internal/tae_service_internal.h index 6aed3687..41a2a238 100644 --- a/common/inc/internal/tae_service_internal.h +++ b/common/inc/internal/tae_service_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/thread_data.h b/common/inc/internal/thread_data.h index 2d383302..5983c0d7 100644 --- a/common/inc/internal/thread_data.h +++ b/common/inc/internal/thread_data.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/trts_inst.h b/common/inc/internal/trts_inst.h index bfceb57f..8c615a44 100644 --- a/common/inc/internal/trts_inst.h +++ b/common/inc/internal/trts_inst.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/tseal_migration_attr.h b/common/inc/internal/tseal_migration_attr.h index 62d05e9c..1fe81f08 100644 --- a/common/inc/internal/tseal_migration_attr.h +++ b/common/inc/internal/tseal_migration_attr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,6 +44,9 @@ #define FLAGS_NON_SECURITY_BITS (0xFFFFFFFFFFFFC0ULL | SGX_FLAGS_MODE64BIT | SGX_FLAGS_PROVISION_KEY| SGX_FLAGS_EINITTOKEN_KEY) #define TSEAL_DEFAULT_FLAGSMASK (~FLAGS_NON_SECURITY_BITS) +#define FLAGS_SECURITY_BITS_RESERVED (~(FLAGS_NON_SECURITY_BITS | SGX_FLAGS_INITTED | SGX_FLAGS_DEBUG | SGX_FLAGS_KSS)) + + #define MISC_NON_SECURITY_BITS 0x0FFFFFFF /* bit[27:0]: have no security implications */ #define TSEAL_DEFAULT_MISCMASK (~MISC_NON_SECURITY_BITS) diff --git a/common/inc/internal/uae_service_internal.h b/common/inc/internal/uae_service_internal.h index 384695bc..50dd8ba6 100644 --- a/common/inc/internal/uae_service_internal.h +++ b/common/inc/internal/uae_service_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/uncopyable.h b/common/inc/internal/uncopyable.h index bc616e5c..d5baae3e 100644 --- a/common/inc/internal/uncopyable.h +++ b/common/inc/internal/uncopyable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/uswitchless.h b/common/inc/internal/uswitchless.h index 57a55a4e..3fd0f065 100644 --- a/common/inc/internal/uswitchless.h +++ b/common/inc/internal/uswitchless.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/util.h b/common/inc/internal/util.h index 95d7ca87..85516b64 100644 --- a/common/inc/internal/util.h +++ b/common/inc/internal/util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/internal/xsave.h b/common/inc/internal/xsave.h index cfdb575e..28c00720 100644 --- a/common/inc/internal/xsave.h +++ b/common/inc/internal/xsave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx.h b/common/inc/sgx.h index 7ed60869..0b90f811 100644 --- a/common/inc/sgx.h +++ b/common/inc/sgx.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_attributes.h b/common/inc/sgx_attributes.h index c407c930..f87df56f 100644 --- a/common/inc/sgx_attributes.h +++ b/common/inc/sgx_attributes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,7 +41,6 @@ #define SGX_FLAGS_PROVISION_KEY 0x0000000000000010ULL /* If set, then the enclave has access to provision key */ #define SGX_FLAGS_EINITTOKEN_KEY 0x0000000000000020ULL /* If set, then the enclave has access to EINITTOKEN key */ #define SGX_FLAGS_KSS 0x0000000000000080ULL /* If set enclave uses KSS */ -#define SGX_FLAGS_RESERVED (~(SGX_FLAGS_INITTED | SGX_FLAGS_DEBUG | SGX_FLAGS_MODE64BIT | SGX_FLAGS_PROVISION_KEY | SGX_FLAGS_EINITTOKEN_KEY | SGX_FLAGS_KSS)) /* XSAVE Feature Request Mask */ #define SGX_XFRM_LEGACY 0x0000000000000003ULL /* Legacy XFRM which includes the basic feature bits required by SGX, x87 state(0x01) and SSE state(0x02) */ @@ -49,7 +48,7 @@ #define SGX_XFRM_AVX512 0x00000000000000E6ULL /* AVX-512 XFRM - not supported */ #define SGX_XFRM_MPX 0x0000000000000018ULL /* MPX XFRM - not supported */ -#define SGX_XFRM_RESERVED (~(SGX_XFRM_LEGACY | SGX_XFRM_AVX)) +#define SGX_XFRM_RESERVED (~(SGX_XFRM_LEGACY | SGX_XFRM_AVX | SGX_XFRM_AVX512)) typedef struct _attributes_t { diff --git a/common/inc/sgx_capable.h b/common/inc/sgx_capable.h index 15b2fc40..ae2641ca 100644 --- a/common/inc/sgx_capable.h +++ b/common/inc/sgx_capable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_cpuid.h b/common/inc/sgx_cpuid.h index fdb97537..e4b0ff60 100644 --- a/common/inc/sgx_cpuid.h +++ b/common/inc/sgx_cpuid.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_defs.h b/common/inc/sgx_defs.h index 33484c9b..81a36c32 100644 --- a/common/inc/sgx_defs.h +++ b/common/inc/sgx_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_dh.h b/common/inc/sgx_dh.h index 2f9d06ef..d29a67ce 100644 --- a/common/inc/sgx_dh.h +++ b/common/inc/sgx_dh.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_ecp_types.h b/common/inc/sgx_ecp_types.h index f3844015..23b87208 100644 --- a/common/inc/sgx_ecp_types.h +++ b/common/inc/sgx_ecp_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_edger8r.h b/common/inc/sgx_edger8r.h index 091d3d77..4ad34ea9 100644 --- a/common/inc/sgx_edger8r.h +++ b/common/inc/sgx_edger8r.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_eid.h b/common/inc/sgx_eid.h index dbbb2456..96e1008b 100644 --- a/common/inc/sgx_eid.h +++ b/common/inc/sgx_eid.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_error.h b/common/inc/sgx_error.h index 39629981..8525f4c6 100644 --- a/common/inc/sgx_error.h +++ b/common/inc/sgx_error.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -113,6 +113,11 @@ typedef enum _status_t SGX_ERROR_FILE_CLOSE_FAILED = SGX_MK_ERROR(0x7009), /* fclose operation (to disk) failed (only used when no EXXX is returned) */ + SGX_ERROR_UNSUPPORTED_ATT_KEY_ID = SGX_MK_ERROR(0x8001), /* platform quoting infrastructure does not support the key.*/ + SGX_ERROR_ATT_KEY_CERTIFICATION_FAILURE = SGX_MK_ERROR(0x8002), /* Failed to generate and certify the attestation key.*/ + SGX_ERROR_ATT_KEY_UNINITIALIZED = SGX_MK_ERROR(0x8003), /* The platform quoting infrastructure does not have the attestation key available to generate quote.*/ + SGX_ERROR_INVALID_ATT_KEY_CERT_DATA = SGX_MK_ERROR(0x8004), /* TThe data returned by the platform library's sgx_get_quote_config() is invalid.*/ + SGX_INTERNAL_ERROR_ENCLAVE_CREATE_INTERRUPTED = SGX_MK_ERROR(0xF001), /* The ioctl for enclave_create unexpectedly failed with EINTR. */ } sgx_status_t; diff --git a/common/inc/sgx_intrin.h b/common/inc/sgx_intrin.h index 7dbd14b7..12f3135b 100644 --- a/common/inc/sgx_intrin.h +++ b/common/inc/sgx_intrin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_key.h b/common/inc/sgx_key.h index 3e558676..d7b73e1c 100644 --- a/common/inc/sgx_key.h +++ b/common/inc/sgx_key.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_key_exchange.h b/common/inc/sgx_key_exchange.h index c200d445..4abf88f0 100644 --- a/common/inc/sgx_key_exchange.h +++ b/common/inc/sgx_key_exchange.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_lfence.h b/common/inc/sgx_lfence.h index 1909e636..c161c480 100644 --- a/common/inc/sgx_lfence.h +++ b/common/inc/sgx_lfence.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_pcl_guid.h b/common/inc/sgx_pcl_guid.h index e5d24f78..92cf75b2 100644 --- a/common/inc/sgx_pcl_guid.h +++ b/common/inc/sgx_pcl_guid.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_quote.h b/common/inc/sgx_quote.h index 98c592ab..17652286 100644 --- a/common/inc/sgx_quote.h +++ b/common/inc/sgx_quote.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -99,6 +99,16 @@ typedef struct _update_info_bit int pswUpdate; } sgx_update_info_bit_t; +typedef struct _att_key_id_t { + uint8_t att_key_id[158]; +}sgx_att_key_id_t; + +typedef struct _qe_report_info_t { + sgx_quote_nonce_t nonce; + sgx_target_info_t app_enclave_target_info; + sgx_report_t qe_report; +}sgx_qe_report_info_t; + #pragma pack(pop) diff --git a/common/inc/sgx_random_buffers.h b/common/inc/sgx_random_buffers.h index ac904074..1940aa03 100644 --- a/common/inc/sgx_random_buffers.h +++ b/common/inc/sgx_random_buffers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -78,7 +78,7 @@ __attribute__((noinline)) static R _random_stack_noinline_wrapper(R(*f)(Ps...), template R random_stack_advance(R(*f)(Ps...), Qs&&... args) { -#if defined(MAXIMAL_CALLSTACK) || (defined(SGX_DEBUG_FLAG) && SGX_DEBUG_FLAG) +#if defined(MAXIMAL_CALLSTACK) unsigned size = M; #else unsigned size = rdrand() % M + 1; diff --git a/common/inc/sgx_report.h b/common/inc/sgx_report.h index 42321138..d7b9ac7f 100644 --- a/common/inc/sgx_report.h +++ b/common/inc/sgx_report.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_spinlock.h b/common/inc/sgx_spinlock.h index 3aa1dcaa..aaecfb11 100644 --- a/common/inc/sgx_spinlock.h +++ b/common/inc/sgx_spinlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tae_service.edl b/common/inc/sgx_tae_service.edl index 213cbc0e..c40f8c54 100644 --- a/common/inc/sgx_tae_service.edl +++ b/common/inc/sgx_tae_service.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tae_service.h b/common/inc/sgx_tae_service.h index 63e12cd5..e840ff0a 100644 --- a/common/inc/sgx_tae_service.h +++ b/common/inc/sgx_tae_service.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tcrypto.h b/common/inc/sgx_tcrypto.h index c87c16b2..c2053f25 100644 --- a/common/inc/sgx_tcrypto.h +++ b/common/inc/sgx_tcrypto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_thread.h b/common/inc/sgx_thread.h index 5a00ecd2..575b5d2b 100644 --- a/common/inc/sgx_thread.h +++ b/common/inc/sgx_thread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tkey_exchange.edl b/common/inc/sgx_tkey_exchange.edl index da0ea0ee..82f42822 100644 --- a/common/inc/sgx_tkey_exchange.edl +++ b/common/inc/sgx_tkey_exchange.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tkey_exchange.h b/common/inc/sgx_tkey_exchange.h index 15d2113a..b2d28d2b 100644 --- a/common/inc/sgx_tkey_exchange.h +++ b/common/inc/sgx_tkey_exchange.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tprotected_fs.edl b/common/inc/sgx_tprotected_fs.edl index 59e8e66a..2ac53116 100644 --- a/common/inc/sgx_tprotected_fs.edl +++ b/common/inc/sgx_tprotected_fs.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tprotected_fs.h b/common/inc/sgx_tprotected_fs.h index 8fc9d889..910ad104 100644 --- a/common/inc/sgx_tprotected_fs.h +++ b/common/inc/sgx_tprotected_fs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_trts.h b/common/inc/sgx_trts.h index 044d0a83..e8f6ae44 100644 --- a/common/inc/sgx_trts.h +++ b/common/inc/sgx_trts.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_trts_exception.h b/common/inc/sgx_trts_exception.h index e7aef66a..12bdf2e8 100644 --- a/common/inc/sgx_trts_exception.h +++ b/common/inc/sgx_trts_exception.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tseal.h b/common/inc/sgx_tseal.h index cc4364c0..419993a4 100644 --- a/common/inc/sgx_tseal.h +++ b/common/inc/sgx_tseal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_tstdc.edl b/common/inc/sgx_tstdc.edl index 0ca6b596..4124debc 100644 --- a/common/inc/sgx_tstdc.edl +++ b/common/inc/sgx_tstdc.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_uae_service.h b/common/inc/sgx_uae_service.h index 999c5b4a..b1ae4e14 100644 --- a/common/inc/sgx_uae_service.h +++ b/common/inc/sgx_uae_service.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -188,6 +188,173 @@ sgx_status_t SGXAPI sgx_report_attestation_status( */ sgx_status_t SGXAPI sgx_register_wl_cert_chain(uint8_t* p_wl_cert_chain, uint32_t wl_cert_chain_size); +/** + * Function used to select the attestation key from the list provided by the off-platform Quote verifier. + * + * @param p_att_key_id_list [In] List of the supported attestation key IDs provided by the quote verifier. Can not be + * NULL. it will use the p_att_key_id_list and compare it with the + * supported values. + * @param att_key_id_list_size The size of attestation key ID list. + * @param pp_selected_key_id [In, Out] Pointer to the selected attestation key in the list. This should be used by the + * application as input to the quoting and remote attestation APIs. Must not be NULL. Note, + * it will point to one of the entries in the p_att_key_id_list and the application must copy + * it if the memory for p_att_key_id_list will not persist for future quoting APIs calls. + * + * @return SGX_SUCCESS Successfully selected an attestation key. The pp_selected_key_id will point an entry in the + * p_att_key_id_list. + * @return SGX_ERROR_INVALID_PARAMETER Invalid parameter if p_att_key_id_list, pp_selected_key_id is NULL, + * list header is incorrect, or the number of key IDs in the list exceed the maximum. + * @return SGX_ERROR_UNSUPPORTED_ATT_KEY_ID The platform quoting infrastructure does not support any of the keys in the + * list. This can be because it doesn't carry the QE that owns the attestation key or the platform is in a + * mode that doesn't allow any of the listed keys; for example, for privacy reasons. + * @return SGX_ERROR_UNEXPECTED Unexpected internal error. + */ +sgx_status_t SGXAPI sgx_select_att_key_id(const uint8_t *p_att_key_id_list, uint32_t att_key_id_list_size, + sgx_att_key_id_t **pp_selected_key_id); + + + +/** + * The application calls this API to request the selected platform's attestation key owner to generate or obtain + * the attestation key. Once called, the QE that owns the attestation key described by the inputted attestation + * key id will do what is required to get this platform’s attestation including getting any certification data + * required from the PCE. Depending on the type of attestation key and the attestation key owner, this API will + * return the same attestation key public ID or generate a new one. The caller can request that the attestation + * key owner "refresh" the key. This will cause the owner to either re-get the key or generate a new one. The + * platform's attestation key owner is expected to store the key in persistent memory and use it in the + * subsequent quote generation APIs described below. + * + * In an environment where attestation key provisioning and certification needs to take place during a platform + * deployment phase, an application can generate the attestation key, certify it with the PCK Cert and register + * it with the attestation owners cloud infrastructure. That way, the key is available during the run time + * phase to generate code without requiring re-certification. + * + * The QE's target info is also returned by this API that will allow the application's enclave to generate a + * REPORT that the attestation key owner's QE can verify using local REPORT-based attestation when generating a + * quote. + * + * In order to allow the application to allocate the public key id buffer first, the application can call this + * function with the p_pub_key_id set to NULL and the p_pub_key_id_size to a valid size_t pointer. In this + * case, the function will return the required buffer size to contain the p_pub_key_id_size and ignore the other + * parameters. The application can then call this API again with the correct p_pub_key_size and the pointer to + * the allocated buffer in p_pub_key_id. + * + * + * @param p_att_key_id The selected att_key_id from the quote verifier's list. It includes the QE identity as + * well as the attestation key's algorithm type. It cannot be NULL. + * @param p_qe_target_info Pointer to QE's target info required by the application to generate an enclave REPORT + * targeting the selected QE. Must not be NULL when p_pub_key_id is not NULL. + * @param refresh_att_key A flag indicating the attestation key owner should re-generated and certify or + * otherwise attempt to re-provision the attestation key. For example, for ECDSDA, the + * platform will generate a new key and request the PCE to recertify it. For EPID, the + * platform will attempt to re-provision the EPID key. The behavior is dependent on the + * key type and the key owner, but it should make an attempt to refresh the key typically + * to update the key to the current platform's TCB. + * @param p_pub_key_id_size This parameter can be used in 2 ways. When p_pub_key_id is NULL, the API will + * return the buffer size required to hold the attestation's public key ID. The + * application can then allocate the buffer and call it again with p_pub_key_id not set + * to NULL and the other parameters valid. If p_pub_key_id is not NULL, p_pub_key_size + * must be large enough to hold the return attestation's public key ID. Must not be + * NULL. + * @param p_pub_key_id This parameter can be used in 2 ways. When it is passed in as NULL and p_pub_key_id_size + * is not NULL, the API will return the buffer size required to hold the attestation's + * public key ID. The other parameters will be ignored. When it is not NULL, it must point + * to a buffer which is at least a long as the value passed in by p_pub_key_id. Can either + * be NULL or point to the correct buffer.his will point to the buffer that will contain the + * attestation key's public identifier. If first called with a NULL pointer, the API will + * return the required length of the buffer in p_pub_key_id_size. + + * @return SGX_SUCCESS Successfully selected an attestation key. Either returns the required attestation's + * public key ID size in p_pub_key_id_size when p_pub_key_id is passed in as NULL. When p_pub_key_id is + * not NULL, p_qe_target_info will contain the attestation key's QE target info for REPORT generation + * and p_pub_key_id will contain the attestation's public key ID. + * @return SGX_ERROR_INVALID_PARAMETER Invalid parameter if p_pub_key_id_size, p_att_key_id is NULL. + * If p_pub_key_size is not NULL, the other parameters must be valid. + * @return SGX_ERROR_UNSUPPORTED_ATT_KEY_ID The platform quoting infrastructure does not support the key described + * in p_att_key_id. + * @return SGX_ERROR_ATT_KEY_CERTIFICATION_FAILURE Failed to generate and certify the attestation key. + * + */ +sgx_status_t SGXAPI sgx_init_quote_ex(const sgx_att_key_id_t* p_att_key_id, + sgx_target_info_t *p_qe_target_info, + bool refresh_att_key, + size_t* p_pub_key_id_size, + uint8_t* p_pub_key_id); + +/** + * The application needs to call this function before generating a quote. The quote size is variable + * depending on the type of attestation key selected and other platform or key data required to generate the + * quote. Once the application calls this API, it will use the returned p_quote_size to allocate the buffer + * required to hold the generated quote. A pointer to this buffer is provided to the ref_get_quote() API. + * + * If the key is not available, this API may return an error (SGX_ATT_KEY_NOT_INITIALIZED) depending on + * the algorithm. In this case, the caller must call sgx_init_quote() to re-generate and certify the + * attestation key. + * + * @param p_att_key_id The selected attestation key ID from the quote verifier's list. It includes the QE + * identity as well as the attestation key's algorithm type. It cannot be NULL. + * @param p_quote_size Pointer to the location where the required quote buffer size will be returned. Must + * not be NULL. + * + * @return SGX_SUCCESS Successfully calculated the required quote size. The required size in bytes is returned in the + * memory pointed to by p_quote_size. + * @return SGX_ERROR_INVALID_PARAMETER Invalid parameter. p_quote_size and p_att_key_id must not be NULL. + * @return SGX_ERROR_ATT_KEY_UNINITIALIZED The platform quoting infrastructure does not have the attestation + * key available to generate quotes. sgx_init_quote() must be called again. + * @return SGX_ERROR_UNSUPPORTED_ATT_KEY_ID The platform quoting infrastructure does not support the key + * described in p_att_key_id. + * @return SGX_ERROR_INVALID_ATT_KEY_CERT_DATA The data returned by the platform library's sgx_get_quote_config() is + * invalid. + */ +sgx_status_t SGXAPI sgx_get_quote_size_ex(const sgx_att_key_id_t *p_att_key_id, + uint32_t* p_quote_size); + +/** + * This function is c-code wrapper for getting the quote. The function will take the application enclave's REPORT that + * will be converted into a quote after the QE verifies the REPORT. Once verified it will sign it with platform's + * attestation key matching the selected attestation key ID. If the key is not available, this API may return an error + * (SGX_ATT_KEY_NOT_INITIALIZED) depending on the algorithm. In this case, the caller must call sgx_init_quote() + * to re-generate and certify the attestation key. an attestation key. + * + * The caller can request a REPORT from the QE using a supplied nonce. This will allow the enclave requesting the quote + * to verify the QE used to generate the quote. This makes it more difficult for something to spoof a QE and allows the + * app enclave to catch it earlier. But since the authenticity of the QE lies in knowledge of the Quote signing key, + * such spoofing will ultimately be detected by the quote verifier. QE REPORT.ReportData = + * SHA256(*p_nonce||*p_quote)||32-0x00's. + * + * @param p_app_report Pointer to the enclave report that needs the quote. The report needs to be generated using the + * QE's target info returned by the sgx_init_quote() API. Must not be NULL. + * @param p_att_key_id The selected attestation key ID from the quote verifier's list. It includes the QE identity as + * well as the attestation key's algorithm type. It cannot be NULL. + * @param p_qe_report_info Pointer to a data structure that will contain the information required for the QE to generate + * a REPORT that can be verified by the application enclave. The inputted data structure + * contains the application's TARGET_INFO, a nonce and a buffer to hold the generated report. + * The QE Report will be generated using the target information and the QE's REPORT.ReportData = + * SHA256(*p_nonce||*p_quote)||32-0x00's. This parameter is used when the application wants to + * verify the QE's REPORT to provide earlier detection that the QE is not being spoofed by + * untrusted code. A spoofed QE will ultimately be rejected by the remote verifier. This + * parameter is optional and will be ignored when NULL. + * @param p_quote Pointer to the buffer that will contain the quote. + * @param quote_size Size of the buffer pointed to by p_quote. + * + * @return SGX_SUCCESS Successfully generated the quote. + * @return SGX_ERROR_INVALID_PARAMETER If either p_app_report or p_quote is null. Or, if quote_size isn't large + * enough, p_att_key_id is NULL. + * @return SGX_ERROR_ATT_KEY_UNINITIALIZED The platform quoting infrastructure does not have the attestation key + * available to generate quotes. sgx_init_quote() must be called again. + * @return SGX_ERROR_UNSUPPORTED_ATT_KEY_ID The platform quoting infrastructure does not support the key described in + * p_att_key_id. + * @return SGX_ERROR_INVALID_ATT_KEY_CERT_DATA The data returned by the platform library's sgx_get_quote_config() is + * invalid. + * @return SGX_ERROR_MAC_MISMATCH Report MAC check failed on application report. + */ +sgx_status_t SGXAPI sgx_get_quote_ex(const sgx_report_t *p_app_report, + const sgx_att_key_id_t *p_att_key_id, + sgx_qe_report_info_t *p_qe_report_info, + uint8_t *p_quote, + uint32_t quote_size); + + #ifdef __cplusplus } #endif diff --git a/common/inc/sgx_ukey_exchange.h b/common/inc/sgx_ukey_exchange.h index c5da42f6..a77872de 100644 --- a/common/inc/sgx_ukey_exchange.h +++ b/common/inc/sgx_ukey_exchange.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -160,7 +160,7 @@ sgx_status_t SGXAPI sgx_ra_get_msg1( * membership revoked. * SGX_ERROR_INVALID_SIGNATURE The signature is invalid. * SGX_ERROR_MAC_MISMATCH Indicates verification - * error for reports, sealed + * error for reports, sealed * data, etc. * SGX_ERROR_KDF_MISMATCH Indicates key derivation * function doesn't match. @@ -192,6 +192,156 @@ sgx_status_t SGXAPI sgx_ra_proc_msg2( sgx_ra_msg3_t **pp_msg3, uint32_t *p_msg3_size); +/* + * sgx_ra_get_msg1_ex is used to get the remote attestation and key exchange + * protocol message 1 to send to a service provider. The application enclave + * should use sgx_ra_init/sgx_ra_init_ex function to create the remote + * attestation and key exchange process context and return it to the untrusted + * code. Besides, application also need to call sgx_select_att_key_id to select + * the attestation key from the list provided by the off-platform Quote verifier + * before the untrusted code can invoke this function. It is designed to be + * algorithm agnostic, it supports both EPID and ECDSA based remote attestation. + * Currently, only ECDSA is supported in this API. If you want to use EPID + * based attestation, please use sgx_ra_get_msg1. + * + * @param p_att_key_id Selected attestation key ID returned from + * sgx_select_att_key_id + * @param context Context returned by the sgx_ra_init function inside the + * application enclave. + * @param eid ID of the application enclave which is going to be + * attested. + * @param p_get_ga Function pointer of the ECALL proxy sgx_ra_get_ga + * generated by sgx_edger8r. The application enclave should + * link with sgx_tkey_exchange library and import + * sgx_tkey_exchange.edl in the enclave's EDL file to + * expose the ECALL proxy for sgx_ra_get_ga. + * @param p_msg1 Message 1 used by the remote attestation and key + * exchange protocol. + * @return sgx_status_t SGX_SUCCESS Indicates success. + * SGX_ERROR_INVALID_PARAMETER Invalid input parameters + * detected. + * SGX_ERROR_AE_INVALID_EPIDBLOB The EPID blob is + * corrupted. + * SGX_ERROR_INVALID_STATE SGX API is invoked in + * incorrect order or + * state. + * SGX_ERROR_BUSY The requested service is + * temporarily not + * available. + * SGX_ERROR_UPDATE_NEEDED SGX needs to be updated. + * SGX_ERROR_SERVICE_UNAVAILABLE The AE service did not + * respond. + * SGX_ERROR_SERVICE_TIMEOUT A request to the AE + * service timed out. + * SGX_ERROR_NETWORK_FAILURE Network connecting or + * proxy setting issue was + * encountered. + * SGX_ERROR_OUT_OF_MEMORY There is not enough + * memory available to + * complete this operation. + * SGX_ERROR_UNEXPECTED Indicates an unexpected + * error occurs. + * SGX_ERROR_UNSUPPORTED_ATT_KEY_ID The platform quoting + * infrastructure does not + * support the key described + * in p_att_key_id. + * SGX_ERROR_ATT_KEY_CERTIFICATION_FAILURE Failed to generate and + * certify the attestation + * key. + * And other possible return code from sgx_ecall. + */ +sgx_status_t SGXAPI sgx_ra_get_msg1_ex( + const sgx_att_key_id_t *p_att_key_id, + sgx_ra_context_t context, + sgx_enclave_id_t eid, + sgx_ecall_get_ga_trusted_t p_get_ga, + sgx_ra_msg1_t *p_msg1); + +/* + * sgx_ra_proc_msg2_ex is used to process the remote attestation and key exchange + * protocol message 2 from the service provider and generate message 3 to send + * to the service provider. If the service provider accepts message 3, + * negotiated session keys between the application enclave and the service + * provider are ready for use. The application enclave can use sgx_ra_get_keys + * function to retrieve the negotiated keys and use sgx_ra_close function to + * release the context of the remote attestation and key exchange process. + * It is designed to be algorithm agnostic, it supports both EPID and ECDSA + * based remote attestation. Currently, only ECDSA is supported in this API. + * If you want to use EPID based attestation, please use sgx_ra_proc_msg2. + * + * @param p_att_key_id Selected attestation key ID returned from + * sgx_select_att_key_id + * @param context Context returned by the sgx_ra_init function inside the + * application enclave. + * @param eid ID of the application enclave which is going to be + * attested. + * @param p_proc_msg2 Function pointer of the ECALL proxy sgx_ra_proc_msg2_trusted + * generated by sgx_edger8r. The application enclave should + * link with sgx_tkey_exchange library and import the + * sgx_tkey_exchange.edl in the application enclave's EDL + * file to expose the ECALL proxy for sgx_ra_proc_msg2. + * @param p_get_msg3 Function pointer of the ECALL proxy sgx_ra_get_msg3_trusted + * generated by sgx_edger8r. The application enclave should + * link with sgx_tkey_exchange library and import the + * sgx_tkey_exchange.edl in the application enclave's EDL + * file to expose the ECALL proxy for sgx_ra_get_msg3. + * @param p_msg2 sgx_ra_msg2_t message 2 from the service provider + * received by application. + * @param msg2_size The length of msg2 (in bytes). + * @param pp_msg3 sgx_ra_msg3_t message 3 to be sent to the service + * provider. The message buffer is allocated by the + * sgx_ukey_exchange library. The caller should free the + * buffer after use. + * @param p_msg3_size The length of msg3 (in bytes). + * @return sgx_status_t SGX_SUCCESS Indicates success. + * SGX_ERROR_INVALID_PARAMETER Invalid input parameters + * detected. + * SGX_ERROR_INVALID_STATE SGX API is invoked in + * incorrect order or + * state. + * SGX_ERROR_INVALID_SIGNATURE The signature is invalid. + * SGX_ERROR_MAC_MISMATCH Indicates verification + * error for reports, sealed + * data, etc. + * SGX_ERROR_KDF_MISMATCH Indicates key derivation + * function doesn't match. + * SGX_ERROR_BUSY The requested service is + * temporarily not + * available. + * SGX_ERROR_UPDATE_NEEDED SGX needs to be updated. + * SGX_ERROR_SERVICE_UNAVAILABLE The AE service did not + * respond. + * SGX_ERROR_SERVICE_TIMEOUT A request to the AE + * service timed out. + * SGX_ERROR_NETWORK_FAILURE Network connecting or + * proxy setting issue was + * encountered. + * SGX_ERROR_OUT_OF_MEMORY There is not enough + * memory available to + * complete this operation. + * SGX_ERROR_UNEXPECTED Indicates an unexpected + * error occurs. + * SGX_ERROR_UNSUPPORTED_ATT_KEY_ID The platform quoting + * infrastructure does not + * support the key described + * in p_att_key_id. + * SGX_ERROR_INVALID_ATT_KEY_CERT_DATA The data returned by the + * platform library's + * sgx_get_quote_config() is + * invalid. + * And other possible return code from sgx_ecall. + */ +sgx_status_t SGXAPI sgx_ra_proc_msg2_ex( + const sgx_att_key_id_t *p_att_key_id, + sgx_ra_context_t context, + sgx_enclave_id_t eid, + sgx_ecall_proc_msg2_trusted_t p_proc_msg2, + sgx_ecall_get_msg3_trusted_t p_get_msg3, + const sgx_ra_msg2_t *p_msg2, + uint32_t msg2_size, + sgx_ra_msg3_t **pp_msg3, + uint32_t *p_msg3_size); + #ifdef __cplusplus } #endif diff --git a/common/inc/sgx_urts.h b/common/inc/sgx_urts.h index 6c9d8a22..20cb0d7f 100644 --- a/common/inc/sgx_urts.h +++ b/common/inc/sgx_urts.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -80,9 +80,9 @@ typedef uint8_t sgx_launch_token_t[1024]; /* Convenient macro to be passed to sgx_create_enclave(). */ #if !defined(NDEBUG) || defined(EDEBUG) -#define SGX_DEBUG_FLAG ((int)1) +#define SGX_DEBUG_FLAG 1 #else -#define SGX_DEBUG_FLAG ((int)0) +#define SGX_DEBUG_FLAG 0 #endif sgx_status_t SGXAPI sgx_create_enclave(const char *file_name, diff --git a/common/inc/sgx_uswitchless.h b/common/inc/sgx_uswitchless.h index 4819faaa..45c95ccf 100644 --- a/common/inc/sgx_uswitchless.h +++ b/common/inc/sgx_uswitchless.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/sgx_utils.h b/common/inc/sgx_utils.h index 85ab64df..50785cb4 100644 --- a/common/inc/sgx_utils.h +++ b/common/inc/sgx_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/stdc++/exception b/common/inc/stdc++/exception index 30dc0e7e..ac8e3f18 100644 --- a/common/inc/stdc++/exception +++ b/common/inc/stdc++/exception @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/stdc++/new b/common/inc/stdc++/new index 761cea8d..5b278935 100644 --- a/common/inc/stdc++/new +++ b/common/inc/stdc++/new @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/inc/stdc++/typeinfo b/common/inc/stdc++/typeinfo index 6ddcb0c9..6ad7cb8f 100644 --- a/common/inc/stdc++/typeinfo +++ b/common/inc/stdc++/typeinfo @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/se_wrapper/Makefile b/common/se_wrapper/Makefile index 685f0247..bdb0b75a 100644 --- a/common/se_wrapper/Makefile +++ b/common/se_wrapper/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/common/src/crypto_cmac_128.cpp b/common/src/crypto_cmac_128.cpp index acc6b3ce..6071785c 100644 --- a/common/src/crypto_cmac_128.cpp +++ b/common/src/crypto_cmac_128.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/crypto_evp_digest.cpp b/common/src/crypto_evp_digest.cpp index 7db8bc3e..7596a02e 100644 --- a/common/src/crypto_evp_digest.cpp +++ b/common/src/crypto_evp_digest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/dh.cpp b/common/src/dh.cpp index 520aef16..692cb438 100644 --- a/common/src/dh.cpp +++ b/common/src/dh.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/ecp.cpp b/common/src/ecp.cpp index 5d3c452b..dd9f3d24 100644 --- a/common/src/ecp.cpp +++ b/common/src/ecp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/linux/xsave_gnu.S b/common/src/linux/xsave_gnu.S index 2df71303..665ec162 100644 --- a/common/src/linux/xsave_gnu.S +++ b/common/src/linux/xsave_gnu.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/se_event.c b/common/src/se_event.c index 68daffc7..cfe6f589 100644 --- a/common/src/se_event.c +++ b/common/src/se_event.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/se_map.c b/common/src/se_map.c index 30759ec0..2e8b3314 100644 --- a/common/src/se_map.c +++ b/common/src/se_map.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/se_memory.c b/common/src/se_memory.c index 22fc4f45..7d287682 100644 --- a/common/src/se_memory.c +++ b/common/src/se_memory.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/se_rwlock.c b/common/src/se_rwlock.c index ee4aff62..bfff783a 100644 --- a/common/src/se_rwlock.c +++ b/common/src/se_rwlock.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/se_thread.c b/common/src/se_thread.c index c8e19958..2bfed7b2 100644 --- a/common/src/se_thread.c +++ b/common/src/se_thread.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/se_time.c b/common/src/se_time.c index d1c8f287..0bc627e2 100644 --- a/common/src/se_time.c +++ b/common/src/se_time.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/se_trace.c b/common/src/se_trace.c index dfe3dd1b..e0bb949c 100644 --- a/common/src/se_trace.c +++ b/common/src/se_trace.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/sgx_profile.cpp b/common/src/sgx_profile.cpp index aa08d4b2..9ee26bce 100644 --- a/common/src/sgx_profile.cpp +++ b/common/src/sgx_profile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/sgx_read_rand.cpp b/common/src/sgx_read_rand.cpp index 55f85625..7c198061 100644 --- a/common/src/sgx_read_rand.cpp +++ b/common/src/sgx_read_rand.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/sgx_sha256_128.cpp b/common/src/sgx_sha256_128.cpp index 24ba3783..1247945f 100644 --- a/common/src/sgx_sha256_128.cpp +++ b/common/src/sgx_sha256_128.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/sl_fcall_mngr_common.c b/common/src/sl_fcall_mngr_common.c index aa3de70e..e23b3fcf 100644 --- a/common/src/sl_fcall_mngr_common.c +++ b/common/src/sl_fcall_mngr_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/sl_memlog_common.c b/common/src/sl_memlog_common.c index 8b2c7488..68d98a75 100644 --- a/common/src/sl_memlog_common.c +++ b/common/src/sl_memlog_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/sl_once_common.c b/common/src/sl_once_common.c index b2085378..41a20de8 100644 --- a/common/src/sl_once_common.c +++ b/common/src/sl_once_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/common/src/sl_siglines_common.c b/common/src/sl_siglines_common.c index a177c782..43320a2f 100644 --- a/common/src/sl_siglines_common.c +++ b/common/src/sl_siglines_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/download_prebuilt.sh b/download_prebuilt.sh index 247fcb83..87ead394 100755 --- a/download_prebuilt.sh +++ b/download_prebuilt.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -33,10 +33,10 @@ top_dir=`dirname $0` out_dir=$top_dir -optlib_name=optimized_libs_2.4.tar.gz -ae_file_name=prebuilt_ae_2.4.tar.gz -checksum_file=SHA256SUM_prebuilt_2.4.txt -server_url_path=https://download.01.org/intel-sgx/linux-2.4/ +optlib_name=optimized_libs_2.5.tar.gz +ae_file_name=prebuilt_ae_2.5.tar.gz +checksum_file=SHA256SUM_prebuilt_2.5.txt +server_url_path=https://download.01.org/intel-sgx/linux-2.5/ server_optlib_url=$server_url_path/$optlib_name server_ae_url=$server_url_path/$ae_file_name server_checksum_url=$server_url_path/$checksum_file diff --git a/external/CppMicroServices/.clang-format b/external/CppMicroServices/.clang-format new file mode 100644 index 00000000..2892f235 --- /dev/null +++ b/external/CppMicroServices/.clang-format @@ -0,0 +1,9 @@ +--- +BasedOnStyle: Mozilla + +# Reflowing comments interfers with .rst identation +ReflowComments: false +AlwaysBreakAfterReturnType: None +AlwaysBreakAfterDefinitionReturnType: None +IndentPPDirectives: AfterHash +... diff --git a/external/CppMicroServices/.gitignore b/external/CppMicroServices/.gitignore new file mode 100644 index 00000000..fa8bd9dc --- /dev/null +++ b/external/CppMicroServices/.gitignore @@ -0,0 +1,50 @@ +*~ +*.o +*.so +CMakeLists.txt.user* +CMakeSettings.json +gh-pages +doc/_api +doc/_build +doc/src/examples/makefile/main +*.tlog +*.lastbuildstate +*.obj +*.unsuccessfulbuild +*.lib +*.bak +*.map +*.pdb +*.dll +*.exe +*.vcxproj +*.filters +*.stamp +*.log +*.zip +*.cache +*.depend +*.suo +*.opensdf +*.sdf +*.rule +*.sln +*.exp +*.bin +*.user +._* +*.dylib +*.xcconfig +*.pbxproj +*.DS_Store +*.pyc +third_party/googletest +!third_party/googletest/CMakeLists.txt +!third_party/googletest/README.md +!third_party/googletest/googletest/LICENSE +!third_party/googletest/googletest/README.md +!third_party/googletest/googletest/CMakeLists.txt +!third_party/googletest/googletest/cmake +!third_party/googletest/googletest/include +!third_party/googletest/googletest/src +/build* diff --git a/external/CppMicroServices/.travis.yml b/external/CppMicroServices/.travis.yml new file mode 100644 index 00000000..8374cbb2 --- /dev/null +++ b/external/CppMicroServices/.travis.yml @@ -0,0 +1,118 @@ +sudo: false + +language: cpp + +env: + global: + - PATH=$HOME/cache/bin/:$PATH + - BUILD_DIR=/tmp/cppmicroservices_builds + - BUILD_CONFIGURATION=0 + - secure: "g2dT1rLVDXAR7uFkhgKlm7rUqCPHwl+o4CFSqEo5w9H/M5xuuQLP597J8qwhgkWutJABM4G4zLF9yzb5rTbUH1BSdGTzmdUkvJGvLOFq09xwLQP5PAKlq6s1dpVr7J9Ciy49cEVDD2leaikMf9zK3ty9Fv5F2mL3Itd6a/U5M5o=" + +# We do not test all build configurations with all compiler / platform +# combinations. For now, just the latest compilers being tested will +# run all build configurations. + +matrix: + include: + + # Test our minimum GCC version, which is gcc 5.4 on Ubuntu Trusty + - os: linux + addons: { apt: { packages: ["valgrind", "gcc-5", "g++-5"], sources: ["ubuntu-toolchain-r-test"] } } + env: MY_CC=gcc-5 MY_CXX=g++-5 + + # Test our minium Clang version, which is clang 3.4 on Ubuntu Trusty + - os: linux + addons: { apt: { packages: ["valgrind", "clang-3.4", "libc++-dev", "libc++abi-dev"], sources: ["ubuntu-toolchain-r-test"] } } + # Travis puts /usr/local/clang-5.0.0/bin in front of the path, so we have to "fix" that + env: MY_CC=clang MY_CXX=clang++ PATH=/usr/bin:$PATH + + # Test one build configuration with the latest available Clang + - os: linux + addons: { apt: { packages: ["valgrind", "clang-6.0", "libc++-dev", "libc++abi-dev"], sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-6.0"] } } + env: MY_CC=clang-6.0 MY_CXX=clang++-6.0 + + # Test all build configuration with the latest available GCC + - os: linux + addons: &gcc8-valgrind { apt: { packages: ["valgrind", "gcc-8", "g++-8"], sources: ["ubuntu-toolchain-r-test"] } } + env: MY_CC=gcc-8 MY_CXX=g++-8 WITH_COVERAGE=1 + + - os: linux + addons: *gcc8-valgrind + env: MY_CC=gcc-8 MY_CXX=g++-8 BUILD_CONFIGURATION=1 WITH_COVERAGE=1 + + - os: linux + addons: *gcc8-valgrind + env: MY_CC=gcc-8 MY_CXX=g++-8 BUILD_CONFIGURATION=2 WITH_COVERAGE=1 + + - os: linux + addons: *gcc8-valgrind + env: MY_CC=gcc-8 MY_CXX=g++-8 BUILD_CONFIGURATION=3 WITH_COVERAGE=1 + + # minimum supported compiler on OS X + - os: osx + osx_image: xcode7.3 + compiler: clang + env: MACOSX_DEPLOYMENT_TARGET=10.11 + + - os: osx + osx_image: xcode7.3 + compiler: clang + env: BUILD_CONFIGURATION=1 MACOSX_DEPLOYMENT_TARGET=10.11 + + # latest compiler on OS X + - os: osx + osx_image: xcode9.4 + compiler: clang + env: BUILD_CONFIGURATION=0 MACOSX_DEPLOYMENT_TARGET=10.13 WITH_COVERAGE=1 + + - os: osx + osx_image: xcode9.4 + compiler: clang + env: BUILD_CONFIGURATION=1 MACOSX_DEPLOYMENT_TARGET=10.13 WITH_COVERAGE=1 + + - os: osx + osx_image: xcode9.4 + compiler: clang + env: BUILD_CONFIGURATION=2 MACOSX_DEPLOYMENT_TARGET=10.13 WITH_COVERAGE=1 + + - os: osx + osx_image: xcode9.4 + compiler: clang + env: BUILD_CONFIGURATION=3 MACOSX_DEPLOYMENT_TARGET=10.13 WITH_COVERAGE=1 + +cache: + directories: + - $HOME/cache + +branches: + except: + - gh_pages + +addons: + coverity_scan: + project: + name: CppMicroServices/CppMicroServices + description: "Build submitted via Travis CI" + notification_email: sascha.zelzer@gmail.com + build_command_prepend: "mkdir us-cov; cd us-cov; cmake -DCMAKE_BUILD_TYPE:STRING=Release -DUS_BUILD_EXAMPLES:BOOL=ON -DUS_BUILD_TESTING:BOOL=ON -DUS_BUILD_SHARED_LIBS:BOOL=ON ../" + build_command: "make -j 4" + branch_pattern: coverity_scan + + +before_install: + - test $TRAVIS_BRANCH != coverity_scan -o ${TRAVIS_JOB_NUMBER##*.} = 1 || exit 0 + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then bash install_cmake.sh ; fi + - export CC=$MY_CC CXX=$MY_CXX + - env + - cmake --version + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then $CXX --version; fi + + +script: + - test $TRAVIS_BRANCH != coverity_scan || exit 0 + - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ctest -VV -S ./cmake/usCTestScript_travis.cmake ; fi + +after_success: + - bash <(curl -s https://codecov.io/bash) -X gcov -s "/tmp/cppmicroservices_builds" + diff --git a/external/CppMicroServices/CHANGELOG.rst b/external/CppMicroServices/CHANGELOG.rst new file mode 100644 index 00000000..8c212483 --- /dev/null +++ b/external/CppMicroServices/CHANGELOG.rst @@ -0,0 +1,314 @@ +Change Log +========== + +All notable changes to this project will be documented in this file. + +The format is based on `Keep a Changelog `_ +and this project adheres to `Semantic Versioning `_. + +`Unreleased v4.0.0 `_ (2018-XX-XX) +--------------------------------------------------------------------------------------------------------- + +`Full Changelog `_ + +Added +----- + +Changed +------- + +Removed +------- + +Deprecated +---------- + +Fixed +----- + + +`v3.3.0 `_ (2018-02-20) +----------------------------------------------------------------------------------------- + +`Full Changelog `_ + +Added +----- + +- Support constructing long LDAP expressions using concise C++ + `#246 `_ +- Bundle manifest validation + `#182 `_ + +Fixed +----- + +- Fix seg faults when using default constructed LDAPFilter + `#251 `_ + +`v3.2.0 `_ (2017-10-30) +----------------------------------------------------------------------------------------- + +`Full Changelog `_ + +Added +----- + +- Code coverage metrics. + `#219 `_ +- GTest integration. + `#200 `_ +- Support boolean properties in LDAP filter creation. + `#224 `_ +- Unicode support. + `#245 `_ + +Changed +------- + +- Re-enable single-threaded build configuration. + `#239 `_ + +Fixed +----- + +- Fix a race condition when getting and ungetting a service. + `#202 `_ +- Make reading the current working directory thread-safe. + `#209 `_ +- Guard against recursive service factory calls. + `#213 `_ +- Fix LDAP filter match logic to properly handle keys starting with the same sub-string. + `#227 `_ +- Fix seg fault when using a default constructed LDAPFilter instance. + `#232 `_ +- Several fixes with respect to error code handling. + `#238 `_ +- IsConvertibleTo method doesn't check for validity of member. + `#240 `_ + +`v3.1.0 `_ (2017-06-01) +----------------------------------------------------------------------------------------- + +`Full Changelog `_ + +Changed +~~~~~~~ + +- Improved BadAnyCastException message. `#181 `_ +- Support installing bundles that do not have .DLL/.so/.dylib file extensions. `#205 `_ + +Deprecated +~~~~~~~~~~ + +- The following BundleContext member functions: + + * ``RemoveBundleListener`` + * ``RemoveFrameworkListener`` + * ``RemoveServiceListener`` + + And the variants of + + * ``AddBundleListener`` + * ``AddFrameworkListener``, + * ``AddServiceListener`` + + that take member functions. + +- The free functions: + + * ``ServiceListenerMemberFunctor`` + * ``BundleListenerMemberFunctor`` + * ``BindFrameworkListenerToFunctor`` + +- The functions + + * ``ShrinkableVector::operator[std::size_t]`` + * ``ShrinkableMap::operator[const Key&]`` + + +Fixed +~~~~~ + +- Cannot add more than one listener if its expressed as a lambda. + `#95 `_ +- Removing Listeners does not work well + `#83 `_ +- Crash when trying to acquire bundle context + `#172 `_ +- Fix for ``unsafe_any_cast`` + `#198 `_ +- Stopping a framework while bundle threads are still running may deadlock + `#210 `_ + +`v3.0.0 `_ (2017-02-08) +----------------------------------------------------------------------------------------- + +`Full Changelog `_ + +See the `migration guide `_ +for moving from a 2.x release to 3.x. + +Added +~~~~~ + +- Added MinGW-w64 to the continuous integration matrix + `#168 `_ +- Include major version number in library names and install dirs + `#144 `_ +- Integrated coverity scan reports + `#16 `_ +- Added OS X to the continuous integration matrix + `#136 `_ +- Building for Android is now supported + `#106 `_ +- Enhanced the project structure to support sub-projects + `#14 `_ +- The bundle life-cycle now supports all states as described by OSGi + and is controllable by the user + `#25 `_ +- Added support for framework listeners and improved logging + `#40 `_ +- Implemented framework properties + `#42 `_ +- Static bundles embedded into an executable are now auto-installed + `#109 `_ +- LDAP queries can now be run against bundle meta-data + `#53 `_ +- Resources from bundles can now be accessed without loading their + shared library + `#15 `_ +- Support last modified time for embedded resources + `#13 `_ + +Changed +~~~~~~~ + +- Fix up bundle property and manifest header handling + `#135 `_ +- Introduced C++11 features + `#35 `_ +- Re-organize header files + `#43 `_, + `#67 `_ +- Improved memory management for framework objects and services + `#38 `_ +- Removed static globals + `#31 `_ +- Switched to using OSGi nomenclature in class names and functions + `#46 `_ +- Improved static bundle support + `#21 `_ +- The resource compiler was ported to C++ and gained improved command line options + `#55 `_ +- Changed System Bundle ID to ``0`` + `#45 `_ +- Output exception details (if available) for troubleshooting + `#27 `_ +- Using the ``US_DECLARE_SERVICE_INTERFACE`` macro is now optional + `#24 `_ +- The ``Any::ToString()`` function now outputs JSON formatted text + `#12 `_ + +Removed +~~~~~~~ + +- The autoload feature was removed from the framework + `#75 `__ + +Fixed +~~~~~ + +- Headers with ``_p.h`` suffix do not get resolved in Xcode for automatic-tracking of counterparts + `#93 `_ +- ``usUtils.cpp`` - Crash can occur if ``FormatMessage(...)`` fails + `#33 `_ +- Using ``US_DECLARE_SERVICE_INTERFACE`` with Qt does not work + `#19 `_ +- Fixed documentation of public headers. + `#165 `_ + +`v2.1.1 `_ (2014-01-22) +----------------------------------------------------------------------------------------- + +`Full Changelog `_ + +Fixed +~~~~~ + +- Resource compiler not found error + `#11 `_ + +`v2.1.0 `_ (2014-01-11) +----------------------------------------------------------------------------------------- + +`Full Changelog `_ + +Changed +~~~~~~~ + +- Use the version number from CMakeLists.txt in the manifest file + `#10 `_ + +Fixed +~~~~~ + +- Build fails on Mac OS Mavericks with 10.9 SDK + `#7 `_ +- Comparison of service listener objects is buggy on VS 2008 + `#9 `_ +- Service listener memory leak + `#8 `_ + +`v2.0.0 `_ (2013-12-23) +----------------------------------------------------------------------------------------- + +`Full Changelog `_ + +Major release with backwards incompatible changes. See the `migration guide +`_ +for a detailed list of changes. + +Added +~~~~~ + +- Removed the base class requirement for service objects +- Improved compile time type checking when working with the service + registry +- Added a new service factory class for creating multiple service + instances based on RFC 195 Service Scopes +- Added ModuleFindHook and ModuleEventHook classes +- Added Service Hooks support +- Added the utility class ``us::LDAPProp`` for creating LDAP filter + strings fluently +- Added support for getting file locations for writing persistent data + +Removed +~~~~~~~ + +- Removed the output stream operator for ``us::Any`` + +Fixed +~~~~~ + +- ``US_ABI_LOCAL`` and symbol visibility for gcc < 4 + `#6 `_ + +`v1.0.0 `_ (2013-07-18) +----------------------------------------------------------------------------------------- + +Initial release. + +Fixed +~~~~~ + +- Build fails on Windows with VS 2012 RC due to CreateMutex + `#5 `_ +- usConfig.h not added to framework on Mac + `#4 `_ +- ``US_DEBUG`` logs even when not in debug mode + `#3 `_ +- Segmentation error after unloading module + `#2 `_ +- Build fails on Ubuntu 12.04 + `#1 `_ diff --git a/external/CppMicroServices/CMakeLists.txt b/external/CppMicroServices/CMakeLists.txt new file mode 100644 index 00000000..0e8a661c --- /dev/null +++ b/external/CppMicroServices/CMakeLists.txt @@ -0,0 +1,655 @@ +# Extract the current version from the VERSION file +file(STRINGS VERSION _version LIMIT_COUNT 1) + +set(US_CMAKE_MINIMUM_REQUIRED_VERSION 3.2) + +cmake_minimum_required(VERSION ${US_CMAKE_MINIMUM_REQUIRED_VERSION}) + +project(CppMicroServices VERSION ${_version}) + +set(US_GLOBAL_VERSION_SUFFIX ${${PROJECT_NAME}_VERSION_MAJOR}) +if (${PROJECT_NAME}_VERSION_MINOR EQUAL 99) + math(EXPR US_GLOBAL_VERSION_SUFFIX "${US_GLOBAL_VERSION_SUFFIX}+1") +endif() + +string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) + +cmake_policy(VERSION ${US_CMAKE_MINIMUM_REQUIRED_VERSION}) + +list(APPEND policies_new + CMP0025 # Compiler id for Apple Clang is now AppleClang (CMake 3.0) + CMP0054 # Only interpret if() arguments as variables or keywords when unquoted + ) +foreach(policy ${policies_new}) + if(POLICY ${policy}) + cmake_policy(SET ${policy} NEW) + endif() +endforeach() + +#----------------------------------------------------------------------------- +# Check minimum required compiler versions +#------------------------------------------------------------------------------ + +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED 1) +set(CMAKE_CXX_STANDARD 11) + +# Since version 3.1, CMake pulls in implicit link libraries when compiling +# source files in C mode. Because we mix C and C++ code in the test driver +# executable, we end up with a gcc_eh link dependency when using MinGW +# which breaks exception handling in the executable. See also: +# +# https://stackoverflow.com/questions/46688200/mixing-c-and-c-causing-exceptions-to-terminate +# +set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "") + +# We make use of the following C++11 language and library features: +# +# Language feature GCC Clang Xcode VisualStudio +# ------------------------------------------------------------------- +# Rvalue references 4.3 2.9 6 2012 +# Variadic templates 4.3 2.9 6 2013* +# Initializer lists 4.4 3.1 6 2013 +# Static assertions 4.3 2.9 6 2010 +# auto 4.4 2.9 6 2010 +# Lambdas 4.5 3.1 6 2012 +# decltype 4.3 2.9 6 2012 +# Right angle brackets 4.3 2.9 6 2010 +# Null pointer constant 4.6 3.0 6 2010 +# Explicit conversion operators 4.5 3.0 6 2013 +# Defaulted functions 4.4 3.0 6 2013* +# Deleted functions 4.4 2.9 6 2013* +# Range-based for 4.6 3.0 6 2012 +# Atomic operations 4.4 3.1 6 2012 +# thread_local (optional) 4.8 3.3 8 2015 +# +# Library features used +# --------------------- +# function +# unique_ptr +# shared_ptr +# unordered_map +# unordered_set +# atomic +# mutex +# wait_condition +# exception_ptr + +set(US_COMPILER_GNU_MINIMUM_VERSION 4.8 ) +set(US_COMPILER_Clang_MINIMUM_VERSION 3.4 ) +set(US_COMPILER_AppleClang_MINIMUM_VERSION 7.3 ) +set(US_COMPILER_MSVC_MINIMUM_VERSION 19.00.23026 ) + +set(US_COMPILER_GNU_MINIMUM_VERSION_PRODUCT "GCC ${US_COMPILER_GNU_MINIMUM_VERSION}") +set(US_COMPILER_Clang_MINIMUM_VERSION_PRODUCT "Clang ${US_COMPILER_CLANG_MINIMUM_VERSION}") +set(US_COMPILER_AppleClang_MINIMUM_VERSION_PRODUCT "Xcode 7.3 (Clang ${US_COMPILER_AppleClang_MINIMUM_VERSION})") +set(US_COMPILER_MSVC_MINIMUM_VERSION_PRODUCT "Visual Studio 2015 (MSVC ${US_COMPILER_MSVC_MINIMUM_VERSION})") + +set(US_COMPILER_GNU_MINIMUM_RECOMMENDED_VERSION 5.4 ) +set(US_COMPILER_Clang_MINIMUM_RECOMMENDED_VERSION 3.4 ) +set(US_COMPILER_AppleClang_MINIMUM_RECOMMENDED_VERSION 8.0 ) +set(US_COMPILER_MSVC_MINIMUM_RECOMMENDED_VERSION 19.00 ) + +set(US_COMPILER_GNU_MINIMUM_RECOMMENDED_VERSION_PRODUCT "GCC ${US_COMPILER_GNU_MINIMUM_RECOMMENDED_VERSION}") +set(US_COMPILER_Clang_MINIMUM_RECOMMENDED_VERSION_PRODUCT "Clang ${US_COMPILER_Clang_MINIMUM_RECOMMENDED_VERSION}") +set(US_COMPILER_AppleClang_MINIMUM_RECOMMENDED_VERSION_PRODUCT "Xcode 8.0 (Clang ${US_COMPILER_AppleClang_MINIMUM_RECOMMENDED_VERSION})") +set(US_COMPILER_MSVC_MINIMUM_RECOMMENDED_VERSION_PRODUCT "Visual Studio 2015 (MSVC ${US_COMPILER_MSVC_MINIMUM_RECOMMENDED_VERSION})") + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(US_COMPILER_GNU 1) +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(US_COMPILER_CLANG 1) +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + set(US_COMPILER_APPLE_CLANG 1) +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(US_COMPILER_MSVC 1) +else() + message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang (Linux or Apple), GCC and MSVC.") +endif() + +if (CMAKE_CXX_COMPILER_VERSION AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${US_COMPILER_${CMAKE_CXX_COMPILER_ID}_MINIMUM_VERSION}) + message(FATAL_ERROR "${US_COMPILER_${CMAKE_CXX_COMPILER_ID}_MINIMUM_VERSION_PRODUCT} or higher required (you are using ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}).") +endif() + +#----------------------------------------------------------------------------- +# Update CMake module path +#------------------------------------------------------------------------------ + +set(US_CMAKE_DIR ${PROJECT_SOURCE_DIR}/cmake) + +set(CMAKE_MODULE_PATH + ${US_CMAKE_DIR} + ${CMAKE_MODULE_PATH} + ) + +#----------------------------------------------------------------------------- +# CMake function(s) and macro(s) +#----------------------------------------------------------------------------- + +include(CMakeParseArguments) +include(CMakePackageConfigHelpers) +include(CheckCXXSourceCompiles) +include(usFunctionAddResources) +include(usFunctionEmbedResources) +include(usFunctionGetResourceSource) +include(usFunctionCheckResourceLinking) +include(usFunctionCheckCompilerFlags) +include(usFunctionGenerateBundleInit) +include(usMacroCreateBundle) + +if(US_BUILD_TESTING) + include(usFunctionCompileSnippets) +endif() + +#----------------------------------------------------------------------------- +# Init output directories +#----------------------------------------------------------------------------- + +set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") + +foreach(_type ARCHIVE LIBRARY RUNTIME) + if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) + set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) + endif() +endforeach() + +#----------------------------------------------------------------------------- +# Set a default build type if none was specified +#----------------------------------------------------------------------------- + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'Debug' as none was specified.") + set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) + + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +#----------------------------------------------------------------------------- +# CMake options +#----------------------------------------------------------------------------- + +function(us_cache_var _var_name _var_default _var_type _var_help) + set(_advanced 0) + set(_force) + foreach(_argn ${ARGN}) + if(_argn STREQUAL ADVANCED) + set(_advanced 1) + elseif(_argn STREQUAL FORCE) + set(_force FORCE) + endif() + endforeach() + + set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) + if(_advanced) + mark_as_advanced(${_var_name}) + endif() +endfunction() + +# Determine the name of the install component for "SDK" artifacts. +# The default is "sdk" +if(NOT DEFINED US_SDK_INSTALL_COMPONENT) + set(US_SDK_INSTALL_COMPONENT COMPONENT sdk) +elseif(US_SDK_INSTALL_COMPONENT) + set(US_SDK_INSTALL_COMPONENT COMPONENT ${US_SDK_INSTALL_COMPONENT}) +endif() + +us_cache_var(CMAKE_DEBUG_POSTFIX d STRING "Executable and library debug name postfix" ADVANCED) + +us_cache_var(US_ENABLE_THREADING_SUPPORT ON BOOL "Enable threading support") +us_cache_var(US_ENABLE_TSAN OFF BOOL "Enable tsan (thread sanitizer)" ADVANCED) +us_cache_var(US_ENABLE_COVERAGE OFF BOOL "Enable code coverage" ADVANCED) +us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") +us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") +us_cache_var(US_BUILD_EXAMPLES OFF BOOL "Build example projects") +us_cache_var(US_USE_SYSTEM_GTEST OFF BOOL "Build using an external GTest installation" ADVANCED) + +if(NOT US_ENABLE_THREADING_SUPPORT AND US_ENABLE_TSAN) + message(SEND_WARN "Thread-sanitizer enabled without threading support. Forcing US_ENABLE_TSAN to OFF") + set(US_ENABLE_TSAN OFF) +endif() + +if(WIN32 AND NOT CYGWIN) + set(default_runtime_install_dir bin/) + set(default_library_install_dir bin/) + set(default_archive_install_dir lib/) + set(default_header_install_dir include/${PROJECT_NAME_LOWER}${US_GLOBAL_VERSION_SUFFIX}) + set(default_auxiliary_install_dir share/${PROJECT_NAME_LOWER}${US_GLOBAL_VERSION_SUFFIX}) + set(default_doc_install_dir ${default_auxiliary_install_dir}/doc) + set(default_man_install_dir share/man) +else() + set(default_runtime_install_dir bin/) + set(default_library_install_dir lib/) + set(default_archive_install_dir lib/) + set(default_header_install_dir include/${PROJECT_NAME_LOWER}${US_GLOBAL_VERSION_SUFFIX}) + set(default_auxiliary_install_dir share/${PROJECT_NAME_LOWER}${US_GLOBAL_VERSION_SUFFIX}) + set(default_doc_install_dir ${default_auxiliary_install_dir}/doc) + set(default_man_install_dir share/man) +endif() + +us_cache_var(RUNTIME_INSTALL_DIR ${default_runtime_install_dir} STRING "Relative install location for binaries" ADVANCED) +us_cache_var(LIBRARY_INSTALL_DIR ${default_library_install_dir} STRING "Relative install location for libraries" ADVANCED) +us_cache_var(ARCHIVE_INSTALL_DIR ${default_archive_install_dir} STRING "Relative install location for archives" ADVANCED) +us_cache_var(HEADER_INSTALL_DIR ${default_header_install_dir} STRING "Relative install location for headers" ADVANCED) +us_cache_var(AUXILIARY_INSTALL_DIR ${default_auxiliary_install_dir} STRING "Relative install location for auxiliary files" ADVANCED) +us_cache_var(DOC_INSTALL_DIR ${default_doc_install_dir} STRING "Relative install location for documentation files" ADVANCED) +us_cache_var(MAN_INSTALL_DIR ${default_man_install_dir} STRING "Relative install location for man pages" ADVANCED) +set(AUXILIARY_CMAKE_INSTALL_DIR ${AUXILIARY_INSTALL_DIR}/cmake) + +us_cache_var(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS} BOOL "Build shared libraries" ADVANCED) + +set(US_BUNDLE_INIT_TEMPLATE "${US_CMAKE_DIR}/BundleInit.cpp" CACHE INTERNAL "The bundle initialization template code") +set(US_RESOURCE_RC_TEMPLATE "${US_CMAKE_DIR}/cppmicroservices_resources.rc.in" CACHE INTERNAL "The Windows RC resource template") +set(US_CMAKE_RESOURCE_DEPENDENCIES_CPP "${US_CMAKE_DIR}/CMakeResourceDependencies.cpp" CACHE INTERNAL "The dummy resource dependencies code") +if(APPLE) + # Avoid RPATH warning in cmakegui + set(CMAKE_MACOSX_RPATH ON) +endif() + +# Cross-compiled builds need access to the host version of usResourceCompiler. +# ImportExecutables.cmake is generated by the host build and contains the cmake target +# for the host built usResourceCompiler. ImportExecutables.cmake can be included by the +# cross-compiled build to access the host built usResourceCompiler. +# +set(IMPORT_EXECUTABLES "${CMAKE_BINARY_DIR}/ImportExecutables.cmake" CACHE FILEPATH "A file containing the CMake target definition for the host build version of usResourceCompiler.") + +#----------------------------------------------------------------------------- +# Testing configuration +#----------------------------------------------------------------------------- + +function(us_add_tests test_driver) + foreach(test ${ARGN}) + add_test(NAME ${test} COMMAND ${test_driver} ${test} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + set_property(TEST ${test} PROPERTY LABELS regular) + if(US_MEMCHECK_COMMAND) + add_test(NAME memcheck_${test} COMMAND ${US_MEMCHECK_COMMAND} --error-exitcode=1 ${US_RUNTIME_OUTPUT_DIRECTORY}/${test_driver} ${test} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + set_property(TEST memcheck_${test} PROPERTY LABELS valgrind memcheck) + if(US_ENABLE_HELGRIND) + # By default, these tests are not active until the concurrent bundle + # start / stop mechanism has been properly implemented (GitHub Issue #25) + add_test(NAME helgrind_${test} COMMAND ${US_MEMCHECK_COMMAND} --tool=helgrind --error-exitcode=1 ${US_RUNTIME_OUTPUT_DIRECTORY}/${test_driver} ${test} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + set_property(TEST helgrind_${test} PROPERTY LABELS valgrind helgrind) + endif() + endif() + if(US_COVERAGE_COMMAND) + file(TO_NATIVE_PATH ${PROJECT_SOURCE_DIR} PROJECT_SOURCE_NATIVE_PATH) + file(TO_NATIVE_PATH ${US_RUNTIME_OUTPUT_DIRECTORY} US_RUNTIME_OUTPUT_NATIVE_DIRECTORY) + # skip the unicode test bundle because opencppcoverage tool fails if a module is located in a path with unicode characters + add_test(NAME coverage_${test} COMMAND ${US_COVERAGE_COMMAND} --verbose --cover_children --sources=${PROJECT_SOURCE_NATIVE_PATH} --export_type=binary:${test}.cov --continue_after_cpp_exception --excluded_modules *TestBundleU.dll -- $ ${test} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + set_property(TEST coverage_${test} PROPERTY LABELS opencppcoverage) + endif() + endforeach() +endfunction() + +# Valgrind rc file +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/valgrindrc + ${CMAKE_BINARY_DIR}/.valgrindrc + @ONLY + ) + +if(US_BUILD_TESTING) + enable_testing() + find_program(US_MEMCHECK_COMMAND valgrind) + mark_as_advanced(US_MEMCHECK_COMMAND) + if(WIN32 AND US_ENABLE_COVERAGE) + find_program(US_COVERAGE_COMMAND NAMES OpenCppCoverage OpenCppCoverage.exe DOC "path to the code coverage tool" HINTS "C:/Program Files/OpenCppCoverage" "C:/Program Files (x86)/OpenCppCoverage") + mark_as_advanced(US_COVERAGE_COMMAND) + endif() + + if(US_USE_SYSTEM_GTEST) + find_package(GTest REQUIRED) + else() + # This keeps GTest CMake variables hidden from users unless they explicitly want to view/modify them. + + # Workaround an apparent bug in GCC 4.6 with C++11 variadic templates. Don't build gmock for any platform + # for now (we don't use it yet anyway). See https://groups.google.com/forum/#!topic/googlemock/XvPDUENM5JM + # for details. + us_cache_var(BUILD_GMOCK OFF BOOL "Build GMock" ADVANCED FORCE) + us_cache_var(BUILD_GTEST ON BOOL "Build GTest" ADVANCED FORCE) + + us_cache_var(gtest_build_samples OFF BOOL "Build GTest samples" ADVANCED) + us_cache_var(gtest_build_tests OFF BOOL "Build GTest tests" ADVANCED) + us_cache_var(gtest_disable_pthreads OFF BOOL "Disable the use of pthreads" ADVANCED) + + # Prevent overriding the parent project's compiler/linker + # settings on Windows + us_cache_var(gtest_force_shared_crt ON BOOL "" ADVANCED FORCE) + + us_cache_var(gtest_hide_internal_symbols OFF BOOL "" ADVANCED) + + # pthreads on MinGW is not supported, turn it off. Refer to + # https://github.com/google/googletest/pull/721/files for details. + if(MINGW) + set(gtest_disable_pthreads ON CACHE BOOL "" FORCE) + endif() + + set(GTEST_BOTH_LIBRARIES gtest gtest_main) + + # Prevent GTest from installing libraries into our install dir. + set(GTEST_NO_INSTALL 1) + + # This project also sets BUILD_SHARED_LIBS. We want to guarantee that GTest is always built as a + # static library even if CppMicroServices is a shared library. + set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + add_subdirectory(third_party/googletest) + set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS} CACHE BOOL "" FORCE) + endif() +endif() + + +#----------------------------------------------------------------------------- +# US C/CXX Flags +#----------------------------------------------------------------------------- + +set(US_HAVE_VISIBILITY_ATTRIBUTE 0) +set(US_CXX11_FLAGS ) +set(US_CXX_TSAN_FLAGS ) +set(US_TSAN_LINK_FLAGS ) +set(US_CXX_COVERAGE_FLAGS ) + +if(MSVC) + set(disabled_warnings + 4251 # 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' + ) + foreach(wd ${disabled_warnings}) + set(US_CXX_FLAGS "/wd${wd} ${US_CXX_FLAGS}") + endforeach() + set(US_CXX_FLAGS "/MP /WX ${US_CXX_FLAGS}") +else() + + if(US_COMPILER_APPLE_CLANG) + set(US_CXX_FLAGS "${US_CXX_FLAGS} -stdlib=libc++") + endif() + + # If not cross-compiling, turn on Stack Smashing Protection. + # This is done in cases where libssp.so may not be available in the + # cross build toolchain. The dependency with libssp.so was originally + # discovered building with the Android ARM gcc toolchain. It is + # being applied to any cross compilation as a precaution. + if(NOT CMAKE_CROSSCOMPILING) + usFunctionCheckCompilerFlags(-fstack-protector-all US_CXX_FLAGS) + endif() + + foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align + -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast + -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option ) + usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) + endforeach() + + if(US_COMPILER_CLANG OR US_COMPILER_APPLE_CLANG) + # The check does not work reliably for gcc + usFunctionCheckCompilerFlags(-Wno-mismatched-tags US_CXX_FLAGS) + endif() + + # Issue #56: Workaround a clang compiler issue (https://llvm.org/bugs/show_bug.cgi?id=26749). + # The typeinfo symbols do not have reliable symbol visibility. Instead of exporting only + # symbols and associated typeinfo symbols which have explicit "default" visibility, + # export all typeinfo symbols by default and maintain hidden symbol visibility for all other + # symbols (unless explicitly overriden). See + # https://developer.apple.com/library/mac/technotes/tn2185/_index.html#//apple_ref/doc/uid/DTS10004200-CH1-SUBSECTION2 + # to understand what -fvisibility-ms-compat does. + if(APPLE AND (US_COMPILER_CLANG OR US_COMPILER_APPLE_CLANG)) + usFunctionCheckCompilerFlags("-fvisibility-ms-compat" _have_visibility) + else() + usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" _have_visibility) + endif() + + if(_have_visibility) + set(US_HAVE_VISIBILITY_ATTRIBUTE 1) + set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") + endif() + + usFunctionCheckCompilerFlags("-O1 -D_FORTIFY_SOURCE=2" _fortify_source_flag) + if(_fortify_source_flag) + set(US_CXX_FLAGS_RELEASE "${US_CXX_FLAGS_RELEASE} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") + endif() + + set(_orig_req_libs ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES "-fsanitize=thread") + usFunctionCheckCompilerFlags("-O1 -fsanitize=thread" US_CXX_TSAN_FLAGS) + set(CMAKE_REQUIRED_LIBRARIES "${_orig_req_libs}") + if(NOT US_CXX_TSAN_FLAGS AND US_ENABLE_TSAN) + message(WARNING "TSAN requested, but compiler does not recognize it") + endif() + + set(CMAKE_REQUIRED_LIBRARIES "-fprofile-arcs -ftest-coverage") + usFunctionCheckCompilerFlags("-fprofile-arcs -ftest-coverage" US_CXX_COVERAGE_FLAGS) + set(CMAKE_REQUIRED_LIBRARIES "${_orig_req_libs}") + if(NOT US_CXX_COVERAGE_FLAGS AND US_ENABLE_COVERAGE) + message(WARNING "Code coverage requested, but compiler does not recognize it") + endif() +endif() + +if(MINGW) + # suppress warnings about auto imported symbols + set(US_CXX_FLAGS "-Wl,--enable-auto-import ${US_CXX_FLAGS}") + # we need to define a Windows version (Windows Vista) + set(US_CXX_FLAGS "-D_WIN32_WINNT=0x0600 -DNTDDI_VERSION=0x06000000 ${US_CXX_FLAGS}") +endif() + +if(US_ENABLE_THREADING_SUPPORT) + set(THREADS_PREFER_PTHREAD_FLAG 1) + find_package(Threads REQUIRED) + + if(US_ENABLE_TSAN AND US_CXX_TSAN_FLAGS) + set(US_CXX_FLAGS "${US_CXX_FLAGS} ${US_CXX_TSAN_FLAGS}") + endif() +endif() + +if(US_ENABLE_COVERAGE AND US_CXX_COVERAGE_FLAGS) + # US_CXX_COVERAGE_FLAGS is used for both the compiler and the linker + set(US_CXX_FLAGS "${US_CXX_FLAGS} ${US_CXX_COVERAGE_FLAGS}") +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${US_CXX_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${US_C_FLAGS_RELEASE}") + +#----------------------------------------------------------------------------- +# US Link Flags +#----------------------------------------------------------------------------- + +set(US_LINK_FLAGS ) +if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) + foreach(_linkflag -Wl,--no-undefined) + set(_add_flag) + usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) + if(_add_flag) + set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") + endif() + endforeach() +endif() + +if(NOT MSVC) + if (US_ENABLE_TSAN AND US_CXX_TSAN_FLAGS) + set(US_TSAN_LINK_FLAGS "-fsanitize=thread") + endif() +endif() + +if(US_ENABLE_THREADING_SUPPORT AND US_TSAN_LINK_FLAGS) + set(US_LINK_FLAGS "${US_LINK_FLAGS} ${US_TSAN_LINK_FLAGS}") +endif() + +if(US_ENABLE_COVERAGE AND US_CXX_COVERAGE_FLAGS) + # US_CXX_COVERAGE_FLAGS is used for both the compiler and the linker + set(US_LINK_FLAGS "${US_LINK_FLAGS} ${US_CXX_COVERAGE_FLAGS}") +endif() + +usFunctionCheckResourceLinking() + +#----------------------------------------------------------------------------- +# US Header Checks +#----------------------------------------------------------------------------- + +include(CheckIncludeFileCXX) + +CHECK_INCLUDE_FILE_CXX(cxxabi.h US_HAVE_CXXABI_H) + +#----------------------------------------------------------------------------- +# C++ language support +#----------------------------------------------------------------------------- + +set(disabled_func ) + +file(GLOB try_compile_srcs ${CMAKE_CURRENT_SOURCE_DIR}/cmake/try_compile/*.cpp) +foreach(try_compile_src ${try_compile_srcs}) + get_filename_component(try_compile_var ${try_compile_src} NAME_WE) + string(TOUPPER ${try_compile_var} try_compile_var) + try_compile( + ${try_compile_var} + ${CMAKE_CURRENT_BINARY_DIR}/try_compile/${try_compile_var} + SOURCES ${try_compile_src} + CMAKE_FLAGS -DCMAKE_CXX_EXTENSIONS:BOOL=OFF -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=ON -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} + # The line below only works on CMake 3.8 and higher + # CXX_STANDARD ${CMAKE_CXX_STANDARD} + ) +endforeach() + +if(MINGW) + # + # The MinGW winpthread implementation does not properly destruct + # non-POD thread-local objects, leading to segmentation faults on + # thread exit. See + # + # https://github.com/Alexpux/MINGW-packages/issues/2519 + # https://sourceforge.net/p/mingw-w64/bugs/527/ + # + set(US_HAVE_THREAD_LOCAL 0) + set(disabled_func "${disabled_func}MinGW winpthread: ") +endif() + +if(NOT US_HAVE_THREAD_LOCAL AND US_ENABLE_THREADING_SUPPORT) + set(disabled_func "${disabled_func}thread_local support unavailable. Recursive service factory calls will not be detected. See also https://github.com/CppMicroServices/CppMicroServices/issues/213\n") +endif() + +#----------------------------------------------------------------------------- +# C++ library support +#----------------------------------------------------------------------------- + +# c++11 regular expressions are used in the unit tests. +# Currently the default C++ library for gcc < 4.9 doesn't +# fully support c++11 regex. +# Generalize the detection of regex and make its availability +# conditional of whether the compiler's C++ library supports it +# or not. +# This can be removed once the minimum supported gcc version is 4.9 +if(NOT US_HAVE_REGEX AND US_BUILD_TESTING) + set(disabled_func "${disabled_func}regular expression support unavailable. Some tests will be disabled.\n") +endif() + +# Print a warning summary +if (disabled_func) + message(WARNING "${US_COMPILER_${CMAKE_CXX_COMPILER_ID}_MINIMUM_RECOMMENDED_VERSION_PRODUCT} or higher recommended (you are using ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}). The following functionality will not be available:\n${disabled_func}") +endif() + +#----------------------------------------------------------------------------- +# System Information +#----------------------------------------------------------------------------- + +include(TestBigEndian) + +test_big_endian(US_BIG_ENDIAN) + +if(NOT US_BIG_ENDIAN) + set(US_LITTLE_ENDIAN 1) +endif() + +#----------------------------------------------------------------------------- +# Source directory +#----------------------------------------------------------------------------- + +# Configure CppMicroServicesConfig.cmake for the build tree. +# The file is used in sub-directories. + +set(PACKAGE_CONFIG_RUNTIME_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +set(PACKAGE_CONFIG_CMAKE_DIR ${US_CMAKE_DIR}) + +set(US_RCC_EXECUTABLE_TARGET usResourceCompiler CACHE INTERNAL "The target name of the usResourceCompiler executable.") +set(US_RCC_EXECUTABLE_OUTPUT_NAME ${US_RCC_EXECUTABLE_TARGET}${US_GLOBAL_VERSION_SUFFIX}) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + @ONLY + ) + +set(global_config_h_file "${PROJECT_BINARY_DIR}/include/${PROJECT_NAME_LOWER}/GlobalConfig.h") +configure_file(${US_CMAKE_DIR}/GlobalConfig.h.in ${global_config_h_file}) + +# Version information +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + @ONLY + ) + +add_subdirectory(tools/rc) + +export(TARGETS ${US_RCC_EXECUTABLE_TARGET} + FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake) + +add_subdirectory(util) +add_subdirectory(framework) + +#----------------------------------------------------------------------------- +# Documentation +#----------------------------------------------------------------------------- + +add_subdirectory(doc) + +#----------------------------------------------------------------------------- +# Installation +#----------------------------------------------------------------------------- + +if(NOT US_NO_INSTALL) + +install(EXPORT ${PROJECT_NAME}Targets + FILE ${PROJECT_NAME}Targets.cmake + DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) + + set(_install_cmake_scripts + ${US_BUNDLE_INIT_TEMPLATE} + ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} + ${US_CMAKE_DIR}/usFunctionGenerateBundleInit.cmake + ${US_CMAKE_DIR}/usFunctionAddResources.cmake + ${US_CMAKE_DIR}/usFunctionEmbedResources.cmake + ${US_CMAKE_DIR}/usFunctionGetResourceSource.cmake + ${US_CMAKE_DIR}/usFunctionCheckResourceLinking.cmake + ${US_CMAKE_DIR}/usFunctionCheckCompilerFlags.cmake + ) + + install(FILES ${_install_cmake_scripts} + DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) + + install(FILES ${global_config_h_file} + DESTINATION ${HEADER_INSTALL_DIR}/${PROJECT_NAME_LOWER}) + + # Configure CppMicroServicesConfig.cmake for the install tree + set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) + set(CONFIG_RUNTIME_DIR ${RUNTIME_INSTALL_DIR}) + set(CONFIG_CMAKE_DIR ${AUXILIARY_CMAKE_INSTALL_DIR}) + configure_package_config_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in + ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} + PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_DIR CONFIG_CMAKE_DIR + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO + ) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} + ${US_SDK_INSTALL_COMPONENT} + ) + +endif() diff --git a/external/CppMicroServices/CODE_OF_CONDUCT.rst b/external/CppMicroServices/CODE_OF_CONDUCT.rst new file mode 100644 index 00000000..a8c90a44 --- /dev/null +++ b/external/CppMicroServices/CODE_OF_CONDUCT.rst @@ -0,0 +1,84 @@ +.. _code-of-conduct: + +Contributor Covenant Code of Conduct +------------------------------------ + +Our Pledge +~~~~~~~~~~ + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our +project and our community a harassment-free experience for everyone, +regardless of age, body size, disability, ethnicity, gender identity and +expression, level of experience, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +Our Standards +~~~~~~~~~~~~~ + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual + attention or advances +- Trolling, insulting/derogatory comments, and personal or political + attacks +- Public or private harassment +- Publishing others' private information, such as a physical or + electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +Our Responsibilities +~~~~~~~~~~~~~~~~~~~~ + +Project maintainers are responsible for clarifying the standards of +acceptable behavior and are expected to take appropriate and fair +corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, +or reject comments, commits, code, wiki edits, issues, and other +contributions that are not aligned to this Code of Conduct, or to ban +temporarily or permanently any contributor for other behaviors that they +deem inappropriate, threatening, offensive, or harmful. + +Scope +~~~~~ + +This Code of Conduct applies both within project spaces and in public +spaces when an individual is representing the project or its community. +Examples of representing a project or community include using an +official project e-mail address, posting via an official social media +account, or acting as an appointed representative at an online or +offline event. Representation of a project may be further defined and +clarified by project maintainers. + +Enforcement +~~~~~~~~~~~ + +Instances of abusive, harassing, or otherwise unacceptable behavior may +be reported by contacting the project team at info@cppmicroservices.org. +All complaints will be reviewed and investigated and will result in a +response that is deemed necessary and appropriate to the circumstances. +The project team is obligated to maintain confidentiality with regard to +the reporter of an incident. Further details of specific enforcement +policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in +good faith may face temporary or permanent repercussions as determined +by other members of the project's leadership. + +Attribution +~~~~~~~~~~~ + +This Code of Conduct is adapted from the `Contributor +Covenant `_, version 1.4, available at +`http://contributor-covenant.org/version/1/4 `_. diff --git a/external/CppMicroServices/CONTRIBUTING.rst b/external/CppMicroServices/CONTRIBUTING.rst new file mode 100644 index 00000000..c78a7560 --- /dev/null +++ b/external/CppMicroServices/CONTRIBUTING.rst @@ -0,0 +1,167 @@ +.. _contributing: + +Contributing to C++ Micro Services +================================== + +This page contains information about reporting issues as well as some +tips and guidelines useful to experienced open source contributors. Make +sure you read the contribution guideline before you start participating. + +Reporting issues +---------------- + +A great way to contribute to the project is to send a detailed report +when you encounter an issue. We always appreciate a well-written, +thorough bug report, and will thank you for it! + +Check that the `issue +database `_ +doesn't already include that problem or suggestion before submitting an +issue. If you find a match, add a quick "+1" or "I have this problem +too." Doing this helps prioritize the most common problems and requests. + +When reporting issues, please include your host OS and compiler vendor +and version. Please also include the steps required to reproduce the +problem if possible and applicable. + +CppMicroServices RFCs +--------------------- + +Many changes, including bug fixes and documentation improvements can be +implemented and reviewed via the normal GitHub pull request workflow. + +Some changes though are "substantial", and we ask that these be put through a +bit of a design process and produce a consensus among the CppMicroServices core +team. + +The "RFC" (request for comments) process is intended to provide a consistent and +controlled path for new features to enter the framework. + +Please refer to the `RFC repository `_ +for more information. + +Contribution guidelines +----------------------- + +This section gives the experienced contributor some tips and guidelines. + +Conventions +~~~~~~~~~~~ + +Fork the repository and make changes on your fork in a feature branch: + +- If it's a bug fix branch, name it ``XXXX-something`` where XXXX is the + number of the issue. +- If it's a feature branch, create an enhancement issue to announce + your intentions, and name it ``XXXX-something`` where XXXX is the number + of the issue. + +Code must be formatted according to our ```.clang-format``` file, using +the clang-format tool. + +Submit unit tests for your changes. + +Update the documentation when creating or modifying features. Test your +documentation changes for clarity, concision, and correctness. + +Pull request descriptions should be as clear as possible and include a +reference to all the issues that they address. If the pull +request is a result of a RFC process, include the link to the corresponding +RFC pull request. + +Commit messages must start with a capitalized and short summary (max. 50 +chars) written in the imperative, followed by an optional, more detailed +explanatory text which is separated from the summary by an empty line. + +Code review comments may be added to your pull request. Discuss, then +make the suggested modifications and push additional commits to your +feature branch. Post a comment after pushing. New commits show up in the +pull request automatically, but the reviewers are notified only when you +comment. + +Pull requests must be cleanly rebased on top of *development* without +multiple branches mixed into the PR. + +.. tip:: + + **Git tip**: If your PR no longer merges cleanly, use + ``rebase development`` in your feature branch to update your pull + request rather than ``merge development``. + +Before you make a pull request, squash your commits into logical units +of work using ``git rebase -i`` and ``git push -f``. A logical unit of +work is a consistent set of patches that should be reviewed together: +for example, upgrading the version of a vendored dependency and taking +advantage of its now available new feature constitute two separate units +of work. Implementing a new function and calling it in another file +constitute a single logical unit of work. The very high majority of +submissions should have a single commit, so if in doubt: squash down to +one. + +After every commit, make sure the test suite passes. Include +documentation changes in the same pull request so that a revert would +remove all traces of the feature or fix. + +Include an issue reference like ``Closes #XXXX`` or ``Fixes #XXXX`` in +commits that close an issue. Including references automatically closes +the issue on a merge. + +If your change is large enough to warrant a copyright statement, add +yourself to the ``COPYRIGHT`` file, using the same style as the existing +entries. + +Sign your work +~~~~~~~~~~~~~~ + +The sign-off is a simple line at the end of the explanation for the +patch. Your signature certifies that you wrote the patch or otherwise +have the right to pass it on as an open-source patch. The rules are +pretty simple: if you can certify the below (from +`developercertificate.org `_):: + + Developer Certificate of Origin + Version 1.1 + + Copyright (C) 2004, 2006 The Linux Foundation and its contributors. + 660 York Street, Suite 102, + San Francisco, CA 94110 USA + + Everyone is permitted to copy and distribute verbatim copies of this + license document, but changing it is not allowed. + + Developer's Certificate of Origin 1.1 + + By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +Then you just add a line to every git commit message:: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions). + +If you set your ``user.name`` and ``user.email`` git configs, you can +sign your commit automatically with ``git commit -s``. + +.. include:: CODE_OF_CONDUCT.rst diff --git a/external/CppMicroServices/COPYRIGHT b/external/CppMicroServices/COPYRIGHT new file mode 100644 index 00000000..4c2ba890 --- /dev/null +++ b/external/CppMicroServices/COPYRIGHT @@ -0,0 +1,19 @@ +Source: https://github.com/CppMicroServices/CppMicroServices + +Files: * (see the VCS history for detailed change information) +Copyright: 2015 Sascha Zelzer +Copyright: 2012 - 2015 Sascha Zelzer, German Cancer Research Center +License: Apache License 2.0 + +Files: * (see the VCS history for detailed change information) +Copyright: 2015 The MathWorks, Inc. +License: Apache License 2.0 + +Files: core/include/usAny.h +Copyright: Kevlin Henney, 2000, 2001, 2002. All rights reserved. + Extracted from Boost 1.46.1 and adapted for CppMicroServices. +License: See the file header + +Files: third_party/* +Copyright: See third_party/README +License: See third_party/README diff --git a/external/CppMicroServices/CTestConfig.cmake b/external/CppMicroServices/CTestConfig.cmake new file mode 100644 index 00000000..65ff58f0 --- /dev/null +++ b/external/CppMicroServices/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "CppMicroServices") +#set(CTEST_NIGHTLY_START_TIME "23:00:00 EDT") + +#set(CTEST_DROP_METHOD "http") +#set(CTEST_DROP_SITE "my.cdash.org") +#set(CTEST_DROP_LOCATION "/submit.php?project=${CTEST_PROJECT_NAME}") +#set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/external/CppMicroServices/CppMicroServicesConfig.cmake.in b/external/CppMicroServices/CppMicroServicesConfig.cmake.in new file mode 100644 index 00000000..ff37c604 --- /dev/null +++ b/external/CppMicroServices/CppMicroServicesConfig.cmake.in @@ -0,0 +1,155 @@ +# A package config for @PROJECT_NAME@. +# This file loads component specific configuration files and +# sets the following variables which can be used in other +# CMake projects to build and link against @PROJECT_NAME@: +# +# US_LIBRARIES +# US_RUNTIME_LIBRARY_DIRS +# +# The following variables are aliases for the ones above: +# +# CppMicroServices_LIBRARIES +# CppMicroServices_RUNTIME_LIBRARY_DIRS +# +# To specify a compatible version for a specific component, +# set the following variable before calling find_package: +# +# US__FIND_VERSION +# +# After find_package returns successfully, the following additional +# variables will be set: +# +# US_FOUND +# CPPMICROSERVICES_FOUND +# +# US_RCC_EXECUTABLE_TARGET +# +# US_VERSION +# US_VERSION_MAJOR +# US_VERSION_MINOR +# US_VERSION_PATCH +# US_VERSION_TWEAK +# US_VERSION_COUNT +# +# Additional component specific variables: +# +# US__FOUND +# +# US__VERSION +# US__VERSION_MAJOR +# US__VERSION_MINOR +# US__VERSION_PATCH +# US__VERSION_TWEAK +# US__VERSION_COUNT +# + +@PACKAGE_INIT@ + +set(US_CMAKE_MINIMUM_REQUIRED_VERSION @US_CMAKE_MINIMUM_REQUIRED_VERSION@) +set(US_ENABLE_THREADING_SUPPORT @US_ENABLE_THREADING_SUPPORT@) + +cmake_minimum_required(VERSION ${US_CMAKE_MINIMUM_REQUIRED_VERSION}) + +list(APPEND CMAKE_MODULE_PATH "@PACKAGE_CONFIG_CMAKE_DIR@") + +set(US_BUNDLE_INIT_TEMPLATE "@PACKAGE_CONFIG_CMAKE_DIR@/BundleInit.cpp") +set(US_RESOURCE_RC_TEMPLATE "@PACKAGE_CONFIG_CMAKE_DIR@/cppmicroservices_resources.rc.in") +set(US_CMAKE_RESOURCE_DEPENDENCIES_CPP "@PACKAGE_CONFIG_CMAKE_DIR@/CMakeResourceDependencies.cpp") + +set(US_RCC_EXECUTABLE_TARGET @US_RCC_EXECUTABLE_TARGET@) +if(NOT TARGET ${US_RCC_EXECUTABLE_TARGET}) + include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +endif() + +# Include helper macros +include(CMakeParseArguments) +include(FindPackageHandleStandardArgs) + +include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionGenerateBundleInit.cmake") +include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionAddResources.cmake") +include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionCheckCompilerFlags.cmake") +include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionEmbedResources.cmake") +include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionCheckResourceLinking.cmake") +include("@PACKAGE_CONFIG_CMAKE_DIR@/usFunctionGetResourceSource.cmake") + +usFunctionCheckResourceLinking() + +# Required packages + +if(US_ENABLE_THREADING_SUPPORT AND NOT CMAKE_THREAD_LIBS_INIT) + set(THREADS_PREFER_PTHREAD_FLAG 1) + find_package(Threads REQUIRED) +endif() + +# Clear variables +set(US_LIBRARIES ) +set(US_RUNTIME_LIBRARY_DIRS ) + +# Components support +set(US_BUNDLES Framework HttpService WebConsole ShellService) # ConfigAdmin EventAdmin ... + +set(US_Framework_BUNDLE_DEPS ) +set(US_HttpService_BUNDLE_DEPS Framework) +set(US_WebConsole_BUNDLE_DEPS ${US_HttpService_BUNDLE_DEPS} HttpService) +set(US_ShellService_BUNDLE_DEPS Framework) + +if(NOT @PROJECT_NAME@_FIND_COMPONENTS) + set(@PROJECT_NAME@_FIND_COMPONENTS Framework) +endif() + +set(US_BUNDLES_NEEDED ) +foreach(component ${@PROJECT_NAME@_FIND_COMPONENTS}) + list(APPEND US_BUNDLES_NEEDED ${US_${component}_BUNDLE_DEPS} ${component}) +endforeach() +list(REMOVE_DUPLICATES US_BUNDLES_NEEDED) + +set(@PROJECT_NAME@_FOUND TRUE) +foreach(component ${US_BUNDLES_NEEDED}) + if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/us${component}Config.cmake") + set(US_${component}_FOUND 0) + set(CppMicroServices_${component}_FOUND 0) + else() + find_package(us${component} ${US_${component}_FIND_VERSION} QUIET REQUIRED + HINTS ${CMAKE_CURRENT_LIST_DIR} + NO_DEFAULT_PATH + ) + mark_as_advanced(us${component}_DIR) + set(US_${component}_FOUND ${us${component}_FOUND}) + set(CppMicroServices_${component}_FOUND ${US_${component}_FOUND}) + endif() + + if(US_${component}_FOUND) + list(APPEND US_LIBRARIES ${US_${component}_LIBRARIES}) + list(APPEND US_RUNTIME_LIBRARY_DIRS ${US_${component}_RUNTIME_LIBRARY_DIRS}) + + set(US_${component}_VERSION ${${component}_VERSION}) + set(US_${component}_VERSION_MAJOR ${${component}_VERSION_MAJOR}) + set(US_${component}_VERSION_MINOR ${${component}_VERSION_MINOR}) + set(US_${component}_VERSION_PATCH ${${component}_VERSION_PATCH}) + set(US_${component}_VERSION_TWEAK ${${component}_VERSION_TWEAK}) + set(US_${component}_VERSION_COUNT ${${component}_VERSION_COUNT}) + else() + if(@PROJECT_NAME@_FIND_REQUIRED_${component}) + set(@PROJECT_NAME@_FOUND FALSE) + endif() + endif() +endforeach() + +if(US_LIBRARIES) + list(REMOVE_DUPLICATES US_LIBRARIES) +endif() +if(US_RUNTIME_LIBRARY_DIRS) + list(REMOVE_DUPLICATES US_RUNTIME_LIBRARY_DIRS) +endif() + +set(CppMicroServices_LIBRARIES ${US_LIBRARIES}) +set(CppMicroServices_RUNTIME_LIBRARY_DIRS ${US_RUNTIME_LIBRARY_DIRS}) + +set(@PROJECT_NAME@_CONFIG ${CMAKE_CURRENT_LIST_FILE}) +find_package_handle_standard_args(@PROJECT_NAME@ + HANDLE_COMPONENTS + CONFIG_MODE +) + +string(TOUPPER "@PROJECT_NAME@" @PROJECT_NAME@_UPPER) +set(US_FOUND ${${@PROJECT_NAME@_UPPER}_FOUND}) diff --git a/external/CppMicroServices/CppMicroServicesConfigVersion.cmake.in b/external/CppMicroServices/CppMicroServicesConfigVersion.cmake.in new file mode 100644 index 00000000..ad9d8603 --- /dev/null +++ b/external/CppMicroServices/CppMicroServicesConfigVersion.cmake.in @@ -0,0 +1,34 @@ +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version major number == requested version major number +# and the current version minor number >= requested version minor number + +set(PACKAGE_VERSION_MAJOR @CppMicroServices_VERSION_MAJOR@) +set(PACKAGE_VERSION_MINOR @CppMicroServices_VERSION_MINOR@) +set(PACKAGE_VERSION_PATCH @CppMicroServices_VERSION_PATCH@) +set(PACKAGE_VERSION "@CppMicroServices_VERSION@") + +if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) +else() + set(PACKAGE_VERSION_EXACT FALSE) + if(NOT PACKAGE_VERSION_MAJOR EQUAL PACKAGE_FIND_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + elseif(PACKAGE_VERSION_MINOR LESS PACKAGE_FIND_VERSION_MINOR) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + endif() +endif() + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "@CMAKE_SIZEOF_VOID_P@") + math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/external/CppMicroServices/LICENSE b/external/CppMicroServices/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/external/CppMicroServices/LICENSE @@ -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 --git a/external/CppMicroServices/README.rst b/external/CppMicroServices/README.rst new file mode 100644 index 00000000..9e6e3147 --- /dev/null +++ b/external/CppMicroServices/README.rst @@ -0,0 +1,201 @@ + +.. rubric:: Continuous Integration Status + ++-------------+-------------------------+--------------------------+------------------------+ +| Branch | GCC 5.4 and 8.0 | Visual Studio 2015 | | +| +-------------------------+--------------------------+------------------------+ +| | Xcode 7.3 and 9.4 | Visual Studio 2017 | | +| +-------------------------+--------------------------+------------------------+ +| | Clang 3.4 and 6.0 | MinGW-w64 | | ++=============+=========================+==========================+========================+ +| master | |Linux Build Status| | |Windows Build status| | |Code Coverage Status| | ++-------------+-------------------------+--------------------------+------------------------+ +| development | |Linux Build Status | |Windows Build status | |Code Coverage Status | +| | (development)| | (development)| | (development)| | ++-------------+-------------------------+--------------------------+------------------------+ + +|Coverity Scan Build Status| + + +C++ Micro Services +================== + +|RTD Build Status (stable)| |RTD Build Status (development)| + +`Download `_ + +Introduction +------------ + +The C++ Micro Services project is a collection of components for building +modular and dynamic service-oriented applications. It is based on +`OSGi `_, but tailored to support native cross-platform solutions. + +Proper usage of C++ Micro Services patterns and concepts leads to systems +with one or more of the following properties: + +- Re-use of software components +- Loose coupling between service providers and consumers +- Separation of concerns, based on a service-oriented design +- Clean APIs based on service interfaces +- Extensible and reconfigurable systems + + +Requirements +------------ + +None, except a recent enough C++ compiler. All third-party library +dependencies are included and mostly used for implementation details. + +Supported Platforms +------------------- + +The library makes use of C++14 language and library features and compiles +on many different platforms. + +Recommended minimum required compiler versions: + +- GCC 5.4 +- Clang 3.4 +- Clang from Xcode 8.0 +- Visual Studio 2015 + +You may use older compilers, but certain functionality may not be +available. Check the warnings printed during configuration of +your build tree. The following are the absolute minimum requirements: + +- GCC 5.1 +- Clang 3.4 +- Clang from Xcode 7.3 +- Visual Studio 2015 (MSVC++ 14.0) + +Below is a list of tested compiler/OS combinations: + +- GCC 5.4 (Ubuntu 14.04) via Travis CI +- GCC 8.0 (Ubuntu 14.04) via Travis CI +- Clang 3.4 (Ubuntu 14.04) via Travis CI +- Clang 6.0 (Ubuntu 14.04) via Travis CI +- Clang Xcode 7.3 (OS X 10.11) via Travis CI +- Clang Xcode 9.4 (OS X 10.13) via Travis CI +- Visual Studio 2015 via Appveyor +- Visual Studio 2017 via Appveyor +- MinGW-w64 via Appveyor + +Legal +----- + +The C++ Micro Services project was initially developed at the German +Cancer Research Center. Its source code is hosted as a `GitHub Project`_. +See the `COPYRIGHT file`_ in the top-level directory for detailed +copyright information. + +This project is licensed under the `Apache License v2.0`_. + +Code of Conduct +--------------- + +CppMicroServices.org welcomes developers with different backgrounds and +a broad range of experience. A diverse and inclusive community will +create more great ideas, provide more unique perspectives, and produce +more outstanding code. Our aim is to make the CppMicroServices community +welcoming to everyone. + +To provide clarity of what is expected of our members, CppMicroServices +has adopted the code of conduct defined by +`contributor-covenant.org `_. This +document is used across many open source communities, and we believe it +articulates our values well. + +Please refer to the :any:`Code of Conduct ` for further +details. + +Quick Start +----------- + +Essentially, the C++ Micro Services library provides you with a powerful +dynamic service registry on top of a managed lifecycle. The framework manages, +among other things, logical units of modularity called *bundles* that +are contained in shared or static libraries. Each bundle +within a library has an associated :any:`cppmicroservices::BundleContext` +object, through which the service registry is accessed. + +To query the registry for a service object implementing one or more +specific interfaces, the code would look like this: + +.. code:: cpp + + #include "cppmicroservices/BundleContext.h" + #include "SomeInterface.h" + + using namespace cppmicroservices; + + void UseService(BundleContext context) + { + auto serviceRef = context.GetServiceReference(); + if (serviceRef) + { + auto service = context.GetService(serviceRef); + if (service) { /* do something */ } + } + } + +Registering a service object against a certain interface looks like +this: + +.. code:: cpp + + #include "cppmicroservices/BundleContext.h" + #include "SomeInterface.h" + + using namespace cppmicroservices; + + void RegisterSomeService(BundleContext context, const std::shared_ptr& service) + { + context.RegisterService(service); + } + +The OSGi service model additionally allows to annotate services with +properties and using these properties during service look-ups. It also +allows to track the life-cycle of service objects. Please see the +`Documentation `_ +for more examples and tutorials and the API reference. There is also a +blog post about `OSGi Lite for C++ `_. + +Git Branch Conventions +---------------------- + +The Git repository contains two eternal branches, +`master `_ +and +`development `_. +The master branch contains production quality code and its HEAD points +to the latest released version. The development branch is the default +branch and contains the current state of development. Pull requests by +default target the development branch. See the :ref:`CONTRIBUTING ` +file for details about the contribution process. + + +.. _COPYRIGHT file: https://github.com/CppMicroServices/CppMicroServices/blob/development/COPYRIGHT +.. _GitHub Project: https://github.com/CppMicroServices/CppMicroServices +.. _Apache License v2.0: http://www.apache.org/licenses/LICENSE-2.0 + +.. |Linux Build Status| image:: https://img.shields.io/travis/CppMicroServices/CppMicroServices/master.svg?style=flat-square&label=Linux%20%26%20OS%20X + :target: http://travis-ci.org/CppMicroServices/CppMicroServices +.. |Windows Build status| image:: https://img.shields.io/appveyor/ci/cppmicroservices/cppmicroservices/master.svg?style=flat-square&label=Windows + :target: https://ci.appveyor.com/project/cppmicroservices/cppmicroservices/branch/master +.. |Linux Build Status (development)| image:: https://img.shields.io/travis/CppMicroServices/CppMicroServices/development.svg?style=flat-square&label=Linux%20%26%20OS%20X + :target: https://travis-ci.org/CppMicroServices/CppMicroServices +.. |Windows Build status (development)| image:: https://img.shields.io/appveyor/ci/cppmicroservices/cppmicroservices/development.svg?style=flat-square&label=Windows + :target: https://ci.appveyor.com/project/cppmicroservices/cppmicroservices/branch/development +.. |Coverity Scan Build Status| image:: https://img.shields.io/coverity/scan/1329.svg?style=flat-square + :target: https://scan.coverity.com/projects/1329 +.. |RTD Build Status (stable)| image:: https://readthedocs.org/projects/cppmicroservices/badge/?version=stable&style=flat-square + :target: http://docs.cppmicroservices.org/en/stable/?badge=stable + :alt: Documentation Status (stable) +.. |RTD Build Status (development)| image:: https://readthedocs.org/projects/cppmicroservices/badge/?version=latest&style=flat-square + :target: http://docs.cppmicroservices.org/en/latest/?badge=development + :alt: Documentation Status (development) +.. |Code Coverage Status| image:: https://img.shields.io/codecov/c/github/CppMicroServices/CppMicroServices/master.svg?style=flat-square + :target: https://codecov.io/gh/cppmicroservices/CppMicroServices/branch/master +.. |Code Coverage Status (development)| image:: https://img.shields.io/codecov/c/github/CppMicroServices/CppMicroServices/development.svg?style=flat-square + :target: https://codecov.io/gh/cppmicroservices/CppMicroServices/branch/development diff --git a/external/CppMicroServices/VERSION b/external/CppMicroServices/VERSION new file mode 100644 index 00000000..fcdb2e10 --- /dev/null +++ b/external/CppMicroServices/VERSION @@ -0,0 +1 @@ +4.0.0 diff --git a/external/CppMicroServices/appveyor.yml b/external/CppMicroServices/appveyor.yml new file mode 100644 index 00000000..52283eed --- /dev/null +++ b/external/CppMicroServices/appveyor.yml @@ -0,0 +1,191 @@ +os: Visual Studio 2015 +version: 3.99.{build} + +pull_requests: + do_not_increment_build_number: true + +branches: + except: + - coverity_scan + - gh_pages + +skip_tags: true + +matrix: + fast_finish: true + +# We do not test all build configurations with all compiler / platform +# combinations. For now, just the latest compilers being tested will +# run all build configurations. + +environment: + matrix: + # ---------- Visual Studio 2015 ------------ + #---- Win32 + #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + # platform: Win32 + # configuration: Release + # gen: "Visual Studio 14 2015" + # US_SHARED: 0 + # US_THREADED: 0 + #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + # platform: Win32 + # configuration: Release + # gen: "Visual Studio 14 2015" + # US_SHARED: 1 + # US_THREADED: 0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + platform: Win32 + configuration: Release + gen: "Visual Studio 14 2015" + US_SHARED: 0 + US_THREADED: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + platform: Win32 + configuration: Release + gen: "Visual Studio 14 2015" + US_SHARED: 1 + US_THREADED: 1 + #---- Win64 + #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + # platform: Win64 + # configuration: Release + # gen: "Visual Studio 14 2015 Win64" + # US_SHARED: 0 + # US_THREADED: 0 + #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + # platform: x64 + # configuration: Release + # gen: "Visual Studio 14 2015 Win64" + # US_SHARED: 1 + # US_THREADED: 0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + platform: x64 + configuration: Release + gen: "Visual Studio 14 2015 Win64" + US_SHARED: 0 + US_THREADED: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + platform: x64 + configuration: Release + gen: "Visual Studio 14 2015 Win64" + US_SHARED: 1 + US_THREADED: 1 + # ---------- Visual Studio 2017 ------------ + #---- Win32 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: Win32 + configuration: Release + gen: "Visual Studio 15 2017" + US_SHARED: 0 + US_THREADED: 0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: Win32 + configuration: Release + gen: "Visual Studio 15 2017" + US_SHARED: 1 + US_THREADED: 0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: Win32 + configuration: Release + gen: "Visual Studio 15 2017" + US_SHARED: 0 + US_THREADED: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: Win32 + configuration: Release + gen: "Visual Studio 15 2017" + US_SHARED: 1 + US_THREADED: 1 + #---- Win64 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x64 + configuration: Debug + gen: "Visual Studio 15 2017 Win64" + US_SHARED: 0 + US_THREADED: 1 + WITH_COVERAGE: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x64 + configuration: Debug + gen: "Visual Studio 15 2017 Win64" + US_SHARED: 1 + US_THREADED: 1 + WITH_COVERAGE: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x64 + configuration: Release + gen: "Visual Studio 15 2017 Win64" + US_SHARED: 0 + US_THREADED: 0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x64 + configuration: Release + gen: "Visual Studio 15 2017 Win64" + US_SHARED: 1 + US_THREADED: 0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x64 + configuration: Release + gen: "Visual Studio 15 2017 Win64" + US_SHARED: 0 + US_THREADED: 1 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + platform: x64 + configuration: Release + gen: "Visual Studio 15 2017 Win64" + US_SHARED: 1 + US_THREADED: 1 + # ---------- MinGW-w64 (via MSYS2) ------------ + - platform: mingw-w64 + configuration: Release + gen: "MinGW Makefiles" + US_SHARED: 0 + US_THREADED: 0 + - platform: mingw-w64 + configuration: Release + gen: "MinGW Makefiles" + US_SHARED: 1 + US_THREADED: 0 + - platform: mingw-w64 + configuration: Release + gen: "MinGW Makefiles" + US_SHARED: 0 + US_THREADED: 1 + - platform: mingw-w64 + configuration: Release + gen: "MinGW Makefiles" + US_SHARED: 1 + US_THREADED: 1 + +init: +- echo %APPVEYOR_BUILD_WORKER_IMAGE% +- cmake -version +- git config --global core.autocrlf true + +before_build: +- mkdir build & cd build +- echo %PATH% +- if "%platform%"=="mingw-w64" set PATH=%PATH:C:\Program Files\Git\usr\bin;=% +- if "%platform%"=="mingw-w64" set PATH=C:\msys64\mingw64\bin;%PATH% +- if [%WITH_COVERAGE%]==[1] set PATH=%PATH%;C:\Program Files\OpenCppCoverage +- echo %PATH% +- cmake .. -G"%gen%" -DCMAKE_BUILD_TYPE=%configuration% -DUS_BUILD_SHARED_LIBS:BOOL=%US_SHARED% -DUS_ENABLE_THREADING_SUPPORT:BOOL=%US_THREADED% -DUS_ENABLE_COVERAGE:BOOL=%WITH_COVERAGE% -DUS_BUILD_TESTING:BOOL=1 2>&1 + +install: +- if [%WITH_COVERAGE%]==[1] choco install opencppcoverage +- if [%WITH_COVERAGE%]==[1] pip install codecov + +build_script: +- if NOT "%platform%"=="mingw-w64" cmake --build %APPVEYOR_BUILD_FOLDER%/build --config %configuration% -- /maxcpucount +- if "%platform%"=="mingw-w64" cmake --build %APPVEYOR_BUILD_FOLDER%/build -- -j2 + +after_test: +- if [%WITH_COVERAGE%]==[1] %APPVEYOR_BUILD_FOLDER%/opencppcoverage_mergereports.bat +- if [%WITH_COVERAGE%]==[1] python %APPVEYOR_BUILD_FOLDER%/fixcoveragefilepaths.py -i coverage.xml -s %APPVEYOR_BUILD_FOLDER% -o coverage_pathsfixed.xml +- if [%WITH_COVERAGE%]==[1] codecov -X gcov -f coverage_pathsfixed.xml + +test_script: +- cd %APPVEYOR_BUILD_FOLDER%/build +- ctest -j2 -C %CONFIGURATION% --output-on-failure + diff --git a/external/CppMicroServices/cmake/BundleInit.cpp b/external/CppMicroServices/cmake/BundleInit.cpp new file mode 100644 index 00000000..bd8366d2 --- /dev/null +++ b/external/CppMicroServices/cmake/BundleInit.cpp @@ -0,0 +1,25 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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 "cppmicroservices/BundleInitialization.h" + +CPPMICROSERVICES_INITIALIZE_BUNDLE diff --git a/external/CppMicroServices/cmake/CMakeResourceDependencies.cpp b/external/CppMicroServices/cmake/CMakeResourceDependencies.cpp new file mode 100644 index 00000000..f6bc0241 --- /dev/null +++ b/external/CppMicroServices/cmake/CMakeResourceDependencies.cpp @@ -0,0 +1,33 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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 + +namespace { + +// This is dummy code to silence some linkers warning about +// empty object files. +struct CMakeResourceDependencies +{ + CMakeResourceDependencies() { std::cout << std::flush; } +}; +} diff --git a/external/CppMicroServices/cmake/Export.h.in b/external/CppMicroServices/cmake/Export.h.in new file mode 100644 index 00000000..16032b2d --- /dev/null +++ b/external/CppMicroServices/cmake/Export.h.in @@ -0,0 +1,24 @@ +///------------------------------------------------------------------- +// Macros for import/export declarations +//------------------------------------------------------------------- + +#ifndef CPPMICROSERVICES_@PROJECT_NAME@EXPORT_H +#define CPPMICROSERVICES_@PROJECT_NAME@EXPORT_H + +#include "cppmicroservices/GlobalConfig.h" + +#ifdef US_BUILD_SHARED_LIBS + // We are building a shared lib + #ifdef @PROJECT_TARGET@_EXPORTS + #define US_@PROJECT_NAME@_EXPORT US_ABI_EXPORT + #else + #define US_@PROJECT_NAME@_EXPORT US_ABI_IMPORT + #endif +#else + // We are building a static lib + // Don't hide RTTI symbols of definitions in the C++ Micro Services + // headers that are included in DSOs with hidden visibility + #define US_@PROJECT_NAME@_EXPORT US_ABI_EXPORT +#endif + +#endif // CPPMICROSERVICES_@PROJECT_NAME@EXPORT_H diff --git a/external/CppMicroServices/cmake/GlobalConfig.h.in b/external/CppMicroServices/cmake/GlobalConfig.h.in new file mode 100644 index 00000000..d6b65e11 --- /dev/null +++ b/external/CppMicroServices/cmake/GlobalConfig.h.in @@ -0,0 +1,186 @@ +/* + GlobalConfig.h + this file is generated. Do not change! +*/ + +#ifndef CPPMICROSERVICES_GLOBALCONFIG_H +#define CPPMICROSERVICES_GLOBALCONFIG_H + +#cmakedefine US_BUILD_SHARED_LIBS +#cmakedefine US_ENABLE_THREADING_SUPPORT +#cmakedefine US_HAVE_VISIBILITY_ATTRIBUTE + +#define US_DEBUG_POSTFIX "@CMAKE_DEBUG_POSTFIX@" + +//------------------------------------------------------------------- +// Header Availability +//------------------------------------------------------------------- + +#cmakedefine US_HAVE_CXXABI_H + +//------------------------------------------------------------------- +// Version information +//------------------------------------------------------------------- + +#define CppMicroServices_VERSION_MAJOR @CppMicroServices_VERSION_MAJOR@ +#define CppMicroServices_VERSION_MINOR @CppMicroServices_VERSION_MINOR@ +#define CppMicroServices_VERSION_PATCH @CppMicroServices_VERSION_PATCH@ +#define CppMicroServices_VERSION @CppMicroServices_VERSION@ +#define CppMicroServices_VERSION_STR "@CppMicroServices_VERSION@" + +#define US_VERSION_MAJOR @CppMicroServices_VERSION_MAJOR@ +#define US_VERSION_MINOR @CppMicroServices_VERSION_MINOR@ +#define US_VERSION_PATCH @CppMicroServices_VERSION_PATCH@ +#define US_VERSION @CppMicroServices_VERSION@ +#define US_VERSION_STR "@CppMicroServices_VERSION@" + +//------------------------------------------------------------------- +// Platform defines +//------------------------------------------------------------------- + +#if defined(__APPLE__) + #define US_PLATFORM_APPLE +#endif + +#if defined(__linux__) + #define US_PLATFORM_LINUX +#endif + +#if defined(_WIN32) || defined(_WIN64) + #define US_PLATFORM_WINDOWS +#else + #define US_PLATFORM_POSIX +#endif + +#cmakedefine US_BIG_ENDIAN +#cmakedefine US_LITTLE_ENDIAN + +#define US_LIB_PREFIX "@CMAKE_SHARED_LIBRARY_PREFIX@" +#define US_LIB_EXT "@CMAKE_SHARED_LIBRARY_SUFFIX@" +#define US_EXE_EXT "@CMAKE_EXECUTABLE_SUFFIX@" + +///------------------------------------------------------------------- +// Macros for import/export declarations +//------------------------------------------------------------------- + +#if defined(US_PLATFORM_WINDOWS) + #define US_ABI_EXPORT __declspec(dllexport) + #define US_ABI_IMPORT __declspec(dllimport) + #define US_ABI_LOCAL +#elif defined(US_HAVE_VISIBILITY_ATTRIBUTE) + #define US_ABI_EXPORT __attribute__ ((visibility ("default"))) + #define US_ABI_IMPORT __attribute__ ((visibility ("default"))) + #define US_ABI_LOCAL __attribute__ ((visibility ("hidden"))) +#else + #define US_ABI_EXPORT + #define US_ABI_IMPORT + #define US_ABI_LOCAL +#endif + +//------------------------------------------------------------------- +// Macros for suppressing warnings +//------------------------------------------------------------------- + +#ifdef _MSC_VER +#define US_MSVC_PUSH_DISABLE_WARNING(wn) \ +__pragma(warning(push)) \ +__pragma(warning(disable:wn)) +#define US_MSVC_POP_WARNING \ +__pragma(warning(pop)) +#define US_MSVC_DISABLE_WARNING(wn) \ +__pragma(warning(disable:wn)) +#else +#define US_MSVC_PUSH_DISABLE_WARNING(wn) +#define US_MSVC_POP_WARNING +#define US_MSVC_DISABLE_WARNING(wn) +#endif + +#ifdef __GNUC__ +#define us_gcc_pragma_expand(x) _Pragma (#x) +#define US_GCC_PUSH_DISABLE_WARNING(wn) \ +_Pragma ("GCC diagnostic push") \ +us_gcc_pragma_expand(GCC diagnostic ignored "-W" #wn) +#define US_GCC_POP_WARNING \ +_Pragma ("GCC diagnostic pop") +#else +#define US_GCC_PUSH_DISABLE_WARNING(wn) +#define US_GCC_POP_WARNING +#endif + +#if defined(__GNUC__) + #define US_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define US_DEPRECATED __declspec(deprecated) +#else + #pragma message("WARNING: You need to implement US_DEPRECATED for your compiler!") + #define US_DEPRECATED +#endif + +// Do not warn about the usage of deprecated unsafe functions +US_MSVC_DISABLE_WARNING(4996) + +// Mark a variable or expression result as unused +#define US_UNUSED(x) (void)(x) + +//------------------------------------------------------------------- +// C++ Language features +//------------------------------------------------------------------- + +#cmakedefine US_HAVE_THREAD_LOCAL + +//------------------------------------------------------------------- +// C++ Library features +//------------------------------------------------------------------- + +#cmakedefine US_HAVE_REGEX + +//------------------------------------------------------------------- +// Hash Container +//------------------------------------------------------------------- + +#define US_HASH_FUNCTION_BEGIN(type) \ +namespace std { \ +template<> \ +struct hash : std::unary_function { \ +std::size_t operator()(const type& arg) const { + +#define US_HASH_FUNCTION_END } }; } + + +//------------------------------------------------------------------- +// Utility macros +//------------------------------------------------------------------- + +#define US_STR_(x) #x +#define US_STR(x) US_STR_(x) +#define US_CONCAT_(x,y) x ## y +#define US_CONCAT(x,y) US_CONCAT_(x,y) + +#define US_GET_CTX_PREFIX _us_get_bundle_context_instance_ +#define US_SET_CTX_PREFIX _us_set_bundle_context_instance_ +#define US_CTX_INS_PREFIX _us_bundle_context_instance_ + +#define US_GET_CTX_FUNC(bsn) US_CONCAT(US_GET_CTX_PREFIX, bsn) +#define US_SET_CTX_FUNC(bsn) US_CONCAT(US_SET_CTX_PREFIX, bsn) +#define US_CTX_INS(bsn) US_CONCAT(US_CTX_INS_PREFIX, bsn) + +#define US_CREATE_ACTIVATOR_PREFIX _us_create_activator_ +#define US_DESTROY_ACTIVATOR_PREFIX _us_destroy_activator_ + +#define US_CREATE_ACTIVATOR_FUNC(bsn) US_CONCAT(US_CREATE_ACTIVATOR_PREFIX, bsn) +#define US_DESTROY_ACTIVATOR_FUNC(bsn) US_CONCAT(US_DESTROY_ACTIVATOR_PREFIX, bsn) + + +//------------------------------------------------------------------- +// Backwards compatibility macros +//------------------------------------------------------------------- + +#if !defined(__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7 +#define US_FUTURE_READY true +#define US_FUTURE_TIMEOUT false +#else +#define US_FUTURE_READY std::future_status::ready +#define US_FUTURE_TIMEOUT std::future_status::timeout +#endif + +#endif // CPPMICROSERVICES_GLOBALCONFIG_H diff --git a/external/CppMicroServices/cmake/cppmicroservices_resources.rc.in b/external/CppMicroServices/cmake/cppmicroservices_resources.rc.in new file mode 100644 index 00000000..0d626d2b --- /dev/null +++ b/external/CppMicroServices/cmake/cppmicroservices_resources.rc.in @@ -0,0 +1,4 @@ +#define US_RESOURCE 200 +#define IDR_US_RESOURCE 101 + +IDR_US_RESOURCE US_RESOURCE "@US_RESOURCE_ARCHIVE@" diff --git a/external/CppMicroServices/cmake/try_compile/us_have_regex.cpp b/external/CppMicroServices/cmake/try_compile/us_have_regex.cpp new file mode 100644 index 00000000..2cec5323 --- /dev/null +++ b/external/CppMicroServices/cmake/try_compile/us_have_regex.cpp @@ -0,0 +1,7 @@ +#include +int main() +{ + auto regex_iter_end = std::sregex_iterator(); + (void)regex_iter_end; + return 0; +} diff --git a/external/CppMicroServices/cmake/try_compile/us_have_thread_local.cpp b/external/CppMicroServices/cmake/try_compile/us_have_thread_local.cpp new file mode 100644 index 00000000..afbb6de4 --- /dev/null +++ b/external/CppMicroServices/cmake/try_compile/us_have_thread_local.cpp @@ -0,0 +1,8 @@ +#include + +// We use a non-POD type for this test +static thread_local std::string dummy; +int main() +{ + return 0; +} diff --git a/external/CppMicroServices/cmake/usBundleConfig.cmake.in b/external/CppMicroServices/cmake/usBundleConfig.cmake.in new file mode 100644 index 00000000..c9cf7437 --- /dev/null +++ b/external/CppMicroServices/cmake/usBundleConfig.cmake.in @@ -0,0 +1,8 @@ +@PACKAGE_INIT@ + +set(US_@PROJECT_NAME@_LIBRARIES @PROJECT_TARGET@) +set(US_@PROJECT_NAME@_RUNTIME_LIBRARY_DIRS "@PACKAGE_CONFIG_RUNTIME_LIBRARY_DIR@") + +if(NOT TARGET @PROJECT_TARGET@) + include("${CMAKE_CURRENT_LIST_DIR}/us@PROJECT_NAME@Targets.cmake") +endif() diff --git a/external/CppMicroServices/cmake/usBundleConfigVersion.cmake.in b/external/CppMicroServices/cmake/usBundleConfigVersion.cmake.in new file mode 100644 index 00000000..260b783d --- /dev/null +++ b/external/CppMicroServices/cmake/usBundleConfigVersion.cmake.in @@ -0,0 +1,34 @@ +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version major number == requested version major number +# and the current version minor number >= requested version minor number + +set(PACKAGE_VERSION_MAJOR @Framework_VERSION_MAJOR@) +set(PACKAGE_VERSION_MINOR @Framework_VERSION_MINOR@) +set(PACKAGE_VERSION_PATCH @Framework_VERSION_PATCH@) +set(PACKAGE_VERSION "@Framework_VERSION@") + +if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) +else() + set(PACKAGE_VERSION_EXACT FALSE) + if(NOT PACKAGE_VERSION_MAJOR EQUAL PACKAGE_FIND_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + elseif(PACKAGE_VERSION_MINOR LESS PACKAGE_FIND_VERSION_MINOR) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + endif() +endif() + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "@CMAKE_SIZEOF_VOID_P@" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "@CMAKE_SIZEOF_VOID_P@") + math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/external/CppMicroServices/cmake/usCTestScript.cmake b/external/CppMicroServices/cmake/usCTestScript.cmake new file mode 100644 index 00000000..d5566d9f --- /dev/null +++ b/external/CppMicroServices/cmake/usCTestScript.cmake @@ -0,0 +1,103 @@ + +macro(build_and_test) + + set(CTEST_SOURCE_DIRECTORY ${US_SOURCE_DIR}) + set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/${CTEST_PROJECT_NAME}_${CTEST_DASHBOARD_NAME}") + + #if(NOT CTEST_BUILD_NAME) + # set(CTEST_BUILD_NAME "${CMAKE_SYSTEM}_${CTEST_COMPILER}_${CTEST_DASHBOARD_NAME}") + #endif() + + ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY}) + + ctest_start("Experimental") + + if(NOT EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt") + file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "${CTEST_INITIAL_CACHE}") + endif() + + ctest_configure(RETURN_VALUE res) + if (res) + message(FATAL_ERROR "CMake configure error") + endif() + ctest_build(RETURN_VALUE res) + if (res) + message(FATAL_ERROR "CMake build error") + endif() + + ctest_test(RETURN_VALUE res PARALLEL_LEVEL ${CTEST_PARALLEL_LEVEL}) + if (res) + message(FATAL_ERROR "CMake test error") + endif() + + + if(WITH_MEMCHECK AND CTEST_MEMORYCHECK_COMMAND) + ctest_memcheck() + endif() + + if(WITH_COVERAGE) + if(CTEST_COVERAGE_COMMAND) + ctest_coverage() + else() + message(FATAL_ERROR "CMake could not find coverage tool") + endif() + endif() + + #ctest_submit() + +endmacro() + +function(create_initial_cache var _shared _threading) + + set(_initial_cache " + US_BUILD_TESTING:BOOL=ON + US_ENABLE_COVERAGE:BOOL=$ENV{WITH_COVERAGE} + US_BUILD_SHARED_LIBS:BOOL=${_shared} + US_ENABLE_THREADING_SUPPORT:BOOL=${_threading} + US_BUILD_EXAMPLES:BOOL=ON + ") + + set(${var} ${_initial_cache} PARENT_SCOPE) + + if(_shared) + set(CTEST_DASHBOARD_NAME "shared") + else() + set(CTEST_DASHBOARD_NAME "static") + endif() + + if(_threading) + set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME}-threading") + endif() + + set(CTEST_DASHBOARD_NAME "${CTEST_DASHBOARD_NAME} (${_generator})" PARENT_SCOPE) + +endfunction() + +#========================================================= + +set(CTEST_PROJECT_NAME CppMicroServices) + +if(NOT CTEST_PARALLEL_LEVEL) + set(CTEST_PARALLEL_LEVEL 1) +endif() + + +# SHARED THREADING + +set(config0 1 1 ) +set(config1 0 1 ) +set(config2 1 0 ) +set(config3 0 0 ) + +if(NOT US_CMAKE_GENERATOR) + set(US_CMAKE_GENERATOR "Unix Makefiles") +endif() + +foreach (_generator ${US_CMAKE_GENERATOR}) + set(CTEST_CMAKE_GENERATOR ${_generator}) + foreach(i ${US_BUILD_CONFIGURATION}) + create_initial_cache(CTEST_INITIAL_CACHE ${config${i}}) + message("Testing build configuration: ${CTEST_DASHBOARD_NAME}") + build_and_test() + endforeach() +endforeach() diff --git a/external/CppMicroServices/cmake/usCTestScript_custom.cmake b/external/CppMicroServices/cmake/usCTestScript_custom.cmake new file mode 100644 index 00000000..b6e0b95c --- /dev/null +++ b/external/CppMicroServices/cmake/usCTestScript_custom.cmake @@ -0,0 +1,41 @@ + +find_program(CTEST_COVERAGE_COMMAND NAMES gcov) +find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) +find_program(CTEST_GIT_COMMAND NAMES git) + +set(CTEST_SITE "bigeye") +if(WIN32) + set(CTEST_DASHBOARD_ROOT "C:/tmp/us") +else() + set(CTEST_DASHBOARD_ROOT "/tmp/us") + set(CTEST_BUILD_FLAGS "-j") + #set(CTEST_COMPILER "gcc-4.5") +endif() + +set(CTEST_CONFIGURATION_TYPE Release) +set(CTEST_BUILD_CONFIGURATION Release) + +set(CTEST_PARALLEL_LEVEL 4) + +set(US_TEST_SHARED 1) +set(US_TEST_STATIC 1) + +set(US_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../") + +set(US_BUILD_CONFIGURATION ) +foreach(i RANGE 3) + list(APPEND US_BUILD_CONFIGURATION ${i}) +endforeach() + +if(WIN32 AND NOT MINGW) + set(US_CMAKE_GENERATOR + "Visual Studio 12" + ) + if (NOT ${CMAKE_VERSION} VERSION_LESS "3.1") + list(APPEND US_CMAKE_GENERATOR + "Visual Studio 14 2015" + ) + endif() +endif() + +include(${US_SOURCE_DIR}/cmake/usCTestScript.cmake) diff --git a/external/CppMicroServices/cmake/usCTestScript_travis.cmake b/external/CppMicroServices/cmake/usCTestScript_travis.cmake new file mode 100644 index 00000000..a6d1c7f8 --- /dev/null +++ b/external/CppMicroServices/cmake/usCTestScript_travis.cmake @@ -0,0 +1,28 @@ + +find_program(CTEST_COVERAGE_COMMAND NAMES gcov) +find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) +find_program(CTEST_GIT_COMMAND NAMES git) + +set(CTEST_SITE "travis-ci") +if(DEFINED ENV{BUILD_DIR}) + set(CTEST_DASHBOARD_ROOT $ENV{BUILD_DIR}) +else() + set(CTEST_DASHBOARD_ROOT "/tmp/us builds") +endif() +#set(CTEST_COMPILER "gcc-4.5") +set(CTEST_CMAKE_GENERATOR "Unix Makefiles") +if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + # gcc in combination with gcov seems to consume a lot of memory + # and may lead to OOM error on Travis containers. Hence we compile + # with -j for non-GNU compilers only. +set(CTEST_BUILD_FLAGS "-j") +endif() + +set(CTEST_CONFIGURATION_TYPE Release) +set(CTEST_BUILD_CONFIGURATION Release) + +set(US_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../") + +set(US_BUILD_CONFIGURATION $ENV{BUILD_CONFIGURATION}) +set(WITH_COVERAGE $ENV{WITH_COVERAGE}) +include(${US_SOURCE_DIR}/cmake/usCTestScript.cmake) diff --git a/external/CppMicroServices/cmake/usFunctionAddResources.cmake b/external/CppMicroServices/cmake/usFunctionAddResources.cmake new file mode 100755 index 00000000..746e10d1 --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionAddResources.cmake @@ -0,0 +1,187 @@ + +#.rst: +# +# .. cmake:command:: usFunctionAddResources +# +# Add resources to a library or executable. +# +# .. code-block:: cmake +# +# usFunctionAddResources(TARGET target [BUNDLE_NAME bundle_name] +# [WORKING_DIRECTORY dir] [COMPRESSION_LEVEL level] +# [FILES res1...] [ZIP_ARCHIVES archive1...]) +# +# This CMake function uses an external command line program to generate a ZIP archive +# containing data from external resources such as text files or images or other ZIP +# archives. The created archive file can be appended or linked into the target file +# using the :cmake:command:`usFunctionEmbedResources` function. +# +# Each bundle can call this function to add resources and make them available at +# runtime through the Bundle class. Multiple calls to this function append the +# input files. +# +# In the case of linking static bundles which contain resources to the target bundle, +# adding the static bundle target name to the ``ZIP_ARCHIVES`` list will merge its +# resources into the target bundle. +# +# .. code-block:: cmake +# :caption: Example +# +# set(bundle_srcs ) +# usFunctionAddResources(TARGET mylib +# BUNDLE_NAME org_me_mylib +# FILES config.properties logo.png +# ) +# +# **One-value keywords** +# * ``TARGET`` (required): The target to which the resource files are added. +# * ``BUNDLE_NAME`` (required/optional): The bundle name of the target, as specified in +# the \c US_BUNDLE_NAME pre-processor definition of that target. This parameter +# is optional if a target property with the name US_BUNDLE_NAME exists, containing +# the required bundle name. +# * ``COMPRESSION_LEVEL`` (optional): The zip compression level (0-9). Defaults to the default zip +# level. Level 0 disables compression. +# * ``WORKING_DIRECTORY`` (optional): The root path for all resource files listed after the +# FILES argument. If no or a relative path is given, it is considered relative to the +# current CMake source directory. +# +# **Multi-value keywords** +# * ``FILES`` (optional): A list of resource files (paths to external files in the file system) +# relative to the current working directory. +# * ``ZIP_ARCHIVES`` (optional): A list of zip archives (relative to the current working directory +# or absolute file paths) whose contents is merged into the target bundle. If a list entry +# is a valid target name and that target is a static library, its absolute file path is +# used instead. +# +# .. seealso:: +# +# | :cmake:command:`usFunctionEmbedResources` +# | :any:`concept-resources` +# +function(usFunctionAddResources) + + cmake_parse_arguments(US_RESOURCE "" "TARGET;BUNDLE_NAME;WORKING_DIRECTORY;COMPRESSION_LEVEL" "FILES;ZIP_ARCHIVES" ${ARGN}) + + if(NOT US_RESOURCE_TARGET) + message(SEND_ERROR "TARGET argument not specified.") + endif() + + if(NOT US_RESOURCE_BUNDLE_NAME) + get_target_property(US_RESOURCE_BUNDLE_NAME ${US_RESOURCE_TARGET} US_BUNDLE_NAME) + if(NOT US_RESOURCE_BUNDLE_NAME) + message(SEND_ERROR "Either the BUNDLE_NAME argument or the US_BUNDLE_NAME target property is required.") + endif() + endif() + + if(NOT US_RESOURCE_FILES AND NOT US_RESOURCE_ZIP_ARCHIVES) + message(WARNING "No resources specified. Skipping resource processing.") + return() + endif() + + if(NOT US_RESOURCE_WORKING_DIRECTORY) + set(US_RESOURCE_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + if(NOT IS_ABSOLUTE ${US_RESOURCE_WORKING_DIRECTORY}) + set(US_RESOURCE_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${US_RESOURCE_WORKING_DIRECTORY}") + endif() + + if(US_RESOURCE_COMPRESSION_LEVEL) + set(cmd_line_args -c ${US_RESOURCE_COMPRESSION_LEVEL}) + endif() + + if(CMAKE_CROSSCOMPILING) + # Cross-compiled builds need to use the imported host version of usResourceCompiler + include(${IMPORT_EXECUTABLES}) + set(resource_compiler native-${US_RCC_EXECUTABLE_TARGET}) + else() + set(resource_compiler ${US_RCC_EXECUTABLE}) + if(TARGET ${US_RCC_EXECUTABLE_TARGET}) + set(resource_compiler ${US_RCC_EXECUTABLE_TARGET}) + elseif(NOT resource_compiler) + message(FATAL_ERROR "The CppMicroServices resource compiler was not found. Check the US_RCC_EXECUTABLE CMake variable.") + endif() + endif() + + set(_cmd_deps ) + foreach(_file ${US_RESOURCE_FILES}) + if(IS_ABSOLUTE ${_file}) + list(APPEND _cmd_deps ${_file}) + else() + list(APPEND _cmd_deps ${US_RESOURCE_WORKING_DIRECTORY}/${_file}) + endif() + endforeach() + + set(_zip_args ) + if(US_RESOURCE_ZIP_ARCHIVES) + foreach(_zip_archive ${US_RESOURCE_ZIP_ARCHIVES}) + if(TARGET ${_zip_archive}) + get_target_property(_is_static_lib ${_zip_archive} TYPE) + if(_is_static_lib STREQUAL "STATIC_LIBRARY") + list(APPEND _cmd_deps ${_zip_archive}) + list(APPEND _zip_args $) + endif() + else() + if(IS_ABSOLUTE ${_zip_archive}) + list(APPEND _cmd_deps ${_zip_archive}) + else() + list(APPEND _cmd_deps ${US_RESOURCE_WORKING_DIRECTORY}/${_zip_archive}) + endif() + list(APPEND _zip_args ${_zip_archive}) + endif() + endforeach() + endif() + + if(NOT US_RESOURCE_FILES AND NOT _zip_args) + return() + endif() + + if(US_RESOURCE_FILES) + set(_file_args ) + foreach(_file ${US_RESOURCE_FILES}) + list(APPEND _file_args -r) + list(APPEND _file_args ${_file}) + endforeach() + endif() + if(_zip_args) + set(_us_zip_args ) + foreach(_file ${_zip_args}) + list(APPEND _us_zip_args -z) + list(APPEND _us_zip_args ${_file}) + endforeach() + endif() + + if(US_RESOURCE_BUNDLE_NAME) + set(_bundle_args -n ${US_RESOURCE_BUNDLE_NAME}) + endif() + + get_target_property(_counter ${US_RESOURCE_TARGET} _us_resource_counter) + if((NOT ${_counter} EQUAL 0) AND NOT _counter) + set(_counter 0) + else() + math(EXPR _counter "${_counter} + 1") + endif() + + set(_res_zip "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_TARGET}/res_${_counter}.zip") + + add_custom_command( + OUTPUT ${_res_zip} + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_TARGET}" + COMMAND ${resource_compiler} ${cmd_line_args} -o ${_res_zip} ${_bundle_args} ${_file_args} ${_us_zip_args} + WORKING_DIRECTORY ${US_RESOURCE_WORKING_DIRECTORY} + DEPENDS ${_cmd_deps} ${resource_compiler} + COMMENT "Checking resource dependencies for ${US_RESOURCE_TARGET}" + VERBATIM + ) + + get_target_property(_res_zips ${US_RESOURCE_TARGET} _us_resource_zips) + if(NOT _res_zips) + set(_res_zips ) + endif() + list(APPEND _res_zips ${_res_zip}) + + set_target_properties(${US_RESOURCE_TARGET} PROPERTIES + _us_resource_counter "${_counter}" + _us_resource_zips "${_res_zips}" + ) + +endfunction() diff --git a/external/CppMicroServices/cmake/usFunctionCheckCompilerFlags.cmake b/external/CppMicroServices/cmake/usFunctionCheckCompilerFlags.cmake new file mode 100644 index 00000000..bb3d1828 --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionCheckCompilerFlags.cmake @@ -0,0 +1,68 @@ +# +# Helper macro allowing to check if the given flags are supported +# by the underlying build tool +# +# If the flag(s) is/are supported, they will be appended to the string identified by RESULT_VAR +# +# Usage: +# usFunctionCheckCompilerFlags(FLAGS_TO_CHECK VALID_FLAGS_VAR) +# +# Example: +# +# set(myflags) +# usFunctionCheckCompilerFlags("-fprofile-arcs" myflags) +# message(1-myflags:${myflags}) +# usFunctionCheckCompilerFlags("-fauto-bugfix" myflags) +# message(2-myflags:${myflags}) +# usFunctionCheckCompilerFlags("-Wall" myflags) +# message(1-myflags:${myflags}) +# +# The output will be: +# 1-myflags: -fprofile-arcs +# 2-myflags: -fprofile-arcs +# 3-myflags: -fprofile-arcs -Wall + +include(CheckCXXCompilerFlag) + +function(usFunctionCheckCompilerFlags FLAG_TO_TEST RESULT_VAR) + + if(FLAG_TO_TEST STREQUAL "") + message(FATAL_ERROR "FLAG_TO_TEST shouldn't be empty") + endif() + + # Save the contents of RESULT_VAR temporarily. + # This is needed in case ${RESULT_VAR} is one of the CMAKE__FLAGS_* variables. + set(_saved_result_var ${${RESULT_VAR}}) + + # Clear all flags. If not, existing flags triggering warnings might lead to + # false-negatives when checking for certain compiler flags. + set(CMAKE_C_FLAGS ) + set(CMAKE_C_FLAGS_DEBUG ) + set(CMAKE_C_FLAGS_MINSIZEREL ) + set(CMAKE_C_FLAGS_RELEASE ) + set(CMAKE_C_FLAGS_RELWITHDEBINFO ) + set(CMAKE_CXX_FLAGS ) + set(CMAKE_CXX_FLAGS_DEBUG ) + set(CMAKE_CXX_FLAGS_MINSIZEREL ) + set(CMAKE_CXX_FLAGS_RELEASE ) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ) + + # Internally, the macro CMAKE_CXX_COMPILER_FLAG calls TRY_COMPILE. To avoid + # the cost of compiling the test each time the project is configured, the variable set by + # the macro is added to the cache so that following invocation of the macro with + # the same variable name skip the compilation step. + # For that same reason, the usFunctionCheckCompilerFlags function appends a unique suffix to + # the HAS_CXX_FLAG variable. This suffix is created using a 'clean version' of the + # flag to test. The value of HAS_CXX_FLAG_${suffix} additonally needs to be a valid + # pre-processor token because CHECK_CXX_COMPILER_FLAG adds it as a definition to the compiler + # arguments. An invalid token triggers compiler warnings, which in case of the "-Werror" flag + # leads to false-negative checks. + string(REGEX REPLACE "[=/-]" "_" suffix ${FLAG_TO_TEST}) + string(REGEX REPLACE "[, \\$\\+\\*\\{\\}\\(\\)\\#]" "" suffix ${suffix}) + CHECK_CXX_COMPILER_FLAG(${FLAG_TO_TEST} HAS_CXX_FLAG_${suffix}) + + if(HAS_CXX_FLAG_${suffix}) + set(${RESULT_VAR} "${_saved_result_var} ${FLAG_TO_TEST}" PARENT_SCOPE) + endif() + +endfunction() diff --git a/external/CppMicroServices/cmake/usFunctionCheckResourceLinking.cmake b/external/CppMicroServices/cmake/usFunctionCheckResourceLinking.cmake new file mode 100644 index 00000000..d307682d --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionCheckResourceLinking.cmake @@ -0,0 +1,50 @@ +function(usFunctionCheckResourceLinking) + if(NOT DEFINED US_RESOURCE_LINKING_AVAILABLE) + set(_suffix ) + # Check linking capability + set(_linking_available 0) + if(APPLE) + set(_result ) + # section name is "us_resources" because max length for section names in Mach-O format is 16 characters. + usFunctionCheckCompilerFlags("-Wl,-sectcreate,__TEXT,us_resources,CMakeLists.txt" _result) + if(_result) + set(_linking_available 1) + endif() + set(_suffix .o) + elseif(WIN32 AND CMAKE_RC_COMPILER) + set(_linking_available 1) + set(_suffix .rc) + elseif(UNIX) + execute_process( + COMMAND ${CMAKE_LINKER} -r -b binary -o "${CMAKE_CURRENT_BINARY_DIR}/us_resource_link.o" "${CMAKE_COMMAND}" + RESULT_VARIABLE _result + ) + if(_result EQUAL 0) + set(_linking_available 1) + endif() + set(_suffix .o) + endif() + + set(US_RESOURCE_SOURCE_SUFFIX_LINK ${_suffix} CACHE INTERNAL "CppMicroServices resource source suffix (link)" FORCE) + set(US_RESOURCE_SOURCE_SUFFIX_APPEND ".cpp" CACHE INTERNAL "CppMicroServices resource source suffix (append)" FORCE) + + set(_success "no") + set(_default_mode "APPEND") + if(_linking_available) + set(_success "yes") + if(APPLE) + set(_default_mode "LINK") + endif() + endif() + + message("Checking for CppMicroServices resource linking capability...${_success}") + + set(US_RESOURCE_LINKING_AVAILABLE ${_linking_available} CACHE INTERNAL "CppMicroServices resource linking" FORCE) + set(US_DEFAULT_RESOURCE_MODE ${_default_mode} CACHE INTERNAL "CppMicroServices default resource mode" FORCE) + if(_default_mode STREQUAL "LINK") + set(US_RESOURCE_SOURCE_SUFFIX ${US_RESOURCE_SOURCE_SUFFIX_LINK} CACHE INTERNAL "CppMicroServices resource source suffix" FORCE) + else() + set(US_RESOURCE_SOURCE_SUFFIX ${US_RESOURCE_SOURCE_SUFFIX_APPEND} CACHE INTERNAL "CppMicroServices resource source suffix" FORCE) + endif() + endif() +endfunction() diff --git a/external/CppMicroServices/cmake/usFunctionCompileSnippets.cmake b/external/CppMicroServices/cmake/usFunctionCompileSnippets.cmake new file mode 100644 index 00000000..c106f15d --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionCompileSnippets.cmake @@ -0,0 +1,50 @@ +function(usFunctionCompileSnippets snippet_path) + + # get all files called "main.cpp" + file(GLOB_RECURSE main_cpp_list "${snippet_path}/main.cpp") + + foreach(main_cpp_file ${main_cpp_list}) + # get the directory containing the main.cpp file + get_filename_component(main_cpp_dir "${main_cpp_file}" PATH) + + set(snippet_src_files ) + + # If there exists a "files.cmake" file in the snippet directory, + # include it and assume it sets the variable "snippet_src_files" + # to a list of source files for the snippet. + if(EXISTS "${main_cpp_dir}/files.cmake") + include("${main_cpp_dir}/files.cmake") + set(_tmp_src_files ${snippet_src_files}) + set(snippet_src_files ) + foreach(_src_file ${_tmp_src_files}) + if(IS_ABSOLUTE ${_src_file}) + list(APPEND snippet_src_files ${_src_file}) + else() + list(APPEND snippet_src_files ${main_cpp_dir}/${_src_file}) + endif() + endforeach() + else() + # glob all files in the directory and add them to the snippet src list + file(GLOB_RECURSE snippet_src_files "${main_cpp_dir}/*") + endif() + + # Uset the top-level directory name as the executable name + string(REPLACE "/" ";" main_cpp_dir_tokens "${main_cpp_dir}") + list(GET main_cpp_dir_tokens -1 snippet_exec_name) + set(snippet_target_name "Snippet-${snippet_exec_name}") + + add_executable(${snippet_target_name} ${snippet_src_files}) + target_link_libraries(${snippet_target_name} ${PROJECT_TARGET} ${snippet_link_libraries} ${US_LIBRARIES}) + set_property(TARGET ${snippet_target_name} APPEND PROPERTY COMPILE_DEFINITIONS US_BUNDLE_NAME=main) + set_property(TARGET ${snippet_target_name} PROPERTY US_BUNDLE_NAME main) + set_target_properties(${snippet_target_name} PROPERTIES + LABELS Documentation + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/snippets" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/snippets" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/snippets" + OUTPUT_NAME ${snippet_exec_name} + ) + + endforeach() + +endfunction() diff --git a/external/CppMicroServices/cmake/usFunctionCreateTestBundle.cmake b/external/CppMicroServices/cmake/usFunctionCreateTestBundle.cmake new file mode 100644 index 00000000..2c36d42f --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionCreateTestBundle.cmake @@ -0,0 +1,75 @@ + +macro(_us_create_test_bundle_helper) + + add_library(${name} ${_srcs} $) + if(US_BUILD_SHARED_LIBS AND US_TEST_LIBRARY_EXTENSION) + set_target_properties(${name} PROPERTIES SUFFIX ${US_TEST_LIBRARY_EXTENSION}) + endif() + set_property(TARGET ${name} + APPEND PROPERTY COMPILE_DEFINITIONS US_BUNDLE_NAME=${_bundle_symbolic_name}) + set_property(TARGET ${name} PROPERTY US_BUNDLE_NAME ${_bundle_symbolic_name}) + # Clear a possible debug postfix + set_property(TARGET ${name} PROPERTY DEBUG_POSTFIX "") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + get_property(_compile_flags TARGET ${name} PROPERTY COMPILE_FLAGS) + set_property(TARGET ${name} PROPERTY COMPILE_FLAGS "${_compile_flags} -fPIC") + endif() + + target_include_directories(${name} PRIVATE $) + target_link_libraries(${name} ${${PROJECT_NAME}_TARGET} ${US_TEST_LINK_LIBRARIES} CppMicroServices) + + if(_res_files OR US_TEST_LINK_LIBRARIES) + usFunctionAddResources(TARGET ${name} WORKING_DIRECTORY ${_res_root} + FILES ${_res_files} + ZIP_ARCHIVES ${US_TEST_LINK_LIBRARIES}) + endif() + if(_bin_res_files) + usFunctionAddResources(TARGET ${name} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/resources + FILES ${_bin_res_files}) + endif() + + usFunctionEmbedResources(TARGET ${name} ${_mode}) + + if(NOT US_TEST_SKIP_BUNDLE_LIST) + set(_us_test_bundle_libs "${_us_test_bundle_libs};${name}" CACHE INTERNAL "" FORCE) + endif() + +endmacro() + +function(usFunctionCreateTestBundle name) + set(_srcs ${ARGN}) + set(_res_files ) + set(_bin_res_files ) + set(_bundle_symbolic_name ${name}) + usFunctionGenerateBundleInit(TARGET ${name} OUT _srcs) + _us_create_test_bundle_helper() +endfunction() + +function(usFunctionCreateTestBundleWithResources name) + cmake_parse_arguments(US_TEST "SKIP_BUNDLE_LIST;LINK_RESOURCES;APPEND_RESOURCES" "RESOURCES_ROOT;LIBRARY_EXTENSION;BUNDLE_SYMBOLIC_NAME" "SOURCES;RESOURCES;BINARY_RESOURCES;LINK_LIBRARIES" "" ${ARGN}) + + if(US_TEST_BUNDLE_SYMBOLIC_NAME) + set(_bundle_symbolic_name ${US_TEST_BUNDLE_SYMBOLIC_NAME}) + else() + set(_bundle_symbolic_name ${name}) + endif() + + set(_mode ) + if(US_TEST_LINK_RESOURCES) + set(_mode LINK) + elseif(US_TEST_APPEND_RESOURCES) + set(_mode APPEND) + endif() + + set(_srcs ${US_TEST_SOURCES}) + usFunctionGetResourceSource(TARGET ${name} OUT _srcs ${_mode}) + set(_res_files ${US_TEST_RESOURCES}) + set(_bin_res_files ${US_TEST_BINARY_RESOURCES}) + if(US_TEST_RESOURCES_ROOT) + set(_res_root ${US_TEST_RESOURCES_ROOT}) + else() + set(_res_root ${CMAKE_CURRENT_SOURCE_DIR}/resources) + endif() + usFunctionGenerateBundleInit(TARGET ${name} OUT _srcs) + _us_create_test_bundle_helper() +endfunction() diff --git a/external/CppMicroServices/cmake/usFunctionEmbedResources.cmake b/external/CppMicroServices/cmake/usFunctionEmbedResources.cmake new file mode 100644 index 00000000..902fe695 --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionEmbedResources.cmake @@ -0,0 +1,240 @@ + +#.rst: +# +# .. cmake:command:: usFunctionEmbedResources +# +# Embed resources in a library or executable. +# +# .. code-block:: cmake +# +# usFunctionEmbedResources(TARGET target [BUNDLE_NAME bundle_name] [APPEND | LINK] +# [WORKING_DIRECTORY dir] [COMPRESSION_LEVEL level] +# [FILES res1...] [ZIP_ARCHIVES archive1...]) +# +# This CMake function uses an external command line program to generate a ZIP archive +# containing data from external resources such as text files or images or other ZIP +# archives. External resources can be added to a bundle using the +# :cmake:command:`usFunctionAddResources` function or directly using this function +# using similar parameters. The created archive file is appended or embedded as a +# binary blob to the target file. +# +# .. note:: +# +# To set-up correct file dependencies from your bundle target to your resource +# files, you have to add a special source file to the source list of the target. +# The source file name can be retrieved by using :cmake:command:`usFunctionGetResourceSource`. +# This ensures that changed resource files will automatically be re-added to the +# bundle. +# +# There are two differend modes for including resources: *APPEND* and *LINK*. In *APPEND* mode, +# the generated zip file is appended at the end of the target file. In *LINK* mode, the +# zip file is compiled / linked into the target using platform specific techniques. *LINK* +# mode is necessary if certain tools make additional assumptions about the object layout +# of the target file (e.g. codesign on MacOS). *LINK* mode may result in slower bundle +# initialization and bigger object files. The default mode is *LINK* mode on MacOS and +# *APPEND* mode on all other platforms. +# +# .. code-block:: cmake +# :caption: Example +# +# usFunctionEmbedResources(TARGET mylib +# BUNDLE_NAME org_me_mylib +# FILES config.properties logo.png +# ) +# +# **One-value keywords** +# * ``TARGET`` (required): The target to which the resource files are added. +# * ``BUNDLE_NAME`` (required/optional): The bundle name of the target, as specified in +# the ``US_BUNDLE_NAME`` pre-processor definition of that target. This parameter +# is optional if a target property with the name ``US_BUNDLE_NAME`` exists, containing +# the required bundle name. +# +# **Options** +# * ``APPEND``: Append the resources zip file to the target file. +# * ``LINK``: Link (embed) the resources zip file if possible. +# +# For the ``WORKING_DIRECTORY``, ``COMPRESSION_LEVEL``, ``FILES``, ``ZIP_ARCHIVES`` parameters see the +# documentation of the usFunctionAddResources macro which is called with these parameters if set. +# +# .. seealso:: +# +# | :cmake:command:`usFunctionAddResources` +# | :cmake:command:`usFunctionGetResourceSource` +# | :any:`concept-resources` +# +function(usFunctionEmbedResources) + + cmake_parse_arguments(US_RESOURCE "APPEND;LINK" "TARGET;BUNDLE_NAME;WORKING_DIRECTORY;COMPRESSION_LEVEL" "FILES;ZIP_ARCHIVES" ${ARGN}) + + if(NOT US_RESOURCE_TARGET) + message(SEND_ERROR "TARGET argument not specified.") + endif() + + if(US_RESOURCE_FILES OR US_RESOURCE_ZIP_ARCHIVES) + usFunctionAddResources(TARGET ${US_RESOURCE_TARGET} + BUNDLE_NAME ${US_RESOURCE_BUNDLE_NAME} + WORKING_DIRECTORY ${US_RESOURCE_WORKING_DIRECTORY} + COMPRESSION_LEVEL ${US_RESOURCE_COMPRESSION_LEVEL} + FILES ${US_RESOURCE_FILES} + ZIP_ARCHIVES ${US_RESOURCE_ZIP_ARCHIVES} + ) + endif() + + get_target_property(_res_zips ${US_RESOURCE_TARGET} _us_resource_zips) + if(NOT _res_zips) + return() + endif() + + if(US_RESOURCE_APPEND AND US_RESOURCE_LINK) + message(WARNING "Both APPEND and LINK options specified. Falling back to default behaviour.") + set(US_RESOURCE_APPEND 0) + set(US_RESOURCE_LINK 0) + endif() + + if(US_RESOURCE_LINK AND NOT US_RESOURCE_LINKING_AVAILABLE) + message(WARNING "Resource linking not available. Falling back to APPEND mode.") + set(US_RESOURCE_LINK 0) + set(US_RESOURCE_APPEND 1) + endif() + + # Set default resource mode + if(NOT US_RESOURCE_APPEND AND NOT US_RESOURCE_LINK) + if(US_DEFAULT_RESOURCE_MODE STREQUAL "LINK") + set(US_RESOURCE_LINK 1) + else() + set(US_RESOURCE_APPEND 1) + endif() + endif() + + set(_mode ) + if(US_RESOURCE_LINK) + set(_mode LINK) + elseif(US_RESOURCE_APPEND) + set(_mode APPEND) + endif() + usFunctionGetResourceSource(TARGET ${US_RESOURCE_TARGET} OUT _source_output ${_mode}) + + if(NOT US_RESOURCE_WORKING_DIRECTORY) + set(US_RESOURCE_WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + if(NOT IS_ABSOLUTE ${US_RESOURCE_WORKING_DIRECTORY}) + set(US_RESOURCE_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${US_RESOURCE_WORKING_DIRECTORY}") + endif() + + if(CMAKE_CROSSCOMPILING) + # Cross-compiled builds need to use the imported host version of usResourceCompiler + include(${IMPORT_EXECUTABLES}) + set(resource_compiler native-${US_RCC_EXECUTABLE_TARGET}) + else() + set(resource_compiler ${US_RCC_EXECUTABLE}) + if(TARGET ${US_RCC_EXECUTABLE_TARGET}) + set(resource_compiler ${US_RCC_EXECUTABLE_TARGET}) + elseif(NOT resource_compiler) + message(FATAL_ERROR "The CppMicroServices resource compiler was not found. Check the US_RCC_EXECUTABLE CMake variable.") + endif() + endif() + + set(_zip_archive ) + get_target_property(_counter ${US_RESOURCE_TARGET} _us_resource_counter) + if(_counter EQUAL 0) + set(_zip_archive ${_res_zips}) + else() + set(_zip_archive ${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_TARGET}/res.zip) + if(_res_zips) + set(_zip_args ) + foreach(_file ${_res_zips}) + list(APPEND _zip_args -z) + list(APPEND _zip_args ${_file}) + endforeach() + endif() + add_custom_command( + OUTPUT ${_zip_archive} + COMMAND ${resource_compiler} -o ${_zip_archive} -n dummy ${_zip_args} + DEPENDS ${_res_zips} ${resource_compiler} + COMMENT "Creating resources zip file for ${US_RESOURCE_TARGET}" + VERBATIM + ) + endif() + get_filename_component(_zip_archive_name ${_zip_archive} NAME) + get_filename_component(_zip_archive_path ${_zip_archive} PATH) + + if(US_RESOURCE_LINK) + if(APPLE) + # This resolves an issue where passing in CMAKE_CXX_FLAGS using + # -D CMAKE_CXX_FLAGS:STRING="..." results in a quoted string being passed to + # the command below which results in the command being: + # >> clang "..." -c ... -o stub.o + # when it should really be: + # >> clang ... -c ... -o stub.o + # (pardon the elipsis for abbreviation) + separate_arguments(_us_resource_cxx_flags UNIX_COMMAND ${CMAKE_CXX_FLAGS}) + + # section name is "us_resources" because max length for section names in Mach-O format is 16 characters. + add_custom_command( + OUTPUT ${_source_output} + COMMAND ${CMAKE_CXX_COMPILER} ${_us_resource_cxx_flags} -c ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} -o stub.o + COMMAND ${CMAKE_LINKER} -r -sectcreate __TEXT us_resources ${_zip_archive_name} stub.o -o ${_source_output} + DEPENDS ${_zip_archive} + WORKING_DIRECTORY ${_zip_archive_path} + COMMENT "Linking resources zip file for ${US_RESOURCE_TARGET}" + VERBATIM + ) + set_source_files_properties(${_source_output} PROPERTIES EXTERNAL_OBJECT 1 GENERATED 1) + elseif(WIN32 AND CMAKE_RC_COMPILER) + set(US_RESOURCE_ARCHIVE ${_zip_archive}) + # If the file generated in "Configure" step is specified as the OUTPUT of add_custom_command, + # "Clean" target will delete the file and subsequent build will fail. To avoid failures in + # "ReBuild", generate the resource file in the "Configure" step and copy it in "Build" step + configure_file(${US_RESOURCE_RC_TEMPLATE} ${_source_output}_autogen) + add_custom_command( + OUTPUT ${_source_output} + COMMAND ${CMAKE_COMMAND} -E copy ${_source_output}_autogen ${_source_output} + DEPENDS ${_zip_archive} + WORKING_DIRECTORY ${_zip_archive_path} + COMMENT "Linking resources zip file for ${US_RESOURCE_TARGET}" + VERBATIM + ) + set_source_files_properties(${_source_output} PROPERTIES GENERATED 1) + elseif(UNIX) + add_custom_command( + OUTPUT ${_source_output} + COMMAND ${CMAKE_LINKER} -r -b binary -o ${_source_output} ${_zip_archive_name} + COMMAND objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents ${_source_output} ${_source_output} + DEPENDS ${_zip_archive} + WORKING_DIRECTORY ${_zip_archive_path} + COMMENT "Linking resources zip file for ${US_RESOURCE_TARGET}" + VERBATIM + ) + set_source_files_properties(${_source_output} PROPERTIES EXTERNAL_OBJECT 1 GENERATED 1) + else() + message(WARNING "Internal error: Resource linking not available. Falling back to APPEND mode.") + set(US_RESOURCE_LINK 0) + set(US_RESOURCE_APPEND 1) + endif() + endif() + + if(US_RESOURCE_APPEND) + # This command depends on the given resource files and creates a source + # file which must be added to the source list of the related target. + # This way, the following command is executed if the resources change + # and it just touches the created source file to force a (actually unnecessary) + # re-linking and hence the execution of POST_BUILD commands. + add_custom_command( + OUTPUT ${_source_output} + COMMAND ${CMAKE_COMMAND} -E copy ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} ${_source_output} + DEPENDS ${_zip_archive} + COMMENT "Checking resource dependencies for ${US_RESOURCE_TARGET}" + VERBATIM + ) + + add_custom_command( + TARGET ${US_RESOURCE_TARGET} + POST_BUILD + COMMAND objcopy --add-section .note.sgx.aesm_resource=${_zip_archive} $ + WORKING_DIRECTORY ${US_RESOURCE_WORKING_DIRECTORY} + COMMENT "Appending zipped resources to ${US_RESOURCE_TARGET}" + VERBATIM + ) + endif() + +endfunction() diff --git a/external/CppMicroServices/cmake/usFunctionGenerateBundleInit.cmake b/external/CppMicroServices/cmake/usFunctionGenerateBundleInit.cmake new file mode 100644 index 00000000..d7229a41 --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionGenerateBundleInit.cmake @@ -0,0 +1,42 @@ +#.rst: +# +# .. cmake:command:: usFunctionGenerateBundleInit +# +# Generate a source file which handles proper initialization of a bundle. +# +# .. code-block:: cmake +# +# usFunctionGenerateBundleInit(TARGET target OUT ) +# +# This CMake function will append the path to a generated source file to the +# out_var variable, which should be compiled into a bundle. The bundles source +# code must be compiled with the ``US_BUNDLE_NAME`` pre-processor definition. +# +# .. code-block:: cmake +# :caption: Example +# +# set(bundle_srcs ) +# usFunctionGenerateBundleInit(TARGET mylib OUT bundle_srcs) +# add_library(mylib ${bundle_srcs}) +# set_property(TARGET ${mylib} APPEND PROPERTY COMPILE_DEFINITIONS US_BUNDLE_NAME=MyBundle) +# +# **One-value keywords** +# * ``TARGET`` (required): The name of the target for which the source file +# is generated. +# * ``OUT`` (required): A list variable to which the path of the generated +# source file will be appended. +# +function(usFunctionGenerateBundleInit) + cmake_parse_arguments(_gen "" "TARGET;OUT" "" "" ${ARGN}) + if(NOT _gen_TARGET) + message(SEND_ERROR "TARGET must not be empty") + endif() + if(NOT _gen_OUT) + message(SEND_ERROR "OUT argument must not be empty") + endif() + + set(_out "${CMAKE_CURRENT_BINARY_DIR}/${_gen_TARGET}/cppmicroservices_init.cpp") + configure_file(${US_BUNDLE_INIT_TEMPLATE} ${_out} @ONLY) + + set(${_gen_OUT} ${${_gen_OUT}} ${_out} PARENT_SCOPE) +endfunction() diff --git a/external/CppMicroServices/cmake/usFunctionGetResourceSource.cmake b/external/CppMicroServices/cmake/usFunctionGetResourceSource.cmake new file mode 100644 index 00000000..2a536eca --- /dev/null +++ b/external/CppMicroServices/cmake/usFunctionGetResourceSource.cmake @@ -0,0 +1,59 @@ +#.rst: +# +# .. cmake:command:: usFunctionGetResourceSource +# +# Get a source file name for handling resource dependencies +# +# .. code-block:: cmake +# +# usFunctionGetResourceSource(TARGET target OUT [LINK | APPEND]) +# +# This CMake function retrieves the name of a generated file which has to be added +# to a bundles source file list to set-up resource file dependencies. This ensures +# that changed resource files will automatically be re-added to the bundle. +# +# .. code-block:: cmake +# :caption: Example +# +# set(bundle_srcs mylib.cpp) +# usFunctionGetResourceSource(TARGET mylib +# OUT bundle_srcs +# ) +# add_library(mylib ${bundle_srcs}) +# +# **One-value keywords** +# * ``TARGET`` (required): The name of the target to which the resource files are added. +# * ``OUT`` (required): A list variable to which the file name will be appended. +# +# **Options** +# * ``LINK`` (optional): Generate a suitable source file for *LINK* mode. +# * ``APPEND`` (optional): Generate a suitable source file for *APPEND* mode. +# +# .. seealso:: +# +# | :cmake:command:`usFunctionAddResources` +# | :cmake:command:`usFunctionEmbedResources` +# +function(usFunctionGetResourceSource) + cmake_parse_arguments(_res "LINK;APPEND" "TARGET;OUT" "" "" ${ARGN}) + if(NOT _res_TARGET) + message(SEND_ERROR "TARGET must not be empty") + endif() + if(NOT _res_OUT) + message(SEND_ERROR "OUT argument must not be empty") + endif() + if(_res_LINK AND _res_APPEND) + message(SEND_ERROR "Both LINK and APPEND options given.") + endif() + + set(_out "${CMAKE_CURRENT_BINARY_DIR}/${_res_TARGET}/cppmicroservices_resources") + if(_res_LINK) + set(_out "${_out}${US_RESOURCE_SOURCE_SUFFIX_LINK}") + elseif(_res_APPEND) + set(_out "${_out}${US_RESOURCE_SOURCE_SUFFIX_APPEND}") + else() + set(_out "${_out}${US_RESOURCE_SOURCE_SUFFIX}") + endif() + + set(${_res_OUT} ${${_res_OUT}} ${_out} PARENT_SCOPE) +endfunction() diff --git a/external/CppMicroServices/cmake/usMacroCreateBundle.cmake b/external/CppMicroServices/cmake/usMacroCreateBundle.cmake new file mode 100644 index 00000000..c5ba81d2 --- /dev/null +++ b/external/CppMicroServices/cmake/usMacroCreateBundle.cmake @@ -0,0 +1,242 @@ +# For internal use only + +macro(usMacroCreateBundle _project_name) + +project(${_project_name}) + +cmake_parse_arguments(${PROJECT_NAME} + "SKIP_EXAMPLES;SKIP_INIT" + "VERSION;TARGET;SYMBOLIC_NAME" + "DEPENDS;PRIVATE_INCLUDE_DIRS;LINK_LIBRARIES;SOURCES;PRIVATE_HEADERS;PUBLIC_HEADERS;RESOURCES;BINARY_RESOURCES" + ${ARGN} +) + +if(NOT ${PROJECT_NAME}_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+$") + message(SEND_ERROR "VERSION argument invalid: ${${PROJECT_NAME}_VERSION}") +endif() + +string(REPLACE "." ";" _version_numbers ${${PROJECT_NAME}_VERSION}) +list(GET _version_numbers 0 ${PROJECT_NAME}_VERSION_MAJOR) +list(GET _version_numbers 1 ${PROJECT_NAME}_VERSION_MINOR) +list(GET _version_numbers 2 ${PROJECT_NAME}_VERSION_PATCH) + +# Set the logical target name +if(NOT ${PROJECT_NAME}_TARGET) + set(${PROJECT_NAME}_TARGET us${PROJECT_NAME}) +endif() +set(PROJECT_TARGET ${${PROJECT_NAME}_TARGET}) + +# Set the target output name +set(PROJECT_OUTPUT_NAME ${PROJECT_TARGET}) +if(WIN32 AND NOT CYGWIN) + set(PROJECT_OUTPUT_NAME "${PROJECT_OUTPUT_NAME}${${PROJECT_NAME}_VERSION_MAJOR}") +endif() + +if(NOT ${PROJECT_NAME}_SYMBOLIC_NAME) + set(${PROJECT_NAME}_SYMBOLIC_NAME ${${PROJECT_NAME}_TARGET}) +endif() + +if(${PROJECT_NAME}_DEPENDS) + find_package(CppMicroServices REQUIRED ${${PROJECT_NAME}_DEPENDS} QUIET + HINTS ${CppMicroServices_BINARY_DIR} + NO_DEFAULT_PATH + ) +endif() + +#----------------------------------------------------------------------------- +# Configure files +#----------------------------------------------------------------------------- + +set(${PROJECT_NAME}_INCLUDE_SUBDIR "cppmicroservices") +if(NOT ${PROJECT_NAME} STREQUAL "Framework") + string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) + set(${PROJECT_NAME}_INCLUDE_SUBDIR "${${PROJECT_NAME}_INCLUDE_SUBDIR}/${PROJECT_NAME_LOWER}") +endif() + +configure_file(${CppMicroServices_SOURCE_DIR}/cmake/Export.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/${${PROJECT_NAME}_INCLUDE_SUBDIR}/${PROJECT_NAME}Export.h) +list(APPEND ${PROJECT_NAME}_PUBLIC_HEADERS + ${CMAKE_CURRENT_BINARY_DIR}/include/${${PROJECT_NAME}_INCLUDE_SUBDIR}/${PROJECT_NAME}Export.h) + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}Config.h.in) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}Config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/${${PROJECT_NAME}_INCLUDE_SUBDIR}/${PROJECT_NAME}Config.h) + list(APPEND ${PROJECT_NAME}_PUBLIC_HEADERS + ${CMAKE_CURRENT_BINARY_DIR}/include/${${PROJECT_NAME}_INCLUDE_SUBDIR}/${PROJECT_NAME}Config.h) +endif() + +#----------------------------------------------------------------------------- +# Create library +#----------------------------------------------------------------------------- + +# Generate the bundle init file +if(NOT ${PROJECT_NAME}_SKIP_INIT) + usFunctionGenerateBundleInit(TARGET ${${PROJECT_NAME}_TARGET} OUT ${PROJECT_NAME}_SOURCES) +endif() + +if(${PROJECT_NAME}_RESOURCES OR ${PROJECT_NAME}_BINARY_RESOURCES) + usFunctionGetResourceSource(TARGET ${${PROJECT_NAME}_TARGET} OUT ${PROJECT_NAME}_SOURCES) +endif() + +list(APPEND ${PROJECT_NAME}_SOURCES $) + +# Create the bundle library +add_library(${PROJECT_TARGET} ${${PROJECT_NAME}_SOURCES} + ${${PROJECT_NAME}_PRIVATE_HEADERS} ${${PROJECT_NAME}_PUBLIC_HEADERS}) +set_property(TARGET ${PROJECT_TARGET} PROPERTY OUTPUT_NAME ${PROJECT_OUTPUT_NAME}) + +target_link_libraries(${PROJECT_TARGET} PUBLIC ${US_LIBRARIES}) + +target_compile_features(${PROJECT_TARGET} + PUBLIC cxx_variadic_templates cxx_nullptr + ) + +# Include directories +target_include_directories(${PROJECT_TARGET} + PUBLIC + $ + $ + $ + $ + PRIVATE + ${${PROJECT_NAME}_PRIVATE_INCLUDE_DIRS} + $ + ) + +# Compile definitions +target_compile_definitions(${PROJECT_TARGET} + PRIVATE US_BUNDLE_NAME=${${PROJECT_NAME}_SYMBOLIC_NAME} + ) + +# Convenience properties +set_property(TARGET ${PROJECT_TARGET} PROPERTY US_BUNDLE_NAME ${${PROJECT_NAME}_SYMBOLIC_NAME}) + +# Link flags +if(${PROJECT_NAME}_LINK_FLAGS OR US_LINK_FLAGS) + set_target_properties(${${PROJECT_NAME}_TARGET} PROPERTIES + LINK_FLAGS "${US_LINK_FLAGS} ${${PROJECT_NAME}_LINK_FLAGS}" + ) +endif() + +set_target_properties(${${PROJECT_NAME}_TARGET} PROPERTIES + SOVERSION ${${PROJECT_NAME}_VERSION} +) + +# Link additional libraries +if(${PROJECT_NAME}_LINK_LIBRARIES) + target_link_libraries(${${PROJECT_NAME}_TARGET} ${${PROJECT_NAME}_LINK_LIBRARIES}) +endif() + +# Embed bundle resources + +if(${PROJECT_NAME}_RESOURCES) + set(_wd ${CMAKE_CURRENT_SOURCE_DIR}) + if(${PROJECT_NAME}_RESOURCES) + set(_wd ${CMAKE_CURRENT_SOURCE_DIR}/resources) + endif() + usFunctionAddResources(TARGET ${${PROJECT_NAME}_TARGET} + WORKING_DIRECTORY ${_wd} + FILES ${${PROJECT_NAME}_RESOURCES} + ) +endif() +if(${PROJECT_NAME}_BINARY_RESOURCES) + usFunctionAddResources(TARGET ${${PROJECT_NAME}_TARGET} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/resources + FILES ${${PROJECT_NAME}_BINARY_RESOURCES} + ) +endif() +usFunctionEmbedResources(TARGET ${${PROJECT_NAME}_TARGET}) + +#----------------------------------------------------------------------------- +# Install support +#----------------------------------------------------------------------------- + +if(NOT US_NO_INSTALL) + install(TARGETS ${${PROJECT_NAME}_TARGET} + EXPORT us${PROJECT_NAME}Targets + RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} + LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} + ARCHIVE DESTINATION ${ARCHIVE_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT}) + + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/cppmicroservices DESTINATION ${HEADER_INSTALL_DIR}) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/cppmicroservices DESTINATION ${HEADER_INSTALL_DIR}) +endif() + +#----------------------------------------------------------------------------- +# US testing +#----------------------------------------------------------------------------- + +if(US_BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + add_subdirectory(test) +endif() + +#----------------------------------------------------------------------------- +# Documentation +#----------------------------------------------------------------------------- + +if(US_BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doc/snippets/CMakeLists.txt") + # Compile source code snippets + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/doc/snippets) +endif() + +#----------------------------------------------------------------------------- +# Last configuration and install steps +#----------------------------------------------------------------------------- + +# Version information +configure_file( + ${US_CMAKE_DIR}/usBundleConfigVersion.cmake.in + ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}ConfigVersion.cmake + @ONLY + ) + +export(TARGETS ${${PROJECT_NAME}_TARGET} ${US_LIBRARIES} + FILE ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}Targets.cmake) +if(NOT US_NO_INSTALL) + install(EXPORT us${PROJECT_NAME}Targets + FILE us${PROJECT_NAME}Targets.cmake + DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) +endif() + +# Configure config file for the build tree + +set(PACKAGE_CONFIG_RUNTIME_LIBRARY_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + +configure_file( + ${US_CMAKE_DIR}/usBundleConfig.cmake.in + ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}Config.cmake + @ONLY + ) + +# Configure config file for the install tree + +if(NOT US_NO_INSTALL) + set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) + set(CONFIG_RUNTIME_LIBRARY_DIR ${RUNTIME_INSTALL_DIR}) + + configure_package_config_file( + ${US_CMAKE_DIR}/usBundleConfig.cmake.in + ${CppMicroServices_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/us${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} + PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_LIBRARY_DIR + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO + ) + + install(FILES ${CppMicroServices_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/us${PROJECT_NAME}Config.cmake + ${CppMicroServices_BINARY_DIR}/us${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} + ${US_SDK_INSTALL_COMPONENT}) +endif() + +#----------------------------------------------------------------------------- +# Build the examples +#----------------------------------------------------------------------------- + +if(US_BUILD_EXAMPLES AND NOT ${PROJECT_NAME}_SKIP_EXAMPLES AND + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt) + set(CppMicroServices_DIR ${CppMicroServices_BINARY_DIR}) + add_subdirectory(examples) +endif() + +endmacro() diff --git a/external/CppMicroServices/codecov.yml b/external/CppMicroServices/codecov.yml new file mode 100644 index 00000000..633a0e4b --- /dev/null +++ b/external/CppMicroServices/codecov.yml @@ -0,0 +1,15 @@ +comment: + layout: "reach, diff, flags, files" + behavior: default + require_changes: true # if true: only post the comment if coverage changes + require_base: no # [yes :: must have a base report to post] + require_head: yes # [yes :: must have a head report to post] + branches: null + +coverage: + ignore: + - "third_party/.*" # ignore folder and all its contents + - "**/test/.*" # ignore test code + + fixes: + - "projects/cppmicroservices::" diff --git a/external/CppMicroServices/conf.py b/external/CppMicroServices/conf.py new file mode 100644 index 00000000..fb95ba6a --- /dev/null +++ b/external/CppMicroServices/conf.py @@ -0,0 +1,413 @@ +# -*- coding: utf-8 -*- +# +# CppMicroServices documentation build configuration file, created by +# sphinx-quickstart on Mon Nov 28 18:59:28 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import subprocess, os, sys, tempfile + +sys.path.insert(0, os.path.abspath('./doc')) + +# on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + + +def generate_doxygen_xml(app): + """Run the doxygen command to generate XML info""" + + try: + # Read in the file + filedata = None + with open('doc/doxygen-breathe.conf', 'r') as file : + filedata = file.read() + + cwd = os.getcwd() + + # Replace the target string + filedata = filedata.replace('@SOURCE_DIR@', cwd) + + # Write the file out again + file = tempfile.NamedTemporaryFile(mode='w', delete=False) + file.write(filedata) + + retcode = subprocess.call("doxygen %s" % file.name, shell=True) + if retcode < 0: + sys.stderr.write("doxygen terminated by signal %s" % (-retcode)) + except OSError as e: + sys.stderr.write("doxygen execution failed: %s" % e) + + +def setup(app): + + # Add hook for building doxygen xml when needed + app.connect("builder-inited", generate_doxygen_xml) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['breathe', 'cmake'] + +breathe_projects = { "us": "doc/_api/xml/" } + +breathe_default_project = "us" + +breathe_default_members = ('members', 'protected-members', 'undoc-members') + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['doc/_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'C++ Micro Services' +copyright = u'2017, CppMicroServices Contributors' +author = u'CppMicroServices Team' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +# version = u'3.0' +with open('VERSION') as f: + version = f.readline().strip() + +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [ + 'doc/_build', + 'Thumbs.db', + '.DS_Store', + 'CODE_OF_CONDUCT.rst', + ] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +highlight_language = 'none' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + html_style = 'css/custom.css' +else: + html_context = { + 'css_files': [ + 'https://media.readthedocs.org/css/sphinx_rtd_theme.css', + 'https://media.readthedocs.org/css/readthedocs-doc-embed.css', + '_static/css/custom.css', + ], + } + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +#html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = u'CppMicroServices v3.0' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['doc/_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} +#html_sidebars = { '**': ['globaltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html'], } + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'CppMicroServicesdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'CppMicroServices.tex', u'CppMicroServices Documentation', + u'CppMicroServices Contributors', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, itleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('doc/man/cppmicroservices.7', 'cppmicroservices', u'CppMicroServices Documentation', [author], 7), + ('doc/man/cppmicroservices-httpservice.7', 'cppmicroservices-httpservice', u'Http Service', [author], 7), + ('doc/man/cppmicroservices-webconsole.7', 'cppmicroservices-webconsole', u'Web Console', [author], 7), + ('doc/man/cppmicroservices-shellservice.7', 'cppmicroservices-shellservice', u'Shell Service', [author], 7), + ('doc/man/cppmicroservices.3', 'cppmicroservices', u'CppMicroServices', [author], 3), + ('doc/man/cppmicroservices-framework.3', 'cppmicroservices-framework', u'CppMicroServices Framework API', [author], 3), + ('doc/man/cppmicroservices-httpservice.3', 'cppmicroservices-httpservice', u'CppMicroServices Http Service API', [author], 3), + ('doc/man/cppmicroservices-webconsole.3', 'cppmicroservices-webconsole', u'CppMicroServices Web Console API', [author], 3), + ('doc/man/cppmicroservices-shellservice.3', 'cppmicroservices-shellservice', u'CppMicroServices Shell Service API', [author], 3), + ('doc/man/usResourceCompiler3.1', 'usResourceCompiler3', u'CppMicroServices Resource Compiler', [author], 1), + ('doc/man/usShell3.1', 'usShell3', u'CppMicroServices Shell', [author], 1), +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'CppMicroServices', u'CppMicroServices Documentation', + author, 'CppMicroServices', 'An OSGi-like C++ dynamic module system and service registry.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False diff --git a/external/CppMicroServices/doc/CMakeLists.txt b/external/CppMicroServices/doc/CMakeLists.txt new file mode 100644 index 00000000..844e74ec --- /dev/null +++ b/external/CppMicroServices/doc/CMakeLists.txt @@ -0,0 +1,89 @@ +#----------------------------------------------------------------------------- +# Build the tutorial and example code +#----------------------------------------------------------------------------- + +if(US_BUILD_EXAMPLES AND NOT ${PROJECT_NAME}_SKIP_EXAMPLES AND + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt) + set(CppMicroServices_DIR ${CppMicroServices_BINARY_DIR}) + add_subdirectory(src) +endif() + +#----------------------------------------------------------------------------- +# Build the documentation itself +#----------------------------------------------------------------------------- + +us_cache_var(US_BUILD_DOC_MAN OFF BOOL "Build man pages") +us_cache_var(US_BUILD_DOC_HTML OFF BOOL "Build html documentation") + +find_package(Doxygen) + +find_program(SPHINX_EXECUTABLE + NAMES sphinx-build + DOC "Sphinx Documentation Builder (sphinx-doc.org)" + ) +us_cache_var(SPHINX_FLAGS "" STRING "Flags to pass to sphinx-build" ADVANCED) +separate_arguments(sphinx_flags UNIX_COMMAND "${SPHINX_FLAGS}") + +if(NOT US_BUILD_DOC_MAN AND NOT US_BUILD_DOC_HTML) + return() +elseif(NOT SPHINX_EXECUTABLE) + message(FATAL_ERROR "SPHINX_EXECUTABLE (sphinx-build) is not found!") +elseif(NOT Doxygen_FOUND) + message(FATAL_ERROR "Doxygen is not found!") +endif() + +set(doc_formats "") +if(US_BUILD_DOC_HTML) + list(APPEND doc_formats html) +endif() +if(US_BUILD_DOC_MAN) + list(APPEND doc_formats man) +endif() + +set(doc_format_outputs "") +set(doc_format_last "") +foreach(format ${doc_formats}) + set(doc_format_output "doc_format_${format}") + set(doc_format_log "build-${format}.log") + add_custom_command( + OUTPUT ${doc_format_output} + COMMAND ${SPHINX_EXECUTABLE} + -c ${CppMicroServices_SOURCE_DIR} + -d ${CppMicroServices_BINARY_DIR}/doctrees + -b ${format} + ${sphinx_flags} + ${CppMicroServices_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/${format} + > ${doc_format_log} # log stdout, pass stderr + DEPENDS ${doc_format_last} + WORKING_DIRECTORY ${CppMicroServices_SOURCE_DIR} + COMMENT "sphinx-build ${format}: see doc/${doc_format_log}" + VERBATIM + ) + set_property(SOURCE ${doc_format_output} PROPERTY SYMBOLIC 1) + list(APPEND doc_format_outputs ${doc_format_output}) + set(doc_format_last ${doc_format_output}) +endforeach() + +add_custom_target(doc ALL DEPENDS ${doc_format_outputs}) + +if(US_BUILD_DOC_MAN AND NOT US_NO_INSTALL) + file(GLOB man_rst RELATIVE ${CppMicroServices_SOURCE_DIR}/doc/man + ${CppMicroServices_SOURCE_DIR}/doc/man/*.[1-9].rst) + foreach(m ${man_rst}) + if("x${m}" MATCHES "^x(.+)\\.([1-9])\\.rst$") + set(name "${CMAKE_MATCH_1}") + set(sec "${CMAKE_MATCH_2}") + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/${name}.${sec} + DESTINATION ${MAN_INSTALL_DIR}/man${sec} + COMPONENT doc) + endif() + endforeach() +endif() + +if(US_BUILD_DOC_HTML AND NOT US_NO_INSTALL) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html + DESTINATION ${DOC_INSTALL_DIR} + COMPONENT doc + ) +endif() diff --git a/external/CppMicroServices/doc/Makefile b/external/CppMicroServices/doc/Makefile new file mode 100644 index 00000000..5eea0706 --- /dev/null +++ b/external/CppMicroServices/doc/Makefile @@ -0,0 +1,225 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = doc/_build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + cd .. && rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + cd .. && $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + cd.. && $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + cd .. && $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + cd .. && $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + cd .. && $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + cd .. && $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + cd .. && $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/CppMicroServices.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/CppMicroServices.qhc" + +.PHONY: applehelp +applehelp: + cd .. && $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + cd .. && $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/CppMicroServices" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/CppMicroServices" + @echo "# devhelp" + +.PHONY: epub +epub: + cd .. && $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + cd .. && $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + cd .. && $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + cd .. && $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + cd .. && $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + cd .. && $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + cd .. && $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + cd .. && $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + cd .. && $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + cd .. && $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + cd .. && $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + cd .. && $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + cd .. && $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + cd .. && $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + cd .. && $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + cd .. && $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + cd .. && $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/external/CppMicroServices/doc/_static/css/custom.css b/external/CppMicroServices/doc/_static/css/custom.css new file mode 100644 index 00000000..00f66b93 --- /dev/null +++ b/external/CppMicroServices/doc/_static/css/custom.css @@ -0,0 +1,48 @@ +@import url("theme.css"); + +.wy-nav-side { + width: 400px !important; +} + +.wy-side-scroll { + width: 420px !important; +} + +.wy-side-nav-search { + width: 400px !important; + background-color: #607d8b; +} + +.wy-menu-vertical { + width: 400px !important; +} + +.wy-nav-content-wrap { + margin-left: 400px !important; +} + +.wy-nav-content { + max-width: 860px !important; +} + +.kbd { + -moz-border-radius:3px; + -moz-box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; + -webkit-border-radius:3px; + -webkit-box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; + background-color:#f7f7f7; + border:1px solid #ccc; + border-radius:3px; + box-shadow:0 1px 0 rgba(0,0,0,0.2),0 0 0 2px #fff inset; + color:#333; + font-family:Arial,Helvetica,sans-serif; + font-size:11px; + line-height:1.4; + margin:0 .1em; + padding:.1em .6em; + text-shadow:0 1px 0 #fff; +} + +img.screenshot { + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 3px 10px 0 rgba(0, 0, 0, 0.19); +} \ No newline at end of file diff --git a/external/CppMicroServices/doc/_templates/layout.html b/external/CppMicroServices/doc/_templates/layout.html new file mode 100644 index 00000000..447758b1 --- /dev/null +++ b/external/CppMicroServices/doc/_templates/layout.html @@ -0,0 +1,27 @@ +{% extends "!layout.html" %} + + {% block menu %} + {{ super() }} + Index + {% endblock %} + + {% block extrahead %} + + + + + + + {% endblock %} \ No newline at end of file diff --git a/external/CppMicroServices/doc/cmake.py b/external/CppMicroServices/doc/cmake.py new file mode 100644 index 00000000..398cdbae --- /dev/null +++ b/external/CppMicroServices/doc/cmake.py @@ -0,0 +1,378 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +import os +import re + +# Monkey patch for pygments reporting an error when generator expressions are +# used. +# https://bitbucket.org/birkenfeld/pygments-main/issue/942/cmake-generator-expressions-not-handled +from pygments.lexers import CMakeLexer +from pygments.token import Name, Operator +from pygments.lexer import bygroups +CMakeLexer.tokens["args"].append(('(\\$<)(.+?)(>)', + bygroups(Operator, Name.Variable, Operator))) + +# Monkey patch for sphinx generating invalid content for qcollectiongenerator +# https://bitbucket.org/birkenfeld/sphinx/issue/1435/qthelp-builder-should-htmlescape-keywords +from sphinx.util.pycompat import htmlescape +from sphinx.builders.qthelp import QtHelpBuilder +old_build_keywords = QtHelpBuilder.build_keywords +def new_build_keywords(self, title, refs, subitems): + old_items = old_build_keywords(self, title, refs, subitems) + new_items = [] + for item in old_items: + before, rest = item.split("ref=\"", 1) + ref, after = rest.split("\"") + if ("<" in ref and ">" in ref): + new_items.append(before + "ref=\"" + htmlescape(ref) + "\"" + after) + else: + new_items.append(item) + return new_items +QtHelpBuilder.build_keywords = new_build_keywords + + +from docutils.parsers.rst import Directive, directives +from docutils.transforms import Transform +try: + from docutils.utils.error_reporting import SafeString, ErrorString +except ImportError: + # error_reporting was not in utils before version 0.11: + from docutils.error_reporting import SafeString, ErrorString + +from docutils import io, nodes + +from sphinx.directives import ObjectDescription +from sphinx.domains import Domain, ObjType +from sphinx.roles import XRefRole +from sphinx.util.nodes import make_refnode +from sphinx import addnodes + +class CMakeModule(Directive): + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = True + option_spec = {'encoding': directives.encoding} + + def __init__(self, *args, **keys): + self.re_start = re.compile(r'^#\[(?P=*)\[\.rst:$') + Directive.__init__(self, *args, **keys) + + def run(self): + settings = self.state.document.settings + if not settings.file_insertion_enabled: + raise self.warning('"%s" directive disabled.' % self.name) + + env = self.state.document.settings.env + rel_path, path = env.relfn2path(self.arguments[0]) + path = os.path.normpath(path) + encoding = self.options.get('encoding', settings.input_encoding) + e_handler = settings.input_encoding_error_handler + try: + settings.record_dependencies.add(path) + f = io.FileInput(source_path=path, encoding=encoding, + error_handler=e_handler) + except UnicodeEncodeError as error: + raise self.severe('Problems with "%s" directive path:\n' + 'Cannot encode input file path "%s" ' + '(wrong locale?).' % + (self.name, SafeString(path))) + except IOError as error: + raise self.severe('Problems with "%s" directive path:\n%s.' % + (self.name, ErrorString(error))) + raw_lines = f.read().splitlines() + f.close() + rst = None + lines = [] + for line in raw_lines: + if rst is not None and rst != '#': + # Bracket mode: check for end bracket + pos = line.find(rst) + if pos >= 0: + if line[0] == '#': + line = '' + else: + line = line[0:pos] + rst = None + else: + # Line mode: check for .rst start (bracket or line) + m = self.re_start.match(line) + if m: + rst = ']%s]' % m.group('eq') + line = '' + elif line == '#.rst:': + rst = '#' + line = '' + elif rst == '#': + if line == '#' or line[:2] == '# ': + line = line[2:] + else: + rst = None + line = '' + elif rst is None: + line = '' + lines.append(line) + if rst is not None and rst != '#': + raise self.warning('"%s" found unclosed bracket "#[%s[.rst:" in %s' % + (self.name, rst[1:-1], path)) + self.state_machine.insert_input(lines, path) + return [] + +class _cmake_index_entry: + def __init__(self, desc): + self.desc = desc + + def __call__(self, title, targetid, main = 'main'): + return ('pair', u'%s ; %s' % (self.desc, title), targetid, main, None) + +_cmake_index_objs = { + 'command': _cmake_index_entry('command'), + 'generator': _cmake_index_entry('generator'), + 'manual': _cmake_index_entry('manual'), + 'module': _cmake_index_entry('module'), + 'policy': _cmake_index_entry('policy'), + 'prop_cache': _cmake_index_entry('cache property'), + 'prop_dir': _cmake_index_entry('directory property'), + 'prop_gbl': _cmake_index_entry('global property'), + 'prop_inst': _cmake_index_entry('installed file property'), + 'prop_sf': _cmake_index_entry('source file property'), + 'prop_test': _cmake_index_entry('test property'), + 'prop_tgt': _cmake_index_entry('target property'), + 'variable': _cmake_index_entry('variable'), + } + +def _cmake_object_inventory(env, document, line, objtype, targetid): + inv = env.domaindata['cmake']['objects'] + if targetid in inv: + document.reporter.warning( + 'CMake object "%s" also described in "%s".' % + (targetid, env.doc2path(inv[targetid][0])), line=line) + inv[targetid] = (env.docname, objtype) + +class CMakeTransform(Transform): + + # Run this transform early since we insert nodes we want + # treated as if they were written in the documents. + default_priority = 210 + + def __init__(self, document, startnode): + Transform.__init__(self, document, startnode) + self.titles = {} + + def parse_title(self, docname): + """Parse a document title as the first line starting in [A-Za-z0-9<] + or fall back to the document basename if no such line exists. + The cmake --help-*-list commands also depend on this convention. + Return the title or False if the document file does not exist. + """ + env = self.document.settings.env + title = self.titles.get(docname) + if title is None: + fname = os.path.join(env.srcdir, docname+'.rst') + try: + f = open(fname, 'r') + except IOError: + title = False + else: + for line in f: + if len(line) > 0 and (line[0].isalnum() or line[0] == '<'): + title = line.rstrip() + break + f.close() + if title is None: + title = os.path.basename(docname) + self.titles[docname] = title + return title + + def apply(self): + env = self.document.settings.env + + # Treat some documents as cmake domain objects. + objtype, sep, tail = env.docname.rpartition('/') + make_index_entry = _cmake_index_objs.get(objtype) + if make_index_entry: + title = self.parse_title(env.docname) + # Insert the object link target. + targetname = title + targetid = '%s:%s' % (objtype, targetname) + targetnode = nodes.target('', '', ids=[targetid]) + self.document.note_explicit_target(targetnode) + self.document.insert(0, targetnode) + # Insert the object index entry. + indexnode = addnodes.index() + indexnode['entries'] = [make_index_entry(title, targetid)] + self.document.insert(0, indexnode) + # Add to cmake domain object inventory + _cmake_object_inventory(env, self.document, 1, objtype, targetid) + +class CMakeObject(ObjectDescription): + + def handle_signature(self, sig, signode): + # called from sphinx.directives.ObjectDescription.run() + signode += addnodes.desc_name(sig, sig) + return sig + + def add_target_and_index(self, name, sig, signode): + targetname = name + targetid = '%s:%s' % (self.objtype, targetname) + if targetid not in self.state.document.ids: + signode['names'].append(targetid) + signode['ids'].append(targetid) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + _cmake_object_inventory(self.env, self.state.document, + self.lineno, self.objtype, targetid) + + make_index_entry = _cmake_index_objs.get(self.objtype) + if make_index_entry: + self.indexnode['entries'].append(make_index_entry(name, targetid)) + +class CMakeXRefRole(XRefRole): + + # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'. + _re = re.compile(r'^(.+?)(\s*)(?$', re.DOTALL) + _re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL) + + def __call__(self, typ, rawtext, text, *args, **keys): + # Translate CMake command cross-references of the form: + # `command_name(SUB_COMMAND)` + # to have an explicit target: + # `command_name(SUB_COMMAND) ` + if typ == 'cmake:command': + m = CMakeXRefRole._re_sub.match(text) + if m: + text = '%s <%s>' % (text, m.group(1)) + # CMake cross-reference targets frequently contain '<' so escape + # any explicit `` with '<' not preceded by whitespace. + while True: + m = CMakeXRefRole._re.match(text) + if m and len(m.group(2)) == 0: + text = '%s\x00<%s>' % (m.group(1), m.group(3)) + else: + break + return XRefRole.__call__(self, typ, rawtext, text, *args, **keys) + + # We cannot insert index nodes using the result_nodes method + # because CMakeXRefRole is processed before substitution_reference + # nodes are evaluated so target nodes (with 'ids' fields) would be + # duplicated in each evaluted substitution replacement. The + # docutils substitution transform does not allow this. Instead we + # use our own CMakeXRefTransform below to add index entries after + # substitutions are completed. + # + # def result_nodes(self, document, env, node, is_ref): + # pass + +class CMakeXRefTransform(Transform): + + # Run this transform early since we insert nodes we want + # treated as if they were written in the documents, but + # after the sphinx (210) and docutils (220) substitutions. + default_priority = 221 + + def apply(self): + env = self.document.settings.env + + # Find CMake cross-reference nodes and add index and target + # nodes for them. + for ref in self.document.traverse(addnodes.pending_xref): + if not ref['refdomain'] == 'cmake': + continue + + objtype = ref['reftype'] + make_index_entry = _cmake_index_objs.get(objtype) + if not make_index_entry: + continue + + objname = ref['reftarget'] + targetnum = env.new_serialno('index-%s:%s' % (objtype, objname)) + + targetid = 'index-%s-%s:%s' % (targetnum, objtype, objname) + targetnode = nodes.target('', '', ids=[targetid]) + self.document.note_explicit_target(targetnode) + + indexnode = addnodes.index() + indexnode['entries'] = [make_index_entry(objname, targetid, '')] + ref.replace_self([indexnode, targetnode, ref]) + +class CMakeDomain(Domain): + """CMake domain.""" + name = 'cmake' + label = 'CMake' + object_types = { + 'command': ObjType('command', 'command'), + 'generator': ObjType('generator', 'generator'), + 'variable': ObjType('variable', 'variable'), + 'module': ObjType('module', 'module'), + 'policy': ObjType('policy', 'policy'), + 'prop_cache': ObjType('prop_cache', 'prop_cache'), + 'prop_dir': ObjType('prop_dir', 'prop_dir'), + 'prop_gbl': ObjType('prop_gbl', 'prop_gbl'), + 'prop_inst': ObjType('prop_inst', 'prop_inst'), + 'prop_sf': ObjType('prop_sf', 'prop_sf'), + 'prop_test': ObjType('prop_test', 'prop_test'), + 'prop_tgt': ObjType('prop_tgt', 'prop_tgt'), + 'manual': ObjType('manual', 'manual'), + } + directives = { + 'command': CMakeObject, + 'variable': CMakeObject, + # Other object types cannot be created except by the CMakeTransform + # 'generator': CMakeObject, + # 'module': CMakeObject, + # 'policy': CMakeObject, + # 'prop_cache': CMakeObject, + # 'prop_dir': CMakeObject, + # 'prop_gbl': CMakeObject, + # 'prop_inst': CMakeObject, + # 'prop_sf': CMakeObject, + # 'prop_test': CMakeObject, + # 'prop_tgt': CMakeObject, + # 'manual': CMakeObject, + } + roles = { + 'command': CMakeXRefRole(fix_parens = True, lowercase = False), + 'generator': CMakeXRefRole(), + 'variable': CMakeXRefRole(), + 'module': CMakeXRefRole(), + 'policy': CMakeXRefRole(), + 'prop_cache': CMakeXRefRole(), + 'prop_dir': CMakeXRefRole(), + 'prop_gbl': CMakeXRefRole(), + 'prop_inst': CMakeXRefRole(), + 'prop_sf': CMakeXRefRole(), + 'prop_test': CMakeXRefRole(), + 'prop_tgt': CMakeXRefRole(), + 'manual': CMakeXRefRole(), + } + initial_data = { + 'objects': {}, # fullname -> docname, objtype + } + + def clear_doc(self, docname): + to_clear = set() + for fullname, (fn, _) in self.data['objects'].items(): + if fn == docname: + to_clear.add(fullname) + for fullname in to_clear: + del self.data['objects'][fullname] + + def resolve_xref(self, env, fromdocname, builder, + typ, target, node, contnode): + targetid = '%s:%s' % (typ, target) + obj = self.data['objects'].get(targetid) + if obj is None: + # TODO: warn somehow? + return None + return make_refnode(builder, fromdocname, obj[0], targetid, + contnode, target) + + def get_objects(self): + for refname, (docname, type) in self.data['objects'].items(): + yield (refname, refname, type, docname, refname, 1) + +def setup(app): + app.add_directive('cmake-module', CMakeModule) + app.add_transform(CMakeTransform) + app.add_transform(CMakeXRefTransform) + app.add_domain(CMakeDomain) diff --git a/external/CppMicroServices/doc/doxygen-breathe.conf b/external/CppMicroServices/doc/doxygen-breathe.conf new file mode 100644 index 00000000..c21d92c5 --- /dev/null +++ b/external/CppMicroServices/doc/doxygen-breathe.conf @@ -0,0 +1,2385 @@ +# Doxyfile 1.8.9.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "C++ Micro Services" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "A dynamic OSGi-like C++ service registry" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc/_api + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = "@SOURCE_DIR@/framework/include" \ + "@SOURCE_DIR@/httpservice/include" \ + "@SOURCE_DIR@/webconsole/include" \ + "@SOURCE_DIR@/shellservice/include" + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = "rst=\verbatim embed:rst" \ + "endrst=\endverbatim" \ + "rststar=\verbatim embed:rst:leading-asterisk" \ + "endrststar=\endverbatim" + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = YES + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = YES + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 0 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = "framework/include" \ + "httpservice/include" \ + "webconsole/include" \ + "shellservice/include" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = *Private* \ + ServiceObjectsBase* \ + TrackedService* \ + detail \ + testing + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = framework/doc/snippets/ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 3 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: NO. + +GENERATE_HTML = NO + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 300 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , / + /doc/src/legal + +.. toctree:: + :caption: Best Practices + :name: best_practices + + /doc/src/tutorial/index + /doc/src/best_practices/emulate_singleton + +.. toctree:: + :caption: Bundles & Tools + :name: bundles_tools + + /doc/man/cppmicroservices.7 + /doc/man/cppmicroservices-httpservice.7 + /doc/man/cppmicroservices-webconsole.7 + /doc/man/cppmicroservices-shellservice.7 + /doc/man/usResourceCompiler3.1 + /doc/man/usShell3.1 + +.. toctree:: + :caption: API Reference + :name: api_ref + + /doc/man/cppmicroservices.3 + /doc/man/cppmicroservices-framework.3 + /doc/man/cppmicroservices-httpservice.3 + /doc/man/cppmicroservices-webconsole.3 + /doc/man/cppmicroservices-shellservice.3 + +.. toctree:: + :caption: Appendix + :hidden: + + CHANGELOG + diff --git a/external/CppMicroServices/install_cmake.sh b/external/CppMicroServices/install_cmake.sh new file mode 100755 index 00000000..546f50e4 --- /dev/null +++ b/external/CppMicroServices/install_cmake.sh @@ -0,0 +1,22 @@ +#!/bin/sh +set -e +if [ ! -d "$HOME/cache" ]; then + mkdir $HOME/cache; +fi + +CTEST_EXEC="$HOME/cache/bin/ctest" + +# check to see if CMake is cached +if [[ ! -f "$CTEST_EXEC" || ! "$($CTEST_EXEC --version)" =~ "3.2.3" ]]; then + wget --no-check-certificate https://cmake.org/files/v3.2/cmake-3.2.3.tar.gz -O /tmp/cmake.tar.gz; + tar -xzvf /tmp/cmake.tar.gz -C /tmp; + cd /tmp/cmake-3.2.3; + ./configure --prefix=$HOME/cache; + make -j2; + make install; +else + echo "Using cached bin dir: $HOME/cache/bin"; + ls -la $HOME/cache/bin; + echo "Using cached CMake installation:"; + cmake -version; +fi diff --git a/external/CppMicroServices/opencppcoverage_mergereports.bat b/external/CppMicroServices/opencppcoverage_mergereports.bat new file mode 100644 index 00000000..5d537f6d --- /dev/null +++ b/external/CppMicroServices/opencppcoverage_mergereports.bat @@ -0,0 +1,16 @@ +@echo off +rem This script uses OpenCppCoverage tool to merge all the .cov files in the current directory into one file. +rem The final merged file is a Cobertura compatible XML file + +setlocal enabledelayedexpansion +set myvar=OpenCppCoverage.exe --verbose --export_type=cobertura:coverage.xml +for /r %%i in (*.cov) do ( + call :concat %%~nxi +) +@echo on +%myvar% +goto :eof + +:concat +set myvar=%myvar% --input_coverage %1 +goto :eof diff --git a/external/CppMicroServices/revision_info.txt b/external/CppMicroServices/revision_info.txt new file mode 100644 index 00000000..1a1bc06f --- /dev/null +++ b/external/CppMicroServices/revision_info.txt @@ -0,0 +1,10 @@ +commit 29348046dd8b680051de55c4eddee4222e2fae02 (HEAD -> development, origin/development, origin/HEAD) +Author: Charles Wilcox <44209640+mw-cwilcox@users.noreply.github.com> +Date: Wed Oct 24 09:08:10 2018 -0400 + + 307 bundle crc32 (#308) + + * Adding 'uint32_t 'BundleResource::GetCrc32() const;'. + + Signed-off-by: Charles Wilcox + diff --git a/external/CppMicroServices/third_party/README b/external/CppMicroServices/third_party/README new file mode 100644 index 00000000..e3957b08 --- /dev/null +++ b/external/CppMicroServices/third_party/README @@ -0,0 +1,140 @@ +README +====== + +This directory contains several third-party libraries. + +For detailed copyright and license information see the header of the respective +file. A record of their origin and version is provided in the list below. + +If a third-party library has been modified for the purposes of the +CppMicroServices library, it is marked as such. + +dirent_win32 +------------ + +See file for license information. + +http://softagalleria.net/dirent.php +1.20.1 + +Patches + + * Set errno to ENAMETOOLONG if opendir() is called with a path argument + longer than MAX_PATH. + +jsoncpp +------- + +MIT License or Public Domain + +https://github.com/open-source-parsers/jsoncpp +(formerly http://jsoncpp.sourceforge.net) +0.10.6 + +Patches + + * Suppress -Wimplicit-fallthrough warning in GCC 7 + +miniz +----- + +Public Domain + +https://code.google.com/p/miniz/ +v1.15 r4 + +Patches + + * Support for zip files with prepended binary blobs. + * Write to C file streams. + +libtelnet +--------- + +Public Domain + +https://github.com/seanmiddleditch/libtelnet +574eef9fd7f373fb2812939456fc5a4c3e975b44 + +tinyscheme +---------- + +BSD-style license + +http://tinyscheme.sourceforge.net/home.html +1.41 + +Patches + + * Added header for missing off_t declaration. + * Disable Windows warnings C4244 and C4267. + * Do not use dllexport/dllimport specs on Windows + +Linenoise +--------- + +BSD license + +https://github.com/msteveb/linenoise +0f2343d2bc763b735b6242b5831be611703965a1 + +This is a fork of the original antirez/linenoise project +which contains Windows support and a few additional features. + +Patches + + * Don't depend on utf8.h because it is not supported + on Windows. + * Disable Windows warnings C4244 and C4267. + * Do not define snprintf for MSC_VER 1900 or higher + +The Lean Mean C++ Option Parser +------------------------------- + +MIT License + +http://sourceforge.net/projects/optionparser +1.7 + +Patches + + * Added virtual destructors + * Converted old-style casts to C++ casts + +Civetweb +-------- + +MIT License + +https://github.com/civetweb/civetweb +1.8 + +Patches + + * Use system function clock_gettime on Mac OS X 10.12 and above + +Mustache +-------- + +See webconsole/include/cppmicroservices/webconsole/mustache.hpp for license information. + +https://github.com/kainjow/Mustache/releases +2.0 + +Patches + + * Support GCC 4.6 + + +Google Test and Google Mock +---------------------------- + +See https://github.com/google/googletest/blob/master/googletest/LICENSE for license information. + +https://github.com/google/googletest/releases +1.8.0 + +Patches + + * Suppress CMake warning about policy CMP0048 + * Suppress tr1 namespace deprecation warnings diff --git a/external/CppMicroServices/third_party/cppmicroservices_elf.h b/external/CppMicroServices/third_party/cppmicroservices_elf.h new file mode 100644 index 00000000..7a240366 --- /dev/null +++ b/external/CppMicroServices/third_party/cppmicroservices_elf.h @@ -0,0 +1,483 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + This file is a modified version of the elf.h header included + in the libc6-dev package. Unneeded definitions have been removed. + +=============================================================================*/ + +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef CPPMICROSERVICES_ELF_H +#define CPPMICROSERVICES_ELF_H 1 + +/* Standard ELF types. */ + +#include + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ +#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +#endif /* elf.h */ diff --git a/external/CppMicroServices/third_party/cppmicroservices_mach-o.h b/external/CppMicroServices/third_party/cppmicroservices_mach-o.h new file mode 100644 index 00000000..5b92c3a9 --- /dev/null +++ b/external/CppMicroServices/third_party/cppmicroservices_mach-o.h @@ -0,0 +1,710 @@ +/* + * Portions Copyright (c) 1999-2010 Apple Inc. All Rights Reserved. + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + */ +#ifndef CPPMICROSERVICES_MACHO_LOADER_H +#define CPPMICROSERVICES_MACHO_LOADER_H + +/* + * This file describes the format of mach object files. + */ +#include + +typedef int32_t cpu_type_t; +typedef int32_t cpu_subtype_t; +typedef int32_t vm_prot_t; + +/* + * Capability bits used in the definition of cpu_type. + */ +#define CPU_ARCH_MASK 0xff000000 /* mask for architecture bits */ +#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */ + +/* + * Machine types known by all. + */ + +#define CPU_TYPE_ANY (-1) + +#define CPU_TYPE_VAX (1) +/* skip (2) */ +/* skip (3) */ +/* skip (4) */ +/* skip (5) */ +#define CPU_TYPE_MC680x0 (6) +#define CPU_TYPE_X86 (7) +#define CPU_TYPE_I386 CPU_TYPE_X86 /* compatibility */ +#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) + +/* skip CPU_TYPE_MIPS (8) */ +/* skip (9) */ +#define CPU_TYPE_MC98000 (10) +#define CPU_TYPE_HPPA (11) +#define CPU_TYPE_ARM (12) +#define CPU_TYPE_MC88000 (13) +#define CPU_TYPE_SPARC (14) +#define CPU_TYPE_I860 (15) +/* skip CPU_TYPE_ALPHA (16) */ +/* skip (17) */ +#define CPU_TYPE_POWERPC (18) +#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) + +#ifndef _MACH_O_FAT_H_ +#define _MACH_O_FAT_H_ +/* + * This header file describes the structures of the file format for "fat" + * architecture specific file (wrapper design). At the begining of the file + * there is one fat_header structure followed by a number of fat_arch + * structures. For each architecture in the file, specified by a pair of + * cputype and cpusubtype, the fat_header describes the file offset, file + * size and alignment in the file of the architecture specific member. + * The padded bytes in the file to place each member on it's specific alignment + * are defined to be read as zeros and can be left as "holes" if the file system + * can support them as long as they read as zeros. + * + * All structures defined here are always written and read to/from disk + * in big-endian order. + */ + +#define FAT_MAGIC 0xcafebabe +#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */ + +struct fat_header { + uint32_t magic; /* FAT_MAGIC */ + uint32_t nfat_arch; /* number of structs that follow */ +}; + +struct fat_arch { + cpu_type_t cputype; /* cpu specifier (int) */ + cpu_subtype_t cpusubtype; /* machine specifier (int) */ + uint32_t offset; /* file offset to this object file */ + uint32_t size; /* size of this object file */ + uint32_t align; /* alignment as a power of 2 */ +}; + +#endif /* _MACH_O_FAT_H_ */ + +/* + * The 32-bit mach header appears at the very beginning of the object file for + * 32-bit architectures. + */ +struct mach_header { + uint32_t magic; /* mach magic number identifier */ + cpu_type_t cputype; /* cpu specifier */ + cpu_subtype_t cpusubtype; /* machine specifier */ + uint32_t filetype; /* type of file */ + uint32_t ncmds; /* number of load commands */ + uint32_t sizeofcmds; /* the size of all the load commands */ + uint32_t flags; /* flags */ +}; + +/* Constant for the magic field of the mach_header (32-bit architectures) */ +#define MH_MAGIC 0xfeedface /* the mach magic number */ +#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ + +/* + * The 64-bit mach header appears at the very beginning of object files for + * 64-bit architectures. + */ +struct mach_header_64 { + uint32_t magic; /* mach magic number identifier */ + cpu_type_t cputype; /* cpu specifier */ + cpu_subtype_t cpusubtype; /* machine specifier */ + uint32_t filetype; /* type of file */ + uint32_t ncmds; /* number of load commands */ + uint32_t sizeofcmds; /* the size of all the load commands */ + uint32_t flags; /* flags */ + uint32_t reserved; /* reserved */ +}; + +/* Constant for the magic field of the mach_header_64 (64-bit architectures) */ +#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */ +#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */ + +/* + * The layout of the file depends on the filetype. For all but the MH_OBJECT + * file type the segments are padded out and aligned on a segment alignment + * boundary for efficient demand pageing. The MH_EXECUTE, MH_FVMLIB, MH_DYLIB, + * MH_DYLINKER and MH_BUNDLE file types also have the headers included as part + * of their first segment. + * + * The file type MH_OBJECT is a compact format intended as output of the + * assembler and input (and possibly output) of the link editor (the .o + * format). All sections are in one unnamed segment with no segment padding. + * This format is used as an executable format when the file is so small the + * segment padding greatly increases its size. + * + * The file type MH_PRELOAD is an executable format intended for things that + * are not executed under the kernel (proms, stand alones, kernels, etc). The + * format can be executed under the kernel but may demand paged it and not + * preload it before execution. + * + * A core file is in MH_CORE format and can be any in an arbritray legal + * Mach-O file. + * + * Constants for the filetype field of the mach_header + */ +#define MH_OBJECT 0x1 /* relocatable object file */ +#define MH_EXECUTE 0x2 /* demand paged executable file */ +#define MH_FVMLIB 0x3 /* fixed VM shared library file */ +#define MH_CORE 0x4 /* core file */ +#define MH_PRELOAD 0x5 /* preloaded executable file */ +#define MH_DYLIB 0x6 /* dynamically bound shared library */ +#define MH_DYLINKER 0x7 /* dynamic link editor */ +#define MH_BUNDLE 0x8 /* dynamically bound bundle file */ +#define MH_DYLIB_STUB 0x9 /* shared library stub for static */ + /* linking only, no section contents */ +#define MH_DSYM 0xa /* companion file with only debug */ + /* sections */ +#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */ + +/* Constants for the flags field of the mach_header */ +#define MH_NOUNDEFS 0x1 /* the object file has no undefined + references */ +#define MH_INCRLINK 0x2 /* the object file is the output of an + incremental link against a base file + and can't be link edited again */ +#define MH_DYLDLINK 0x4 /* the object file is input for the + dynamic linker and can't be staticly + link edited again */ +#define MH_BINDATLOAD 0x8 /* the object file's undefined + references are bound by the dynamic + linker when loaded. */ +#define MH_PREBOUND 0x10 /* the file has its dynamic undefined + references prebound. */ +#define MH_SPLIT_SEGS 0x20 /* the file has its read-only and + read-write segments split */ +#define MH_LAZY_INIT 0x40 /* the shared library init routine is + to be run lazily via catching memory + faults to its writeable segments + (obsolete) */ +#define MH_TWOLEVEL 0x80 /* the image is using two-level name + space bindings */ +#define MH_FORCE_FLAT 0x100 /* the executable is forcing all images + to use flat name space bindings */ +#define MH_NOMULTIDEFS 0x200 /* this umbrella guarantees no multiple + defintions of symbols in its + sub-images so the two-level namespace + hints can always be used. */ +#define MH_NOFIXPREBINDING 0x400 /* do not have dyld notify the + prebinding agent about this + executable */ +#define MH_PREBINDABLE 0x800 /* the binary is not prebound but can + have its prebinding redone. only used + when MH_PREBOUND is not set. */ +#define MH_ALLMODSBOUND 0x1000 /* indicates that this binary binds to + all two-level namespace modules of + its dependent libraries. only used + when MH_PREBINDABLE and MH_TWOLEVEL + are both set. */ +#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000/* safe to divide up the sections into + sub-sections via symbols for dead + code stripping */ +#define MH_CANONICAL 0x4000 /* the binary has been canonicalized + via the unprebind operation */ +#define MH_WEAK_DEFINES 0x8000 /* the final linked image contains + external weak symbols */ +#define MH_BINDS_TO_WEAK 0x10000 /* the final linked image uses + weak symbols */ + +#define MH_ALLOW_STACK_EXECUTION 0x20000/* When this bit is set, all stacks + in the task will be given stack + execution privilege. Only used in + MH_EXECUTE filetypes. */ +#define MH_ROOT_SAFE 0x40000 /* When this bit is set, the binary + declares it is safe for use in + processes with uid zero */ + +#define MH_SETUID_SAFE 0x80000 /* When this bit is set, the binary + declares it is safe for use in + processes when issetugid() is true */ + +#define MH_NO_REEXPORTED_DYLIBS 0x100000 /* When this bit is set on a dylib, + the static linker does not need to + examine dependent dylibs to see + if any are re-exported */ +#define MH_PIE 0x200000 /* When this bit is set, the OS will + load the main executable at a + random address. Only used in + MH_EXECUTE filetypes. */ +#define MH_DEAD_STRIPPABLE_DYLIB 0x400000 /* Only for use on dylibs. When + linking against a dylib that + has this bit set, the static linker + will automatically not create a + LC_LOAD_DYLIB load command to the + dylib if no symbols are being + referenced from the dylib. */ +#define MH_HAS_TLV_DESCRIPTORS 0x800000 /* Contains a section of type + S_THREAD_LOCAL_VARIABLES */ + +#define MH_NO_HEAP_EXECUTION 0x1000000 /* When this bit is set, the OS will + run the main executable with + a non-executable heap even on + platforms (e.g. i386) that don't + require it. Only used in MH_EXECUTE + filetypes. */ + +/* + * The load commands directly follow the mach_header. The total size of all + * of the commands is given by the sizeofcmds field in the mach_header. All + * load commands must have as their first two fields cmd and cmdsize. The cmd + * field is filled in with a constant for that command type. Each command type + * has a structure specifically for it. The cmdsize field is the size in bytes + * of the particular load command structure plus anything that follows it that + * is a part of the load command (i.e. section structures, strings, etc.). To + * advance to the next load command the cmdsize can be added to the offset or + * pointer of the current load command. The cmdsize for 32-bit architectures + * MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple + * of 8 bytes (these are forever the maximum alignment of any load commands). + * The padded bytes must be zero. All tables in the object file must also + * follow these rules so the file can be memory mapped. Otherwise the pointers + * to these tables will not work well or at all on some machines. With all + * padding zeroed like objects will compare byte for byte. + */ +struct load_command { + uint32_t cmd; /* type of load command */ + uint32_t cmdsize; /* total size of command in bytes */ +}; + +/* + * After MacOS X 10.1 when a new load command is added that is required to be + * understood by the dynamic linker for the image to execute properly the + * LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic + * linker sees such a load command it it does not understand will issue a + * "unknown load command required for execution" error and refuse to use the + * image. Other load commands without this bit that are not understood will + * simply be ignored. + */ +#define LC_REQ_DYLD 0x80000000 + +/* Constants for the cmd field of all load commands, the type */ +#define LC_SEGMENT 0x1 /* segment of this file to be mapped */ +#define LC_SYMTAB 0x2 /* link-edit stab symbol table info */ +#define LC_SYMSEG 0x3 /* link-edit gdb symbol table info (obsolete) */ +#define LC_THREAD 0x4 /* thread */ +#define LC_UNIXTHREAD 0x5 /* unix thread (includes a stack) */ +#define LC_LOADFVMLIB 0x6 /* load a specified fixed VM shared library */ +#define LC_IDFVMLIB 0x7 /* fixed VM shared library identification */ +#define LC_IDENT 0x8 /* object identification info (obsolete) */ +#define LC_FVMFILE 0x9 /* fixed VM file inclusion (internal use) */ +#define LC_PREPAGE 0xa /* prepage command (internal use) */ +#define LC_DYSYMTAB 0xb /* dynamic link-edit symbol table info */ +#define LC_LOAD_DYLIB 0xc /* load a dynamically linked shared library */ +#define LC_ID_DYLIB 0xd /* dynamically linked shared lib ident */ +#define LC_LOAD_DYLINKER 0xe /* load a dynamic linker */ +#define LC_ID_DYLINKER 0xf /* dynamic linker identification */ +#define LC_PREBOUND_DYLIB 0x10 /* modules prebound for a dynamically */ + /* linked shared library */ +#define LC_ROUTINES 0x11 /* image routines */ +#define LC_SUB_FRAMEWORK 0x12 /* sub framework */ +#define LC_SUB_UMBRELLA 0x13 /* sub umbrella */ +#define LC_SUB_CLIENT 0x14 /* sub client */ +#define LC_SUB_LIBRARY 0x15 /* sub library */ +#define LC_TWOLEVEL_HINTS 0x16 /* two-level namespace lookup hints */ +#define LC_PREBIND_CKSUM 0x17 /* prebind checksum */ + +/* + * load a dynamically linked shared library that is allowed to be missing + * (all symbols are weak imported). + */ +#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) + +#define LC_SEGMENT_64 0x19 /* 64-bit segment of this file to be + mapped */ +#define LC_ROUTINES_64 0x1a /* 64-bit image routines */ +#define LC_UUID 0x1b /* the uuid */ +#define LC_RPATH (0x1c | LC_REQ_DYLD) /* runpath additions */ +#define LC_CODE_SIGNATURE 0x1d /* local of code signature */ +#define LC_SEGMENT_SPLIT_INFO 0x1e /* local of info to split segments */ +#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */ +#define LC_LAZY_LOAD_DYLIB 0x20 /* delay load of dylib until first use */ +#define LC_ENCRYPTION_INFO 0x21 /* encrypted segment information */ +#define LC_DYLD_INFO 0x22 /* compressed dyld information */ +#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) /* compressed dyld information only */ +#define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */ +#define LC_VERSION_MIN_MACOSX 0x24 /* build for MacOSX min OS version */ +#define LC_VERSION_MIN_IPHONEOS 0x25 /* build for iPhoneOS min OS version */ +#define LC_FUNCTION_STARTS 0x26 /* compressed table of function start addresses */ +#define LC_DYLD_ENVIRONMENT 0x27 /* string for dyld to treat + like environment variable */ + +/* + * A variable length string in a load command is represented by an lc_str + * union. The strings are stored just after the load command structure and + * the offset is from the start of the load command structure. The size + * of the string is reflected in the cmdsize field of the load command. + * Once again any padded bytes to bring the cmdsize field to a multiple + * of 4 bytes must be zero. + */ +union lc_str { + uint32_t offset; /* offset to the string */ +#ifndef __LP64__ + char *ptr; /* pointer to the string */ +#endif +}; + +/* + * Dynamicly linked shared libraries are identified by two things. The + * pathname (the name of the library as found for execution), and the + * compatibility version number. The pathname must match and the compatibility + * number in the user of the library must be greater than or equal to the + * library being used. The time stamp is used to record the time a library was + * built and copied into user so it can be use to determined if the library used + * at runtime is exactly the same as used to built the program. + */ +struct dylib { + union lc_str name; /* library's path name */ + uint32_t timestamp; /* library's build time stamp */ + uint32_t current_version; /* library's current version number */ + uint32_t compatibility_version; /* library's compatibility vers number*/ +}; + +/* + * A dynamically linked shared library (filetype == MH_DYLIB in the mach header) + * contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library. + * An object that uses a dynamically linked shared library also contains a + * dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or + * LC_REEXPORT_DYLIB) for each library it uses. + */ +struct dylib_command { + uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, + LC_REEXPORT_DYLIB */ + uint32_t cmdsize; /* includes pathname string */ + struct dylib dylib; /* the library identification */ +}; + +/* + * The symtab_command contains the offsets and sizes of the link-edit 4.3BSD + * "stab" style symbol table information as described in the header files + * and . + */ +struct symtab_command { + uint32_t cmd; /* LC_SYMTAB */ + uint32_t cmdsize; /* sizeof(struct symtab_command) */ + uint32_t symoff; /* symbol table offset */ + uint32_t nsyms; /* number of symbol table entries */ + uint32_t stroff; /* string table offset */ + uint32_t strsize; /* string table size in bytes */ +}; + +/* + * This is the second set of the symbolic information which is used to support + * the data structures for the dynamically link editor. + * + * The original set of symbolic information in the symtab_command which contains + * the symbol and string tables must also be present when this load command is + * present. When this load command is present the symbol table is organized + * into three groups of symbols: + * local symbols (static and debugging symbols) - grouped by module + * defined external symbols - grouped by module (sorted by name if not lib) + * undefined external symbols (sorted by name if MH_BINDATLOAD is not set, + * and in order the were seen by the static + * linker if MH_BINDATLOAD is set) + * In this load command there are offsets and counts to each of the three groups + * of symbols. + * + * This load command contains a the offsets and sizes of the following new + * symbolic information tables: + * table of contents + * module table + * reference symbol table + * indirect symbol table + * The first three tables above (the table of contents, module table and + * reference symbol table) are only present if the file is a dynamically linked + * shared library. For executable and object modules, which are files + * containing only one module, the information that would be in these three + * tables is determined as follows: + * table of contents - the defined external symbols are sorted by name + * module table - the file contains only one module so everything in the + * file is part of the module. + * reference symbol table - is the defined and undefined external symbols + * + * For dynamically linked shared library files this load command also contains + * offsets and sizes to the pool of relocation entries for all sections + * separated into two groups: + * external relocation entries + * local relocation entries + * For executable and object modules the relocation entries continue to hang + * off the section structures. + */ +struct dysymtab_command { + uint32_t cmd; /* LC_DYSYMTAB */ + uint32_t cmdsize; /* sizeof(struct dysymtab_command) */ + + /* + * The symbols indicated by symoff and nsyms of the LC_SYMTAB load command + * are grouped into the following three groups: + * local symbols (further grouped by the module they are from) + * defined external symbols (further grouped by the module they are from) + * undefined symbols + * + * The local symbols are used only for debugging. The dynamic binding + * process may have to use them to indicate to the debugger the local + * symbols for a module that is being bound. + * + * The last two groups are used by the dynamic binding process to do the + * binding (indirectly through the module table and the reference symbol + * table when this is a dynamically linked shared library file). + */ + uint32_t ilocalsym; /* index to local symbols */ + uint32_t nlocalsym; /* number of local symbols */ + + uint32_t iextdefsym;/* index to externally defined symbols */ + uint32_t nextdefsym;/* number of externally defined symbols */ + + uint32_t iundefsym; /* index to undefined symbols */ + uint32_t nundefsym; /* number of undefined symbols */ + + /* + * For the for the dynamic binding process to find which module a symbol + * is defined in the table of contents is used (analogous to the ranlib + * structure in an archive) which maps defined external symbols to modules + * they are defined in. This exists only in a dynamically linked shared + * library file. For executable and object modules the defined external + * symbols are sorted by name and is use as the table of contents. + */ + uint32_t tocoff; /* file offset to table of contents */ + uint32_t ntoc; /* number of entries in table of contents */ + + /* + * To support dynamic binding of "modules" (whole object files) the symbol + * table must reflect the modules that the file was created from. This is + * done by having a module table that has indexes and counts into the merged + * tables for each module. The module structure that these two entries + * refer to is described below. This exists only in a dynamically linked + * shared library file. For executable and object modules the file only + * contains one module so everything in the file belongs to the module. + */ + uint32_t modtaboff; /* file offset to module table */ + uint32_t nmodtab; /* number of module table entries */ + + /* + * To support dynamic module binding the module structure for each module + * indicates the external references (defined and undefined) each module + * makes. For each module there is an offset and a count into the + * reference symbol table for the symbols that the module references. + * This exists only in a dynamically linked shared library file. For + * executable and object modules the defined external symbols and the + * undefined external symbols indicates the external references. + */ + uint32_t extrefsymoff; /* offset to referenced symbol table */ + uint32_t nextrefsyms; /* number of referenced symbol table entries */ + + /* + * The sections that contain "symbol pointers" and "routine stubs" have + * indexes and (implied counts based on the size of the section and fixed + * size of the entry) into the "indirect symbol" table for each pointer + * and stub. For every section of these two types the index into the + * indirect symbol table is stored in the section header in the field + * reserved1. An indirect symbol table entry is simply a 32bit index into + * the symbol table to the symbol that the pointer or stub is referring to. + * The indirect symbol table is ordered to match the entries in the section. + */ + uint32_t indirectsymoff; /* file offset to the indirect symbol table */ + uint32_t nindirectsyms; /* number of indirect symbol table entries */ + + /* + * To support relocating an individual module in a library file quickly the + * external relocation entries for each module in the library need to be + * accessed efficiently. Since the relocation entries can't be accessed + * through the section headers for a library file they are separated into + * groups of local and external entries further grouped by module. In this + * case the presents of this load command who's extreloff, nextrel, + * locreloff and nlocrel fields are non-zero indicates that the relocation + * entries of non-merged sections are not referenced through the section + * structures (and the reloff and nreloc fields in the section headers are + * set to zero). + * + * Since the relocation entries are not accessed through the section headers + * this requires the r_address field to be something other than a section + * offset to identify the item to be relocated. In this case r_address is + * set to the offset from the vmaddr of the first LC_SEGMENT command. + * For MH_SPLIT_SEGS images r_address is set to the the offset from the + * vmaddr of the first read-write LC_SEGMENT command. + * + * The relocation entries are grouped by module and the module table + * entries have indexes and counts into them for the group of external + * relocation entries for that the module. + * + * For sections that are merged across modules there must not be any + * remaining external relocation entries for them (for merged sections + * remaining relocation entries must be local). + */ + uint32_t extreloff; /* offset to external relocation entries */ + uint32_t nextrel; /* number of external relocation entries */ + + /* + * All the local relocation entries are grouped together (they are not + * grouped by their module since they are only used if the object is moved + * from it staticly link edited address). + */ + uint32_t locreloff; /* offset to local relocation entries */ + uint32_t nlocrel; /* number of local relocation entries */ + +}; + +/* + * The rpath_command contains a path which at runtime should be added to + * the current run path used to find @rpath prefixed dylibs. + */ +struct rpath_command { + uint32_t cmd; /* LC_RPATH */ + uint32_t cmdsize; /* includes string */ + union lc_str path; /* path to add to run path */ +}; + + +#ifndef _MACHO_NLIST_H_ +#define _MACHO_NLIST_H_ +/* $NetBSD: nlist.h,v 1.5 1994/10/26 00:56:11 cgd Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)nlist.h 8.2 (Berkeley) 1/21/94 + */ + +/* + * Format of a symbol table entry of a Mach-O file for 32-bit architectures. + * Modified from the BSD format. The modifications from the original format + * were changing n_other (an unused field) to n_sect and the addition of the + * N_SECT type. These modifications are required to support symbols in a larger + * number of sections not just the three sections (text, data and bss) in a BSD + * file. + */ +struct nlist { + union { +#ifndef __LP64__ + char *n_name; /* for use when in-core */ +#endif + int32_t n_strx; /* index into the string table */ + } n_un; + uint8_t n_type; /* type flag, see below */ + uint8_t n_sect; /* section number or NO_SECT */ + int16_t n_desc; /* see */ + uint32_t n_value; /* value of this symbol (or stab offset) */ +}; + +/* + * This is the symbol table entry structure for 64-bit architectures. + */ +struct nlist_64 { + union { + uint32_t n_strx; /* index into the string table */ + } n_un; + uint8_t n_type; /* type flag, see below */ + uint8_t n_sect; /* section number or NO_SECT */ + uint16_t n_desc; /* see */ + uint64_t n_value; /* value of this symbol (or stab offset) */ +}; + +/* + * Symbols with a index into the string table of zero (n_un.n_strx == 0) are + * defined to have a null, "", name. Therefore all string indexes to non null + * names must not have a zero string index. This is bit historical information + * that has never been well documented. + */ + +/* + * The n_type field really contains four fields: + * unsigned char N_STAB:3, + * N_PEXT:1, + * N_TYPE:3, + * N_EXT:1; + * which are used via the following masks. + */ +#define N_STAB 0xe0 /* if any of these bits set, a symbolic debugging entry */ +#define N_PEXT 0x10 /* private external symbol bit */ +#define N_TYPE 0x0e /* mask for the type bits */ +#define N_EXT 0x01 /* external symbol bit, set for external symbols */ + +/* + * Only symbolic debugging entries have some of the N_STAB bits set and if any + * of these bits are set then it is a symbolic debugging entry (a stab). In + * which case then the values of the n_type field (the entire field) are given + * in + */ + +/* + * Values for N_TYPE bits of the n_type field. + */ +#define N_UNDF 0x0 /* undefined, n_sect == NO_SECT */ +#define N_ABS 0x2 /* absolute, n_sect == NO_SECT */ +#define N_SECT 0xe /* defined in section number n_sect */ +#define N_PBUD 0xc /* prebound undefined (defined in a dylib) */ +#define N_INDR 0xa /* indirect */ + +/* + * If the type is N_INDR then the symbol is defined to be the same as another + * symbol. In this case the n_value field is an index into the string table + * of the other symbol's name. When the other symbol is defined then they both + * take on the defined type and value. + */ + +/* + * If the type is N_SECT then the n_sect field contains an ordinal of the + * section the symbol is defined in. The sections are numbered from 1 and + * refer to sections in order they appear in the load commands for the file + * they are in. This means the same ordinal may very well refer to different + * sections in different files. + * + * The n_value field for all symbol table entries (including N_STAB's) gets + * updated by the link editor based on the value of it's n_sect field and where + * the section n_sect references gets relocated. If the value of the n_sect + * field is NO_SECT then it's n_value field is not changed by the link editor. + */ +#define NO_SECT 0 /* symbol is not in any section */ +#define MAX_SECT 255 /* 1 thru 255 inclusive */ + +#endif /* _MACHO_LIST_H_ */ + +#endif /* CPPMICROSERVICES_MACHO_LOADER_H */ diff --git a/external/CppMicroServices/third_party/cppmicroservices_pe.h b/external/CppMicroServices/third_party/cppmicroservices_pe.h new file mode 100644 index 00000000..6dd5b710 --- /dev/null +++ b/external/CppMicroServices/third_party/cppmicroservices_pe.h @@ -0,0 +1,239 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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. + +=============================================================================*/ + +// The contents of this file was created from Microsoft's publicly +// available PE/COFF format document: +// +// Microsoft Portable Executable and Common Object File Format Specification +// Revision 8.3 – February 6, 2013 +// +// http://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx + +#ifndef CPPMICROSERVICES_PE_H +#define CPPMICROSERVICES_PE_H + +#include + +#include "cppmicroservices/GlobalConfig.h" + +namespace cppmicroservices { + +static const uint32_t PE_SIGNATURE = 0x00004550; // { 'P', 'E', '\0', '\0' } +static const uint16_t DOS_SIGNATURE = 0x5A4D; // { 'M', 'Z' } + +static const uint16_t OPTIONAL_PE32_MAGIC = 0x10b; // PE32 format +static const uint16_t OPTIONAL_PE64_MAGIC = 0x20b; // PE32+ format + +enum { + NameSize = 8, + NumberOfDataDirectories = 16 +}; + +struct DOSHeader +{ + uint16_t Magic; + uint16_t Useduint8_tsInTheLastPage; + uint16_t FileSizeInPages; + uint16_t NumberOfRelocationItems; + uint16_t HeaderSizeInParagraphs; + uint16_t MinimumExtraParagraphs; + uint16_t MaximumExtraParagraphs; + uint16_t InitialRelativeSS; + uint16_t InitialSP; + uint16_t Checksum; + uint16_t InitialIP; + uint16_t InitialRelativeCS; + uint16_t AddressOfRelocationTable; + uint16_t OverlayNumber; + uint16_t Reserved[4]; + uint16_t OEMid; + uint16_t OEMinfo; + uint16_t Reserved2[10]; + uint32_t AddressOfNewExeHeader; +}; + +struct COFFHeader +{ + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; +}; + +enum Characteristics { + IMAGE_FILE_RELOCS_STRIPPED = 0x0001, + IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002, + IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004, + IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008, + IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010, + IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020, + IMAGE_FILE_uint8_tS_REVERSED_LO = 0x0080, + IMAGE_FILE_32BIT_MACHINE = 0x0100, + IMAGE_FILE_DEBUG_STRIPPED = 0x0200, + IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400, + IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800, + IMAGE_FILE_SYSTEM = 0x1000, + IMAGE_FILE_DLL = 0x2000, + IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000, + IMAGE_FILE_uint8_tS_REVERSED_HI = 0x8000 +}; + +struct DataDirectory +{ + uint32_t VirtualAddress; + uint32_t Size; +}; + +struct OptionalHeader32 +{ + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; + uint32_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Win32VersionValue; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t Dllcharacteristics; + uint32_t SizeOfStackReserve; + uint32_t SizeOfStackCommit; + uint32_t SizeOfHeapReserve; + uint32_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + DataDirectory DataDirectories[NumberOfDataDirectories]; +}; + +struct OptionalHeader64 +{ + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint64_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Win32VersionValue; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t Dllcharacteristics; + uint64_t SizeOfStackReserve; + uint64_t SizeOfStackCommit; + uint64_t SizeOfHeapReserve; + uint64_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + DataDirectory DataDirectories[NumberOfDataDirectories]; +}; + +// Directory entry types + +enum { + IMAGE_DIRECTORY_ENTRY_EXPORT = 0, + IMAGE_DIRECTORY_ENTRY_IMPORT = 1 +}; + +struct PEHeader32 +{ + uint32_t Signature; + COFFHeader CoffHeader; + OptionalHeader64 OptionalHeader; +}; + +struct PEHeader64 +{ + uint32_t Signature; + COFFHeader CoffHeader; + OptionalHeader32 OptionalHeader; +}; + +struct SectionHeader +{ + char Name[NameSize]; + uint32_t VirtualSize; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +}; + +struct ExportDirectory +{ + uint32_t ExportFlags; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Name; // RVA + uint32_t Base; + uint32_t NumberOfFuncions; + uint32_t NumberOfNames; + uint32_t AddressOfFunctions; // RVA from base of image + uint32_t AddressOfNames; // RVA from base of image + uint32_t AddressOfNameOrdinals; // RVA from base of image +}; + +struct IMAGE_IMPORT_DESCRIPTOR +{ + uint32_t AddressOfLookupTable; // RVA + uint32_t TimeDateStamp; + uint32_t ForwarderChain; + uint32_t Name; // RVA from base of image + uint32_t AddressOfImportAddressTable; +}; + +} + +#endif /* CPPMICROSERVICES_PE_H */ diff --git a/external/CppMicroServices/third_party/dirent_win32.h b/external/CppMicroServices/third_party/dirent_win32.h new file mode 100755 index 00000000..e459f904 --- /dev/null +++ b/external/CppMicroServices/third_party/dirent_win32.h @@ -0,0 +1,842 @@ +/* + * dirent.h - dirent API for Microsoft Visual Studio + * + * Copyright (C) 2006-2012 Toni Ronkko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * ``Software''), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $ + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* + * Define architecture flags so we don't need to include windows.h. + * Avoiding windows.h makes it simpler to use windows sockets in conjunction + * with dirent.h. + */ +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) +# define _X86_ +#endif +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64) +#define _AMD64_ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +# define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat() */ +#if !defined(S_IFMT) +# define S_IFMT _S_IFMT /* File type mask */ +#endif +#if !defined(S_IFDIR) +# define S_IFDIR _S_IFDIR /* Directory */ +#endif +#if !defined(S_IFCHR) +# define S_IFCHR _S_IFCHR /* Character device */ +#endif +#if !defined(S_IFFIFO) +# define S_IFFIFO _S_IFFIFO /* Pipe */ +#endif +#if !defined(S_IFREG) +# define S_IFREG _S_IFREG /* Regular file */ +#endif +#if !defined(S_IREAD) +# define S_IREAD _S_IREAD /* Read permission */ +#endif +#if !defined(S_IWRITE) +# define S_IWRITE _S_IWRITE /* Write permission */ +#endif +#if !defined(S_IEXEC) +# define S_IEXEC _S_IEXEC /* Execute permission */ +#endif +#if !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO /* Pipe */ +#endif +#if !defined(S_IFBLK) +# define S_IFBLK 0 /* Block device */ +#endif +#if !defined(S_IFLNK) +# define S_IFLNK 0 /* Link */ +#endif +#if !defined(S_IFSOCK) +# define S_IFSOCK 0 /* Socket */ +#endif + +#if defined(_MSC_VER) +# define S_IRUSR S_IREAD /* Read user */ +# define S_IWUSR S_IWRITE /* Write user */ +# define S_IXUSR 0 /* Execute user */ +# define S_IRGRP 0 /* Read group */ +# define S_IWGRP 0 /* Write group */ +# define S_IXGRP 0 /* Execute group */ +# define S_IROTH 0 /* Read others */ +# define S_IWOTH 0 /* Write others */ +# define S_IXOTH 0 /* Execute others */ +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +# define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +# define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +# define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode) & S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices, sockets and links cannot be + * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are + * only defined for compatibility. These macros should always return false + * on Windows. + */ +#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) + +/* Return the exact length of d_namlen without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return number of bytes needed to store d_namlen */ +#define _D_ALLOC_NAMLEN(p) (PATH_MAX) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Wide-character version */ +struct _wdirent { + long d_ino; /* Always zero */ + unsigned short d_reclen; /* Structure size */ + size_t d_namlen; /* Length of name without \0 */ + int d_type; /* File type */ + wchar_t d_name[PATH_MAX]; /* File name */ +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + struct _wdirent ent; /* Current directory entry */ + WIN32_FIND_DATAW data; /* Private file data */ + int cached; /* True if data is valid */ + HANDLE handle; /* Win32 search handle */ + wchar_t *patt; /* Initial directory name */ +}; +typedef struct _WDIR _WDIR; + +static _WDIR *_wopendir (const wchar_t *dirname); +static struct _wdirent *_wreaddir (_WDIR *dirp); +static int _wclosedir (_WDIR *dirp); +static void _wrewinddir (_WDIR* dirp); + + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir + + +/* Multi-byte character versions */ +struct dirent { + long d_ino; /* Always zero */ + unsigned short d_reclen; /* Structure size */ + size_t d_namlen; /* Length of name without \0 */ + int d_type; /* File type */ + char d_name[PATH_MAX]; /* File name */ +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + +static DIR *opendir (const char *dirname); +static struct dirent *readdir (DIR *dirp); +static int closedir (DIR *dirp); +static void rewinddir (DIR* dirp); + + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); + +static int dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count); + +static int dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, + const wchar_t *wcstr, + size_t count); + +static void dirent_set_errno (int error); + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR* +_wopendir( + const wchar_t *dirname) +{ + _WDIR *dirp = NULL; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); + if (dirp != NULL) { + DWORD n; + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + + /* Compute the length of full path plus zero terminator */ + n = GetFullPathNameW (dirname, 0, NULL, NULL); + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); + if (dirp->patt) { + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + */ + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); + if (n > 0) { + wchar_t *p; + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + if (dirp->patt < p) { + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (dirent_first (dirp)) { + /* Directory stream opened successfully */ + error = 0; + } else { + /* Cannot retrieve first entry */ + error = 1; + dirent_set_errno (ENOENT); + } + + } else { + /* Cannot retrieve full path name */ + dirent_set_errno (ENOENT); + error = 1; + } + + } else { + /* Cannot allocate memory for search pattern */ + error = 1; + } + + } else { + /* Cannot allocate _WDIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + _wclosedir (dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. The directory entry is returned in dirent + * structure in the d_name field. Individual directory entries returned by + * this function include regular files, sub-directories, pseudo-directories + * "." and ".." as well as volume labels, hidden files and system files. + */ +static struct _wdirent* +_wreaddir( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + struct _wdirent *entp; + + /* Read next directory entry */ + datap = dirent_next (dirp); + if (datap) { + size_t n; + DWORD attr; + + /* Pointer to directory entry to return */ + entp = &dirp->ent; + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + n = 0; + while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) { + entp->d_name[n] = datap->cFileName[n]; + n++; + } + dirp->ent.d_name[n] = 0; + + /* Length of file name excluding zero terminator */ + entp->d_namlen = n; + + /* File type */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entp->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entp->d_type = DT_DIR; + } else { + entp->d_type = DT_REG; + } + + /* Reset dummy fields */ + entp->d_ino = 0; + entp->d_reclen = sizeof (struct _wdirent); + + } else { + + /* Last directory entry read */ + entp = NULL; + + } + + return entp; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int +_wclosedir( + _WDIR *dirp) +{ + int ok; + if (dirp) { + + /* Release search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + } + + /* Release search pattern */ + if (dirp->patt) { + free (dirp->patt); + dirp->patt = NULL; + } + + /* Release directory structure */ + free (dirp); + ok = /*success*/0; + + } else { + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + } + return ok; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void +_wrewinddir( + _WDIR* dirp) +{ + if (dirp) { + /* Release existing search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + } + + /* Open new search handle */ + dirent_first (dirp); + } +} + +/* Get first directory entry (internal) */ +static WIN32_FIND_DATAW* +dirent_first( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); + if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* a directory entry is now waiting in memory */ + datap = &dirp->data; + dirp->cached = 1; + + } else { + + /* Failed to re-open directory: no directory entry in memory */ + dirp->cached = 0; + datap = NULL; + + } + return datap; +} + +/* Get next directory entry (internal) */ +static WIN32_FIND_DATAW* +dirent_next( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *p; + + /* Get next directory entry */ + if (dirp->cached != 0) { + + /* A valid directory entry already in memory */ + p = &dirp->data; + dirp->cached = 0; + + } else if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* Get the next directory entry from stream */ + if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { + /* Got a file */ + p = &dirp->data; + } else { + /* The very last entry has been processed or an error occured */ + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + p = NULL; + } + + } else { + + /* End of directory stream reached */ + p = NULL; + + } + + return p; +} + +/* + * Open directory stream using plain old C-string. + */ +static DIR* +opendir( + const char *dirname) +{ + struct DIR *dirp; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + if (strlen(dirname) > PATH_MAX) { + dirent_set_errno (ENAMETOOLONG); + return NULL; + } + + /* Allocate memory for DIR structure */ + dirp = (DIR*) malloc (sizeof (struct DIR)); + if (dirp) { + wchar_t wname[PATH_MAX + 1]; + size_t n; + + /* Convert directory name to wide-character string */ + error = dirent_mbstowcs_s (&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); + if (!error) { + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir (wname); + if (dirp->wdirp) { + /* Directory stream opened */ + error = 0; + } else { + /* Failed to open directory stream */ + error = 1; + } + + } else { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + error = 1; + } + + } else { + /* Cannot allocate DIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + free (dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. + * + * When working with text consoles, please note that file names returned by + * readdir() are represented in the default ANSI code page while any output to + * console is typically formatted on another code page. Thus, non-ASCII + * characters in file names will not usually display correctly on console. The + * problem can be fixed in two ways: (1) change the character set of console + * to 1252 using chcp utility and use Lucida Console font, or (2) use + * _cprintf function when writing to console. The _cprinf() will re-encode + * ANSI strings to the console code page so many non-ASCII characters will + * display correcly. + */ +static struct dirent* +readdir( + DIR *dirp) +{ + WIN32_FIND_DATAW *datap; + struct dirent *entp; + + /* Read next directory entry */ + datap = dirent_next (dirp->wdirp); + if (datap) { + size_t n; + int error; + + /* Attempt to convert file name to multi-byte string */ + error = dirent_wcstombs_s( + &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX); + + /* + * If the file name cannot be represented by a multi-byte string, + * then attempt to use old 8+3 file name. This allows traditional + * Unix-code to access some file names despite of unicode + * characters, although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file + * name unless the file system provides one. At least + * VirtualBox shared folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = dirent_wcstombs_s( + &n, dirp->ent.d_name, PATH_MAX, + datap->cAlternateFileName, PATH_MAX); + } + + if (!error) { + DWORD attr; + + /* Initialize directory entry for return */ + entp = &dirp->ent; + + /* Length of file name excluding zero terminator */ + entp->d_namlen = n - 1; + + /* File attributes */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entp->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entp->d_type = DT_DIR; + } else { + entp->d_type = DT_REG; + } + + /* Reset dummy fields */ + entp->d_ino = 0; + entp->d_reclen = sizeof (struct dirent); + + } else { + /* + * Cannot convert file name to multi-byte string so construct + * an errornous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entp = &dirp->ent; + entp->d_name[0] = '?'; + entp->d_name[1] = '\0'; + entp->d_namlen = 1; + entp->d_type = DT_UNKNOWN; + entp->d_ino = 0; + entp->d_reclen = 0; + } + + } else { + /* No more directory entries */ + entp = NULL; + } + + return entp; +} + +/* + * Close directory stream. + */ +static int +closedir( + DIR *dirp) +{ + int ok; + if (dirp) { + + /* Close wide-character directory stream */ + ok = _wclosedir (dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free (dirp); + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream to beginning. + */ +static void +rewinddir( + DIR* dirp) +{ + /* Rewind wide-character string directory stream */ + _wrewinddir (dirp->wdirp); +} + +/* Convert multi-byte string to wide character string */ +static int +dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to wide-character string (or count characters) */ + n = mbstowcs (wcstr, mbstr, sizeInWords); + if (!wcstr || n < count) { + + /* Zero-terminate output buffer */ + if (wcstr && sizeInWords) { + if (n >= sizeInWords) { + n = sizeInWords - 1; + } + wcstr[n] = 0; + } + + /* Length of resuting multi-byte string WITH zero terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Could not convert string */ + error = 1; + + } + +#endif + + return error; +} + +/* Convert wide-character string to multi-byte string */ +static int +dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, /* max size of mbstr */ + const wchar_t *wcstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to multi-byte string (or count the number of bytes needed) */ + n = wcstombs (mbstr, wcstr, sizeInBytes); + if (!mbstr || n < count) { + + /* Zero-terminate output buffer */ + if (mbstr && sizeInBytes) { + if (n >= sizeInBytes) { + n = sizeInBytes - 1; + } + mbstr[n] = '\0'; + } + + /* Lenght of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Cannot convert string */ + error = 1; + + } + +#endif + + return error; +} + +/* Set errno variable */ +static void +dirent_set_errno( + int error) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 and later */ + _set_errno (error); + +#else + + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; + +#endif +} + + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ diff --git a/external/CppMicroServices/third_party/json/json-forwards.h b/external/CppMicroServices/third_party/json/json-forwards.h new file mode 100644 index 00000000..ccbdb2b1 --- /dev/null +++ b/external/CppMicroServices/third_party/json/json-forwards.h @@ -0,0 +1,255 @@ +/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED +# define JSON_FORWARD_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__clang__) && defined(__has_feature) +#if __has_feature(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#endif +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff --git a/external/CppMicroServices/third_party/json/json.h b/external/CppMicroServices/third_party/json/json.h new file mode 100644 index 00000000..6859137e --- /dev/null +++ b/external/CppMicroServices/third_party/json/json.h @@ -0,0 +1,1981 @@ +/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGATED_H_INCLUDED +# define JSON_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "0.10.6" +# define JSONCPP_VERSION_MAJOR 0 +# define JSONCPP_VERSION_MINOR 10 +# define JSONCPP_VERSION_PATCH 6 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6 +// Microsoft Visual Studio 6 only support conversion from __int64 to double +// (no conversion from unsigned __int64). +#define JSON_USE_INT64_DOUBLE_CONVERSION 1 +// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' +// characters in the debug information) +// All projects I've ever seen with VS6 were using this globally (not bothering +// with pragma push/pop). +#pragma warning(disable : 4786) +#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6 + +#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__clang__) && defined(__has_feature) +#if __has_feature(attribute_deprecated_with_message) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#endif +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +#define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +#endif + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_; +}; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(std::string const& msg); + virtual ~Exception() throw(); + virtual char const* what() const throw(); +protected: + std::string const msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(std::string const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(std::string const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(std::string const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(std::string const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +#if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + static const Value& nullRef; +#if !defined(__ARMEL__) + /// \deprecated This exists for binary compatibility only. Use nullRef. + static const Value null; +#endif + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); + ~CZString(); + CZString& operator=(CZString other); + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. +This is useful since clear() and resize() will not alter types. + + Examples: +\code +Json::Value null_value; // null +Json::Value arr_value(Json::arrayValue); // [] +Json::Value obj_value(Json::objectValue); // {} +\endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value &operator=(const Value &other); + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! + std::string asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex size); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](int index); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](int index) const; + + /// If the array contains at least index+1 elements, returns the element + /// value, + /// otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const std::string& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const std::string& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const std::string& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + /// \deprecated + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + Value removeMember(const std::string& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(std::string const& key, Value* removed); + /// Same as removeMember(std::string const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const std::string& key) const; + /// Same as isMember(std::string const& key)const + bool isMember(const char* begin, const char* end) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const std::string& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + std::string getComment(CommentPlacement placement) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + +private: + void initBasic(ValueType type, bool allocated = false); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + char* comment_; + }; + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. + CommentInfo* comments_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const std::string& key); + +private: + enum Kind { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + ArrayIndex index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class JSON_API Path { +public: + Path(const std::string& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const std::string& path, const InArgs& in); + void addPathInArg(const std::string& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + void invalidPath(const std::string& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + std::string name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + Value& deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + //typedef unsigned int size_t; + //typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +} // namespace Json + + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +#define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + * back during + * serialization, \c false to discard comments. + * This parameter is ignored if + * Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON + document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + back during + * serialization, \c false to discard comments. + * This parameter is ignored if + Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(std::istream& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + std::string getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + */ + std::string getFormattedErrorMessages() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, std::string& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const std::string& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + std::string getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a JSON + document. + * The document must be a UTF-8 encoded string containing the document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, std::string* errs) = 0; + + class Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + std::string errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + virtual ~CharReaderBuilder(); + + virtual CharReader* newCharReader() const; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](std::string key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream( + CharReader::Factory const&, + std::istream&, + Value* root, std::string* errs); + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +JSON_API std::istream& operator>>(std::istream&, Value&); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + std::ostream* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, std::ostream* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + virtual ~StreamWriterBuilder(); + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](std::string key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual std::string write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API FastWriter : public Writer { + +public: + FastWriter(); + virtual ~FastWriter() {} + + void enableYAMLCompatibility(); + +public: // overridden from Writer + virtual std::string write(const Value& root); + +private: + void writeValue(const Value& value); + + std::string document_; + bool yamlCompatiblityEnabled_; +}; + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + virtual ~StyledWriter() {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write(const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const std::string& value); + void writeIndent(); + void writeWithIndent(const std::string& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static std::string normalizeEOL(const std::string& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledStreamWriter { +public: + StyledStreamWriter(std::string indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(std::ostream& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const std::string& value); + void writeIndent(); + void writeWithIndent(const std::string& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static std::string normalizeEOL(const std::string& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#if defined(JSON_HAS_INT64) +std::string JSON_API valueToString(Int value); +std::string JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +std::string JSON_API valueToString(LargestInt value); +std::string JSON_API valueToString(LargestUInt value); +std::string JSON_API valueToString(double value); +std::string JSON_API valueToString(bool value); +std::string JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API std::ostream& operator<<(std::ostream&, const Value& root); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + std::ostringstream oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +# define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ + { \ + std::ostringstream oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/external/CppMicroServices/third_party/jsoncpp.cpp b/external/CppMicroServices/third_party/jsoncpp.cpp new file mode 100644 index 00000000..d827863d --- /dev/null +++ b/external/CppMicroServices/third_party/jsoncpp.cpp @@ -0,0 +1,4945 @@ +/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json/json.h" + +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { + +/// Converts a unicode code-point to UTF-8. +static inline std::string codePointToUTF8(unsigned int cp) { + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +/// Returns true if ch is a control character (in range [1,31]). +static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned interger to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast(value % 10U + static_cast('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +static inline void fixNumericLocale(char* begin, char* end) { + while (begin < end) { + if (*begin == ',') { + *begin = '.'; + } + ++begin; + } +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#define snprintf std::snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +static int const stackLimit_g = 1000; +static int stackDepth_g = 0; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr CharReaderPtr; +#else +typedef std::auto_ptr CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false) +{} +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +static bool containsNewLine(Reader::Location begin, Reader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool +Reader::parse(const std::string& document, Value& root, bool collectComments) { + document_ = document; + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { + // std::istream_iterator begin(sin); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, static_cast(EOF)); + return parse(doc, root, collectComments); +} + +bool Reader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + stackDepth_g = 0; // Yes, this is bad coding, but options are limited. + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // This is a non-reentrant way to support a stackLimit. Terrible! + // But this deprecated class has a security problem: Bad input can + // cause a seg-fault. This seems like a fair, binary-compatible way + // to prevent the problem. + if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_g; + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + break; + case tokenArrayBegin: + successful = readArray(token); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + } + break; + // Else, fall through... + default: + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_g; + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { + std::string normalized; + normalized.reserve(end - begin); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +Reader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const std::string& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char *p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } +} + +bool Reader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& /*tokenStart*/) { + Token tokenName; + std::string name; + Value init(objectValue); + currentValue().swapPayload(init); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool Reader::readArray(Token& /*tokenStart*/) { + Value init(arrayValue); + currentValue().swapPayload(init); + skipSpaces(); + if (*current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(c - '0'); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + std::string buffer(token.start_, token.end_); + std::istringstream is(buffer); + if (!(is >> value)) + return addError("'" + std::string(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + std::string decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + return true; +} + +bool Reader::decodeString(Token& token, std::string& decoded) { + decoded.reserve(token.end_ - token.start_ - 2); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + return true; +} + +bool +Reader::addError(const std::string& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + int errorCount = int(errors_.size()); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +std::string Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +std::string Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +std::string Reader::getFormattedErrorMessages() const { + std::string formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +// Reader +///////////////////////// + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + OurFeatures(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures::OurFeatures() + : allowComments_(true), strictRoot_(false) + , allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) + , allowSingleQuotes_(false) + , failIfExtra_(false) + , allowSpecialFloats_(false) +{ +} + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + size_t offset_start; + size_t offset_limit; + std::string message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + std::string getFormattedErrorMessages() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, std::string& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const std::string& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + std::string getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + std::string commentsBefore_; + int stackDepth_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool OurReader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + stackDepth_ = 0; + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if (token.type_ != tokenError && token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_; + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + break; + case tokenArrayBegin: + successful = readArray(token); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + break; + } // else, fall through ... + default: + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_; + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else fall through + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +void +OurReader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const std::string& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& /*tokenStart*/) { + Token tokenName; + std::string name; + Value init(objectValue); + currentValue().swapPayload(init); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + std::string msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover( + msg, tokenName, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool OurReader::readArray(Token& /*tokenStart*/) { + Value init(arrayValue); + currentValue().swapPayload(init); + skipSpaces(); + if (*current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(c - '0'); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + std::string buffer( token.start_, token.end_ ); + std::istringstream is(buffer); + if (!(is >> value)) + return addError("'" + std::string(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + std::string decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + return true; +} + +bool OurReader::decodeString(Token& token, std::string& decoded) { + decoded.reserve(token.end_ - token.start_ - 2); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + return true; +} + +bool +OurReader::addError(const std::string& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + int errorCount = int(errors_.size()); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const std::string& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +std::string OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +std::string OurReader::getFormattedErrorMessages() const { + std::string formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, std::string* errs) { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() +{ + setDefaults(&settings_); +} +CharReaderBuilder::~CharReaderBuilder() +{} +CharReader* CharReaderBuilder::newCharReader() const +{ + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + std::string const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](std::string key) +{ + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) +{ +//! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) +{ +//! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream( + CharReader::Factory const& fact, std::istream& sin, + Value* root, std::string* errs) +{ + std::ostringstream ssin; + ssin << sin.rdbuf(); + std::string doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +std::istream& operator>>(std::istream& sin, Value& root) { + CharReaderBuilder b; + std::string errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + + throwRuntimeError("reader error"); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - current_; +#else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +#endif +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +std::string ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return std::string(); + return std::string(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +#include +#endif +#include // size_t +#include // min() + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +// This exists for binary compatibility only. Use nullRef. +const Value Value::null; +#define ALIGNAS(byte_alignment) +#endif +static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +const unsigned char& kNullRef = kNull[0]; +const Value& Value::nullRef = reinterpret_cast(kNullRef); + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template +static inline bool InRange(double d, T min, U max) { + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); +} + +template static inline double integerToDouble(T value) { + return static_cast(value); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, + size_t length) { + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; + char* newString = static_cast(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +static inline void releaseStringValue(char* value) { free(value); } + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(std::string const& msg) + : msg_(msg) +{} +Exception::~Exception() throw() +{} +char const* Exception::what() const throw() +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(std::string const& msg) + : Exception(msg) +{} +LogicError::LogicError(std::string const& msg) + : Exception(msg) +{} +JSONCPP_NORETURN void throwRuntimeError(std::string const& msg) +{ + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(std::string const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) {} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} + +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) +{ + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) + : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_) +{ + storage_.policy_ = (other.cstr_ + ? (static_cast(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast(other.storage_.policy_)); + storage_.length_ = other.storage_.length_; +} + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) + releaseStringValue(const_cast(cstr_)); +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(CZString other) { + swap(other); + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType vtype) { + initBasic(vtype); + switch (vtype) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); +} + +Value::Value(const char* beginValue, const char* endValue) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); +} + +Value::Value(const std::string& value) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(Value const& other) + : type_(other.type_), allocated_(false) + , + comments_(0) +{ + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + allocated_ = false; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } + if (other.comments_) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment( + otherComment.comment_, strlen(otherComment.comment_)); + } + } +} + +Value::~Value() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releaseStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + + if (comments_) + delete[] comments_; +} + +Value &Value::operator=(const Value &other) { + Value temp(other); + swap(temp); + return *this; +} + +void Value::swapPayload(Value& other) { + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap(value_, other.value_); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2 & 0x1; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); +} + +ValueType Value::type() const { return type_; } + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type_ - other.type_; + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type_) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + // if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if (type_ != temp) + return false; + switch (type_) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +bool Value::getString(char const** str, char const** cend) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *cend = *str + length; + return true; +} + +std::string Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return std::string(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString() == "") || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; +} + +bool Value::operator!() const { return isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + (*this)[newSize - 1]; + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + assert(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + CZString key(index); + ObjectValues::iterator it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullRef); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullRef; + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullRef; + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; + allocated_ = allocated; + comments_ = 0; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(strlen(key)), CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* cend) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(cend-key), CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullRef ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* key, char const* cend) const +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullRef; + return *found; +} +Value const& Value::operator[](std::string const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullRef; + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const std::string& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullRef; + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const +{ + Value const* found = find(key, cend); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(std::string const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); +} + + +bool Value::removeMember(const char* key, const char* cend, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + *removed = it->second; + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(std::string const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); +} +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullRef; + + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const std::string& key) +{ + return removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* key, char const* cend) const +{ + Value const* value = find(key, cend); + return NULL != value; +} +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(std::string const& key) const +{ + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(std::string((*it).first.data(), + (*it).first.length())); + } + return members; +} +// +//# ifdef JSON_USE_CPPTL +// EnumMemberNames +// Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: + return value_.int_ >= minInt && value_.int_ <= maxInt; + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); + case uintValue: + return value_.uint_ <= maxUInt; + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { +#if defined(JSON_HAS_INT64) + return isInt64() || isUInt64(); +#else + return isInt() || isUInt(); +#endif +} + +bool Value::isDouble() const { return type_ == realValue || isIntegral(); } + +bool Value::isNumeric() const { return isIntegral() || isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const std::string& comment, CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +std::string Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +std::string Value::toStyledString() const { + StyledWriter writer; + return writer.write(*this); +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const std::string& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const std::string& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const std::string& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *current++ != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(std::string(beginName, current)); + } + } +} + +void Path::addPathInArg(const std::string& /*path*/, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg); + } +} + +void Path::invalidPath(const std::string& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if (node == &Value::nullRef) { + // Error: unable to resolve path (object has no member named '' at + // position...) + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullRef) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#include +#define isfinite finite +#else +#include +#define isfinite std::isfinite +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#define snprintf std::snprintf +#endif + +#if defined(__BORLANDC__) +#include +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr StreamWriterPtr; +#else +typedef std::auto_ptr StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +std::string valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +std::string valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +std::string valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +std::string valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[32]; + int len = -1; + + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + // For those, we do not need to call fixNumLoc, but it is fast. + } + assert(len >= 0); + fixNumericLocale(buffer, buffer + len); + return buffer; +} + +std::string valueToString(double value) { return valueToString(value, false, 17); } + +std::string valueToString(bool value) { return value ? "true" : "false"; } + +std::string valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && + !containsControlCharacter(value)) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + std::string::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c = value; *c != 0; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static std::string valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + std::string::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +std::string FastWriter::write(const Value& root) { + document_ = ""; + writeValue(root); + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast(end-str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + int size = value.size(); + for (int index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (Value::Members::iterator it = members.begin(); it != members.end(); + ++it) { + const std::string& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +std::string StyledWriter::write(const Value& root) { + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += "\n"; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const std::string& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultineArray(const Value& value) { + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = + isMultiLine || ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const std::string& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const std::string& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(int(indentString_.size()) >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += "\n"; + writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(std::string indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(std::ostream& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const std::string& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultineArray(const Value& value) { + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = + isMultiLine || ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const std::string& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const std::string& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + std::string const& indentation, + CommentStyle::Enum cs, + std::string const& colonSymbol, + std::string const& nullSymbol, + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + virtual int write(Value const& root, std::ostream* sout); +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(std::string const& value); + void writeIndent(); + void writeWithIndent(std::string const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector ChildValues; + + ChildValues childValues_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + CommentStyle::Enum cs_; + std::string colonSymbol_; + std::string nullSymbol_; + std::string endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + std::string const& indentation, + CommentStyle::Enum cs, + std::string const& colonSymbol, + std::string const& nullSymbol, + std::string const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_ = ""; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + std::string const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ", "; + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + int size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (int index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = + isMultiLine || ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (int index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += int(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(std::string const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const std::string& comment = root.getComment(commentBefore); + std::string::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + std::string indentation = settings_["indentation"].asString(); + std::string cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + std::string colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + std::string nullSymbol = "null"; + if (dnp) { + nullSymbol = ""; + } + if (pre > 17) pre = 17; + std::string endingLineFeedSymbol = ""; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + std::string const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](std::string key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +std::string writeString(StreamWriter::Factory const& builder, Value const& root) { + std::ostringstream sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +std::ostream& operator<<(std::ostream& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + diff --git a/external/CppMicroServices/third_party/libtelnet.c b/external/CppMicroServices/third_party/libtelnet.c new file mode 100644 index 00000000..3a1fb8a1 --- /dev/null +++ b/external/CppMicroServices/third_party/libtelnet.c @@ -0,0 +1,1540 @@ +/* + * libtelnet - TELNET protocol handling library + * + * Sean Middleditch + * sean@sourcemud.org + * + * The author or authors of this code dedicate any and all copyright interest + * in this code to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and successors. We + * intend this dedication to be an overt act of relinquishment in perpetuity of + * all present and future rights to this code under copyright law. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include + +/* Win32 compatibility */ +#if defined(_WIN32) +# define vsnprintf _vsnprintf +# define __func__ __FUNCTION__ +# define ZLIB_WINAPI 1 +#endif + +#if defined(HAVE_ZLIB) +# include +#endif + +#include "libtelnet.h" + +/* inlinable functions */ +#if defined(__GNUC__) || __STDC_VERSION__ >= 199901L +# define INLINE __inline__ +#else +# define INLINE +#endif + +/* helper for Q-method option tracking */ +#define Q_US(q) ((q).state & 0x0F) +#define Q_HIM(q) (((q).state & 0xF0) >> 4) +#define Q_MAKE(us,him) ((us) | ((him) << 4)) + +/* helper for the negotiation routines */ +#define NEGOTIATE_EVENT(telnet,cmd,opt) \ + ev.type = (cmd); \ + ev.neg.telopt = (opt); \ + (telnet)->eh((telnet), &ev, (telnet)->ud); + +/* telnet state codes */ +enum telnet_state_t { + TELNET_STATE_DATA = 0, + TELNET_STATE_IAC, + TELNET_STATE_WILL, + TELNET_STATE_WONT, + TELNET_STATE_DO, + TELNET_STATE_DONT, + TELNET_STATE_SB, + TELNET_STATE_SB_DATA, + TELNET_STATE_SB_DATA_IAC +}; +typedef enum telnet_state_t telnet_state_t; + +/* telnet state tracker */ +struct telnet_t { + /* user data */ + void *ud; + /* telopt support table */ + const telnet_telopt_t *telopts; + /* event handler */ + telnet_event_handler_t eh; +#if defined(HAVE_ZLIB) + /* zlib (mccp2) compression */ + z_stream *z; +#endif + /* RFC1143 option negotiation states */ + struct telnet_rfc1143_t *q; + /* sub-request buffer */ + char *buffer; + /* current size of the buffer */ + size_t buffer_size; + /* current buffer write position (also length of buffer data) */ + size_t buffer_pos; + /* current state */ + enum telnet_state_t state; + /* option flags */ + unsigned char flags; + /* current subnegotiation telopt */ + unsigned char sb_telopt; + /* length of RFC1143 queue */ + unsigned char q_size; +}; + +/* RFC1143 option negotiation state */ +typedef struct telnet_rfc1143_t { + unsigned char telopt; + unsigned char state; +} telnet_rfc1143_t; + +/* RFC1143 state names */ +#define Q_NO 0 +#define Q_YES 1 +#define Q_WANTNO 2 +#define Q_WANTYES 3 +#define Q_WANTNO_OP 4 +#define Q_WANTYES_OP 5 + +/* buffer sizes */ +static const size_t _buffer_sizes[] = { 0, 512, 2048, 8192, 16384, }; +static const size_t _buffer_sizes_count = sizeof(_buffer_sizes) / + sizeof(_buffer_sizes[0]); + +/* error generation function */ +static telnet_error_t _error(telnet_t *telnet, unsigned line, + const char* func, telnet_error_t err, int fatal, const char *fmt, + ...) { + telnet_event_t ev; + char buffer[512]; + va_list va; + + /* format informational text */ + va_start(va, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, va); + va_end(va); + + /* send error event to the user */ + ev.type = fatal ? TELNET_EV_ERROR : TELNET_EV_WARNING; + ev.error.file = __FILE__; + ev.error.func = func; + ev.error.line = line; + ev.error.msg = buffer; + telnet->eh(telnet, &ev, telnet->ud); + + return err; +} + +#if defined(HAVE_ZLIB) +/* initialize the zlib box for a telnet box; if deflate is non-zero, it + * initializes zlib for delating (compression), otherwise for inflating + * (decompression). returns TELNET_EOK on success, something else on + * failure. + */ +telnet_error_t _init_zlib(telnet_t *telnet, int deflate, int err_fatal) { + z_stream *z; + int rs; + + /* if compression is already enabled, fail loudly */ + if (telnet->z != 0) + return _error(telnet, __LINE__, __func__, TELNET_EBADVAL, + err_fatal, "cannot initialize compression twice"); + + /* allocate zstream box */ + if ((z= (z_stream *)calloc(1, sizeof(z_stream))) == 0) + return _error(telnet, __LINE__, __func__, TELNET_ENOMEM, err_fatal, + "malloc() failed: %s", strerror(errno)); + + /* initialize */ + if (deflate) { + if ((rs = deflateInit(z, Z_DEFAULT_COMPRESSION)) != Z_OK) { + free(z); + return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, + err_fatal, "deflateInit() failed: %s", zError(rs)); + } + telnet->flags |= TELNET_PFLAG_DEFLATE; + } else { + if ((rs = inflateInit(z)) != Z_OK) { + free(z); + return _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, + err_fatal, "inflateInit() failed: %s", zError(rs)); + } + telnet->flags &= ~TELNET_PFLAG_DEFLATE; + } + + telnet->z = z; + + return TELNET_EOK; +} +#endif /* defined(HAVE_ZLIB) */ + +/* push bytes out, compressing them first if need be */ +static void _send(telnet_t *telnet, const char *buffer, + size_t size) { + telnet_event_t ev; + +#if defined(HAVE_ZLIB) + /* if we have a deflate (compression) zlib box, use it */ + if (telnet->z != 0 && telnet->flags & TELNET_PFLAG_DEFLATE) { + char deflate_buffer[1024]; + int rs; + + /* initialize z state */ + telnet->z->next_in = (unsigned char *)buffer; + telnet->z->avail_in = size; + telnet->z->next_out = (unsigned char *)deflate_buffer; + telnet->z->avail_out = sizeof(deflate_buffer); + + /* deflate until buffer exhausted and all output is produced */ + while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) { + /* compress */ + if ((rs = deflate(telnet->z, Z_SYNC_FLUSH)) != Z_OK) { + _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1, + "deflate() failed: %s", zError(rs)); + deflateEnd(telnet->z); + free(telnet->z); + telnet->z = 0; + break; + } + + /* send event */ + ev.type = TELNET_EV_SEND; + ev.data.buffer = deflate_buffer; + ev.data.size = sizeof(deflate_buffer) - telnet->z->avail_out; + telnet->eh(telnet, &ev, telnet->ud); + + /* prepare output buffer for next run */ + telnet->z->next_out = (unsigned char *)deflate_buffer; + telnet->z->avail_out = sizeof(deflate_buffer); + } + + /* do not continue with remaining code */ + return; + } +#endif /* defined(HAVE_ZLIB) */ + + ev.type = TELNET_EV_SEND; + ev.data.buffer = buffer; + ev.data.size = size; + telnet->eh(telnet, &ev, telnet->ud); +} + +/* to send bags of unsigned chars */ +#define _sendu(t, d, s) _send((t), (const char*)(d), (s)) + +/* check if we support a particular telopt; if us is non-zero, we + * check if we (local) supports it, otherwise we check if he (remote) + * supports it. return non-zero if supported, zero if not supported. + */ +static INLINE int _check_telopt(telnet_t *telnet, unsigned char telopt, + int us) { + int i; + + /* if we have no telopts table, we obviously don't support it */ + if (telnet->telopts == 0) + return 0; + + /* loop unti found or end marker (us and him both 0) */ + for (i = 0; telnet->telopts[i].telopt != -1; ++i) { + if (telnet->telopts[i].telopt == telopt) { + if (us && telnet->telopts[i].us == TELNET_WILL) + return 1; + else if (!us && telnet->telopts[i].him == TELNET_DO) + return 1; + else + return 0; + } + } + + /* not found, so not supported */ + return 0; +} + +/* retrieve RFC1143 option state */ +static INLINE telnet_rfc1143_t _get_rfc1143(telnet_t *telnet, + unsigned char telopt) { + telnet_rfc1143_t empty; + int i; + + /* search for entry */ + for (i = 0; i != telnet->q_size; ++i) { + if (telnet->q[i].telopt == telopt) { + return telnet->q[i]; + } + } + + /* not found, return empty value */ + empty.telopt = telopt; + empty.state = 0; + return empty; +} + +/* save RFC1143 option state */ +static INLINE void _set_rfc1143(telnet_t *telnet, unsigned char telopt, + char us, char him) { + telnet_rfc1143_t *qtmp; + int i; + + /* search for entry */ + for (i = 0; i != telnet->q_size; ++i) { + if (telnet->q[i].telopt == telopt) { + telnet->q[i].state = Q_MAKE(us,him); + return; + } + } + + /* we're going to need to track state for it, so grow the queue + * by 4 (four) elements and put the telopt into it; bail on allocation + * error. we go by four because it seems like a reasonable guess as + * to the number of enabled options for most simple code, and it + * allows for an acceptable number of reallocations for complex code. + */ + if ((qtmp = (telnet_rfc1143_t *)realloc(telnet->q, + sizeof(telnet_rfc1143_t) * (telnet->q_size + 4))) == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "realloc() failed: %s", strerror(errno)); + return; + } + memset(&qtmp[telnet->q_size], 0, sizeof(telnet_rfc1143_t) * 4); + telnet->q = qtmp; + telnet->q[telnet->q_size].telopt = telopt; + telnet->q[telnet->q_size].state = Q_MAKE(us, him); + telnet->q_size += 4; +} + +/* send negotiation bytes */ +static INLINE void _send_negotiate(telnet_t *telnet, unsigned char cmd, + unsigned char telopt) { + unsigned char bytes[3]; + bytes[0] = TELNET_IAC; + bytes[1] = cmd; + bytes[2] = telopt; + _sendu(telnet, bytes, 3); +} + +/* negotiation handling magic for RFC1143 */ +static void _negotiate(telnet_t *telnet, unsigned char telopt) { + telnet_event_t ev; + telnet_rfc1143_t q; + + /* in PROXY mode, just pass it thru and do nothing */ + if (telnet->flags & TELNET_FLAG_PROXY) { + switch ((int)telnet->state) { + case TELNET_STATE_WILL: + NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); + break; + case TELNET_STATE_WONT: + NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt); + break; + case TELNET_STATE_DO: + NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); + break; + case TELNET_STATE_DONT: + NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt); + break; + } + return; + } + + /* lookup the current state of the option */ + q = _get_rfc1143(telnet, telopt); + + /* start processing... */ + switch ((int)telnet->state) { + /* request to enable option on remote end or confirm DO */ + case TELNET_STATE_WILL: + switch (Q_HIM(q)) { + case Q_NO: + if (_check_telopt(telnet, telopt, 0)) { + _set_rfc1143(telnet, telopt, Q_US(q), Q_YES); + _send_negotiate(telnet, TELNET_DO, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); + } else + _send_negotiate(telnet, TELNET_DONT, telopt); + break; + case Q_WANTNO: + _set_rfc1143(telnet, telopt, Q_US(q), Q_NO); + NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt); + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "DONT answered by WILL"); + break; + case Q_WANTNO_OP: + _set_rfc1143(telnet, telopt, Q_US(q), Q_YES); + NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "DONT answered by WILL"); + break; + case Q_WANTYES: + _set_rfc1143(telnet, telopt, Q_US(q), Q_YES); + NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); + break; + case Q_WANTYES_OP: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO); + _send_negotiate(telnet, TELNET_DONT, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); + break; + } + break; + + /* request to disable option on remote end, confirm DONT, reject DO */ + case TELNET_STATE_WONT: + switch (Q_HIM(q)) { + case Q_YES: + _set_rfc1143(telnet, telopt, Q_US(q), Q_NO); + _send_negotiate(telnet, TELNET_DONT, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt); + break; + case Q_WANTNO: + _set_rfc1143(telnet, telopt, Q_US(q), Q_NO); + NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt); + break; + case Q_WANTNO_OP: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES); + NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); + break; + case Q_WANTYES: + case Q_WANTYES_OP: + _set_rfc1143(telnet, telopt, Q_US(q), Q_NO); + break; + } + break; + + /* request to enable option on local end or confirm WILL */ + case TELNET_STATE_DO: + switch (Q_US(q)) { + case Q_NO: + if (_check_telopt(telnet, telopt, 1)) { + _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q)); + _send_negotiate(telnet, TELNET_WILL, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); + } else + _send_negotiate(telnet, TELNET_WONT, telopt); + break; + case Q_WANTNO: + _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q)); + NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt); + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "WONT answered by DO"); + break; + case Q_WANTNO_OP: + _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q)); + NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "WONT answered by DO"); + break; + case Q_WANTYES: + _set_rfc1143(telnet, telopt, Q_YES, Q_HIM(q)); + NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); + break; + case Q_WANTYES_OP: + _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q)); + _send_negotiate(telnet, TELNET_WONT, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_DO, telopt); + break; + } + break; + + /* request to disable option on local end, confirm WONT, reject WILL */ + case TELNET_STATE_DONT: + switch (Q_US(q)) { + case Q_YES: + _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q)); + _send_negotiate(telnet, TELNET_WONT, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_DONT, telopt); + break; + case Q_WANTNO: + _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q)); + NEGOTIATE_EVENT(telnet, TELNET_EV_WONT, telopt); + break; + case Q_WANTNO_OP: + _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q)); + _send_negotiate(telnet, TELNET_WILL, telopt); + NEGOTIATE_EVENT(telnet, TELNET_EV_WILL, telopt); + break; + case Q_WANTYES: + case Q_WANTYES_OP: + _set_rfc1143(telnet, telopt, Q_NO, Q_HIM(q)); + break; + } + break; + } +} + +/* process an ENVIRON/NEW-ENVIRON subnegotiation buffer + * + * the algorithm and approach used here is kind of a hack, + * but it reduces the number of memory allocations we have + * to make. + * + * we copy the bytes back into the buffer, starting at the very + * beginning, which makes it easy to handle the ENVIRON ESC + * escape mechanism as well as ensure the variable name and + * value strings are NUL-terminated, all while fitting inside + * of the original buffer. + */ +static int _environ_telnet(telnet_t *telnet, unsigned char type, + char* buffer, size_t size) { + telnet_event_t ev; + struct telnet_environ_t *values = 0; + char *c, *last, *out; + size_t index, count; + + /* if we have no data, just pass it through */ + if (size == 0) { + return 0; + } + + /* first byte must be a valid command */ + if ((unsigned)buffer[0] != TELNET_ENVIRON_SEND && + (unsigned)buffer[0] != TELNET_ENVIRON_IS && + (unsigned)buffer[0] != TELNET_ENVIRON_INFO) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "telopt %d subneg has invalid command", type); + return 0; + } + + /* store ENVIRON command */ + ev.environ.cmd = buffer[0]; + + /* if we have no arguments, send an event with no data end return */ + if (size == 1) { + /* no list of variables given */ + ev.environ.values = 0; + ev.environ.size = 0; + + /* invoke event with our arguments */ + ev.type = TELNET_EV_ENVIRON; + telnet->eh(telnet, &ev, telnet->ud); + + return 1; + } + + /* very second byte must be VAR or USERVAR, if present */ + if ((unsigned)buffer[1] != TELNET_ENVIRON_VAR && + (unsigned)buffer[1] != TELNET_ENVIRON_USERVAR) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "telopt %d subneg missing variable type", type); + return 0; + } + + /* ensure last byte is not an escape byte (makes parsing later easier) */ + if ((unsigned)buffer[size - 1] == TELNET_ENVIRON_ESC) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "telopt %d subneg ends with ESC", type); + return 0; + } + + /* count arguments; each valid entry starts with VAR or USERVAR */ + count = 0; + for (c = buffer + 1; c < buffer + size; ++c) { + if (*c == TELNET_ENVIRON_VAR || *c == TELNET_ENVIRON_USERVAR) { + ++count; + } else if (*c == TELNET_ENVIRON_ESC) { + /* skip the next byte */ + ++c; + } + } + + /* allocate argument array, bail on error */ + if ((values = (struct telnet_environ_t *)calloc(count, + sizeof(struct telnet_environ_t))) == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "calloc() failed: %s", strerror(errno)); + return 0; + } + + /* parse argument array strings */ + out = buffer; + c = buffer + 1; + for (index = 0; index != count; ++index) { + /* remember the variable type (will be VAR or USERVAR) */ + values[index].type = *c++; + + /* scan until we find an end-marker, and buffer up unescaped + * bytes into our buffer */ + last = out; + while (c < buffer + size) { + /* stop at the next variable or at the value */ + if ((unsigned)*c == TELNET_ENVIRON_VAR || + (unsigned)*c == TELNET_ENVIRON_VALUE || + (unsigned)*c == TELNET_ENVIRON_USERVAR) { + break; + } + + /* buffer next byte (taking into account ESC) */ + if (*c == TELNET_ENVIRON_ESC) { + ++c; + } + + *out++ = *c++; + } + *out++ = '\0'; + + /* store the variable name we have just received */ + values[index].var = last; + values[index].value = ""; + + /* if we got a value, find the next end marker and + * store the value; otherwise, store empty string */ + if (c < buffer + size && *c == TELNET_ENVIRON_VALUE) { + ++c; + last = out; + while (c < buffer + size) { + /* stop when we find the start of the next variable */ + if ((unsigned)*c == TELNET_ENVIRON_VAR || + (unsigned)*c == TELNET_ENVIRON_USERVAR) { + break; + } + + /* buffer next byte (taking into account ESC) */ + if (*c == TELNET_ENVIRON_ESC) { + ++c; + } + + *out++ = *c++; + } + *out++ = '\0'; + + /* store the variable value */ + values[index].value = last; + } + } + + /* pass values array and count to event */ + ev.environ.values = values; + ev.environ.size = count; + + /* invoke event with our arguments */ + ev.type = TELNET_EV_ENVIRON; + telnet->eh(telnet, &ev, telnet->ud); + + /* clean up */ + free(values); + return 1; +} + +/* process an MSSP subnegotiation buffer */ +static int _mssp_telnet(telnet_t *telnet, char* buffer, size_t size) { + telnet_event_t ev; + struct telnet_environ_t *values; + char *var = 0; + char *c, *last, *out; + size_t i, count; + unsigned char next_type; + + /* if we have no data, just pass it through */ + if (size == 0) { + return 0; + } + + /* first byte must be a VAR */ + if ((unsigned)buffer[0] != TELNET_MSSP_VAR) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "MSSP subnegotiation has invalid data"); + return 0; + } + + /* count the arguments, any part that starts with VALUE */ + for (count = 0, i = 0; i != size; ++i) { + if ((unsigned)buffer[i] == TELNET_MSSP_VAL) { + ++count; + } + } + + /* allocate argument array, bail on error */ + if ((values = (struct telnet_environ_t *)calloc(count, + sizeof(struct telnet_environ_t))) == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "calloc() failed: %s", strerror(errno)); + return 0; + } + + ev.mssp.values = values; + ev.mssp.size = count; + + /* allocate strings in argument array */ + out = last = buffer; + next_type = buffer[0]; + for (i = 0, c = buffer + 1; c < buffer + size;) { + /* search for end marker */ + while (c < buffer + size && (unsigned)*c != TELNET_MSSP_VAR && + (unsigned)*c != TELNET_MSSP_VAL) { + *out++ = *c++; + } + *out++ = '\0'; + + /* if it's a variable name, just store the name for now */ + if (next_type == TELNET_MSSP_VAR) { + var = last; + } else if (next_type == TELNET_MSSP_VAL && var != 0) { + values[i].var = var; + values[i].value = last; + ++i; + } else { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "invalid MSSP subnegotiation data"); + free(values); + return 0; + } + + /* remember our next type and increment c for next loop run */ + last = out; + next_type = *c++; + } + + /* invoke event with our arguments */ + ev.type = TELNET_EV_MSSP; + telnet->eh(telnet, &ev, telnet->ud); + + /* clean up */ + free(values); + + return 0; +} + +/* parse ZMP command subnegotiation buffers */ +static int _zmp_telnet(telnet_t *telnet, const char* buffer, size_t size) { + telnet_event_t ev; + char **argv; + const char *c; + size_t i, argc; + + /* make sure this is a valid ZMP buffer */ + if (size == 0 || buffer[size - 1] != 0) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "incomplete ZMP frame"); + return 0; + } + + /* count arguments */ + for (argc = 0, c = buffer; c != buffer + size; ++argc) + c += strlen(c) + 1; + + /* allocate argument array, bail on error */ + if ((argv = (char **)calloc(argc, sizeof(char *))) == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "calloc() failed: %s", strerror(errno)); + return 0; + } + + /* populate argument array */ + for (i = 0, c = buffer; i != argc; ++i) { + argv[i] = (char *)c; + c += strlen(c) + 1; + } + + /* invoke event with our arguments */ + ev.type = TELNET_EV_ZMP; + ev.zmp.argv = (const char**)argv; + ev.zmp.argc = argc; + telnet->eh(telnet, &ev, telnet->ud); + + /* clean up */ + free(argv); + return 0; +} + +/* parse TERMINAL-TYPE command subnegotiation buffers */ +static int _ttype_telnet(telnet_t *telnet, const char* buffer, size_t size) { + telnet_event_t ev; + + /* make sure request is not empty */ + if (size == 0) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "incomplete TERMINAL-TYPE request"); + return 0; + } + + /* make sure request has valid command type */ + if (buffer[0] != TELNET_TTYPE_IS && + buffer[0] != TELNET_TTYPE_SEND) { + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "TERMINAL-TYPE request has invalid type"); + return 0; + } + + /* send proper event */ + if (buffer[0] == TELNET_TTYPE_IS) { + char *name; + + /* allocate space for name */ + if ((name = (char *)malloc(size)) == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "malloc() failed: %s", strerror(errno)); + return 0; + } + memcpy(name, buffer + 1, size - 1); + name[size - 1] = '\0'; + + ev.type = TELNET_EV_TTYPE; + ev.ttype.cmd = TELNET_TTYPE_IS; + ev.ttype.name = name; + telnet->eh(telnet, &ev, telnet->ud); + + /* clean up */ + free(name); + } else { + ev.type = TELNET_EV_TTYPE; + ev.ttype.cmd = TELNET_TTYPE_SEND; + ev.ttype.name = 0; + telnet->eh(telnet, &ev, telnet->ud); + } + + return 0; +} + +/* process a subnegotiation buffer; return non-zero if the current buffer + * must be aborted and reprocessed due to COMPRESS2 being activated + */ +static int _subnegotiate(telnet_t *telnet) { + telnet_event_t ev; + + /* standard subnegotiation event */ + ev.type = TELNET_EV_SUBNEGOTIATION; + ev.sub.telopt = telnet->sb_telopt; + ev.sub.buffer = telnet->buffer; + ev.sub.size = telnet->buffer_pos; + telnet->eh(telnet, &ev, telnet->ud); + + switch (telnet->sb_telopt) { +#if defined(HAVE_ZLIB) + /* received COMPRESS2 begin marker, setup our zlib box and + * start handling the compressed stream if it's not already. + */ + case TELNET_TELOPT_COMPRESS2: + if (telnet->sb_telopt == TELNET_TELOPT_COMPRESS2) { + if (_init_zlib(telnet, 0, 1) != TELNET_EOK) + return 0; + + /* notify app that compression was enabled */ + ev.type = TELNET_EV_COMPRESS; + ev.compress.state = 1; + telnet->eh(telnet, &ev, telnet->ud); + return 1; + } + return 0; +#endif /* defined(HAVE_ZLIB) */ + + /* specially handled subnegotiation telopt types */ + case TELNET_TELOPT_ZMP: + return _zmp_telnet(telnet, telnet->buffer, telnet->buffer_pos); + case TELNET_TELOPT_TTYPE: + return _ttype_telnet(telnet, telnet->buffer, telnet->buffer_pos); + case TELNET_TELOPT_ENVIRON: + case TELNET_TELOPT_NEW_ENVIRON: + return _environ_telnet(telnet, telnet->sb_telopt, telnet->buffer, + telnet->buffer_pos); + case TELNET_TELOPT_MSSP: + return _mssp_telnet(telnet, telnet->buffer, telnet->buffer_pos); + default: + return 0; + } +} + +/* initialize a telnet state tracker */ +telnet_t *telnet_init(const telnet_telopt_t *telopts, + telnet_event_handler_t eh, unsigned char flags, void *user_data) { + /* allocate structure */ + struct telnet_t *telnet = (telnet_t*)calloc(1, sizeof(telnet_t)); + if (telnet == 0) + return 0; + + /* initialize data */ + telnet->ud = user_data; + telnet->telopts = telopts; + telnet->eh = eh; + telnet->flags = flags; + + return telnet; +} + +/* free up any memory allocated by a state tracker */ +void telnet_free(telnet_t *telnet) { + /* free sub-request buffer */ + if (telnet->buffer != 0) { + free(telnet->buffer); + telnet->buffer = 0; + telnet->buffer_size = 0; + telnet->buffer_pos = 0; + } + +#if defined(HAVE_ZLIB) + /* free zlib box */ + if (telnet->z != 0) { + if (telnet->flags & TELNET_PFLAG_DEFLATE) + deflateEnd(telnet->z); + else + inflateEnd(telnet->z); + free(telnet->z); + telnet->z = 0; + } +#endif /* defined(HAVE_ZLIB) */ + + /* free RFC1143 queue */ + if (telnet->q) { + free(telnet->q); + telnet->q = 0; + telnet->q_size = 0; + } + + /* free the telnet structure itself */ + free(telnet); +} + +/* push a byte into the telnet buffer */ +static telnet_error_t _buffer_byte(telnet_t *telnet, + unsigned char byte) { + char *new_buffer; + size_t i; + + /* check if we're out of room */ + if (telnet->buffer_pos == telnet->buffer_size) { + /* find the next buffer size */ + for (i = 0; i != _buffer_sizes_count; ++i) { + if (_buffer_sizes[i] == telnet->buffer_size) { + break; + } + } + + /* overflow -- can't grow any more */ + if (i >= _buffer_sizes_count - 1) { + _error(telnet, __LINE__, __func__, TELNET_EOVERFLOW, 0, + "subnegotiation buffer size limit reached"); + return TELNET_EOVERFLOW; + } + + /* (re)allocate buffer */ + new_buffer = (char *)realloc(telnet->buffer, _buffer_sizes[i + 1]); + if (new_buffer == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "realloc() failed"); + return TELNET_ENOMEM; + } + + telnet->buffer = new_buffer; + telnet->buffer_size = _buffer_sizes[i + 1]; + } + + /* push the byte, all set */ + telnet->buffer[telnet->buffer_pos++] = byte; + return TELNET_EOK; +} + +static void _process(telnet_t *telnet, const char *buffer, size_t size) { + telnet_event_t ev; + unsigned char byte; + size_t i, start; + for (i = start = 0; i != size; ++i) { + byte = buffer[i]; + switch (telnet->state) { + /* regular data */ + case TELNET_STATE_DATA: + /* on an IAC byte, pass through all pending bytes and + * switch states */ + if (byte == TELNET_IAC) { + if (i != start) { + ev.type = TELNET_EV_DATA; + ev.data.buffer = buffer + start; + ev.data.size = i - start; + telnet->eh(telnet, &ev, telnet->ud); + } + telnet->state = TELNET_STATE_IAC; + } + break; + + /* IAC command */ + case TELNET_STATE_IAC: + switch (byte) { + /* subnegotiation */ + case TELNET_SB: + telnet->state = TELNET_STATE_SB; + break; + /* negotiation commands */ + case TELNET_WILL: + telnet->state = TELNET_STATE_WILL; + break; + case TELNET_WONT: + telnet->state = TELNET_STATE_WONT; + break; + case TELNET_DO: + telnet->state = TELNET_STATE_DO; + break; + case TELNET_DONT: + telnet->state = TELNET_STATE_DONT; + break; + /* IAC escaping */ + case TELNET_IAC: + /* event */ + ev.type = TELNET_EV_DATA; + ev.data.buffer = (char*)&byte; + ev.data.size = 1; + telnet->eh(telnet, &ev, telnet->ud); + + /* state update */ + start = i + 1; + telnet->state = TELNET_STATE_DATA; + break; + /* some other command */ + default: + /* event */ + ev.type = TELNET_EV_IAC; + ev.iac.cmd = byte; + telnet->eh(telnet, &ev, telnet->ud); + + /* state update */ + start = i + 1; + telnet->state = TELNET_STATE_DATA; + } + break; + + /* negotiation commands */ + case TELNET_STATE_WILL: + case TELNET_STATE_WONT: + case TELNET_STATE_DO: + case TELNET_STATE_DONT: + _negotiate(telnet, byte); + start = i + 1; + telnet->state = TELNET_STATE_DATA; + break; + + /* subnegotiation -- determine subnegotiation telopt */ + case TELNET_STATE_SB: + telnet->sb_telopt = byte; + telnet->buffer_pos = 0; + telnet->state = TELNET_STATE_SB_DATA; + break; + + /* subnegotiation -- buffer bytes until end request */ + case TELNET_STATE_SB_DATA: + /* IAC command in subnegotiation -- either IAC SE or IAC IAC */ + if (byte == TELNET_IAC) { + telnet->state = TELNET_STATE_SB_DATA_IAC; + /* buffer the byte, or bail if we can't */ + } else if (_buffer_byte(telnet, byte) != TELNET_EOK) { + start = i + 1; + telnet->state = TELNET_STATE_DATA; + } + break; + + /* IAC escaping inside a subnegotiation */ + case TELNET_STATE_SB_DATA_IAC: + switch (byte) { + /* end subnegotiation */ + case TELNET_SE: + /* return to default state */ + start = i + 1; + telnet->state = TELNET_STATE_DATA; + + /* process subnegotiation */ + if (_subnegotiate(telnet) != 0) { + /* any remaining bytes in the buffer are compressed. + * we have to re-invoke telnet_recv to get those + * bytes inflated and abort trying to process the + * remaining compressed bytes in the current _process + * buffer argument + */ + telnet_recv(telnet, &buffer[start], size - start); + return; + } + break; + /* escaped IAC byte */ + case TELNET_IAC: + /* push IAC into buffer */ + if (_buffer_byte(telnet, TELNET_IAC) != + TELNET_EOK) { + start = i + 1; + telnet->state = TELNET_STATE_DATA; + } else { + telnet->state = TELNET_STATE_SB_DATA; + } + break; + /* something else -- protocol error. attempt to process + * content in subnegotiation buffer, then evaluate the + * given command as an IAC code. + */ + default: + _error(telnet, __LINE__, __func__, TELNET_EPROTOCOL, 0, + "unexpected byte after IAC inside SB: %d", + byte); + + /* enter IAC state */ + start = i + 1; + telnet->state = TELNET_STATE_IAC; + + /* process subnegotiation; see comment in + * TELNET_STATE_SB_DATA_IAC about invoking telnet_recv() + */ + if (_subnegotiate(telnet) != 0) { + telnet_recv(telnet, &buffer[start], size - start); + return; + } else { + /* recursive call to get the current input byte processed + * as a regular IAC command. we could use a goto, but + * that would be gross. + */ + _process(telnet, (char *)&byte, 1); + } + break; + } + break; + } + } + + /* pass through any remaining bytes */ + if (telnet->state == TELNET_STATE_DATA && i != start) { + ev.type = TELNET_EV_DATA; + ev.data.buffer = buffer + start; + ev.data.size = i - start; + telnet->eh(telnet, &ev, telnet->ud); + } +} + +/* push a bytes into the state tracker */ +void telnet_recv(telnet_t *telnet, const char *buffer, + size_t size) { +#if defined(HAVE_ZLIB) + /* if we have an inflate (decompression) zlib stream, use it */ + if (telnet->z != 0 && !(telnet->flags & TELNET_PFLAG_DEFLATE)) { + char inflate_buffer[1024]; + int rs; + + /* initialize zlib state */ + telnet->z->next_in = (unsigned char*)buffer; + telnet->z->avail_in = size; + telnet->z->next_out = (unsigned char *)inflate_buffer; + telnet->z->avail_out = sizeof(inflate_buffer); + + /* inflate until buffer exhausted and all output is produced */ + while (telnet->z->avail_in > 0 || telnet->z->avail_out == 0) { + /* reset output buffer */ + + /* decompress */ + rs = inflate(telnet->z, Z_SYNC_FLUSH); + + /* process the decompressed bytes on success */ + if (rs == Z_OK || rs == Z_STREAM_END) + _process(telnet, inflate_buffer, sizeof(inflate_buffer) - + telnet->z->avail_out); + else + _error(telnet, __LINE__, __func__, TELNET_ECOMPRESS, 1, + "inflate() failed: %s", zError(rs)); + + /* prepare output buffer for next run */ + telnet->z->next_out = (unsigned char *)inflate_buffer; + telnet->z->avail_out = sizeof(inflate_buffer); + + /* on error (or on end of stream) disable further inflation */ + if (rs != Z_OK) { + telnet_event_t ev; + + /* disable compression */ + inflateEnd(telnet->z); + free(telnet->z); + telnet->z = 0; + + /* send event */ + ev.type = TELNET_EV_COMPRESS; + ev.compress.state = 0; + telnet->eh(telnet, &ev, telnet->ud); + + break; + } + } + + /* COMPRESS2 is not negotiated, just process */ + } else +#endif /* defined(HAVE_ZLIB) */ + _process(telnet, buffer, size); +} + +/* send an iac command */ +void telnet_iac(telnet_t *telnet, unsigned char cmd) { + unsigned char bytes[2]; + bytes[0] = TELNET_IAC; + bytes[1] = cmd; + _sendu(telnet, bytes, 2); +} + +/* send negotiation */ +void telnet_negotiate(telnet_t *telnet, unsigned char cmd, + unsigned char telopt) { + telnet_rfc1143_t q; + + /* if we're in proxy mode, just send it now */ + if (telnet->flags & TELNET_FLAG_PROXY) { + unsigned char bytes[3]; + bytes[0] = TELNET_IAC; + bytes[1] = cmd; + bytes[2] = telopt; + _sendu(telnet, bytes, 3); + return; + } + + /* get current option states */ + q = _get_rfc1143(telnet, telopt); + + switch (cmd) { + /* advertise willingess to support an option */ + case TELNET_WILL: + switch (Q_US(q)) { + case Q_NO: + _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q)); + _send_negotiate(telnet, TELNET_WILL, telopt); + break; + case Q_WANTNO: + _set_rfc1143(telnet, telopt, Q_WANTNO_OP, Q_HIM(q)); + break; + case Q_WANTYES_OP: + _set_rfc1143(telnet, telopt, Q_WANTYES, Q_HIM(q)); + break; + } + break; + + /* force turn-off of locally enabled option */ + case TELNET_WONT: + switch (Q_US(q)) { + case Q_YES: + _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q)); + _send_negotiate(telnet, TELNET_WONT, telopt); + break; + case Q_WANTYES: + _set_rfc1143(telnet, telopt, Q_WANTYES_OP, Q_HIM(q)); + break; + case Q_WANTNO_OP: + _set_rfc1143(telnet, telopt, Q_WANTNO, Q_HIM(q)); + break; + } + break; + + /* ask remote end to enable an option */ + case TELNET_DO: + switch (Q_HIM(q)) { + case Q_NO: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES); + _send_negotiate(telnet, TELNET_DO, telopt); + break; + case Q_WANTNO: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO_OP); + break; + case Q_WANTYES_OP: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES); + break; + } + break; + + /* demand remote end disable an option */ + case TELNET_DONT: + switch (Q_HIM(q)) { + case Q_YES: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO); + _send_negotiate(telnet, TELNET_DONT, telopt); + break; + case Q_WANTYES: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTYES_OP); + break; + case Q_WANTNO_OP: + _set_rfc1143(telnet, telopt, Q_US(q), Q_WANTNO); + break; + } + break; + } +} + +/* send non-command data (escapes IAC bytes) */ +void telnet_send(telnet_t *telnet, const char *buffer, + size_t size) { + size_t i, l; + + for (l = i = 0; i != size; ++i) { + /* dump prior portion of text, send escaped bytes */ + if (buffer[i] == (char)TELNET_IAC) { + /* dump prior text if any */ + if (i != l) { + _send(telnet, buffer + l, i - l); + } + l = i + 1; + + /* send escape */ + telnet_iac(telnet, TELNET_IAC); + } + } + + /* send whatever portion of buffer is left */ + if (i != l) { + _send(telnet, buffer + l, i - l); + } +} + +/* send subnegotiation header */ +void telnet_begin_sb(telnet_t *telnet, unsigned char telopt) { + unsigned char sb[3]; + sb[0] = TELNET_IAC; + sb[1] = TELNET_SB; + sb[2] = telopt; + _sendu(telnet, sb, 3); +} + + +/* send complete subnegotiation */ +void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt, + const char *buffer, size_t size) { + unsigned char bytes[5]; + bytes[0] = TELNET_IAC; + bytes[1] = TELNET_SB; + bytes[2] = telopt; + bytes[3] = TELNET_IAC; + bytes[4] = TELNET_SE; + + _sendu(telnet, bytes, 3); + telnet_send(telnet, buffer, size); + _sendu(telnet, bytes + 3, 2); + +#if defined(HAVE_ZLIB) + /* if we're a proxy and we just sent the COMPRESS2 marker, we must + * make sure all further data is compressed if not already. + */ + if (telnet->flags & TELNET_FLAG_PROXY && + telopt == TELNET_TELOPT_COMPRESS2) { + telnet_event_t ev; + + if (_init_zlib(telnet, 1, 1) != TELNET_EOK) + return; + + /* notify app that compression was enabled */ + ev.type = TELNET_EV_COMPRESS; + ev.compress.state = 1; + telnet->eh(telnet, &ev, telnet->ud); + } +#endif /* defined(HAVE_ZLIB) */ +} + +void telnet_begin_compress2(telnet_t *telnet) { +#if defined(HAVE_ZLIB) + static const unsigned char compress2[] = { TELNET_IAC, TELNET_SB, + TELNET_TELOPT_COMPRESS2, TELNET_IAC, TELNET_SE }; + + telnet_event_t ev; + + /* attempt to create output stream first, bail if we can't */ + if (_init_zlib(telnet, 1, 0) != TELNET_EOK) + return; + + /* send compression marker. we send directly to the event handler + * instead of passing through _send because _send would result in + * the compress marker itself being compressed. + */ + ev.type = TELNET_EV_SEND; + ev.data.buffer = (const char*)compress2; + ev.data.size = sizeof(compress2); + telnet->eh(telnet, &ev, telnet->ud); + + /* notify app that compression was successfully enabled */ + ev.type = TELNET_EV_COMPRESS; + ev.compress.state = 1; + telnet->eh(telnet, &ev, telnet->ud); +#endif /* defined(HAVE_ZLIB) */ +} + +/* send formatted data with \r and \n translation in addition to IAC IAC */ +int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va) { + static const char CRLF[] = { '\r', '\n' }; + static const char CRNUL[] = { '\r', '\0' }; + char buffer[1024]; + char *output = buffer; + int rs, i, l; + + /* format */ + rs = vsnprintf(buffer, sizeof(buffer), fmt, va); + if (rs >= sizeof(buffer)) { + output = (char*)malloc(rs + 1); + if (output == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "malloc() failed: %s", strerror(errno)); + return -1; + } + rs = vsnprintf(output, rs + 1, fmt, va); + } + + /* send */ + for (l = i = 0; i != rs; ++i) { + /* special characters */ + if (output[i] == (char)TELNET_IAC || output[i] == '\r' || + output[i] == '\n') { + /* dump prior portion of text */ + if (i != l) + _send(telnet, output + l, i - l); + l = i + 1; + + /* IAC -> IAC IAC */ + if (output[i] == (char)TELNET_IAC) + telnet_iac(telnet, TELNET_IAC); + /* automatic translation of \r -> CRNUL */ + else if (output[i] == '\r') + _send(telnet, CRNUL, 2); + /* automatic translation of \n -> CRLF */ + else if (output[i] == '\n') + _send(telnet, CRLF, 2); + } + } + + /* send whatever portion of output is left */ + if (i != l) { + _send(telnet, output + l, i - l); + } + + /* free allocated memory, if any */ + if (output != buffer) { + free(output); + } + + return rs; +} + +/* see telnet_vprintf */ +int telnet_printf(telnet_t *telnet, const char *fmt, ...) { + va_list va; + int rs; + + va_start(va, fmt); + rs = telnet_vprintf(telnet, fmt, va); + va_end(va); + + return rs; +} + +/* send formatted data through telnet_send */ +int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va) { + char buffer[1024]; + char *output = buffer; + int rs; + + /* format; allocate more space if necessary */ + rs = vsnprintf(buffer, sizeof(buffer), fmt, va); + if (rs >= sizeof(buffer)) { + output = (char*)malloc(rs + 1); + if (output == 0) { + _error(telnet, __LINE__, __func__, TELNET_ENOMEM, 0, + "malloc() failed: %s", strerror(errno)); + return -1; + } + rs = vsnprintf(output, rs + 1, fmt, va); + } + + /* send out the formatted data */ + telnet_send(telnet, output, rs); + + /* release allocated memory, if any */ + if (output != buffer) { + free(output); + } + + return rs; +} + +/* see telnet_raw_vprintf */ +int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...) { + va_list va; + int rs; + + va_start(va, fmt); + rs = telnet_raw_vprintf(telnet, fmt, va); + va_end(va); + + return rs; +} + +/* begin NEW-ENVIRON subnegotation */ +void telnet_begin_newenviron(telnet_t *telnet, unsigned char cmd) { + telnet_begin_sb(telnet, TELNET_TELOPT_NEW_ENVIRON); + telnet_send(telnet, (const char *)&cmd, 1); +} + +/* send a NEW-ENVIRON value */ +void telnet_newenviron_value(telnet_t *telnet, unsigned char type, + const char *string) { + telnet_send(telnet, (const char*)&type, 1); + + if (string != 0) { + telnet_send(telnet, string, strlen(string)); + } +} + +/* send TERMINAL-TYPE SEND command */ +void telnet_ttype_send(telnet_t *telnet) { + static const unsigned char SEND[] = { TELNET_IAC, TELNET_SB, + TELNET_TELOPT_TTYPE, TELNET_TTYPE_SEND, TELNET_IAC, TELNET_SE }; + _sendu(telnet, SEND, sizeof(SEND)); +} + +/* send TERMINAL-TYPE IS command */ +void telnet_ttype_is(telnet_t *telnet, const char* ttype) { + static const unsigned char IS[] = { TELNET_IAC, TELNET_SB, + TELNET_TELOPT_TTYPE, TELNET_TTYPE_IS }; + _sendu(telnet, IS, sizeof(IS)); + _send(telnet, ttype, strlen(ttype)); + telnet_finish_sb(telnet); +} + +/* send ZMP data */ +void telnet_send_zmp(telnet_t *telnet, size_t argc, const char **argv) { + size_t i; + + /* ZMP header */ + telnet_begin_zmp(telnet, argv[0]); + + /* send out each argument, including trailing NUL byte */ + for (i = 1; i != argc; ++i) + telnet_zmp_arg(telnet, argv[i]); + + /* ZMP footer */ + telnet_finish_zmp(telnet); +} + +/* send ZMP data using varargs */ +void telnet_send_vzmpv(telnet_t *telnet, va_list va) { + const char* arg; + + /* ZMP header */ + telnet_begin_sb(telnet, TELNET_TELOPT_ZMP); + + /* send out each argument, including trailing NUL byte */ + while ((arg = va_arg(va, const char *)) != 0) + telnet_zmp_arg(telnet, arg); + + /* ZMP footer */ + telnet_finish_zmp(telnet); +} + +/* see telnet_send_vzmpv */ +void telnet_send_zmpv(telnet_t *telnet, ...) { + va_list va; + + va_start(va, telnet); + telnet_send_vzmpv(telnet, va); + va_end(va); +} + +/* begin a ZMP command */ +void telnet_begin_zmp(telnet_t *telnet, const char *cmd) { + telnet_begin_sb(telnet, TELNET_TELOPT_ZMP); + telnet_zmp_arg(telnet, cmd); +} + +/* send a ZMP argument */ +void telnet_zmp_arg(telnet_t *telnet, const char* arg) { + telnet_send(telnet, arg, strlen(arg) + 1); +} diff --git a/external/CppMicroServices/third_party/libtelnet.h b/external/CppMicroServices/third_party/libtelnet.h new file mode 100644 index 00000000..e4eb2d12 --- /dev/null +++ b/external/CppMicroServices/third_party/libtelnet.h @@ -0,0 +1,671 @@ +/*! + * \brief libtelnet - TELNET protocol handling library + * + * SUMMARY: + * + * libtelnet is a library for handling the TELNET protocol. It includes + * routines for parsing incoming data from a remote peer as well as formatting + * data to send to the remote peer. + * + * libtelnet uses a callback-oriented API, allowing application-specific + * handling of various events. The callback system is also used for buffering + * outgoing protocol data, allowing the application to maintain control over + * the actual socket connection. + * + * Features supported include the full TELNET protocol, Q-method option + * negotiation, ZMP, MCCP2, MSSP, and NEW-ENVIRON. + * + * CONFORMS TO: + * + * RFC854 - http://www.faqs.org/rfcs/rfc854.html + * RFC855 - http://www.faqs.org/rfcs/rfc855.html + * RFC1091 - http://www.faqs.org/rfcs/rfc1091.html + * RFC1143 - http://www.faqs.org/rfcs/rfc1143.html + * RFC1408 - http://www.faqs.org/rfcs/rfc1408.html + * RFC1572 - http://www.faqs.org/rfcs/rfc1572.html + * + * LICENSE: + * + * The author or authors of this code dedicate any and all copyright interest + * in this code to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and successors. We + * intend this dedication to be an overt act of relinquishment in perpetuity of + * all present and future rights to this code under copyright law. + * + * \file libtelnet.h + * + * \version 0.21 + * + * \author Sean Middleditch + */ + +#if !defined(LIBTELNET_INCLUDE) +#define LIBTELNET_INCLUDE 1 + +/* standard C headers necessary for the libtelnet API */ +#include + +/* C++ support */ +#if defined(__cplusplus) +extern "C" { +#endif + +/* printf type checking feature in GCC and some other compilers */ +#if __GNUC__ +# define TELNET_GNU_PRINTF(f,a) __attribute__((format(printf, f, a))) /*!< internal helper */ +# define TELNET_GNU_SENTINEL __attribute__((sentinel)) /*!< internal helper */ +#else +# define TELNET_GNU_PRINTF(f,a) /*!< internal helper */ +# define TELNET_GNU_SENTINEL /*!< internal helper */ +#endif + +/*! Telnet state tracker object type. */ +typedef struct telnet_t telnet_t; + +/*! Telnet event object type. */ +typedef union telnet_event_t telnet_event_t; + +/*! Telnet option table element type. */ +typedef struct telnet_telopt_t telnet_telopt_t; + +/*! \name Telnet commands */ +/*@{*/ +/*! Telnet commands and special values. */ +#define TELNET_IAC 255 +#define TELNET_DONT 254 +#define TELNET_DO 253 +#define TELNET_WONT 252 +#define TELNET_WILL 251 +#define TELNET_SB 250 +#define TELNET_GA 249 +#define TELNET_EL 248 +#define TELNET_EC 247 +#define TELNET_AYT 246 +#define TELNET_AO 245 +#define TELNET_IP 244 +#define TELNET_BREAK 243 +#define TELNET_DM 242 +#define TELNET_NOP 241 +#define TELNET_SE 240 +#define TELNET_EOR 239 +#define TELNET_ABORT 238 +#define TELNET_SUSP 237 +#define TELNET_EOF 236 +/*@}*/ + +/*! \name Telnet option values. */ +/*@{*/ +/*! Telnet options. */ +#define TELNET_TELOPT_BINARY 0 +#define TELNET_TELOPT_ECHO 1 +#define TELNET_TELOPT_RCP 2 +#define TELNET_TELOPT_SGA 3 +#define TELNET_TELOPT_NAMS 4 +#define TELNET_TELOPT_STATUS 5 +#define TELNET_TELOPT_TM 6 +#define TELNET_TELOPT_RCTE 7 +#define TELNET_TELOPT_NAOL 8 +#define TELNET_TELOPT_NAOP 9 +#define TELNET_TELOPT_NAOCRD 10 +#define TELNET_TELOPT_NAOHTS 11 +#define TELNET_TELOPT_NAOHTD 12 +#define TELNET_TELOPT_NAOFFD 13 +#define TELNET_TELOPT_NAOVTS 14 +#define TELNET_TELOPT_NAOVTD 15 +#define TELNET_TELOPT_NAOLFD 16 +#define TELNET_TELOPT_XASCII 17 +#define TELNET_TELOPT_LOGOUT 18 +#define TELNET_TELOPT_BM 19 +#define TELNET_TELOPT_DET 20 +#define TELNET_TELOPT_SUPDUP 21 +#define TELNET_TELOPT_SUPDUPOUTPUT 22 +#define TELNET_TELOPT_SNDLOC 23 +#define TELNET_TELOPT_TTYPE 24 +#define TELNET_TELOPT_EOR 25 +#define TELNET_TELOPT_TUID 26 +#define TELNET_TELOPT_OUTMRK 27 +#define TELNET_TELOPT_TTYLOC 28 +#define TELNET_TELOPT_3270REGIME 29 +#define TELNET_TELOPT_X3PAD 30 +#define TELNET_TELOPT_NAWS 31 +#define TELNET_TELOPT_TSPEED 32 +#define TELNET_TELOPT_LFLOW 33 +#define TELNET_TELOPT_LINEMODE 34 +#define TELNET_TELOPT_XDISPLOC 35 +#define TELNET_TELOPT_ENVIRON 36 +#define TELNET_TELOPT_AUTHENTICATION 37 +#define TELNET_TELOPT_ENCRYPT 38 +#define TELNET_TELOPT_NEW_ENVIRON 39 +#define TELNET_TELOPT_MSSP 70 +#define TELNET_TELOPT_COMPRESS2 86 +#define TELNET_TELOPT_ZMP 93 +#define TELNET_TELOPT_EXOPL 255 + +#define TELNET_TELOPT_MCCP2 86 +/*@}*/ + +/*! \name Protocol codes for TERMINAL-TYPE commands. */ +/*@{*/ +/*! TERMINAL-TYPE codes. */ +#define TELNET_TTYPE_IS 0 +#define TELNET_TTYPE_SEND 1 +/*@}*/ + +/*! \name Protocol codes for NEW-ENVIRON/ENVIRON commands. */ +/*@{*/ +/*! NEW-ENVIRON/ENVIRON codes. */ +#define TELNET_ENVIRON_IS 0 +#define TELNET_ENVIRON_SEND 1 +#define TELNET_ENVIRON_INFO 2 +#define TELNET_ENVIRON_VAR 0 +#define TELNET_ENVIRON_VALUE 1 +#define TELNET_ENVIRON_ESC 2 +#define TELNET_ENVIRON_USERVAR 3 +/*@}*/ + +/*! \name Protocol codes for MSSP commands. */ +/*@{*/ +/*! MSSP codes. */ +#define TELNET_MSSP_VAR 1 +#define TELNET_MSSP_VAL 2 +/*@}*/ + +/*! \name Telnet state tracker flags. */ +/*@{*/ +/*! Control behavior of telnet state tracker. */ +#define TELNET_FLAG_PROXY (1<<0) + +#define TELNET_PFLAG_DEFLATE (1<<7) +/*@}*/ + +/*! + * error codes + */ +enum telnet_error_t { + TELNET_EOK = 0, /*!< no error */ + TELNET_EBADVAL, /*!< invalid parameter, or API misuse */ + TELNET_ENOMEM, /*!< memory allocation failure */ + TELNET_EOVERFLOW, /*!< data exceeds buffer size */ + TELNET_EPROTOCOL, /*!< invalid sequence of special bytes */ + TELNET_ECOMPRESS /*!< error handling compressed streams */ +}; +typedef enum telnet_error_t telnet_error_t; /*!< Error code type. */ + +/*! + * event codes + */ +enum telnet_event_type_t { + TELNET_EV_DATA = 0, /*!< raw text data has been received */ + TELNET_EV_SEND, /*!< data needs to be sent to the peer */ + TELNET_EV_IAC, /*!< generic IAC code received */ + TELNET_EV_WILL, /*!< WILL option negotiation received */ + TELNET_EV_WONT, /*!< WONT option neogitation received */ + TELNET_EV_DO, /*!< DO option negotiation received */ + TELNET_EV_DONT, /*!< DONT option negotiation received */ + TELNET_EV_SUBNEGOTIATION, /*!< sub-negotiation data received */ + TELNET_EV_COMPRESS, /*!< compression has been enabled */ + TELNET_EV_ZMP, /*!< ZMP command has been received */ + TELNET_EV_TTYPE, /*!< TTYPE command has been received */ + TELNET_EV_ENVIRON, /*!< ENVIRON command has been received */ + TELNET_EV_MSSP, /*!< MSSP command has been received */ + TELNET_EV_WARNING, /*!< recoverable error has occured */ + TELNET_EV_ERROR /*!< non-recoverable error has occured */ +}; +typedef enum telnet_event_type_t telnet_event_type_t; /*!< Telnet event type. */ + +/*! + * environ/MSSP command information + */ +struct telnet_environ_t { + unsigned char type; /*!< either TELNET_ENVIRON_VAR or TELNET_ENVIRON_USERVAR */ + char *var; /*!< name of the variable being set */ + char *value; /*!< value of variable being set; empty string if no value */ +}; + +/*! + * event information + */ +union telnet_event_t { + /*! + * \brief Event type + * + * The type field will determine which of the other event structure fields + * have been filled in. For instance, if the event type is TELNET_EV_ZMP, + * then the zmp event field (and ONLY the zmp event field) will be filled + * in. + */ + enum telnet_event_type_t type; + + /*! + * data event: for DATA and SEND events + */ + struct data_t { + enum telnet_event_type_t _type; /*!< alias for type */ + const char *buffer; /*!< byte buffer */ + size_t size; /*!< number of bytes in buffer */ + } data; + + /*! + * WARNING and ERROR events + */ + struct error_t { + enum telnet_event_type_t _type; /*!< alias for type */ + const char *file; /*!< file the error occured in */ + const char *func; /*!< function the error occured in */ + const char *msg; /*!< error message string */ + int line; /*!< line of file error occured on */ + telnet_error_t errcode; /*!< error code */ + } error; + + /*! + * command event: for IAC + */ + struct iac_t { + enum telnet_event_type_t _type; /*!< alias for type */ + unsigned char cmd; /*!< telnet command received */ + } iac; + + /*! + * negotiation event: WILL, WONT, DO, DONT + */ + struct negotiate_t { + enum telnet_event_type_t _type; /*!< alias for type */ + unsigned char telopt; /*!< option being negotiated */ + } neg; + + /*! + * subnegotiation event + */ + struct subnegotiate_t { + enum telnet_event_type_t _type; /*!< alias for type */ + const char *buffer; /*!< data of sub-negotiation */ + size_t size; /*!< number of bytes in buffer */ + unsigned char telopt; /*!< option code for negotiation */ + } sub; + + /*! + * ZMP event + */ + struct zmp_t { + enum telnet_event_type_t _type; /*!< alias for type */ + const char **argv; /*!< array of argument string */ + size_t argc; /*!< number of elements in argv */ + } zmp; + + /*! + * TTYPE event + */ + struct ttype_t { + enum telnet_event_type_t _type; /*!< alias for type */ + unsigned char cmd; /*!< TELNET_TTYPE_IS or TELNET_TTYPE_SEND */ + const char* name; /*!< terminal type name (IS only) */ + } ttype; + + /*! + * COMPRESS event + */ + struct compress_t { + enum telnet_event_type_t _type; /*!< alias for type */ + unsigned char state; /*!< 1 if compression is enabled, + 0 if disabled */ + } compress; + + /*! + * ENVIRON/NEW-ENVIRON event + */ + struct environ_t { + enum telnet_event_type_t _type; /*!< alias for type */ + const struct telnet_environ_t *values; /*!< array of variable values */ + size_t size; /*!< number of elements in values */ + unsigned char cmd; /*!< SEND, IS, or INFO */ + } environ; + + /*! + * MSSP event + */ + struct mssp_t { + enum telnet_event_type_t _type; /*!< alias for type */ + const struct telnet_environ_t *values; /*!< array of variable values */ + size_t size; /*!< number of elements in values */ + } mssp; +}; + +/*! + * \brief event handler + * + * This is the type of function that must be passed to + * telnet_init() when creating a new telnet object. The + * function will be invoked once for every event generated + * by the libtelnet protocol parser. + * + * \param telnet The telnet object that generated the event + * \param event Event structure with details about the event + * \param user_data User-supplied pointer + */ +typedef void (*telnet_event_handler_t)(telnet_t *telnet, + telnet_event_t *event, void *user_data); + +/*! + * telopt support table element; use telopt of -1 for end marker + */ +struct telnet_telopt_t { + short telopt; /*!< one of the TELOPT codes or -1 */ + unsigned char us; /*!< TELNET_WILL or TELNET_WONT */ + unsigned char him; /*!< TELNET_DO or TELNET_DONT */ +}; + +/*! + * state tracker -- private data structure + */ +struct telnet_t; + +/*! + * \brief Initialize a telnet state tracker. + * + * This function initializes a new state tracker, which is used for all + * other libtelnet functions. Each connection must have its own + * telnet state tracker object. + * + * \param telopts Table of TELNET options the application supports. + * \param eh Event handler function called for every event. + * \param flags 0 or TELNET_FLAG_PROXY. + * \param user_data Optional data pointer that will be passsed to eh. + * \return Telent state tracker object. + */ +extern telnet_t* telnet_init(const telnet_telopt_t *telopts, + telnet_event_handler_t eh, unsigned char flags, void *user_data); + +/*! + * \brief Free up any memory allocated by a state tracker. + * + * This function must be called when a telnet state tracker is no + * longer needed (such as after the connection has been closed) to + * release any memory resources used by the state tracker. + * + * \param telnet Telnet state tracker object. + */ +extern void telnet_free(telnet_t *telnet); + +/*! + * \brief Push a byte buffer into the state tracker. + * + * Passes one or more bytes to the telnet state tracker for + * protocol parsing. The byte buffer is most often going to be + * the buffer that recv() was called for while handling the + * connection. + * + * \param telnet Telnet state tracker object. + * \param buffer Pointer to byte buffer. + * \param size Number of bytes pointed to by buffer. + */ +extern void telnet_recv(telnet_t *telnet, const char *buffer, + size_t size); + +/*! + * \brief Send a telnet command. + * + * \param telnet Telnet state tracker object. + * \param cmd Command to send. + */ +extern void telnet_iac(telnet_t *telnet, unsigned char cmd); + +/*! + * \brief Send negotiation command. + * + * Internally, libtelnet uses RFC1143 option negotiation rules. + * The negotiation commands sent with this function may be ignored + * if they are determined to be redundant. + * + * \param telnet Telnet state tracker object. + * \param cmd TELNET_WILL, TELNET_WONT, TELNET_DO, or TELNET_DONT. + * \param opt One of the TELNET_TELOPT_* values. + */ +extern void telnet_negotiate(telnet_t *telnet, unsigned char cmd, + unsigned char opt); + +/*! + * Send non-command data (escapes IAC bytes). + * + * \param telnet Telnet state tracker object. + * \param buffer Buffer of bytes to send. + * \param size Number of bytes to send. + */ +extern void telnet_send(telnet_t *telnet, + const char *buffer, size_t size); + +/*! + * \brief Begin a sub-negotiation command. + * + * Sends IAC SB followed by the telopt code. All following data sent + * will be part of the sub-negotiation, until telnet_finish_sb() is + * called. + * + * \param telnet Telnet state tracker object. + * \param telopt One of the TELNET_TELOPT_* values. + */ +extern void telnet_begin_sb(telnet_t *telnet, + unsigned char telopt); + +/*! + * \brief Finish a sub-negotiation command. + * + * This must be called after a call to telnet_begin_sb() to finish a + * sub-negotiation command. + * + * \param telnet Telnet state tracker object. + */ +#define telnet_finish_sb(telnet) telnet_iac((telnet), TELNET_SE) + +/*! + * \brief Shortcut for sending a complete subnegotiation buffer. + * + * Equivalent to: + * telnet_begin_sb(telnet, telopt); + * telnet_send(telnet, buffer, size); + * telnet_finish_sb(telnet); + * + * \param telnet Telnet state tracker format. + * \param telopt One of the TELNET_TELOPT_* values. + * \param buffer Byte buffer for sub-negotiation data. + * \param size Number of bytes to use for sub-negotiation data. + */ +extern void telnet_subnegotiation(telnet_t *telnet, unsigned char telopt, + const char *buffer, size_t size); + +/*! + * \brief Begin sending compressed data. + * + * This function will begein sending data using the COMPRESS2 option, + * which enables the use of zlib to compress data sent to the client. + * The client must offer support for COMPRESS2 with option negotiation, + * and zlib support must be compiled into libtelnet. + * + * Only the server may call this command. + * + * \param telnet Telnet state tracker object. + */ +extern void telnet_begin_compress2(telnet_t *telnet); + +/*! + * \brief Send formatted data. + * + * This function is a wrapper around telnet_send(). It allows using + * printf-style formatting. + * + * Additionally, this function will translate \\r to the CR NUL construct and + * \\n with CR LF, as well as automatically escaping IAC bytes like + * telnet_send(). + * + * \param telnet Telnet state tracker object. + * \param fmt Format string. + * \return Number of bytes sent. + */ +extern int telnet_printf(telnet_t *telnet, const char *fmt, ...) + TELNET_GNU_PRINTF(2, 3); + +/*! + * \brief Send formatted data. + * + * See telnet_printf(). + */ +extern int telnet_vprintf(telnet_t *telnet, const char *fmt, va_list va); + +/*! + * \brief Send formatted data (no newline escaping). + * + * This behaves identically to telnet_printf(), except that the \\r and \\n + * characters are not translated. The IAC byte is still escaped as normal + * with telnet_send(). + * + * \param telnet Telnet state tracker object. + * \param fmt Format string. + * \return Number of bytes sent. + */ +extern int telnet_raw_printf(telnet_t *telnet, const char *fmt, ...) + TELNET_GNU_PRINTF(2, 3); + +/*! + * \brief Send formatted data (no newline escaping). + * + * See telnet_raw_printf(). + */ +extern int telnet_raw_vprintf(telnet_t *telnet, const char *fmt, va_list va); + +/*! + * \brief Begin a new set of NEW-ENVIRON values to request or send. + * + * This function will begin the sub-negotiation block for sending or + * requesting NEW-ENVIRON values. + * + * The telnet_finish_newenviron() macro must be called after this + * function to terminate the NEW-ENVIRON command. + * + * \param telnet Telnet state tracker object. + * \param type One of TELNET_ENVIRON_SEND, TELNET_ENVIRON_IS, or + * TELNET_ENVIRON_INFO. + */ +extern void telnet_begin_newenviron(telnet_t *telnet, unsigned char type); + +/*! + * \brief Send a NEW-ENVIRON variable name or value. + * + * This can only be called between calls to telnet_begin_newenviron() and + * telnet_finish_newenviron(). + * + * \param telnet Telnet state tracker object. + * \param type One of TELNET_ENVIRON_VAR, TELNET_ENVIRON_USERVAR, or + * TELNET_ENVIRON_VALUE. + * \param string Variable name or value. + */ +extern void telnet_newenviron_value(telnet_t* telnet, unsigned char type, + const char *string); + +/*! + * \brief Finish a NEW-ENVIRON command. + * + * This must be called after a call to telnet_begin_newenviron() to finish a + * NEW-ENVIRON variable list. + * + * \param telnet Telnet state tracker object. + */ +#define telnet_finish_newenviron(telnet) telnet_finish_sb((telnet)) + +/*! + * \brief Send the TERMINAL-TYPE SEND command. + * + * Sends the sequence IAC TERMINAL-TYPE SEND. + * + * \param telnet Telnet state tracker object. + */ +extern void telnet_ttype_send(telnet_t *telnet); + +/*! + * \brief Send the TERMINAL-TYPE IS command. + * + * Sends the sequence IAC TERMINAL-TYPE IS "string". + * + * According to the RFC, the recipient of a TERMINAL-TYPE SEND shall + * send the next possible terminal-type the client supports. Upon sending + * the type, the client should switch modes to begin acting as the terminal + * type is just sent. + * + * The server may continue sending TERMINAL-TYPE IS until it receives a + * terminal type is understands. To indicate to the server that it has + * reached the end of the available optoins, the client must send the last + * terminal type a second time. When the server receives the same terminal + * type twice in a row, it knows it has seen all available terminal types. + * + * After the last terminal type is sent, if the client receives another + * TERMINAL-TYPE SEND command, it must begin enumerating the available + * terminal types from the very beginning. This allows the server to + * scan the available types for a preferred terminal type and, if none + * is found, to then ask the client to switch to an acceptable + * alternative. + * + * Note that if the client only supports a single terminal type, then + * simply sending that one type in response to every SEND will satisfy + * the behavior requirements. + * + * \param telnet Telnet state tracker object. + * \param ttype Name of the terminal-type being sent. + */ +extern void telnet_ttype_is(telnet_t *telnet, const char* ttype); + +/*! + * \brief Send a ZMP command. + * + * \param telnet Telnet state tracker object. + * \param argc Number of ZMP commands being sent. + * \param argv Array of argument strings. + */ +extern void telnet_send_zmp(telnet_t *telnet, size_t argc, const char **argv); + +/*! + * \brief Send a ZMP command. + * + * Arguments are listed out in var-args style. After the last argument, a + * NULL pointer must be passed in as a sentinel value. + * + * \param telnet Telnet state tracker object. + */ +extern void telnet_send_zmpv(telnet_t *telnet, ...) TELNET_GNU_SENTINEL; + +/*! + * \brief Send a ZMP command. + * + * See telnet_send_zmpv(). + */ +extern void telnet_send_vzmpv(telnet_t *telnet, va_list va); + +/*! + * \brief Begin sending a ZMP command + * + * \param telnet Telnet state tracker object. + * \param cmd The first argument (command name) for the ZMP command. + */ +extern void telnet_begin_zmp(telnet_t *telnet, const char *cmd); + +/*! + * \brief Send a ZMP command argument. + * + * \param telnet Telnet state tracker object. + * \param arg Telnet argument string. + */ +extern void telnet_zmp_arg(telnet_t *telnet, const char *arg); + +/*! + * \brief Finish a ZMP command. + * + * This must be called after a call to telnet_begin_zmp() to finish a + * ZMP argument list. + * + * \param telnet Telnet state tracker object. + */ +#define telnet_finish_zmp(telnet) telnet_finish_sb((telnet)) + +/* C++ support */ +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /* !defined(LIBTELNET_INCLUDE) */ diff --git a/external/CppMicroServices/third_party/linenoise.c b/external/CppMicroServices/third_party/linenoise.c new file mode 100644 index 00000000..2129a858 --- /dev/null +++ b/external/CppMicroServices/third_party/linenoise.c @@ -0,0 +1,1635 @@ +/* linenoise.c -- guerrilla line editing library against the idea that a + * line editing lib needs to be 20,000 lines of C code. + * + * You can find the latest source code at: + * + * http://github.com/msteveb/linenoise + * (forked from http://github.com/antirez/linenoise) + * + * Does a number of crazy assumptions that happen to be true in 99.9999% of + * the 2010 UNIX computers around. + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2010, Salvatore Sanfilippo + * Copyright (c) 2010, Pieter Noordhuis + * Copyright (c) 2011, Steve Bennett + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ------------------------------------------------------------------------ + * + * References: + * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html + * + * Bloat: + * - Completion? + * + * Unix/termios + * ------------ + * List of escape sequences used by this program, we do everything just + * a few sequences. In order to be so cheap we may have some + * flickering effect with some slow terminal, but the lesser sequences + * the more compatible. + * + * EL (Erase Line) + * Sequence: ESC [ n K + * Effect: if n is 0 or missing, clear from cursor to end of line + * Effect: if n is 1, clear from beginning of line to cursor + * Effect: if n is 2, clear entire line + * + * CUF (CUrsor Forward) + * Sequence: ESC [ n C + * Effect: moves cursor forward of n chars + * + * CR (Carriage Return) + * Sequence: \r + * Effect: moves cursor to column 1 + * + * The following are used to clear the screen: ESC [ H ESC [ 2 J + * This is actually composed of two sequences: + * + * cursorhome + * Sequence: ESC [ H + * Effect: moves the cursor to upper left corner + * + * ED2 (Clear entire screen) + * Sequence: ESC [ 2 J + * Effect: clear the whole screen + * + * == For highlighting control characters, we also use the following two == + * SO (enter StandOut) + * Sequence: ESC [ 7 m + * Effect: Uses some standout mode such as reverse video + * + * SE (Standout End) + * Sequence: ESC [ 0 m + * Effect: Exit standout mode + * + * == Only used if TIOCGWINSZ fails == + * DSR/CPR (Report cursor position) + * Sequence: ESC [ 6 n + * Effect: reports current cursor position as ESC [ NNN ; MMM R + * + * win32/console + * ------------- + * If __MINGW32__ is defined, the win32 console API is used. + * This could probably be made to work for the msvc compiler too. + * This support based in part on work by Jon Griffiths. + */ + +#ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */ +#include +#include +#define USE_WINCONSOLE +#ifdef __MINGW32__ +#define HAVE_UNISTD_H +#else +/* Microsoft headers don't like old POSIX names */ +#define strdup _strdup +#if _MSC_VER < 1900 +#define snprintf _snprintf +#endif +#endif +#pragma warning( disable : 4244 4267 ) +#else +#include +#include +#include +#define USE_TERMIOS +#define HAVE_UNISTD_H +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "linenoise.h" + +/* No utf-8 support. 1 byte = 1 char */ +#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B)) +#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1) +#define utf8_index(C, I) (I) +#define utf8_charlen(C) 1 + +//#include "utf8.h" + +#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 +#define LINENOISE_MAX_LINE 4096 + +#define ctrl(C) ((C) - '@') + +/* Use -ve numbers here to co-exist with normal unicode chars */ +enum { + SPECIAL_NONE, + SPECIAL_UP = -20, + SPECIAL_DOWN = -21, + SPECIAL_LEFT = -22, + SPECIAL_RIGHT = -23, + SPECIAL_DELETE = -24, + SPECIAL_HOME = -25, + SPECIAL_END = -26, + SPECIAL_INSERT = -27, + SPECIAL_PAGE_UP = -28, + SPECIAL_PAGE_DOWN = -29 +}; + +static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; +static int history_len = 0; +static char **history = NULL; + +/* Structure to contain the status of the current (being edited) line */ +struct current { + char *buf; /* Current buffer. Always null terminated */ + int bufmax; /* Size of the buffer, including space for the null termination */ + int len; /* Number of bytes in 'buf' */ + int chars; /* Number of chars in 'buf' (utf-8 chars) */ + int pos; /* Cursor position, measured in chars */ + int cols; /* Size of the window, in chars */ + const char *prompt; + char *capture; /* Allocated capture buffer, or NULL for none. Always null terminated */ +#if defined(USE_TERMIOS) + int fd; /* Terminal fd */ +#elif defined(USE_WINCONSOLE) + HANDLE outh; /* Console output handle */ + HANDLE inh; /* Console input handle */ + int rows; /* Screen rows */ + int x; /* Current column during output */ + int y; /* Current row */ +#endif +}; + +static int fd_read(struct current *current); +static int getWindowSize(struct current *current); + +void linenoiseHistoryFree(void) { + if (history) { + int j; + + for (j = 0; j < history_len; j++) + free(history[j]); + free(history); + history = NULL; + history_len = 0; + } +} + +#if defined(USE_TERMIOS) +static void linenoiseAtExit(void); +static struct termios orig_termios; /* in order to restore at exit */ +static int rawmode = 0; /* for atexit() function to check if restore is needed*/ +static int atexit_registered = 0; /* register atexit just 1 time */ + +static const char *unsupported_term[] = {"dumb","cons25",NULL}; + +static int isUnsupportedTerm(void) { + char *term = getenv("TERM"); + + if (term) { + int j; + for (j = 0; unsupported_term[j]; j++) { + if (strcmp(term, unsupported_term[j]) == 0) { + return 1; + } + } + } + return 0; +} + +static int enableRawMode(struct current *current) { + struct termios raw; + + current->fd = STDIN_FILENO; + current->cols = 0; + + if (!isatty(current->fd) || isUnsupportedTerm() || + tcgetattr(current->fd, &orig_termios) == -1) { +fatal: + errno = ENOTTY; + return -1; + } + + if (!atexit_registered) { + atexit(linenoiseAtExit); + atexit_registered = 1; + } + + raw = orig_termios; /* modify the original mode */ + /* input modes: no break, no CR to NL, no parity check, no strip char, + * no start/stop output control. */ + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + /* output modes - disable post processing */ + raw.c_oflag &= ~(OPOST); + /* control modes - set 8 bit chars */ + raw.c_cflag |= (CS8); + /* local modes - choing off, canonical off, no extended functions, + * no signal chars (^Z,^C) */ + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + /* control chars - set return condition: min number of bytes and timer. + * We want read to return every single byte, without timeout. */ + raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ + + /* put terminal in raw mode after flushing */ + if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) { + goto fatal; + } + rawmode = 1; + return 0; +} + +static void disableRawMode(struct current *current) { + /* Don't even check the return value as it's too late. */ + if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1) + rawmode = 0; +} + +/* At exit we'll try to fix the terminal to the initial conditions. */ +static void linenoiseAtExit(void) { + if (rawmode) { + tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios); + } + linenoiseHistoryFree(); +} + +/* gcc/glibc insists that we care about the return code of write! + * Clarification: This means that a void-cast like "(void) (EXPR)" + * does not work. + */ +#define IGNORE_RC(EXPR) if (EXPR) {} + +/* This is fdprintf() on some systems, but use a different + * name to avoid conflicts + */ +static void fd_printf(int fd, const char *format, ...) +{ + va_list args; + char buf[64]; + int n; + + va_start(args, format); + n = vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + IGNORE_RC(write(fd, buf, n)); +} + +static void clearScreen(struct current *current) +{ + fd_printf(current->fd, "\x1b[H\x1b[2J"); +} + +static void cursorToLeft(struct current *current) +{ + fd_printf(current->fd, "\r"); +} + +static int outputChars(struct current *current, const char *buf, int len) +{ + return write(current->fd, buf, len); +} + +static void outputControlChar(struct current *current, char ch) +{ + fd_printf(current->fd, "\x1b[7m^%c\x1b[0m", ch); +} + +static void eraseEol(struct current *current) +{ + fd_printf(current->fd, "\x1b[0K"); +} + +static void setCursorPos(struct current *current, int x) +{ + fd_printf(current->fd, "\r\x1b[%dC", x); +} + +/** + * Reads a char from 'fd', waiting at most 'timeout' milliseconds. + * + * A timeout of -1 means to wait forever. + * + * Returns -1 if no char is received within the time or an error occurs. + */ +static int fd_read_char(int fd, int timeout) +{ + struct pollfd p; + unsigned char c; + + p.fd = fd; + p.events = POLLIN; + + if (poll(&p, 1, timeout) == 0) { + /* timeout */ + return -1; + } + if (read(fd, &c, 1) != 1) { + return -1; + } + return c; +} + +/** + * Reads a complete utf-8 character + * and returns the unicode value, or -1 on error. + */ +static int fd_read(struct current *current) +{ +#ifdef USE_UTF8 + char buf[4]; + int n; + int i; + int c; + + if (read(current->fd, &buf[0], 1) != 1) { + return -1; + } + n = utf8_charlen(buf[0]); + if (n < 1 || n > 3) { + return -1; + } + for (i = 1; i < n; i++) { + if (read(current->fd, &buf[i], 1) != 1) { + return -1; + } + } + buf[n] = 0; + /* decode and return the character */ + utf8_tounicode(buf, &c); + return c; +#else + return fd_read_char(current->fd, -1); +#endif +} + +static int countColorControlChars(const char* prompt) +{ + /* ANSI color control sequences have the form: + * "\x1b" "[" [0-9;]* "m" + * We parse them with a simple state machine. + */ + + enum { + search_esc, + expect_bracket, + expect_trail + } state = search_esc; + int len = 0, found = 0; + char ch; + + /* XXX: Strictly we should be checking utf8 chars rather than + * bytes in case of the extremely unlikely scenario where + * an ANSI sequence is part of a utf8 sequence. + */ + while ((ch = *prompt++) != 0) { + switch (state) { + case search_esc: + if (ch == '\x1b') { + state = expect_bracket; + } + break; + case expect_bracket: + if (ch == '[') { + state = expect_trail; + /* 3 for "\e[ ... m" */ + len = 3; + break; + } + state = search_esc; + break; + case expect_trail: + if ((ch == ';') || ((ch >= '0' && ch <= '9'))) { + /* 0-9, or semicolon */ + len++; + break; + } + if (ch == 'm') { + found += len; + } + state = search_esc; + break; + } + } + + return found; +} + +/** + * Stores the current cursor column in '*cols'. + * Returns 1 if OK, or 0 if failed to determine cursor pos. + */ +static int queryCursor(int fd, int* cols) +{ + /* control sequence - report cursor location */ + fd_printf(fd, "\x1b[6n"); + + /* Parse the response: ESC [ rows ; cols R */ + if (fd_read_char(fd, 100) == 0x1b && + fd_read_char(fd, 100) == '[') { + + int n = 0; + while (1) { + int ch = fd_read_char(fd, 100); + if (ch == ';') { + /* Ignore rows */ + n = 0; + } + else if (ch == 'R') { + /* Got cols */ + if (n != 0 && n < 1000) { + *cols = n; + } + break; + } + else if (ch >= 0 && ch <= '9') { + n = n * 10 + ch - '0'; + } + else { + break; + } + } + return 1; + } + + return 0; +} + +/** + * Updates current->cols with the current window size (width) + */ +static int getWindowSize(struct current *current) +{ + struct winsize ws; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) { + current->cols = ws.ws_col; + return 0; + } + + /* Failed to query the window size. Perhaps we are on a serial terminal. + * Try to query the width by sending the cursor as far to the right + * and reading back the cursor position. + * Note that this is only done once per call to linenoise rather than + * every time the line is refreshed for efficiency reasons. + * + * In more detail, we: + * (a) request current cursor position, + * (b) move cursor far right, + * (c) request cursor position again, + * (d) at last move back to the old position. + * This gives us the width without messing with the externally + * visible cursor position. + */ + + if (current->cols == 0) { + int here; + + current->cols = 80; + + /* (a) */ + if (queryCursor (current->fd, &here)) { + /* (b) */ + fd_printf(current->fd, "\x1b[999C"); + + /* (c). Note: If (a) succeeded, then (c) should as well. + * For paranoia we still check and have a fallback action + * for (d) in case of failure.. + */ + if (!queryCursor (current->fd, ¤t->cols)) { + /* (d') Unable to get accurate position data, reset + * the cursor to the far left. While this may not + * restore the exact original position it should not + * be too bad. + */ + fd_printf(current->fd, "\r"); + } else { + /* (d) Reset the cursor back to the original location. */ + if (current->cols > here) { + fd_printf(current->fd, "\x1b[%dD", current->cols - here); + } + } + } /* 1st query failed, doing nothing => default 80 */ + } + + return 0; +} + +/** + * If escape (27) was received, reads subsequent + * chars to determine if this is a known special key. + * + * Returns SPECIAL_NONE if unrecognised, or -1 if EOF. + * + * If no additional char is received within a short time, + * 27 is returned. + */ +static int check_special(int fd) +{ + int c = fd_read_char(fd, 50); + int c2; + + if (c < 0) { + return 27; + } + + c2 = fd_read_char(fd, 50); + if (c2 < 0) { + return c2; + } + if (c == '[' || c == 'O') { + /* Potential arrow key */ + switch (c2) { + case 'A': + return SPECIAL_UP; + case 'B': + return SPECIAL_DOWN; + case 'C': + return SPECIAL_RIGHT; + case 'D': + return SPECIAL_LEFT; + case 'F': + return SPECIAL_END; + case 'H': + return SPECIAL_HOME; + } + } + if (c == '[' && c2 >= '1' && c2 <= '8') { + /* extended escape */ + c = fd_read_char(fd, 50); + if (c == '~') { + switch (c2) { + case '2': + return SPECIAL_INSERT; + case '3': + return SPECIAL_DELETE; + case '5': + return SPECIAL_PAGE_UP; + case '6': + return SPECIAL_PAGE_DOWN; + case '7': + return SPECIAL_HOME; + case '8': + return SPECIAL_END; + } + } + while (c != -1 && c != '~') { + /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */ + c = fd_read_char(fd, 50); + } + } + + return SPECIAL_NONE; +} +#elif defined(USE_WINCONSOLE) + +static DWORD orig_consolemode = 0; + +static int enableRawMode(struct current *current) { + DWORD n; + INPUT_RECORD irec; + + current->outh = GetStdHandle(STD_OUTPUT_HANDLE); + current->inh = GetStdHandle(STD_INPUT_HANDLE); + + if (!PeekConsoleInput(current->inh, &irec, 1, &n)) { + return -1; + } + if (getWindowSize(current) != 0) { + return -1; + } + if (GetConsoleMode(current->inh, &orig_consolemode)) { + SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT); + } + return 0; +} + +static void disableRawMode(struct current *current) +{ + SetConsoleMode(current->inh, orig_consolemode); +} + +static void clearScreen(struct current *current) +{ + COORD topleft = { 0, 0 }; + DWORD n; + + FillConsoleOutputCharacter(current->outh, ' ', + current->cols * current->rows, topleft, &n); + FillConsoleOutputAttribute(current->outh, + FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, + current->cols * current->rows, topleft, &n); + SetConsoleCursorPosition(current->outh, topleft); +} + +static void cursorToLeft(struct current *current) +{ + COORD pos = { 0, (SHORT)current->y }; + DWORD n; + + FillConsoleOutputAttribute(current->outh, + FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n); + current->x = 0; +} + +static int outputChars(struct current *current, const char *buf, int len) +{ + COORD pos = { (SHORT)current->x, (SHORT)current->y }; + DWORD n; + + WriteConsoleOutputCharacter(current->outh, buf, len, pos, &n); + current->x += len; + return 0; +} + +static void outputControlChar(struct current *current, char ch) +{ + COORD pos = { (SHORT)current->x, (SHORT)current->y }; + DWORD n; + + FillConsoleOutputAttribute(current->outh, BACKGROUND_INTENSITY, 2, pos, &n); + outputChars(current, "^", 1); + outputChars(current, &ch, 1); +} + +static void eraseEol(struct current *current) +{ + COORD pos = { (SHORT)current->x, (SHORT)current->y }; + DWORD n; + + FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n); +} + +static void setCursorPos(struct current *current, int x) +{ + COORD pos = { (SHORT)x, (SHORT)current->y }; + + SetConsoleCursorPosition(current->outh, pos); + current->x = x; +} + +static int fd_read(struct current *current) +{ + while (1) { + INPUT_RECORD irec; + DWORD n; + if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) { + break; + } + if (!ReadConsoleInput (current->inh, &irec, 1, &n)) { + break; + } + if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown) { + KEY_EVENT_RECORD *k = &irec.Event.KeyEvent; + if (k->dwControlKeyState & ENHANCED_KEY) { + switch (k->wVirtualKeyCode) { + case VK_LEFT: + return SPECIAL_LEFT; + case VK_RIGHT: + return SPECIAL_RIGHT; + case VK_UP: + return SPECIAL_UP; + case VK_DOWN: + return SPECIAL_DOWN; + case VK_INSERT: + return SPECIAL_INSERT; + case VK_DELETE: + return SPECIAL_DELETE; + case VK_HOME: + return SPECIAL_HOME; + case VK_END: + return SPECIAL_END; + case VK_PRIOR: + return SPECIAL_PAGE_UP; + case VK_NEXT: + return SPECIAL_PAGE_DOWN; + } + } + /* Note that control characters are already translated in AsciiChar */ + else if (k->wVirtualKeyCode == VK_CONTROL) + continue; + else { +#ifdef USE_UTF8 + return k->uChar.UnicodeChar; +#else + return k->uChar.AsciiChar; +#endif + } + } + } + return -1; +} + +static int countColorControlChars(const char* prompt) +{ + /* For windows we assume that there are no embedded ansi color + * control sequences. + */ + return 0; +} + +static int getWindowSize(struct current *current) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(current->outh, &info)) { + return -1; + } + current->cols = info.dwSize.X; + current->rows = info.dwSize.Y; + if (current->cols <= 0 || current->rows <= 0) { + current->cols = 80; + return -1; + } + current->y = info.dwCursorPosition.Y; + current->x = info.dwCursorPosition.X; + return 0; +} +#endif + +static int utf8_getchars(char *buf, int c) +{ +#ifdef USE_UTF8 + return utf8_fromunicode(buf, c); +#else + *buf = c; + return 1; +#endif +} + +/** + * Returns the unicode character at the given offset, + * or -1 if none. + */ +static int get_char(struct current *current, int pos) +{ + if (pos >= 0 && pos < current->chars) { + int c; + int i = utf8_index(current->buf, pos); + (void)utf8_tounicode(current->buf + i, &c); + return c; + } + return -1; +} + +static void refreshLine(const char *prompt, struct current *current) +{ + int plen; + int pchars; + int backup = 0; + int i; + const char *buf = current->buf; + int chars = current->chars; + int pos = current->pos; + int b; + int ch; + int n; + + /* Should intercept SIGWINCH. For now, just get the size every time */ + getWindowSize(current); + + plen = strlen(prompt); + pchars = utf8_strlen(prompt, plen); + + /* Scan the prompt for embedded ansi color control sequences and + * discount them as characters/columns. + */ + pchars -= countColorControlChars(prompt); + + /* Account for a line which is too long to fit in the window. + * Note that control chars require an extra column + */ + + /* How many cols are required to the left of 'pos'? + * The prompt, plus one extra for each control char + */ + n = pchars + utf8_strlen(buf, current->len); + b = 0; + for (i = 0; i < pos; i++) { + b += utf8_tounicode(buf + b, &ch); + if (ch < ' ') { + n++; + } + } + + /* If too many are needed, strip chars off the front of 'buf' + * until it fits. Note that if the current char is a control character, + * we need one extra col. + */ + if (current->pos < current->chars && get_char(current, current->pos) < ' ') { + n++; + } + + while (n >= current->cols && pos > 0) { + b = utf8_tounicode(buf, &ch); + if (ch < ' ') { + n--; + } + n--; + buf += b; + pos--; + chars--; + } + + /* Cursor to left edge, then the prompt */ + cursorToLeft(current); + outputChars(current, prompt, plen); + + /* Now the current buffer content */ + + /* Need special handling for control characters. + * If we hit 'cols', stop. + */ + b = 0; /* unwritted bytes */ + n = 0; /* How many control chars were written */ + for (i = 0; i < chars; i++) { + int ch; + int w = utf8_tounicode(buf + b, &ch); + if (ch < ' ') { + n++; + } + if (pchars + i + n >= current->cols) { + break; + } + if (ch < ' ') { + /* A control character, so write the buffer so far */ + outputChars(current, buf, b); + buf += b + w; + b = 0; + outputControlChar(current, ch + '@'); + if (i < pos) { + backup++; + } + } + else { + b += w; + } + } + outputChars(current, buf, b); + + /* Erase to right, move cursor to original position */ + eraseEol(current); + setCursorPos(current, pos + pchars + backup); +} + +static void set_current(struct current *current, const char *str) +{ + strncpy(current->buf, str, current->bufmax); + current->buf[current->bufmax - 1] = 0; + current->len = strlen(current->buf); + current->pos = current->chars = utf8_strlen(current->buf, current->len); +} + +static int has_room(struct current *current, int bytes) +{ + return current->len + bytes < current->bufmax - 1; +} + +/** + * Removes the char at 'pos'. + * + * Returns 1 if the line needs to be refreshed, 2 if not + * and 0 if nothing was removed + */ +static int remove_char(struct current *current, int pos) +{ + if (pos >= 0 && pos < current->chars) { + int p1, p2; + int ret = 1; + p1 = utf8_index(current->buf, pos); + p2 = p1 + utf8_index(current->buf + p1, 1); + +#ifdef USE_TERMIOS + /* optimise remove char in the case of removing the last char */ + if (current->pos == pos + 1 && current->pos == current->chars) { + if (current->buf[pos] >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) { + ret = 2; + fd_printf(current->fd, "\b \b"); + } + } +#endif + + /* Move the null char too */ + memmove(current->buf + p1, current->buf + p2, current->len - p2 + 1); + current->len -= (p2 - p1); + current->chars--; + + if (current->pos > pos) { + current->pos--; + } + return ret; + } + return 0; +} + +/** + * Insert 'ch' at position 'pos' + * + * Returns 1 if the line needs to be refreshed, 2 if not + * and 0 if nothing was inserted (no room) + */ +static int insert_char(struct current *current, int pos, int ch) +{ + char buf[3]; + int n = utf8_getchars(buf, ch); + + if (has_room(current, n) && pos >= 0 && pos <= current->chars) { + int p1, p2; + int ret = 1; + p1 = utf8_index(current->buf, pos); + p2 = p1 + n; + +#ifdef USE_TERMIOS + /* optimise the case where adding a single char to the end and no scrolling is needed */ + if (current->pos == pos && current->chars == pos) { + if (ch >= ' ' && utf8_strlen(current->prompt, -1) + utf8_strlen(current->buf, current->len) < current->cols - 1) { + IGNORE_RC(write(current->fd, buf, n)); + ret = 2; + } + } +#endif + + memmove(current->buf + p2, current->buf + p1, current->len - p1); + memcpy(current->buf + p1, buf, n); + current->len += n; + + current->chars++; + if (current->pos >= pos) { + current->pos++; + } + return ret; + } + return 0; +} + +/** + * Captures up to 'n' characters starting at 'pos' for the cut buffer. + * + * This replaces any existing characters in the cut buffer. + */ +static void capture_chars(struct current *current, int pos, int n) +{ + if (pos >= 0 && (pos + n - 1) < current->chars) { + int p1 = utf8_index(current->buf, pos); + int nbytes = utf8_index(current->buf + p1, n); + + if (nbytes) { + free(current->capture); + /* Include space for the null terminator */ + current->capture = (char *)malloc(nbytes + 1); + memcpy(current->capture, current->buf + p1, nbytes); + current->capture[nbytes] = '\0'; + } + } +} + +/** + * Removes up to 'n' characters at cursor position 'pos'. + * + * Returns 0 if no chars were removed or non-zero otherwise. + */ +static int remove_chars(struct current *current, int pos, int n) +{ + int removed = 0; + + /* First save any chars which will be removed */ + capture_chars(current, pos, n); + + while (n-- && remove_char(current, pos)) { + removed++; + } + return removed; +} +/** + * Inserts the characters (string) 'chars' at the cursor position 'pos'. + * + * Returns 0 if no chars were inserted or non-zero otherwise. + */ +static int insert_chars(struct current *current, int pos, const char *chars) +{ + int inserted = 0; + + while (*chars) { + int ch; + int n = utf8_tounicode(chars, &ch); + if (insert_char(current, pos, ch) == 0) { + break; + } + inserted++; + pos++; + chars += n; + } + return inserted; +} + +#ifndef NO_COMPLETION +static linenoiseCompletionCallback *completionCallback = NULL; + +static void beep() { +#ifdef USE_TERMIOS + fprintf(stderr, "\x7"); + fflush(stderr); +#endif +} + +static void freeCompletions(linenoiseCompletions *lc) { + size_t i; + for (i = 0; i < lc->len; i++) + free(lc->cvec[i]); + free(lc->cvec); +} + +static int completeLine(struct current *current) { + linenoiseCompletions lc = { 0, NULL }; + int c = 0; + + completionCallback(current->buf,&lc); + if (lc.len == 0) { + beep(); + } else { + size_t stop = 0, i = 0; + + while(!stop) { + /* Show completion or original buffer */ + if (i < lc.len) { + struct current tmp = *current; + tmp.buf = lc.cvec[i]; + tmp.pos = tmp.len = strlen(tmp.buf); + tmp.chars = utf8_strlen(tmp.buf, tmp.len); + refreshLine(current->prompt, &tmp); + } else { + refreshLine(current->prompt, current); + } + + c = fd_read(current); + if (c == -1) { + break; + } + + switch(c) { + case '\t': /* tab */ + i = (i+1) % (lc.len+1); + if (i == lc.len) beep(); + break; + case 27: /* escape */ + /* Re-show original buffer */ + if (i < lc.len) { + refreshLine(current->prompt, current); + } + stop = 1; + break; + default: + /* Update buffer and return */ + if (i < lc.len) { + set_current(current,lc.cvec[i]); + } + stop = 1; + break; + } + } + } + + freeCompletions(&lc); + return c; /* Return last read character */ +} + +/* Register a callback function to be called for tab-completion. + Returns the prior callback so that the caller may (if needed) + restore it when done. */ +linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { + linenoiseCompletionCallback * old = completionCallback; + completionCallback = fn; + return old; +} + +void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) { + lc->cvec = (char **)realloc(lc->cvec,sizeof(char*)*(lc->len+1)); + lc->cvec[lc->len++] = strdup(str); +} + +#endif + +static int linenoiseEdit(struct current *current) { + int history_index = 0; + + /* The latest history entry is always our current buffer, that + * initially is just an empty string. */ + linenoiseHistoryAdd(""); + + set_current(current, ""); + refreshLine(current->prompt, current); + + while(1) { + int dir = -1; + int c = fd_read(current); + +#ifndef NO_COMPLETION + /* Only autocomplete when the callback is set. It returns < 0 when + * there was an error reading from fd. Otherwise it will return the + * character that should be handled next. */ + if (c == '\t' && current->pos == current->chars && completionCallback != NULL) { + c = completeLine(current); + /* Return on errors */ + if (c < 0) return current->len; + /* Read next character when 0 */ + if (c == 0) continue; + } +#endif + +process_char: + if (c == -1) return current->len; +#ifdef USE_TERMIOS + if (c == 27) { /* escape sequence */ + c = check_special(current->fd); + } +#endif + switch(c) { + case '\r': /* enter */ + history_len--; + free(history[history_len]); + return current->len; + case ctrl('C'): /* ctrl-c */ + errno = EAGAIN; + return -1; + case 127: /* backspace */ + case ctrl('H'): + if (remove_char(current, current->pos - 1) == 1) { + refreshLine(current->prompt, current); + } + break; + case ctrl('D'): /* ctrl-d */ + if (current->len == 0) { + /* Empty line, so EOF */ + history_len--; + free(history[history_len]); + return -1; + } + /* Otherwise fall through to delete char to right of cursor */ + case SPECIAL_DELETE: + if (remove_char(current, current->pos) == 1) { + refreshLine(current->prompt, current); + } + break; + case SPECIAL_INSERT: + /* Ignore. Expansion Hook. + * Future possibility: Toggle Insert/Overwrite Modes + */ + break; + case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */ + /* eat any spaces on the left */ + { + int pos = current->pos; + while (pos > 0 && get_char(current, pos - 1) == ' ') { + pos--; + } + + /* now eat any non-spaces on the left */ + while (pos > 0 && get_char(current, pos - 1) != ' ') { + pos--; + } + + if (remove_chars(current, pos, current->pos - pos)) { + refreshLine(current->prompt, current); + } + } + break; + case ctrl('R'): /* ctrl-r */ + { + /* Display the reverse-i-search prompt and process chars */ + char rbuf[50]; + char rprompt[80]; + int rchars = 0; + int rlen = 0; + int searchpos = history_len - 1; + + rbuf[0] = 0; + while (1) { + int n = 0; + const char *p = NULL; + int skipsame = 0; + int searchdir = -1; + + snprintf(rprompt, sizeof(rprompt), "(reverse-i-search)'%s': ", rbuf); + refreshLine(rprompt, current); + c = fd_read(current); + if (c == ctrl('H') || c == 127) { + if (rchars) { + int p = utf8_index(rbuf, --rchars); + rbuf[p] = 0; + rlen = strlen(rbuf); + } + continue; + } +#ifdef USE_TERMIOS + if (c == 27) { + c = check_special(current->fd); + } +#endif + if (c == ctrl('P') || c == SPECIAL_UP) { + /* Search for the previous (earlier) match */ + if (searchpos > 0) { + searchpos--; + } + skipsame = 1; + } + else if (c == ctrl('N') || c == SPECIAL_DOWN) { + /* Search for the next (later) match */ + if (searchpos < history_len) { + searchpos++; + } + searchdir = 1; + skipsame = 1; + } + else if (c >= ' ') { + if (rlen >= (int)sizeof(rbuf) + 3) { + continue; + } + + n = utf8_getchars(rbuf + rlen, c); + rlen += n; + rchars++; + rbuf[rlen] = 0; + + /* Adding a new char resets the search location */ + searchpos = history_len - 1; + } + else { + /* Exit from incremental search mode */ + break; + } + + /* Now search through the history for a match */ + for (; searchpos >= 0 && searchpos < history_len; searchpos += searchdir) { + p = strstr(history[searchpos], rbuf); + if (p) { + /* Found a match */ + if (skipsame && strcmp(history[searchpos], current->buf) == 0) { + /* But it is identical, so skip it */ + continue; + } + /* Copy the matching line and set the cursor position */ + set_current(current,history[searchpos]); + current->pos = utf8_strlen(history[searchpos], p - history[searchpos]); + break; + } + } + if (!p && n) { + /* No match, so don't add it */ + rchars--; + rlen -= n; + rbuf[rlen] = 0; + } + } + if (c == ctrl('G') || c == ctrl('C')) { + /* ctrl-g terminates the search with no effect */ + set_current(current, ""); + c = 0; + } + else if (c == ctrl('J')) { + /* ctrl-j terminates the search leaving the buffer in place */ + c = 0; + } + /* Go process the char normally */ + refreshLine(current->prompt, current); + goto process_char; + } + break; + case ctrl('T'): /* ctrl-t */ + if (current->pos > 0 && current->pos <= current->chars) { + /* If cursor is at end, transpose the previous two chars */ + int fixer = (current->pos == current->chars); + c = get_char(current, current->pos - fixer); + remove_char(current, current->pos - fixer); + insert_char(current, current->pos - 1, c); + refreshLine(current->prompt, current); + } + break; + case ctrl('V'): /* ctrl-v */ + if (has_room(current, 3)) { + /* Insert the ^V first */ + if (insert_char(current, current->pos, c)) { + refreshLine(current->prompt, current); + /* Now wait for the next char. Can insert anything except \0 */ + c = fd_read(current); + + /* Remove the ^V first */ + remove_char(current, current->pos - 1); + if (c != -1) { + /* Insert the actual char */ + insert_char(current, current->pos, c); + } + refreshLine(current->prompt, current); + } + } + break; + case ctrl('B'): + case SPECIAL_LEFT: + if (current->pos > 0) { + current->pos--; + refreshLine(current->prompt, current); + } + break; + case ctrl('F'): + case SPECIAL_RIGHT: + if (current->pos < current->chars) { + current->pos++; + refreshLine(current->prompt, current); + } + break; + case SPECIAL_PAGE_UP: + dir = history_len - history_index - 1; /* move to start of history */ + goto history_navigation; + case SPECIAL_PAGE_DOWN: + dir = -history_index; /* move to 0 == end of history, i.e. current */ + goto history_navigation; + case ctrl('P'): + case SPECIAL_UP: + dir = 1; + goto history_navigation; + case ctrl('N'): + case SPECIAL_DOWN: +history_navigation: + if (history_len > 1) { + /* Update the current history entry before to + * overwrite it with tne next one. */ + free(history[history_len - 1 - history_index]); + history[history_len - 1 - history_index] = strdup(current->buf); + /* Show the new entry */ + history_index += dir; + if (history_index < 0) { + history_index = 0; + break; + } else if (history_index >= history_len) { + history_index = history_len - 1; + break; + } + set_current(current, history[history_len - 1 - history_index]); + refreshLine(current->prompt, current); + } + break; + case ctrl('A'): /* Ctrl+a, go to the start of the line */ + case SPECIAL_HOME: + current->pos = 0; + refreshLine(current->prompt, current); + break; + case ctrl('E'): /* ctrl+e, go to the end of the line */ + case SPECIAL_END: + current->pos = current->chars; + refreshLine(current->prompt, current); + break; + case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */ + if (remove_chars(current, 0, current->pos)) { + refreshLine(current->prompt, current); + } + break; + case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */ + if (remove_chars(current, current->pos, current->chars - current->pos)) { + refreshLine(current->prompt, current); + } + break; + case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */ + if (current->capture && insert_chars(current, current->pos, current->capture)) { + refreshLine(current->prompt, current); + } + break; + case ctrl('L'): /* Ctrl+L, clear screen */ + clearScreen(current); + /* Force recalc of window size for serial terminals */ + current->cols = 0; + refreshLine(current->prompt, current); + break; + default: + /* Only tab is allowed without ^V */ + if (c == '\t' || c >= ' ') { + if (insert_char(current, current->pos, c) == 1) { + refreshLine(current->prompt, current); + } + } + break; + } + } + return current->len; +} + +int linenoiseColumns(void) +{ + struct current current; + enableRawMode (¤t); + getWindowSize (¤t); + disableRawMode (¤t); + return current.cols; +} + +char *linenoise(const char *prompt) +{ + int count; + struct current current; + char buf[LINENOISE_MAX_LINE]; + + if (enableRawMode(¤t) == -1) { + printf("%s", prompt); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) { + return NULL; + } + count = strlen(buf); + if (count && buf[count-1] == '\n') { + count--; + buf[count] = '\0'; + } + } + else + { + current.buf = buf; + current.bufmax = sizeof(buf); + current.len = 0; + current.chars = 0; + current.pos = 0; + current.prompt = prompt; + current.capture = NULL; + + count = linenoiseEdit(¤t); + + disableRawMode(¤t); + printf("\n"); + + free(current.capture); + if (count == -1) { + return NULL; + } + } + return strdup(buf); +} + +/* Using a circular buffer is smarter, but a bit more complex to handle. */ +int linenoiseHistoryAdd(const char *line) { + char *linecopy; + + if (history_max_len == 0) return 0; + if (history == NULL) { + history = (char **)malloc(sizeof(char*)*history_max_len); + if (history == NULL) return 0; + memset(history,0,(sizeof(char*)*history_max_len)); + } + + /* do not insert duplicate lines into history */ + if (history_len > 0 && strcmp(line, history[history_len - 1]) == 0) { + return 0; + } + + linecopy = strdup(line); + if (!linecopy) return 0; + if (history_len == history_max_len) { + free(history[0]); + memmove(history,history+1,sizeof(char*)*(history_max_len-1)); + history_len--; + } + history[history_len] = linecopy; + history_len++; + return 1; +} + +int linenoiseHistoryGetMaxLen(void) { + return history_max_len; +} + +int linenoiseHistorySetMaxLen(int len) { + char **newHistory; + + if (len < 1) return 0; + if (history) { + int tocopy = history_len; + + newHistory = (char **)malloc(sizeof(char*)*len); + if (newHistory == NULL) return 0; + + /* If we can't copy everything, free the elements we'll not use. */ + if (len < tocopy) { + int j; + + for (j = 0; j < tocopy-len; j++) free(history[j]); + tocopy = len; + } + memset(newHistory,0,sizeof(char*)*len); + memcpy(newHistory,history+(history_len-tocopy), sizeof(char*)*tocopy); + free(history); + history = newHistory; + } + history_max_len = len; + if (history_len > history_max_len) + history_len = history_max_len; + return 1; +} + +/* Save the history in the specified file. On success 0 is returned + * otherwise -1 is returned. */ +int linenoiseHistorySave(const char *filename) { + FILE *fp = fopen(filename,"w"); + int j; + + if (fp == NULL) return -1; + for (j = 0; j < history_len; j++) { + const char *str = history[j]; + /* Need to encode backslash, nl and cr */ + while (*str) { + if (*str == '\\') { + fputs("\\\\", fp); + } + else if (*str == '\n') { + fputs("\\n", fp); + } + else if (*str == '\r') { + fputs("\\r", fp); + } + else { + fputc(*str, fp); + } + str++; + } + fputc('\n', fp); + } + + fclose(fp); + return 0; +} + +/* Load the history from the specified file. If the file does not exist + * zero is returned and no operation is performed. + * + * If the file exists and the operation succeeded 0 is returned, otherwise + * on error -1 is returned. */ +int linenoiseHistoryLoad(const char *filename) { + FILE *fp = fopen(filename,"r"); + char buf[LINENOISE_MAX_LINE]; + + if (fp == NULL) return -1; + + while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) { + char *src, *dest; + + /* Decode backslash escaped values */ + for (src = dest = buf; *src; src++) { + char ch = *src; + + if (ch == '\\') { + src++; + if (*src == 'n') { + ch = '\n'; + } + else if (*src == 'r') { + ch = '\r'; + } else { + ch = *src; + } + } + *dest++ = ch; + } + /* Remove trailing newline */ + if (dest != buf && (dest[-1] == '\n' || dest[-1] == '\r')) { + dest--; + } + *dest = 0; + + linenoiseHistoryAdd(buf); + } + fclose(fp); + return 0; +} + +/* Provide access to the history buffer. + * + * If 'len' is not NULL, the length is stored in *len. + */ +char **linenoiseHistory(int *len) { + if (len) { + *len = history_len; + } + return history; +} diff --git a/external/CppMicroServices/third_party/linenoise.h b/external/CppMicroServices/third_party/linenoise.h new file mode 100644 index 00000000..23f392d7 --- /dev/null +++ b/external/CppMicroServices/third_party/linenoise.h @@ -0,0 +1,128 @@ +/* linenoise.h -- guerrilla line editing library against the idea that a + * line editing lib needs to be 20,000 lines of C code. + * + * See linenoise.c for more information. + * + * ------------------------------------------------------------------------ + * + * Copyright (c) 2010, Salvatore Sanfilippo + * Copyright (c) 2010, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LINENOISE_H +#define __LINENOISE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NO_COMPLETION +typedef struct linenoiseCompletions { + size_t len; + char **cvec; +} linenoiseCompletions; + +/* + * The callback type for tab completion handlers. + */ +typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); + +/* + * Sets the current tab completion handler and returns the previous one, or NULL + * if no prior one has been set. + */ +linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *); + +/* + * Adds a copy of the given string to the given completion list. The copy is owned + * by the linenoiseCompletions object. + */ +void linenoiseAddCompletion(linenoiseCompletions *, const char *); +#endif + +/* + * Prompts for input using the given string as the input + * prompt. Returns when the user has tapped ENTER or (on an empty + * line) EOF (Ctrl-D on Unix, Ctrl-Z on Windows). Returns either + * a copy of the entered string (for ENTER) or NULL (on EOF). The + * caller owns the returned string and must eventually free() it. + */ +char *linenoise(const char *prompt); + +/* + * Adds a copy of the given line of the command history. + */ +int linenoiseHistoryAdd(const char *line); + +/* + * Sets the maximum length of the command history, in lines. + * If the history is currently longer, it will be trimmed, + * retaining only the most recent entries. If len is 0 or less + * then this function does nothing. + */ +int linenoiseHistorySetMaxLen(int len); + +/* + * Returns the current maximum length of the history, in lines. + */ +int linenoiseHistoryGetMaxLen(void); + +/* + * Saves the current contents of the history to the given file. + * Returns 0 on success. + */ +int linenoiseHistorySave(const char *filename); + +/* + * Replaces the current history with the contents + * of the given file. Returns 0 on success. + */ +int linenoiseHistoryLoad(const char *filename); + +/* + * Frees all history entries, clearing the history. + */ +void linenoiseHistoryFree(void); + +/* + * Returns a pointer to the list of history entries, writing its + * length to *len if len is not NULL. The memory is owned by linenoise + * and must not be freed. + */ +char **linenoiseHistory(int *len); + +/* + * Returns the number of display columns in the current terminal. + */ +int linenoiseColumns(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LINENOISE_H */ diff --git a/external/CppMicroServices/third_party/miniz.c b/external/CppMicroServices/third_party/miniz.c new file mode 100644 index 00000000..6b0ebd7a --- /dev/null +++ b/external/CppMicroServices/third_party/miniz.c @@ -0,0 +1,4965 @@ +/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Change History + 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major release with Zip64 support (almost there!): + - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug + would only have occured in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place() + (which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag). + - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size + - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries. + Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice). + - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes + - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed + - Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6. + - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti + - Merged MZ_FORCEINLINE fix from hdeanclark + - Fix include before config #ifdef, thanks emil.brink + - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can + set it to 1 for real-time compression). + - Merged in some compiler fixes from paulharris's github repro. + - Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3. + - Added example6.c, which dumps an image of the mandelbrot set to a PNG file. + - Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. + - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled + - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch + 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. + - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. + - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly + "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). + - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. + - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. + - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. + - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) + - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a + - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). + - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. + - Refactored the compression code for better readability and maintainability. + - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +#include + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. +//#define MINIZ_NO_STDIO + +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or +// get/set file times, and the C run-time funcs that get/set times won't be called. +// The current downside is the times written to your archives will be from 1979. +//#define MINIZ_NO_TIME + +// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_APIS + +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. +//#define MINIZ_NO_ARCHIVE_WRITING_APIS + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) + // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux + #define MINIZ_NO_TIME +#endif + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) + #include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +typedef unsigned long mz_ulong; + +// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +#define MZ_VERSION "9.1.15" +#define MZ_VERNUM 0x91F0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 15 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). +enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s +{ + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used +} mz_stream; + +typedef mz_stream *mz_streamp; + +// Returns the version string of miniz.c. +const char *mz_version(void); + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. +// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) +int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +int mz_deflateEnd(mz_streamp pStream); + +// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +// Single-call compression functions mz_compress() and mz_compress2(): +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). +mz_ulong mz_compressBound(mz_ulong source_len); + +// Initializes a decompressor. +int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when using single call decompression, described above). +int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +int mz_inflateEnd(mz_streamp pStream); + +// Single-call decompression. +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +// Returns a string description of the specified error code, or NULL if the error code is invalid. +const char *mz_error(int err); + +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + typedef unsigned char Byte; + typedef unsigned int uInt; + typedef mz_ulong uLong; + typedef Byte Bytef; + typedef uInt uIntf; + typedef char charf; + typedef int intf; + typedef void *voidpf; + typedef uLong uLongf; + typedef void *voidp; + typedef void *const voidpc; + #define Z_NULL 0 + #define Z_NO_FLUSH MZ_NO_FLUSH + #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH + #define Z_SYNC_FLUSH MZ_SYNC_FLUSH + #define Z_FULL_FLUSH MZ_FULL_FLUSH + #define Z_FINISH MZ_FINISH + #define Z_BLOCK MZ_BLOCK + #define Z_OK MZ_OK + #define Z_STREAM_END MZ_STREAM_END + #define Z_NEED_DICT MZ_NEED_DICT + #define Z_ERRNO MZ_ERRNO + #define Z_STREAM_ERROR MZ_STREAM_ERROR + #define Z_DATA_ERROR MZ_DATA_ERROR + #define Z_MEM_ERROR MZ_MEM_ERROR + #define Z_BUF_ERROR MZ_BUF_ERROR + #define Z_VERSION_ERROR MZ_VERSION_ERROR + #define Z_PARAM_ERROR MZ_PARAM_ERROR + #define Z_NO_COMPRESSION MZ_NO_COMPRESSION + #define Z_BEST_SPEED MZ_BEST_SPEED + #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION + #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION + #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY + #define Z_FILTERED MZ_FILTERED + #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY + #define Z_RLE MZ_RLE + #define Z_FIXED MZ_FIXED + #define Z_DEFLATED MZ_DEFLATED + #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS + #define alloc_func mz_alloc_func + #define free_func mz_free_func + #define internal_state mz_internal_state + #define z_stream mz_stream + #define deflateInit mz_deflateInit + #define deflateInit2 mz_deflateInit2 + #define deflateReset mz_deflateReset + #define deflate mz_deflate + #define deflateEnd mz_deflateEnd + #define deflateBound mz_deflateBound + #define compress mz_compress + #define compress2 mz_compress2 + #define compressBound mz_compressBound + #define inflateInit mz_inflateInit + #define inflateInit2 mz_inflateInit2 + #define inflate mz_inflate + #define inflateEnd mz_inflateEnd + #define uncompress mz_uncompress + #define crc32 mz_crc32 + #define adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 + #define zError mz_error + #define ZLIB_VERSION MZ_VERSION + #define ZLIB_VERNUM MZ_VERNUM + #define ZLIB_VER_MAJOR MZ_VER_MAJOR + #define ZLIB_VER_MINOR MZ_VER_MINOR + #define ZLIB_VER_REVISION MZ_VER_REVISION + #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION + #define zlibVersion mz_version + #define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. +#ifdef _MSC_VER + #define MZ_MACRO_END while (0, 0) +#else + #define MZ_MACRO_END while (0) +#endif + +// ------------------- ZIP archive reading/writing + +#ifndef MINIZ_NO_ARCHIVE_APIS + +enum +{ + MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 +}; + +typedef struct +{ + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + time_t m_time; +#endif + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum +{ + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef struct mz_zip_archive_tag +{ + mz_uint64 m_archive_size; + mz_uint64 m_archive_file_ofs; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef enum +{ + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 +} mz_zip_flags; + +// ZIP archive reading + +// Inits a ZIP archive reader. +// These functions read and validate the archive's central directory. +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +#endif + +// Returns the total number of files in the archive. +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// Returns detailed information about an archive file entry. +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +// Determines if an archive file entry is a directory entry. +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +// Retrieves the filename of an archive file entry. +// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +// Attempts to locates a file in the archive's central directory. +// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH +// Returns -1 if the file cannot be found. +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + +// Extracts a archive file to a memory buffer using no memory allocation. +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +// Extracts a archive file to a memory buffer. +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +// Extracts a archive file to a dynamically allocated heap buffer. +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +// Extracts a archive file using a callback function to output the file's data. +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +// Extracts a archive file to a disk file and sets its last accessed and modified times. +// This function only extracts files, not archive directory records. +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); +#endif + +// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +// ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// Inits a ZIP archive writer. +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +#endif + +// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. +// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. +// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). +// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. +// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before +// the archive is finalized the file's central directory will be hosed. +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); + +// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. +// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +#ifndef MINIZ_NO_STDIO +// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +#endif + +// Adds a file to an archive by fully cloning the data from another archive. +// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); + +// Finalizes the archive by writing the central directory records followed by the end of central directory record. +// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). +// An archive must be manually finalized by calling this function for it to be valid. +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); + +// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. +// Note for the archive to be valid, it must have been finalized before ending. +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +// Misc. high-level helper functions: + +// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +// Reads a single file from an archive into a heap block. +// Returns NULL on failure. +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must call mz_free() on the returned block when it's no longer needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). +enum +{ + TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +// High level compression functions: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of source block to compress. +// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. +// Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// Compresses an image to a compressed PNG file in memory. +// On entry: +// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. +// The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. +// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL +// If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pLen_out will be set to the size of the PNG image file. +// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); + +// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#else +enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#endif + +// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. +typedef enum +{ + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1, +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum +{ + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. +// tdefl_compress_buffer() always consumes the entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; + +#include +#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC + #define MZ_MALLOC(x) NULL + #define MZ_FREE(x) (void)x, ((void)0) + #define MZ_REALLOC(p, x) NULL +#else + #define MZ_MALLOC(x) malloc(x) + #define MZ_FREE(x) free(x) + #define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER + #define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) +#else + #define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +// ------------------- zlib-style API's + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + return (s2 << 16) + s1; +} + +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) return MZ_CRC32_INIT; + crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } + return ~crcu32; +} + +void mz_free(void *p) +{ + MZ_FREE(p); +} + +#ifndef MINIZ_NO_ZLIB_APIS + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } +static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } +static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; + for ( ; ; ) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state* pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + + pState = (inflate_state*)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for ( ; ; ) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. + else if (flush == MZ_FINISH) + { + // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) +{ + static struct { int m_err; const char *m_pDesc; } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, + { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif //MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a +// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read +// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully +// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +// ------------------- Low-level Compression (independent from all decompression API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, + 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, + 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, + 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, + 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, + 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, + 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, + 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7 }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, + 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. +typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; +static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32* pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } + for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } + A[0].m_key += A[1].m_key; root = 0; leaf = 2; + for (next=1; next < n-1; next++) + { + if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; + avbl = 1; used = dpth = 0; root = n-2; next = n-1; + while (avbl>0) + { + while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } + while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } + avbl = 2*used; dpth++; used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; mz_uint32 total = 0; if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) do { \ + mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ +} MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ +} rle_repeat_count = 0; } } + +#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ +} rle_z_count = 0; } } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for ( ; i <= 255; ++i) *p++ = 9; + for ( ; i <= 279; ++i) *p++ = 7; + for ( ; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64*)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. + if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) + { + mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } + } + else + { + mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + if (!probe_len) + { + *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; + if (probe_len > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output buffer. + if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) + { + int n; + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; + d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; + do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); + pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; + } + memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; + *pOut_len = out_buf.m_size; return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; + return out_buf.m_size; +} + +#ifndef MINIZ_NO_ZLIB_APIS +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} +#endif //MINIZ_NO_ZLIB_APIS + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) +#endif + +// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at +// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. +// This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +{ + // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. + static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + // write real header + *pLen_out = out_buf.m_size-41; + { + static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; + mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0, + (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; + c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +} + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +// ------------------- .ZIP archive reading + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef MINIZ_NO_STDIO + #define MZ_FILE void * +#else + #include + #include + + #if defined(_MSC_VER) || defined(__MINGW64__) + #include + #include + #include + + // return NULL if inStr is NULL or if the conversion failed + // The string returned is allocated using 'malloc' and hence should be de-allocated using 'free'. + static wchar_t* utf8_to_wchar(const char* inStr) + { + wchar_t* wstr = NULL; + if (inStr) + { + int wchars_count = MultiByteToWideChar(CP_UTF8, 0, inStr, -1, NULL, 0); + if (wchars_count > 0) + { + wstr = MZ_MALLOC(sizeof(wchar_t)*(wchars_count)); + } + if ((wstr != NULL) && (MultiByteToWideChar(CP_UTF8, 0, inStr, -1, wstr, wchars_count) == 0)) + { + MZ_FREE(wstr); + wstr = NULL; + } + } + return wstr; + } + + static FILE *mz_fopen(const char *pFilename, const char *pMode) + { + FILE* pFile = NULL; + wchar_t* pFilenameW = utf8_to_wchar(pFilename); + wchar_t* pModeW = utf8_to_wchar(pMode); + (void)_wfopen_s(&pFile, pFilenameW, pModeW); + MZ_FREE(pFilenameW); + MZ_FREE(pModeW); + return pFile; + } + + static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) + { + FILE* pFile = NULL; + wchar_t* pFilenameW = utf8_to_wchar(pPath); + wchar_t* pModeW = utf8_to_wchar(pMode); + if (_wfreopen_s(&pFile, pFilenameW, pModeW, pStream)) + { + pFile = NULL; + } + MZ_FREE(pFilenameW); + MZ_FREE(pModeW); + return pFile; + } + #ifndef MINIZ_NO_TIME + #include + #endif + #define MZ_FILE FILE + #define MZ_FOPEN mz_fopen + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 _ftelli64 + #define MZ_FSEEK64 _fseeki64 + #define MZ_FILE_STAT_STRUCT _stat + #define MZ_FILE_STAT _stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN mz_freopen + #define MZ_DELETE_FILE remove + #elif defined(__MINGW32__) + #ifndef MINIZ_NO_TIME + #include + #endif + #define MZ_FILE FILE + #define MZ_FOPEN(f, m) fopen(f, m) + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftello64 + #define MZ_FSEEK64 fseeko64 + #define MZ_FILE_STAT_STRUCT _stat + #define MZ_FILE_STAT _stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN(f, m, s) freopen(f, m, s) + #define MZ_DELETE_FILE remove + #elif defined(__TINYC__) + #ifndef MINIZ_NO_TIME + #include + #endif + #define MZ_FILE FILE + #define MZ_FOPEN(f, m) fopen(f, m) + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftell + #define MZ_FSEEK64 fseek + #define MZ_FILE_STAT_STRUCT stat + #define MZ_FILE_STAT stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN(f, m, s) freopen(f, m, s) + #define MZ_DELETE_FILE remove + #elif defined(__GNUC__) && _LARGEFILE64_SOURCE + #ifndef MINIZ_NO_TIME + #include + #endif + #define MZ_FILE FILE + #define MZ_FOPEN(f, m) fopen64(f, m) + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftello64 + #define MZ_FSEEK64 fseeko64 + #define MZ_FILE_STAT_STRUCT stat64 + #define MZ_FILE_STAT stat64 + #define MZ_FFLUSH fflush + #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) + #define MZ_DELETE_FILE remove + #else + #ifndef MINIZ_NO_TIME + #include + #endif + #define MZ_FILE FILE + #define MZ_FOPEN(f, m) fopen(f, m) + #define MZ_FCLOSE fclose + #define MZ_FREAD fread + #define MZ_FWRITE fwrite + #define MZ_FTELL64 ftello + #define MZ_FSEEK64 fseeko + #define MZ_FILE_STAT_STRUCT stat + #define MZ_FILE_STAT stat + #define MZ_FFLUSH fflush + #define MZ_FREOPEN(f, m, s) freopen(f, m, s) + #define MZ_DELETE_FILE remove + #endif // #ifdef _MSC_VER +#endif // #ifdef MINIZ_NO_STDIO + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. +enum +{ + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +}; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +{ + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +{ + void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; + if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; + pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +{ + if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +{ + if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +{ + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +{ + size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; + memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) + { + *pDOS_date = 0; *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif + +#ifndef MINIZ_NO_STDIO +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef MINIZ_NO_TIME + (void)pFilename; *pDOS_date = *pDOS_time = 0; +#else + struct MZ_FILE_STAT_STRUCT file_stat; + // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) + return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) +{ + struct utimbuf t; t.actime = access_time; t.modtime = modified_time; + return !utime(pFilename, &t); +} +#endif // #ifndef MINIZ_NO_TIME +#endif // #ifndef MINIZ_NO_STDIO + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) +{ + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END + +// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) + { + int child, root = start; + for ( ; ; ) + { + if ((child = (root << 1) + 1) >= size) + break; + child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + } + start--; + } + + end = size - 1; + while (end > 0) + { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for ( ; ; ) + { + if ((child = (root << 1) + 1) >= end) + break; + child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) +{ + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + mz_bool zip_signature_found = 0; + // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + // Find the end of central directory record by scanning the file from the end towards the beginning. + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for ( ; ; ) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) + { + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + { + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs + i, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + continue; + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + continue; + zip_signature_found = 1; + break; + } + } + + if (zip_signature_found) + { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || (cur_file_ofs < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; + + cur_file_ofs = MZ_MAX(cur_file_ofs - (mz_int64)(sizeof(buf_u32) - 3), 0); + } + + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return MZ_FALSE; + + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + + cdir_ofs = cur_file_ofs - cdir_size; + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return MZ_FALSE; + + pZip->m_central_directory_file_ofs = cdir_ofs; + + pZip->m_archive_file_ofs = cdir_ofs - MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if (pZip->m_archive_file_ofs > pZip->m_archive_size) + return MZ_FALSE; + + if (pZip->m_total_files) + { + mz_uint i, n; + + // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return MZ_FALSE; + + if (sort_central_dir) + { + if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) + return MZ_FALSE; + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return MZ_FALSE; + + // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return MZ_FALSE; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) + return MZ_FALSE; + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) + return MZ_FALSE; + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return MZ_FALSE; + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return MZ_FALSE; + n -= total_header_size; p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) +{ + if ((!pZip) || (!pZip->m_pRead)) + return MZ_FALSE; + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) +{ + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +{ + mz_uint64 file_size; + MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return MZ_FALSE; + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_total_files : 0; +} + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +{ + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint filename_len, external_attr; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) + return MZ_FALSE; + + // First see if the filename ends with a '/' character. + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. + // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. + // FIXME: Remove this check? Is it necessary - we already check the filename. + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & 0x10) != 0) + return MZ_TRUE; + + return MZ_FALSE; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) + return MZ_FALSE; + + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; + + return MZ_TRUE; +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +{ + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) + { + int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + return file_index; + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + return -1; +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +{ + mz_uint file_index; size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return -1; + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + return mz_zip_reader_locate_file_binary_search(pZip, pName); + name_len = strlen(pName); if (name_len > 0xFFFF) return -1; + comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + return file_index; + } + return -1; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((buf_size) && (!pBuf)) + return MZ_FALSE; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) + return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) + return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = pZip->m_archive_file_ofs + file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return MZ_FALSE; + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } + + // Decompress the file either directly from memory or from a file input buffer. + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) + { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + // Use a user provided read buffer. + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + else + { + // Temporarily allocate a read buffer. + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#endif + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do + { + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +{ + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) + *pSize = 0; + if (!p) + return NULL; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#endif + return NULL; + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + return NULL; + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + { + if (pSize) *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) + return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) + return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) + return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + // Decompress the file either directly from memory or from a file input buffer. + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) + { +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) +#endif + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + status = TINFL_STATUS_FAILED; + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + status = TINFL_STATUS_FAILED; + else + { + do + { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +{ + (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +{ + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return MZ_FALSE; + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) + return MZ_FALSE; +#ifndef MINIZ_NO_TIME + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + return status; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + + if (pZip->m_pState) + { + mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +{ + int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) + return MZ_FALSE; + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} +#endif + +// ------------------- .ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } +static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +{ + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (pZip->m_file_offset_alignment) + { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return MZ_FALSE; + } + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + return MZ_TRUE; +} + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); +#ifdef _MSC_VER + if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#else + if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#endif + return 0; + if (new_size > pState->m_mem_capacity) + { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + return 0; + pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +{ + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + return MZ_FALSE; + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + MZ_FILE *pFile; + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) + return MZ_FALSE; + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +{ + mz_zip_internal_state *pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + // No sense in trying to write to an archive that's already at the support max size + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if (pState->m_pFile) + { +#ifdef MINIZ_NO_STDIO + pFilename; return MZ_FALSE; +#else + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + if (!pFilename) + return MZ_FALSE; + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } +#endif // #ifdef MINIZ_NO_STDIO + } + else if (pState->m_pMem) + { + // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) + return MZ_FALSE; + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the user has specified a write function too. + else if (!pZip->m_pWrite) + return MZ_FALSE; + + // Start writing new files at the archive's current central directory location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +{ + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +} + +typedef struct +{ + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) +{ + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + return MZ_FALSE; + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +{ + // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. + if (*pArchive_name == '/') + return MZ_FALSE; + while (*pArchive_name) + { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) + return MZ_FALSE; + pArchive_name++; + } + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +{ + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +{ + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return MZ_FALSE; + cur_file_ofs += s; n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +{ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return MZ_FALSE; + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + +#ifndef MINIZ_NO_TIME + { + time_t cur_time; time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif // #ifndef MINIZ_NO_TIME + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + return MZ_FALSE; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) + return MZ_FALSE; + } + + // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return MZ_FALSE; + + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return MZ_FALSE; + } + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + method = MZ_DEFLATED; + } + else if (buf_size) + { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + MZ_FILE *pSrc_file = NULL; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) + return MZ_FALSE; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return MZ_FALSE; + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + if (uncomp_size > 0xFFFFFFFF) + { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) + level = 0; + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (uncomp_size) + { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (!level) + { + while (uncomp_remaining) + { + mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + for ( ; ; ) + { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + break; + + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + break; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + MZ_FCLOSE(pSrc_file); pSrc_file = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) +{ + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; const mz_uint8 *pSrc_central_header; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + return MZ_FALSE; + pState = pZip->m_pState; + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + cur_src_file_ofs = pSource_zip->m_archive_file_ofs + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) + return MZ_FALSE; + + while (comp_bytes_remaining) + { + n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; + + comp_bytes_remaining -= n; + } + + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) + return MZ_FALSE; + + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; + + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + if (pState->m_central_dir.m_size > 0xFFFFFFFF) + return MZ_FALSE; + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return MZ_FALSE; + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + + pState = pZip->m_pState; + + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + return MZ_FALSE; + pZip->m_archive_size += central_dir_size; + } + + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) + return MZ_FALSE; +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return MZ_FALSE; +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_archive_size += sizeof(hdr); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) +{ + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) + return MZ_FALSE; + if (pZip->m_pWrite != mz_zip_heap_write_func) + return MZ_FALSE; + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; + + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + return MZ_FALSE; + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return MZ_FALSE; + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) + return MZ_FALSE; + created_new_archive = MZ_TRUE; + } + else + { + // Append to an existing archive. + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return MZ_FALSE; + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) + { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) + status = MZ_FALSE; + if (!mz_zip_writer_end(&zip_archive)) + status = MZ_FALSE; + if ((!status) && (created_new_archive)) + { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +{ + int file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) + *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) + return NULL; + + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return NULL; + + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + + mz_zip_reader_end(&zip_archive); + return p; +} + +#endif // #ifndef MINIZ_NO_STDIO + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ diff --git a/external/CppMicroServices/third_party/miniz.h b/external/CppMicroServices/third_party/miniz.h new file mode 100644 index 00000000..6a9037bf --- /dev/null +++ b/external/CppMicroServices/third_party/miniz.h @@ -0,0 +1,6 @@ +#ifndef MINIZ_HEADER_FILE_ONLY +#define MINIZ_HEADER_FILE_ONLY + +#include "miniz.c" + +#endif diff --git a/external/CppMicroServices/third_party/optionparser.h b/external/CppMicroServices/third_party/optionparser.h new file mode 100644 index 00000000..dc219300 --- /dev/null +++ b/external/CppMicroServices/third_party/optionparser.h @@ -0,0 +1,2862 @@ +/* + * The Lean Mean C++ Option Parser + * + * Copyright (C) 2012-2017 Matthias S. Benkmann + * + * The "Software" in the following 2 paragraphs refers to this file containing + * the code to The Lean Mean C++ Option Parser. + * The "Software" does NOT refer to any other files which you + * may have received alongside this file (e.g. as part of a larger project that + * incorporates The Lean Mean C++ Option Parser). + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software, to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following + * conditions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * NOTE: It is recommended that you read the processed HTML doxygen documentation + * rather than this source. If you don't know doxygen, it's like javadoc for C++. + * If you don't want to install doxygen you can find a copy of the processed + * documentation at + * + * http://optionparser.sourceforge.net/ + * + */ + +/** + * @file + * + * @brief This is the only file required to use The Lean Mean C++ Option Parser. + * Just \#include it and you're set. + * + * The Lean Mean C++ Option Parser handles the program's command line arguments + * (argc, argv). + * It supports the short and long option formats of getopt(), getopt_long() + * and getopt_long_only() but has a more convenient interface. + * + * @par Feedback: + * Send questions, bug reports, feature requests etc. to: optionparser-feedback(a)lists.sourceforge.net + * + * @par Highlights: + *
    + *
  • It is a header-only library. Just \#include "optionparser.h" and you're set. + *
  • It is freestanding. There are no dependencies whatsoever, not even the + * C or C++ standard library. + *
  • It has a usage message formatter that supports column alignment and + * line wrapping. This aids localization because it adapts to + * translated strings that are shorter or longer (even if they contain + * Asian wide characters). + *
  • Unlike getopt() and derivatives it doesn't force you to loop through + * options sequentially. Instead you can access options directly like this: + *
      + *
    • Test for presence of a switch in the argument vector: + * @code if ( options[QUIET] ) ... @endcode + *
    • Evaluate --enable-foo/--disable-foo pair where the last one used wins: + * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode + *
    • Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): + * @code int verbosity = options[VERBOSE].count(); @endcode + *
    • Iterate over all --file=<fname> arguments: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + *
    • If you really want to, you can still process all arguments in order: + * @code + * for (int i = 0; i < p.optionsCount(); ++i) { + * Option& opt = buffer[i]; + * switch(opt.index()) { + * case HELP: ... + * case VERBOSE: ... + * case FILE: fname = opt.arg; ... + * case UNKNOWN: ... + * @endcode + *
    + *
@n + * Despite these features the code size remains tiny. + * It is smaller than uClibc's GNU getopt() and just a + * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n + * (This does not include the usage formatter, of course. But you don't have to use that.) + * + * @par Download: + * Tarball with examples and test programs: + * optionparser-1.7.tar.gz @n + * Just the header (this is all you really need): + * optionparser.h + * + * @par Changelog: + * Version 1.7: Work on const-correctness. @n + * Version 1.6: Fix for MSC compiler. @n + * Version 1.5: Fixed 2 warnings about potentially uninitialized variables. @n + * Added const version of Option::next(). @n + * Version 1.4: Fixed 2 printUsage() bugs that messed up output with small COLUMNS values. @n + * Version 1.3: Compatible with Microsoft Visual C++. @n + * Version 1.2: Added @ref option::Option::namelen "Option::namelen" and removed the extraction + * of short option characters into a special buffer. @n + * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached + * rather than separate. This is what GNU getopt() does and how POSIX recommends + * utilities should interpret their arguments.@n + * Version 1.1: Optional mode with argument reordering as done by GNU getopt(), so that + * options and non-options can be mixed. See + * @ref option::Parser::parse() "Parser::parse()". + * + * + * @par Example program: + * (Note: @c option::* identifiers are links that take you to their documentation.) + * @code + * #error EXAMPLE SHORTENED FOR READABILITY. BETTER EXAMPLES ARE IN THE .TAR.GZ! + * #include + * #include "optionparser.h" + * + * enum optionIndex { UNKNOWN, HELP, PLUS }; + * const option::Descriptor usage[] = + * { + * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n" + * "Options:" }, + * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." }, + * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." }, + * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n" + * " example --unknown -- --this_is_no_option\n" + * " example -unk --plus -ppp file1 file2\n" }, + * {0,0,0,0,0,0} + * }; + * + * int main(int argc, char* argv[]) + * { + * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present + * option::Stats stats(usage, argc, argv); + * option::Option options[stats.options_max], buffer[stats.buffer_max]; + * option::Parser parse(usage, argc, argv, options, buffer); + * + * if (parse.error()) + * return 1; + * + * if (options[HELP] || argc == 0) { + * option::printUsage(std::cout, usage); + * return 0; + * } + * + * std::cout << "--plus count: " << + * options[PLUS].count() << "\n"; + * + * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next()) + * std::cout << "Unknown option: " << opt->name << "\n"; + * + * for (int i = 0; i < parse.nonOptionsCount(); ++i) + * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; + * } + * @endcode + * + * @par Option syntax: + * @li The Lean Mean C++ Option Parser follows POSIX getopt() conventions and supports + * GNU-style getopt_long() long options as well as Perl-style single-minus + * long options (getopt_long_only()). + * @li short options have the format @c -X where @c X is any character that fits in a char. + * @li short options can be grouped, i.e. -X -Y is equivalent to @c -XY. + * @li a short option may take an argument either separate (-X foo) or + * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by + * registering @c X as a long option (in addition to being a short option) and + * enabling single-minus long options. + * @li an argument-taking short option may be grouped if it is the last in the group, e.g. + * @c -ABCXfoo or -ABCX foo (@c foo is the argument to the @c -X option). + * @li a lone minus character @c '-' is not treated as an option. It is customarily used where + * a file name is expected to refer to stdin or stdout. + * @li long options have the format @c --option-name. + * @li the option-name of a long option can be anything and include any characters. + * Even @c = characters will work, but don't do that. + * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous. + * You can set a minimum length for abbreviations. + * @li [optional] long options may begin with a single minus. The double minus form is always + * accepted, too. + * @li a long option may take an argument either separate ( --option arg ) or + * attached ( --option=arg ). In the attached form the equals sign is mandatory. + * @li an empty string can be passed as an attached long option argument: --option-name= . + * Note the distinction between an empty string as argument and no argument at all. + * @li an empty string is permitted as separate argument to both long and short options. + * @li Arguments to both short and long options may start with a @c '-' character. E.g. + * -X-X , -X -X or --long-X=-X . If @c -X + * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases. + * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must + * be attached. + * @li the special option @c -- (i.e. without a name) terminates the list of + * options. Everything that follows is a non-option argument, even if it starts with + * a @c '-' character. The @c -- itself will not appear in the parse results. + * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to + * a preceding argument-taking option, will terminate the option list and is the + * first non-option argument. All following command line arguments are treated as + * non-option arguments, even if they start with @c '-' . @n + * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is + * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n + * You can enable the GNU behaviour by passing @c true as first argument to + * e.g. @ref option::Parser::parse() "Parser::parse()". + * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but + * aren't, are NOT treated as non-option arguments. They are treated as unknown options and + * are collected into a list of unknown options for error reporting. @n + * This means that in order to pass a first non-option + * argument beginning with the minus character it is required to use the + * @c -- special option, e.g. + * @code + * program -x -- --strange-filename + * @endcode + * In this example, @c --strange-filename is a non-option argument. If the @c -- + * were omitted, it would be treated as an unknown option. @n + * See @ref option::Descriptor::longopt for information on how to collect unknown options. + * + */ + +#ifndef OPTIONPARSER_H_ +#define OPTIONPARSER_H_ + +#ifdef _MSC_VER +#include +#pragma intrinsic(_BitScanReverse) +#endif + +/** @brief The namespace of The Lean Mean C++ Option Parser. */ +namespace option +{ + +#ifdef _MSC_VER +struct MSC_Builtin_CLZ +{ + static int builtin_clz(unsigned x) + { + unsigned long index; + _BitScanReverse(&index, x); + return 32-index; // int is always 32bit on Windows, even for target x64 + } +}; +#define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x) +#endif + +class Option; + +/** + * @brief Possible results when checking if an argument is valid for a certain option. + * + * In the case that no argument is provided for an option that takes an + * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent. + */ +enum ArgStatus +{ + //! The option does not take an argument. + ARG_NONE, + //! The argument is acceptable for the option. + ARG_OK, + //! The argument is not acceptable but that's non-fatal because the option's argument is optional. + ARG_IGNORE, + //! The argument is not acceptable and that's fatal. + ARG_ILLEGAL +}; + +/** + * @brief Signature of functions that check if an argument is valid for a certain type of option. + * + * Every Option has such a function assigned in its Descriptor. + * @code + * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... }; + * @endcode + * + * A CheckArg function has the following signature: + * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode + * + * It is used to check if a potential argument would be acceptable for the option. + * It will even be called if there is no argument. In that case @c option.arg will be @c NULL. + * + * If @c msg is @c true and the function determines that an argument is not acceptable and + * that this is a fatal error, it should output a message to the user before + * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you + * will get duplicate messages). + * + * See @ref ArgStatus for the meaning of the return values. + * + * While you can provide your own functions, + * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice: + * + * @li @c Arg::None @copybrief Arg::None + * @li @c Arg::Optional @copybrief Arg::Optional + * + */ +typedef ArgStatus (*CheckArg)(const Option& option, bool msg); + +/** + * @brief Describes an option, its help text (usage) and how it should be parsed. + * + * The main input when constructing an option::Parser is an array of Descriptors. + + * @par Example: + * @code + * enum OptionIndex {CREATE, ...}; + * enum OptionType {DISABLE, ENABLE, OTHER}; + * + * const option::Descriptor usage[] = { + * { CREATE, // index + * OTHER, // type + * "c", // shortopt + * "create", // longopt + * Arg::None, // check_arg + * "--create Tells the program to create something." // help + * } + * , ... + * }; + * @endcode + */ +struct Descriptor +{ + /** + * @brief Index of this option's linked list in the array filled in by the parser. + * + * Command line options whose Descriptors have the same index will end up in the same + * linked list in the order in which they appear on the command line. If you have + * multiple long option aliases that refer to the same option, give their descriptors + * the same @c index. + * + * If you have options that mean exactly opposite things + * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same + * @c index, but distinguish them through different values for @ref type. + * That way they end up in the same list and you can just take the last element of the + * list and use its type. This way you get the usual behaviour where switches later + * on the command line override earlier ones without having to code it manually. + * + * @par Tip: + * Use an enum rather than plain ints for better readability, as shown in the example + * at Descriptor. + */ + const unsigned index; + + /** + * @brief Used to distinguish between options with the same @ref index. + * See @ref index for details. + * + * It is recommended that you use an enum rather than a plain int to make your + * code more readable. + */ + const int type; + + /** + * @brief Each char in this string will be accepted as a short option character. + * + * The string must not include the minus character @c '-' or you'll get undefined + * behaviour. + * + * If this Descriptor should not have short option characters, use the empty + * string "". NULL is not permitted here! + * + * See @ref longopt for more information. + */ + const char* const shortopt; + + /** + * @brief The long option name (without the leading @c -- ). + * + * If this Descriptor should not have a long option name, use the empty + * string "". NULL is not permitted here! + * + * While @ref shortopt allows multiple short option characters, each + * Descriptor can have only a single long option name. If you have multiple + * long option names referring to the same option use separate Descriptors + * that have the same @ref index and @ref type. You may repeat + * short option characters in such an alias Descriptor but there's no need to. + * + * @par Dummy Descriptors: + * You can use dummy Descriptors with an + * empty string for both @ref shortopt and @ref longopt to add text to + * the usage that is not related to a specific option. See @ref help. + * The first dummy Descriptor will be used for unknown options (see below). + * + * @par Unknown Option Descriptor: + * The first dummy Descriptor in the list of Descriptors, + * whose @ref shortopt and @ref longopt are both the empty string, will be used + * as the Descriptor for unknown options. An unknown option is a string in + * the argument vector that is not a lone minus @c '-' but starts with a minus + * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n + * Note that the dummy descriptor's @ref check_arg function @e will be called and + * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL + * the parsing will be aborted with Parser::error()==true. @n + * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's + * @ref index @e will be used to pick the linked list into which + * to put the unknown option. @n + * If there is no dummy descriptor, unknown options will be dropped silently. + * + */ + const char* const longopt; + + /** + * @brief For each option that matches @ref shortopt or @ref longopt this function + * will be called to check a potential argument to the option. + * + * This function will be called even if there is no potential argument. In that case + * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty + * string. + * + * See @ref CheckArg for more information. + */ + const CheckArg check_arg; + + /** + * @brief The usage text associated with the options in this Descriptor. + * + * You can use option::printUsage() to format your usage message based on + * the @c help texts. You can use dummy Descriptors where + * @ref shortopt and @ref longopt are both the empty string to add text to + * the usage that is not related to a specific option. + * + * See option::printUsage() for special formatting characters you can use in + * @c help to get a column layout. + * + * @attention + * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8" + * prefix to make sure string literals are properly encoded. + */ + const char* help; +}; + +/** + * @brief A parsed option from the command line together with its argument if it has one. + * + * The Parser chains all parsed options with the same Descriptor::index together + * to form a linked list. This allows you to easily implement all of the common ways + * of handling repeated options and enable/disable pairs. + * + * @li Test for presence of a switch in the argument vector: + * @code if ( options[QUIET] ) ... @endcode + * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins: + * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode + * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): + * @code int verbosity = options[VERBOSE].count(); @endcode + * @li Iterate over all --file=<fname> arguments: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + */ +class Option +{ + Option* next_; + Option* prev_; +public: + /** + * @brief Pointer to this Option's Descriptor. + * + * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used + * for unknown options. + * + * @attention + * @c desc==NULL signals that this Option is unused. This is the default state of + * elements in the result array. You don't need to test @c desc explicitly. You + * can simply write something like this: + * @code + * if (options[CREATE]) + * { + * ... + * } + * @endcode + * This works because of operator const Option*() . + */ + const Descriptor* desc; + + /** + * @brief The name of the option as used on the command line. + * + * The main purpose of this string is to be presented to the user in messages. + * + * In the case of a long option, this is the actual @c argv pointer, i.e. the first + * character is a '-'. In the case of a short option this points to the option + * character within the @c argv string. + * + * Note that in the case of a short option group or an attached option argument, this + * string will contain additional characters following the actual name. Use @ref namelen + * to filter out the actual option name only. + * + */ + const char* name; + + /** + * @brief Pointer to this Option's argument (if any). + * + * NULL if this option has no argument. Do not confuse this with the empty string which + * is a valid argument. + */ + const char* arg; + + /** + * @brief The length of the option @ref name. + * + * Because @ref name points into the actual @c argv string, the option name may be + * followed by more characters (e.g. other short options in the same short option group). + * This value is the number of bytes (not characters!) that are part of the actual name. + * + * For a short option, this length is always 1. For a long option this length is always + * at least 2 if single minus long options are permitted and at least 3 if they are disabled. + * + * @note + * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this + * length is incorrect, because this case will be misinterpreted as a long option and the + * name will therefore extend to the string's 0-terminator or a following '=" character + * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you + * really need to distinguish the case of a long and a short option, compare @ref name to + * the @c argv pointers. A long option's @c name is always identical to one of them, + * whereas a short option's is never. + */ + int namelen; + + /** + * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option + * is invalid (unused). + * + * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided + * you arrange your types properly) switch on type() without testing validity first. + * @code + * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 }; + * enum OptionIndex { FOO }; + * const Descriptor usage[] = { + * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 }, + * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 }, + * { 0, 0, 0, 0, 0, 0 } }; + * ... + * switch(options[FOO].last()->type()) // no validity check required! + * { + * case ENABLED: ... + * case DISABLED: ... // UNUSED==DISABLED ! + * } + * @endcode + */ + int type() const + { + return desc == 0 ? 0 : desc->type; + } + + /** + * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option + * is invalid (unused). + */ + int index() const + { + return desc == 0 ? -1 : static_cast( desc->index ); + } + + /** + * @brief Returns the number of times this Option (or others with the same Descriptor::index) + * occurs in the argument vector. + * + * This corresponds to the number of elements in the linked list this Option is part of. + * It doesn't matter on which element you call count(). The return value is always the same. + * + * Use this to implement cumulative options, such as -v, -vv, -vvv for + * different verbosity levels. + * + * Returns 0 when called for an unused/invalid option. + */ + int count() const + { + int c = (desc == 0 ? 0 : 1); + const Option* p = first(); + while (!p->isLast()) + { + ++c; + p = p->next_; + }; + return c; + } + + /** + * @brief Returns true iff this is the first element of the linked list. + * + * The first element in the linked list is the first option on the command line + * that has the respective Descriptor::index value. + * + * Returns true for an unused/invalid option. + */ + bool isFirst() const + { + return isTagged(prev_); + } + + /** + * @brief Returns true iff this is the last element of the linked list. + * + * The last element in the linked list is the last option on the command line + * that has the respective Descriptor::index value. + * + * Returns true for an unused/invalid option. + */ + bool isLast() const + { + return isTagged(next_); + } + + /** + * @brief Returns a pointer to the first element of the linked list. + * + * Use this when you want the first occurrence of an option on the command line to + * take precedence. Note that this is not the way most programs handle options. + * You should probably be using last() instead. + * + * @note + * This method may be called on an unused/invalid option and will return a pointer to the + * option itself. + */ + Option* first() + { + Option* p = this; + while (!p->isFirst()) + p = p->prev_; + return p; + } + + /** + * const version of Option::first(). + */ + const Option* first() const + { + return const_cast(this)->first(); + } + + /** + * @brief Returns a pointer to the last element of the linked list. + * + * Use this when you want the last occurrence of an option on the command line to + * take precedence. This is the most common way of handling conflicting options. + * + * @note + * This method may be called on an unused/invalid option and will return a pointer to the + * option itself. + * + * @par Tip: + * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you + * can assign them the same Descriptor::index to get them into the same list. Distinguish them by + * Descriptor::type and all you have to do is check last()->type() to get + * the state listed last on the command line. + */ + Option* last() + { + return first()->prevwrap(); + } + + /** + * const version of Option::last(). + */ + const Option* last() const + { + return first()->prevwrap(); + } + + /** + * @brief Returns a pointer to the previous element of the linked list or NULL if + * called on first(). + * + * If called on first() this method returns NULL. Otherwise it will return the + * option with the same Descriptor::index that precedes this option on the command + * line. + */ + Option* prev() + { + return isFirst() ? 0 : prev_; + } + + /** + * @brief Returns a pointer to the previous element of the linked list with wrap-around from + * first() to last(). + * + * If called on first() this method returns last(). Otherwise it will return the + * option with the same Descriptor::index that precedes this option on the command + * line. + */ + Option* prevwrap() + { + return untag(prev_); + } + + /** + * const version of Option::prevwrap(). + */ + const Option* prevwrap() const + { + return untag(prev_); + } + + /** + * @brief Returns a pointer to the next element of the linked list or NULL if called + * on last(). + * + * If called on last() this method returns NULL. Otherwise it will return the + * option with the same Descriptor::index that follows this option on the command + * line. + */ + Option* next() + { + return isLast() ? 0 : next_; + } + + /** + * const version of Option::next(). + */ + const Option* next() const + { + return isLast() ? 0 : next_; + } + + /** + * @brief Returns a pointer to the next element of the linked list with wrap-around from + * last() to first(). + * + * If called on last() this method returns first(). Otherwise it will return the + * option with the same Descriptor::index that follows this option on the command + * line. + */ + Option* nextwrap() + { + return untag(next_); + } + + /** + * @brief Makes @c new_last the new last() by chaining it into the list after last(). + * + * It doesn't matter which element you call append() on. The new element will always + * be appended to last(). + * + * @attention + * @c new_last must not yet be part of a list, or that list will become corrupted, because + * this method does not unchain @c new_last from an existing list. + */ + void append(Option* new_last) + { + Option* p = last(); + Option* f = first(); + p->next_ = new_last; + new_last->prev_ = p; + new_last->next_ = tag(f); + f->prev_ = tag(new_last); + } + + /** + * @brief Casts from Option to const Option* but only if this Option is valid. + * + * If this Option is valid (i.e. @c desc!=NULL), returns this. + * Otherwise returns NULL. This allows testing an Option directly + * in an if-clause to see if it is used: + * @code + * if (options[CREATE]) + * { + * ... + * } + * @endcode + * It also allows you to write loops like this: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + */ + operator const Option*() const + { + return desc ? this : 0; + } + + /** + * @brief Casts from Option to Option* but only if this Option is valid. + * + * If this Option is valid (i.e. @c desc!=NULL), returns this. + * Otherwise returns NULL. This allows testing an Option directly + * in an if-clause to see if it is used: + * @code + * if (options[CREATE]) + * { + * ... + * } + * @endcode + * It also allows you to write loops like this: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + */ + operator Option*() + { + return desc ? this : 0; + } + + /** + * @brief Creates a new Option that is a one-element linked list and has NULL + * @ref desc, @ref name, @ref arg and @ref namelen. + */ + Option() : + desc(0), name(0), arg(0), namelen(0) + { + prev_ = tag(this); + next_ = tag(this); + } + + /** + * @brief Creates a new Option that is a one-element linked list and has the given + * values for @ref desc, @ref name and @ref arg. + * + * If @c name_ points at a character other than '-' it will be assumed to refer to a + * short option and @ref namelen will be set to 1. Otherwise the length will extend to + * the first '=' character or the string's 0-terminator. + */ + Option(const Descriptor* desc_, const char* name_, const char* arg_) + { + init(desc_, name_, arg_); + } + + /** + * @brief Makes @c *this a copy of @c orig except for the linked list pointers. + * + * After this operation @c *this will be a one-element linked list. + */ + void operator=(const Option& orig) + { + init(orig.desc, orig.name, orig.arg); + } + + /** + * @brief Makes @c *this a copy of @c orig except for the linked list pointers. + * + * After this operation @c *this will be a one-element linked list. + */ + Option(const Option& orig) + { + init(orig.desc, orig.name, orig.arg); + } + +private: + /** + * @internal + * @brief Sets the fields of this Option to the given values (extracting @c name if necessary). + * + * If @c name_ points at a character other than '-' it will be assumed to refer to a + * short option and @ref namelen will be set to 1. Otherwise the length will extend to + * the first '=' character or the string's 0-terminator. + */ + void init(const Descriptor* desc_, const char* name_, const char* arg_) + { + desc = desc_; + name = name_; + arg = arg_; + prev_ = tag(this); + next_ = tag(this); + namelen = 0; + if (name == 0) + return; + namelen = 1; + if (name[0] != '-') + return; + while (name[namelen] != 0 && name[namelen] != '=') + ++namelen; + } + + static Option* tag(Option* ptr) + { + return reinterpret_cast( reinterpret_cast( ptr ) | 1 ); + } + + static Option* untag(Option* ptr) + { + return reinterpret_cast( reinterpret_cast( ptr ) & ~1ull); + } + + static bool isTagged(Option* ptr) + { + return (reinterpret_cast( ptr ) & 1); + } +}; + +/** + * @brief Functions for checking the validity of option arguments. + * + * @copydetails CheckArg + * + * The following example code + * can serve as starting place for writing your own more complex CheckArg functions: + * @code + * struct Arg: public option::Arg + * { + * static void printError(const char* msg1, const option::Option& opt, const char* msg2) + * { + * fprintf(stderr, "ERROR: %s", msg1); + * fwrite(opt.name, opt.namelen, 1, stderr); + * fprintf(stderr, "%s", msg2); + * } + * + * static option::ArgStatus Unknown(const option::Option& option, bool msg) + * { + * if (msg) printError("Unknown option '", option, "'\n"); + * return option::ARG_ILLEGAL; + * } + * + * static option::ArgStatus Required(const option::Option& option, bool msg) + * { + * if (option.arg != 0) + * return option::ARG_OK; + * + * if (msg) printError("Option '", option, "' requires an argument\n"); + * return option::ARG_ILLEGAL; + * } + * + * static option::ArgStatus NonEmpty(const option::Option& option, bool msg) + * { + * if (option.arg != 0 && option.arg[0] != 0) + * return option::ARG_OK; + * + * if (msg) printError("Option '", option, "' requires a non-empty argument\n"); + * return option::ARG_ILLEGAL; + * } + * + * static option::ArgStatus Numeric(const option::Option& option, bool msg) + * { + * char* endptr = 0; + * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){}; + * if (endptr != option.arg && *endptr == 0) + * return option::ARG_OK; + * + * if (msg) printError("Option '", option, "' requires a numeric argument\n"); + * return option::ARG_ILLEGAL; + * } + * }; + * @endcode + */ +struct Arg +{ + //! @brief For options that don't take an argument: Returns ARG_NONE. + static ArgStatus None(const Option&, bool) + { + return ARG_NONE; + } + + //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise. + static ArgStatus Optional(const Option& option, bool) + { + if (option.arg && option.name[option.namelen] != 0) + return ARG_OK; + else + return ARG_IGNORE; + } +}; + +/** + * @brief Determines the minimum lengths of the buffer and options arrays used for Parser. + * + * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated. + * If you don't want to use fixed size arrays (which may turn out too small, causing + * command line arguments to be dropped), you can use Stats to determine the correct sizes. + * Stats work cumulative. You can first pass in your default options and then the real + * options and afterwards the counts will reflect the union. + */ +struct Stats +{ + /** + * @brief Number of elements needed for a @c buffer[] array to be used for + * @ref Parser::parse() "parsing" the same argument vectors that were fed + * into this Stats object. + * + * @note + * This number is always 1 greater than the actual number needed, to give + * you a sentinel element. + */ + unsigned buffer_max; + + /** + * @brief Number of elements needed for an @c options[] array to be used for + * @ref Parser::parse() "parsing" the same argument vectors that were fed + * into this Stats object. + * + * @note + * @li This number is always 1 greater than the actual number needed, to give + * you a sentinel element. + * @li This number depends only on the @c usage, not the argument vectors, because + * the @c options array needs exactly one slot for each possible Descriptor::index. + */ + unsigned options_max; + + /** + * @brief Creates a Stats object with counts set to 1 (for the sentinel element). + */ + Stats() : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + } + + /** + * @brief Creates a new Stats object and immediately updates it for the + * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, + * if you just want to update @ref options_max. + * + * @note + * The calls to Stats methods must match the later calls to Parser methods. + * See Parser::parse() for the meaning of the arguments. + */ + Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt); + } + + //! @brief Stats(...) with non-const argv. + Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(gnu, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX Stats(...) (gnu==false). + Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX Stats(...) (gnu==false) with non-const argv. + Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(false, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } + + /** + * @brief Updates this Stats object for the + * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, + * if you just want to update @ref options_max. + * + * @note + * The calls to Stats methods must match the later calls to Parser methods. + * See Parser::parse() for the meaning of the arguments. + */ + void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false); + + //! @brief add() with non-const argv. + void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { + add(gnu, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX add() (gnu==false). + void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { + add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX add() (gnu==false) with non-const argv. + void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { + add(false, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } +private: + class CountOptionsAction; +}; + +/** + * @brief Checks argument vectors for validity and parses them into data + * structures that are easier to work with. + * + * @par Example: + * @code + * int main(int argc, char* argv[]) + * { + * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present + * option::Stats stats(usage, argc, argv); + * option::Option options[stats.options_max], buffer[stats.buffer_max]; + * option::Parser parse(usage, argc, argv, options, buffer); + * + * if (parse.error()) + * return 1; + * + * if (options[HELP]) + * ... + * @endcode + */ +class Parser +{ + int op_count; //!< @internal @brief see optionsCount() + int nonop_count; //!< @internal @brief see nonOptionsCount() + const char** nonop_args; //!< @internal @brief see nonOptions() + bool err; //!< @internal @brief see error() +public: + + /** + * @brief Creates a new Parser. + */ + Parser() : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + } + + /** + * @brief Creates a new Parser and immediately parses the given argument vector. + * @copydetails parse() + */ + Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief Parser(...) with non-const argv. + Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(gnu, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX Parser(...) (gnu==false). + Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, + bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX Parser(...) (gnu==false) with non-const argv. + Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, + bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(false, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + /** + * @brief Parses the given argument vector. + * + * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will + * reorder arguments so that all non-options are at the end. This is the default behaviour + * of GNU getopt() but is not conforming to POSIX. @n + * Note, that once the argument vector has been reordered, the @c gnu flag will have + * no further effect on this argument vector. So it is enough to pass @c gnu==true when + * creating Stats. + * @param usage Array of Descriptor objects that describe the options to support. The last entry + * of this array must have 0 in all fields. + * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number + * will be determined automatically. In that case the @c argv list must end with a NULL + * pointer. + * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv + * list must be NULL to mark the end. + * @param options Each entry is the first element of a linked list of Options. Each new option + * that is parsed will be appended to the list specified by that Option's + * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid), + * it will be replaced rather than appended to. @n + * The minimum length of this array is the greatest Descriptor::index value that + * occurs in @c usage @e PLUS ONE. + * @param buffer Each argument that is successfully parsed (including unknown arguments, if they + * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this + * array. parse() scans the array for the first invalid entry and begins writing at that + * index. You can pass @c bufmax to limit the number of options stored. + * @param min_abbr_len Passing a value min_abbr_len > 0 enables abbreviated long + * options. The parser will match a prefix of a long option as if it was + * the full long option (e.g. @c --foob=10 will be interpreted as if it was + * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters + * (not counting the @c -- ) and is unambiguous. + * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true + * because the ambiguity check does not consider short options and abbreviated + * single minus long options will take precedence over short options. + * @param single_minus_longopt Passing @c true for this option allows long options to begin with + * a single minus. The double minus form will still be recognized. Note that + * single minus long options take precedence over short options and short option + * groups. E.g. @c -file would be interpreted as @c --file and not as + * -f -i -l -e (assuming a long option named @c "file" exists). + * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is + * @c bufmax-1. If there are more options, they will be processed (in particular + * their CheckArg will be called) but not stored. @n + * If you used Stats::buffer_max to dimension this array, you can pass + * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is + * "large enough". + * @attention + * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it + * is not possible for the same object to be in both arrays. For those options that are found in + * both @c buffer[] and @c options[] the respective objects are independent copies. And only the + * objects in @c options[] are properly linked via Option::next() and Option::prev(). + * You can iterate over @c buffer[] to + * process all options in the order they appear in the argument vector, but if you want access to + * the other Options with the same Descriptor::index, then you @e must access the linked list via + * @c options[]. You can get the linked list in options from a buffer object via something like + * @c options[buffer[i].index()]. + */ + void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1); + + //! @brief parse() with non-const argv. + void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) + { + parse(gnu, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX parse() (gnu==false). + void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) + { + parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX parse() (gnu==false) with non-const argv. + void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, + bool single_minus_longopt = false, int bufmax = -1) + { + parse(false, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + /** + * @brief Returns the number of valid Option objects in @c buffer[]. + * + * @note + * @li The returned value always reflects the number of Options in the buffer[] array used for + * the most recent call to parse(). + * @li The count (and the buffer[]) includes unknown options if they are collected + * (see Descriptor::longopt). + */ + int optionsCount() + { + return op_count; + } + + /** + * @brief Returns the number of non-option arguments that remained at the end of the + * most recent parse() that actually encountered non-option arguments. + * + * @note + * A parse() that does not encounter non-option arguments will leave this value + * as well as nonOptions() undisturbed. This means you can feed the Parser a + * default argument vector that contains non-option arguments (e.g. a default filename). + * Then you feed it the actual arguments from the user. If the user has supplied at + * least one non-option argument, all of the non-option arguments from the default + * disappear and are replaced by the user's non-option arguments. However, if the + * user does not supply any non-option arguments the defaults will still be in + * effect. + */ + int nonOptionsCount() + { + return nonop_count; + } + + /** + * @brief Returns a pointer to an array of non-option arguments (only valid + * if nonOptionsCount() >0 ). + * + * @note + * @li parse() does not copy arguments, so this pointer points into the actual argument + * vector as passed to parse(). + * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls + * that actually encounter non-option arguments. A parse() call that encounters only + * options, will not change nonOptions(). + */ + const char** nonOptions() + { + return nonop_args; + } + + /** + * @brief Returns nonOptions()[i] (@e without checking if i is in range!). + */ + const char* nonOption(int i) + { + return nonOptions()[i]; + } + + /** + * @brief Returns @c true if an unrecoverable error occurred while parsing options. + * + * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an + * unrecoverable error that aborts the parse. Unknown options are only an error if + * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected. + * In that case if you want to exit the program if either an illegal argument + * or an unknown option has been passed, use code like this + * + * @code + * if (parser.error() || options[UNKNOWN]) + * exit(1); + * @endcode + * + */ + bool error() + { + return err; + } + +private: + friend struct Stats; + class StoreOptionAction; + struct Action; + + /** + * @internal + * @brief This is the core function that does all the parsing. + * @retval false iff an unrecoverable error occurred. + */ + static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, + bool single_minus_longopt, bool print_errors, int min_abbr_len); + + /** + * @internal + * @brief Returns true iff @c st1 is a prefix of @c st2 and + * in case @c st2 is longer than @c st1, then + * the first additional character is '='. + * + * @par Examples: + * @code + * streq("foo", "foo=bar") == true + * streq("foo", "foobar") == false + * streq("foo", "foo") == true + * streq("foo=bar", "foo") == false + * @endcode + */ + static bool streq(const char* st1, const char* st2) + { + while (*st1 != 0) + if (*st1++ != *st2++) + return false; + return (*st2 == 0 || *st2 == '='); + } + + /** + * @internal + * @brief Like streq() but handles abbreviations. + * + * Returns true iff @c st1 and @c st2 have a common + * prefix with the following properties: + * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller). + * @li (if min <= 0) its length is the same as that of @c st1 + * @li within @c st2 the character following the common prefix is either '=' or end-of-string. + * + * Examples: + * @code + * streqabbr("foo", "foo=bar",) == true + * streqabbr("foo", "fo=bar" , 2) == true + * streqabbr("foo", "fo" , 2) == true + * streqabbr("foo", "fo" , 0) == false + * streqabbr("foo", "f=bar" , 2) == false + * streqabbr("foo", "f" , 2) == false + * streqabbr("fo" , "foo=bar",) == false + * streqabbr("foo", "foobar" ,) == false + * streqabbr("foo", "fobar" ,) == false + * streqabbr("foo", "foo" ,) == true + * @endcode + */ + static bool streqabbr(const char* st1, const char* st2, long long min) + { + const char* st1start = st1; + while (*st1 != 0 && (*st1 == *st2)) + { + ++st1; + ++st2; + } + + return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '='); + } + + /** + * @internal + * @brief Returns true iff character @c ch is contained in the string @c st. + * + * Returns @c true for @c ch==0 . + */ + static bool instr(char ch, const char* st) + { + while (*st != 0 && *st != ch) + ++st; + return *st == ch; + } + + /** + * @internal + * @brief Rotates args[-count],...,args[-1],args[0] to become + * args[0],args[-count],...,args[-1]. + */ + static void shift(const char** args, int count) + { + for (int i = 0; i > -count; --i) + { + const char* temp = args[i]; + args[i] = args[i - 1]; + args[i - 1] = temp; + } + } +}; + +/** + * @internal + * @brief Interface for actions Parser::workhorse() should perform for each Option it + * parses. + */ +struct Parser::Action +{ + + virtual ~Action() {} + + /** + * @brief Called by Parser::workhorse() for each Option that has been successfully + * parsed (including unknown + * options if they have a Descriptor whose Descriptor::check_arg does not return + * @ref ARG_ILLEGAL. + * + * Returns @c false iff a fatal error has occured and the parse should be aborted. + */ + virtual bool perform(Option&) + { + return true; + } + + /** + * @brief Called by Parser::workhorse() after finishing the parse. + * @param numargs the number of non-option arguments remaining + * @param args pointer to the first remaining non-option argument (if numargs > 0). + * + * @return + * @c false iff a fatal error has occurred. + */ + virtual bool finished(int numargs, const char** args) + { + (void) numargs; + (void) args; + return true; + } +}; + +/** + * @internal + * @brief An Action to pass to Parser::workhorse() that will increment a counter for + * each parsed Option. + */ +class Stats::CountOptionsAction: public Parser::Action +{ + unsigned* buffer_max; +public: + /** + * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each + * parsed Option. + */ + CountOptionsAction(unsigned* buffer_max_) : + buffer_max(buffer_max_) + { + } + + bool perform(Option&) + { + if (*buffer_max == 0x7fffffff) + return false; // overflow protection: don't accept number of options that doesn't fit signed int + ++*buffer_max; + return true; + } +}; + +/** + * @internal + * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in + * appropriate arrays (see Parser::parse()). + */ +class Parser::StoreOptionAction: public Parser::Action +{ + Parser& parser; + Option* options; + Option* buffer; + int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough". +public: + /** + * @brief Creates a new StoreOption action. + * @param parser_ the parser whose op_count should be updated. + * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index] + * @param buffer_ each Option is appended to this array as long as there's a free slot. + * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough". + */ + StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) : + parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_) + { + // find first empty slot in buffer (if any) + int bufidx = 0; + while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx]) + ++bufidx; + + // set parser's optionCount + parser.op_count = bufidx; + } + + bool perform(Option& option) + { + if (bufmax < 0 || parser.op_count < bufmax) + { + if (parser.op_count == 0x7fffffff) + return false; // overflow protection: don't accept number of options that doesn't fit signed int + + buffer[parser.op_count] = option; + int idx = buffer[parser.op_count].desc->index; + if (options[idx]) + options[idx].append(buffer[parser.op_count]); + else + options[idx] = buffer[parser.op_count]; + ++parser.op_count; + } + return true; // NOTE: an option that is discarded because of a full buffer is not fatal + } + + bool finished(int numargs, const char** args) + { + // only overwrite non-option argument list if there's at least 1 + // new non-option argument. Otherwise we keep the old list. This + // makes it easy to use default non-option arguments. + if (numargs > 0) + { + parser.nonop_count = numargs; + parser.nonop_args = args; + } + + return true; + } +}; + +inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], + Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax) +{ + StoreOptionAction action(*this, options, buffer, bufmax); + err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len); +} + +inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len, + bool single_minus_longopt) +{ + // determine size of options array. This is the greatest index used in the usage + 1 + int i = 0; + while (usage[i].shortopt != 0) + { + if (usage[i].index + 1 >= options_max) + options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel + + ++i; + } + + CountOptionsAction action(&buffer_max); + Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len); +} + +inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, + bool single_minus_longopt, bool print_errors, int min_abbr_len) +{ + // protect against NULL pointer + if (args == 0) + numargs = 0; + + int nonops = 0; + + while (numargs != 0 && *args != 0) + { + const char* param = *args; // param can be --long-option, -srto or non-option argument + + // in POSIX mode the first non-option argument terminates the option list + // a lone minus character is a non-option argument + if (param[0] != '-' || param[1] == 0) + { + if (gnu) + { + ++nonops; + ++args; + if (numargs > 0) + --numargs; + continue; + } + else + break; + } + + // -- terminates the option list. The -- itself is skipped. + if (param[1] == '-' && param[2] == 0) + { + shift(args, nonops); + ++args; + if (numargs > 0) + --numargs; + break; + } + + bool handle_short_options; + const char* longopt_name; + if (param[1] == '-') // if --long-option + { + handle_short_options = false; + longopt_name = param + 2; + } + else + { + handle_short_options = true; + longopt_name = param + 1; //for testing a potential -long-option + } + + bool try_single_minus_longopt = single_minus_longopt; + bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid? + + do // loop over short options in group, for long options the body is executed only once + { + int idx = 0; + + const char* optarg = 0; + + /******************** long option **********************/ + if (handle_short_options == false || try_single_minus_longopt) + { + idx = 0; + while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name)) + ++idx; + + if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options + { + int i1 = 0; + while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len)) + ++i1; + if (usage[i1].longopt != 0) + { // now test if the match is unambiguous by checking for another match + int i2 = i1 + 1; + while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len)) + ++i2; + + if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx + idx = i1; + } + } + + // if we found something, disable handle_short_options (only relevant if single_minus_longopt) + if (usage[idx].longopt != 0) + handle_short_options = false; + + try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group + + optarg = longopt_name; + while (*optarg != 0 && *optarg != '=') + ++optarg; + if (*optarg == '=') // attached argument + ++optarg; + else + // possibly detached argument + optarg = (have_more_args ? args[1] : 0); + } + + /************************ short option ***********************************/ + if (handle_short_options) + { + if (*++param == 0) // point at the 1st/next option character + break; // end of short option group + + idx = 0; + while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt)) + ++idx; + + if (param[1] == 0) // if the potential argument is separate + optarg = (have_more_args ? args[1] : 0); + else + // if the potential argument is attached + optarg = param + 1; + } + + const Descriptor* descriptor = &usage[idx]; + + if (descriptor->shortopt == 0) /************** unknown option ********************/ + { + // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options + idx = 0; + while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0)) + ++idx; + descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]); + } + + if (descriptor != 0) + { + Option option(descriptor, param, optarg); + switch (descriptor->check_arg(option, print_errors)) + { + case ARG_ILLEGAL: + return false; // fatal + case ARG_OK: + // skip one element of the argument vector, if it's a separated argument + if (optarg != 0 && have_more_args && optarg == args[1]) + { + shift(args, nonops); + if (numargs > 0) + --numargs; + ++args; + } + + // No further short options are possible after an argument + handle_short_options = false; + + break; + case ARG_IGNORE: + case ARG_NONE: + option.arg = 0; + break; + } + + if (!action.perform(option)) + return false; + } + + } while (handle_short_options); + + shift(args, nonops); + ++args; + if (numargs > 0) + --numargs; + + } // while + + if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number + numargs = 0; // of arguments, but as a service to the user we fix this if we spot it. + + if (numargs < 0) // if we don't know the number of remaining non-option arguments + { // we need to count them + numargs = 0; + while (args[numargs] != 0) + ++numargs; + } + + return action.finished(numargs + nonops, args - nonops); +} + +/** + * @internal + * @brief The implementation of option::printUsage(). + */ +struct PrintUsageImplementation +{ + /** + * @internal + * @brief Interface for Functors that write (part of) a string somewhere. + */ + struct IStringWriter + { + virtual ~IStringWriter() {} + /** + * @brief Writes the given number of chars beginning at the given pointer somewhere. + */ + virtual void operator()(const char*, int) + { + } + }; + + /** + * @internal + * @brief Encapsulates a function with signature func(string, size) where + * string can be initialized with a const char* and size with an int. + */ + template + struct FunctionWriter: public IStringWriter + { + Function* write; + + virtual void operator()(const char* str, int size) + { + (*write)(str, size); + } + + FunctionWriter(Function* w) : + write(w) + { + } + }; + + /** + * @internal + * @brief Encapsulates a reference to an object with a write(string, size) + * method like that of @c std::ostream. + */ + template + struct OStreamWriter: public IStringWriter + { + OStream& ostream; + + virtual void operator()(const char* str, int size) + { + ostream.write(str, size); + } + + OStreamWriter(OStream& o) : + ostream(o) + { + } + }; + + /** + * @internal + * @brief Like OStreamWriter but encapsulates a @c const reference, which is + * typically a temporary object of a user class. + */ + template + struct TemporaryWriter: public IStringWriter + { + const Temporary& userstream; + + virtual void operator()(const char* str, int size) + { + userstream.write(str, size); + } + + TemporaryWriter(const Temporary& u) : + userstream(u) + { + } + }; + + /** + * @internal + * @brief Encapsulates a function with the signature func(fd, string, size) (the + * signature of the @c write() system call) + * where fd can be initialized from an int, string from a const char* and size from an int. + */ + template + struct SyscallWriter: public IStringWriter + { + Syscall* write; + int fd; + + virtual void operator()(const char* str, int size) + { + (*write)(fd, str, size); + } + + SyscallWriter(Syscall* w, int f) : + write(w), fd(f) + { + } + }; + + /** + * @internal + * @brief Encapsulates a function with the same signature as @c std::fwrite(). + */ + template + struct StreamWriter: public IStringWriter + { + Function* fwrite; + Stream* stream; + + virtual void operator()(const char* str, int size) + { + (*fwrite)(str, size, 1, stream); + } + + StreamWriter(Function* w, Stream* s) : + fwrite(w), stream(s) + { + } + }; + + /** + * @internal + * @brief Sets i1 = max(i1, i2) + */ + static void upmax(int& i1, int i2) + { + i1 = (i1 >= i2 ? i1 : i2); + } + + /** + * @internal + * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x + * and sets @c x=want_x . + * If x > want_x , a line break is output before indenting. + * + * @param write Spaces and possibly a line break are written via this functor to get + * the desired indentation @c want_x . + * @param[in,out] x the current indentation. Set to @c want_x by this method. + * @param want_x the desired indentation. + */ + static void indent(IStringWriter& write, int& x, int want_x) + { + int indent = want_x - x; + if (indent < 0) + { + write("\n", 1); + indent = want_x; + } + + if (indent > 0) + { + char space = ' '; + for (int i = 0; i < indent; ++i) + write(&space, 1); + x = want_x; + } + } + + /** + * @brief Returns true if ch is the unicode code point of a wide character. + * + * @note + * The following character ranges are treated as wide + * @code + * 1100..115F + * 2329..232A (just 2 characters!) + * 2E80..A4C6 except for 303F + * A960..A97C + * AC00..D7FB + * F900..FAFF + * FE10..FE6B + * FF01..FF60 + * FFE0..FFE6 + * 1B000...... + * @endcode + */ + static bool isWideChar(unsigned ch) + { + if (ch == 0x303F) + return false; + + return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6) + || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF) + || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6) + || (0x1B000 <= ch)); + } + + /** + * @internal + * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and + * iterates over these components. + * + * The top-level organizational unit is the @e table. + * A table begins at a Descriptor with @c help!=NULL and extends up to + * a Descriptor with @c help==NULL. + * + * A table consists of @e rows. Due to line-wrapping and explicit breaks + * a row may take multiple lines on screen. Rows within the table are separated + * by \\n. They never cross Descriptor boundaries. This means a row ends either + * at \\n or the 0 at the end of the help string. + * + * A row consists of columns/cells. Columns/cells within a row are separated by \\t. + * Line breaks within a cell are marked by \\v. + * + * Rows in the same table need not have the same number of columns/cells. The + * extreme case are interjections, which are rows that contain neither \\t nor \\v. + * These are NOT treated specially by LinePartIterator, but they are treated + * specially by printUsage(). + * + * LinePartIterator iterates through the usage at 3 levels: table, row and part. + * Tables and rows are as described above. A @e part is a line within a cell. + * LinePartIterator iterates through 1st parts of all cells, then through the 2nd + * parts of all cells (if any),... @n + * Example: The row "1 \v 3 \t 2 \v 4" has 2 cells/columns and 4 parts. + * The parts will be returned in the order 1, 2, 3, 4. + * + * It is possible that some cells have fewer parts than others. In this case + * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator + * always returns the same number of parts for each column. Note that this is different + * from the way rows and columns are handled. LinePartIterator does @e not guarantee that + * the same number of columns will be returned for each row. + * + */ + class LinePartIterator + { + const Descriptor* tablestart; //!< The 1st descriptor of the current table. + const Descriptor* rowdesc; //!< The Descriptor that contains the current row. + const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help. + const char* ptr; //!< Ptr to current part within the current row. + int col; //!< Index of current column. + int len; //!< Length of the current part (that ptr points at) in BYTES + int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account). + int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs. + int line_in_block; //!< Line index within the current cell of the current part. + int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration. + bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell. + + /** + * @brief Determines the byte and character lengths of the part at @ref ptr and + * stores them in @ref len and @ref screenlen respectively. + */ + void update_length() + { + screenlen = 0; + for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len) + { + ++screenlen; + unsigned ch = static_cast( ptr[len] ); + if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte + { + // int __builtin_clz (unsigned int x) + // Returns the number of leading 0-bits in x, starting at the most significant bit + unsigned mask = static_cast( -1 ) >> __builtin_clz(ch ^ 0xff); + ch = ch & mask; // mask out length bits, we don't verify their correctness + while ((static_cast( ptr[len + 1] ) ^ 0x80) <= 0x3F) // while next byte is continuation byte + { + ch = (ch << 6) ^ static_cast( ptr[len + 1] ) ^ 0x80; // add continuation to char code + ++len; + } + // ch is the decoded unicode code point + if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case + ++screenlen; + } + } + } + + public: + //! @brief Creates an iterator for @c usage. + LinePartIterator(const Descriptor usage[]) : + tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), max_line_in_block(0), line_in_block(0), + target_line_in_block(0), hit_target_line(true) + { + } + + /** + * @brief Moves iteration to the next table (if any). Has to be called once on a new + * LinePartIterator to move to the 1st table. + * @retval false if moving to next table failed because no further table exists. + */ + bool nextTable() + { + // If this is NOT the first time nextTable() is called after the constructor, + // then skip to the next table break (i.e. a Descriptor with help == 0) + if (rowdesc != 0) + { + while (tablestart->help != 0 && tablestart->shortopt != 0) + ++tablestart; + } + + // Find the next table after the break (if any) + while (tablestart->help == 0 && tablestart->shortopt != 0) + ++tablestart; + + restartTable(); + return rowstart != 0; + } + + /** + * @brief Reset iteration to the beginning of the current table. + */ + void restartTable() + { + rowdesc = tablestart; + rowstart = tablestart->help; + ptr = 0; + } + + /** + * @brief Moves iteration to the next row (if any). Has to be called once after each call to + * @ref nextTable() to move to the 1st row of the table. + * @retval false if moving to next row failed because no further row exists. + */ + bool nextRow() + { + if (ptr == 0) + { + restartRow(); + return rowstart != 0; + } + + while (*ptr != 0 && *ptr != '\n') + ++ptr; + + if (*ptr == 0) + { + if ((rowdesc + 1)->help == 0) // table break + return false; + + ++rowdesc; + rowstart = rowdesc->help; + } + else // if (*ptr == '\n') + { + rowstart = ptr + 1; + } + + restartRow(); + return true; + } + + /** + * @brief Reset iteration to the beginning of the current row. + */ + void restartRow() + { + ptr = rowstart; + col = -1; + len = 0; + screenlen = 0; + max_line_in_block = 0; + line_in_block = 0; + target_line_in_block = 0; + hit_target_line = true; + } + + /** + * @brief Moves iteration to the next part (if any). Has to be called once after each call to + * @ref nextRow() to move to the 1st part of the row. + * @retval false if moving to next part failed because no further part exists. + * + * See @ref LinePartIterator for details about the iteration. + */ + bool next() + { + if (ptr == 0) + return false; + + if (col == -1) + { + col = 0; + update_length(); + return true; + } + + ptr += len; + while (true) + { + switch (*ptr) + { + case '\v': + upmax(max_line_in_block, ++line_in_block); + ++ptr; + break; + case '\t': + if (!hit_target_line) // if previous column did not have the targetline + { // then "insert" a 0-length part + update_length(); + hit_target_line = true; + return true; + } + + hit_target_line = false; + line_in_block = 0; + ++col; + ++ptr; + break; + case 0: + case '\n': + if (!hit_target_line) // if previous column did not have the targetline + { // then "insert" a 0-length part + update_length(); + hit_target_line = true; + return true; + } + + if (++target_line_in_block > max_line_in_block) + { + update_length(); + return false; + } + + hit_target_line = false; + line_in_block = 0; + col = 0; + ptr = rowstart; + continue; + default: + ++ptr; + continue; + } // switch + + if (line_in_block == target_line_in_block) + { + update_length(); + hit_target_line = true; + return true; + } + } // while + } + + /** + * @brief Returns the index (counting from 0) of the column in which + * the part pointed to by @ref data() is located. + */ + int column() + { + return col; + } + + /** + * @brief Returns the index (counting from 0) of the line within the current column + * this part belongs to. + */ + int line() + { + return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line + } + + /** + * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters). + */ + int length() + { + return len; + } + + /** + * @brief Returns the width in screen columns of the part pointed to by @ref data(). + * Takes multi-byte UTF-8 sequences and wide characters into account. + */ + int screenLength() + { + return screenlen; + } + + /** + * @brief Returns the current part of the iteration. + */ + const char* data() + { + return ptr; + } + }; + + /** + * @internal + * @brief Takes input and line wraps it, writing out one line at a time so that + * it can be interleaved with output from other columns. + * + * The LineWrapper is used to handle the last column of each table as well as interjections. + * The LineWrapper is called once for each line of output. If the data given to it fits + * into the designated width of the last column it is simply written out. If there + * is too much data, an appropriate split point is located and only the data up to this + * split point is written out. The rest of the data is queued for the next line. + * That way the last column can be line wrapped and interleaved with data from + * other columns. The following example makes this clearer: + * @code + * Column 1,1 Column 2,1 This is a long text + * Column 1,2 Column 2,2 that does not fit into + * a single line. + * @endcode + * + * The difficulty in producing this output is that the whole string + * "This is a long text that does not fit into a single line" is the + * 1st and only part of column 3. In order to produce the above + * output the string must be output piecemeal, interleaved with + * the data from the other columns. + */ + class LineWrapper + { + static const int bufmask = 15; //!< Must be a power of 2 minus 1. + /** + * @brief Ring buffer for length component of pair (data, length). + */ + int lenbuf[bufmask + 1]; + /** + * @brief Ring buffer for data component of pair (data, length). + */ + const char* datbuf[bufmask + 1]; + /** + * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer + * assumes that the indentation has already been written when @ref process() + * is called, so this value is only used when a buffer flush requires writing + * additional lines of output. + */ + int x; + /** + * @brief The width of the column to line wrap. + */ + int width; + int head; //!< @brief index for next write + int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read) + + /** + * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to + * free up space. The contract of process() says that only 1 line is output. So + * this variable is used to track whether something has output a line. It is + * reset at the beginning of process() and checked at the end to decide if + * output has already occurred or is still needed. + */ + bool wrote_something; + + bool buf_empty() + { + return ((tail + 1) & bufmask) == head; + } + + bool buf_full() + { + return tail == head; + } + + void buf_store(const char* data, int len) + { + lenbuf[head] = len; + datbuf[head] = data; + head = (head + 1) & bufmask; + } + + //! @brief Call BEFORE reading ...buf[tail]. + void buf_next() + { + tail = (tail + 1) & bufmask; + } + + /** + * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line + * is flushed out of the buffer into @c write. + */ + void output(IStringWriter& write, const char* data, int len) + { + if (buf_full()) + write_one_line(write); + + buf_store(data, len); + } + + /** + * @brief Writes a single line of output from the buffer to @c write. + */ + void write_one_line(IStringWriter& write) + { + if (wrote_something) // if we already wrote something, we need to start a new line + { + write("\n", 1); + int _ = 0; + indent(write, _, x); + } + + if (!buf_empty()) + { + buf_next(); + write(datbuf[tail], lenbuf[tail]); + } + + wrote_something = true; + } + public: + + /** + * @brief Writes out all remaining data from the LineWrapper using @c write. + * Unlike @ref process() this method indents all lines including the first and + * will output a \\n at the end (but only if something has been written). + */ + void flush(IStringWriter& write) + { + if (buf_empty()) + return; + int _ = 0; + indent(write, _, x); + wrote_something = false; + while (!buf_empty()) + write_one_line(write); + write("\n", 1); + } + + /** + * @brief Process, wrap and output the next piece of data. + * + * process() will output at least one line of output. This is not necessarily + * the @c data passed in. It may be data queued from a prior call to process(). + * If the internal buffer is full, more than 1 line will be output. + * + * process() assumes that the a proper amount of indentation has already been + * output. It won't write any further indentation before the 1st line. If + * more than 1 line is written due to buffer constraints, the lines following + * the first will be indented by this method, though. + * + * No \\n is written by this method after the last line that is written. + * + * @param write where to write the data. + * @param data the new chunk of data to write. + * @param len the length of the chunk of data to write. + */ + void process(IStringWriter& write, const char* data, int len) + { + wrote_something = false; + + while (len > 0) + { + if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes) + { + output(write, data, len); + len = 0; + } + else // if (len > width) it's possible (but not guaranteed) that utf8len > width + { + int utf8width = 0; + int maxi = 0; + while (maxi < len && utf8width < width) + { + int charbytes = 1; + unsigned ch = static_cast( data[maxi] ); + if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte + { + // int __builtin_clz (unsigned int x) + // Returns the number of leading 0-bits in x, starting at the most significant bit + unsigned mask = static_cast( -1 ) >> __builtin_clz(ch ^ 0xff); + ch = ch & mask; // mask out length bits, we don't verify their correctness + while ((maxi + charbytes < len) && // + ((static_cast( data[maxi + charbytes] ) ^ 0x80) <= 0x3F)) // while next byte is continuation byte + { + ch = (ch << 6) ^ static_cast( data[maxi + charbytes] ) ^ 0x80; // add continuation to char code + ++charbytes; + } + // ch is the decoded unicode code point + if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case + { + if (utf8width + 2 > width) + break; + ++utf8width; + } + } + ++utf8width; + maxi += charbytes; + } + + // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits + // onto the 1st line. If maxi == len, all characters fit on the line. + + if (maxi == len) + { + output(write, data, len); + len = 0; + } + else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line + { + int i; + for (i = maxi; i >= 0; --i) + if (data[i] == ' ') + break; + + if (i >= 0) + { + output(write, data, i); + data += i + 1; + len -= i + 1; + } + else // did not find a space to split at => split before data[maxi] + { // data[maxi] is always the beginning of a character, never a continuation byte + output(write, data, maxi); + data += maxi; + len -= maxi; + } + } + } + } + if (!wrote_something) // if we didn't already write something to make space in the buffer + write_one_line(write); // write at most one line of actual output + } + + /** + * @brief Constructs a LineWrapper that wraps its output to fit into + * screen columns @c x1 (incl.) to @c x2 (excl.). + * + * @c x1 gives the indentation LineWrapper uses if it needs to indent. + */ + LineWrapper(int x1, int x2) : + x(x1), width(x2 - x1), head(0), tail(bufmask) + { + if (width < 2) // because of wide characters we need at least width 2 or the code breaks + width = 2; + } + }; + + /** + * @internal + * @brief This is the implementation that is shared between all printUsage() templates. + * Because all printUsage() templates share this implementation, there is no template bloat. + */ + static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, // + int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) + { + if (width < 1) // protect against nonsense values + width = 80; + + if (width > 10000) // protect against overflow in the following computation + width = 10000; + + int last_column_min_width = ((width * last_column_min_percent) + 50) / 100; + int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100; + if (last_column_own_line_max_width == 0) + last_column_own_line_max_width = 1; + + LinePartIterator part(usage); + while (part.nextTable()) + { + + /***************** Determine column widths *******************************/ + + const int maxcolumns = 8; // 8 columns are enough for everyone + int col_width[maxcolumns]; + int lastcolumn; + int leftwidth; + int overlong_column_threshold = 10000; + do + { + lastcolumn = 0; + for (int i = 0; i < maxcolumns; ++i) + col_width[i] = 0; + + part.restartTable(); + while (part.nextRow()) + { + while (part.next()) + { + if (part.column() < maxcolumns) + { + upmax(lastcolumn, part.column()); + if (part.screenLength() < overlong_column_threshold) + // We don't let rows that don't use table separators (\t or \v) influence + // the width of column 0. This allows the user to interject section headers + // or explanatory paragraphs that do not participate in the table layout. + if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' + || part.data()[part.length()] == '\v') + upmax(col_width[part.column()], part.screenLength()); + } + } + } + + /* + * If the last column doesn't fit on the same + * line as the other columns, we can fix that by starting it on its own line. + * However we can't do this for any of the columns 0..lastcolumn-1. + * If their sum exceeds the maximum width we try to fix this by iteratively + * ignoring the widest line parts in the width determination until + * we arrive at a series of column widths that fit into one line. + * The result is a layout where everything is nicely formatted + * except for a few overlong fragments. + * */ + + leftwidth = 0; + overlong_column_threshold = 0; + for (int i = 0; i < lastcolumn; ++i) + { + leftwidth += col_width[i]; + upmax(overlong_column_threshold, col_width[i]); + } + + } while (leftwidth > width); + + /**************** Determine tab stops and last column handling **********************/ + + int tabstop[maxcolumns]; + tabstop[0] = 0; + for (int i = 1; i < maxcolumns; ++i) + tabstop[i] = tabstop[i - 1] + col_width[i - 1]; + + int rightwidth = width - tabstop[lastcolumn]; + bool print_last_column_on_own_line = false; + if (rightwidth < last_column_min_width && // if we don't have the minimum requested width for the last column + ( col_width[lastcolumn] == 0 || // and all last columns are > overlong_column_threshold + rightwidth < col_width[lastcolumn] // or there is at least one last column that requires more than the space available + ) + ) + { + print_last_column_on_own_line = true; + rightwidth = last_column_own_line_max_width; + } + + // If lastcolumn == 0 we must disable print_last_column_on_own_line because + // otherwise 2 copies of the last (and only) column would be output. + // Actually this is just defensive programming. It is currently not + // possible that lastcolumn==0 and print_last_column_on_own_line==true + // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 => + // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes + // a bullshit value >100 for last_column_min_percent) => the above if condition + // is false => print_last_column_on_own_line==false + if (lastcolumn == 0) + print_last_column_on_own_line = false; + + LineWrapper lastColumnLineWrapper(width - rightwidth, width); + LineWrapper interjectionLineWrapper(0, width); + + part.restartTable(); + + /***************** Print out all rows of the table *************************************/ + + while (part.nextRow()) + { + int x = -1; + while (part.next()) + { + if (part.column() > lastcolumn) + continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1) + + if (part.column() == 0) + { + if (x >= 0) + write("\n", 1); + x = 0; + } + + indent(write, x, tabstop[part.column()]); + + if ((part.column() < lastcolumn) + && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' + || part.data()[part.length()] == '\v')) + { + write(part.data(), part.length()); + x += part.screenLength(); + } + else // either part.column() == lastcolumn or we are in the special case of + // an interjection that doesn't contain \v or \t + { + // NOTE: This code block is not necessarily executed for + // each line, because some rows may have fewer columns. + + LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper; + + if (!print_last_column_on_own_line || part.column() != lastcolumn) + lineWrapper.process(write, part.data(), part.length()); + } + } // while + + if (print_last_column_on_own_line) + { + part.restartRow(); + while (part.next()) + { + if (part.column() == lastcolumn) + { + write("\n", 1); + int _ = 0; + indent(write, _, width - rightwidth); + lastColumnLineWrapper.process(write, part.data(), part.length()); + } + } + } + + write("\n", 1); + lastColumnLineWrapper.flush(write); + interjectionLineWrapper.flush(write); + } + } + } + +} +; + +/** + * @brief Outputs a nicely formatted usage string with support for multi-column formatting + * and line-wrapping. + * + * printUsage() takes the @c help texts of a Descriptor[] array and formats them into + * a usage message, wrapping lines to achieve the desired output width. + * + * Table formatting: + * + * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables + * are used to align elements in the output. + * + * @code + * // Without a table. The explanatory texts are not aligned. + * -c, --create |Creates something. + * -k, --kill |Destroys something. + * + * // With table formatting. The explanatory texts are aligned. + * -c, --create |Creates something. + * -k, --kill |Destroys something. + * @endcode + * + * Table formatting removes the need to pad help texts manually with spaces to achieve + * alignment. To create a table, simply insert \\t (tab) characters to separate the cells + * within a row. + * + * @code + * const option::Descriptor usage[] = { + * {..., "-c, --create \tCreates something." }, + * {..., "-k, --kill \tDestroys something." }, ... + * @endcode + * + * Note that you must include the minimum amount of space desired between cells yourself. + * Table formatting will insert further spaces as needed to achieve alignment. + * + * You can insert line breaks within cells by using \\v (vertical tab). + * + * @code + * const option::Descriptor usage[] = { + * {..., "-c,\v--create \tCreates\vsomething." }, + * {..., "-k,\v--kill \tDestroys\vsomething." }, ... + * + * // results in + * + * -c, Creates + * --create something. + * -k, Destroys + * --kill something. + * @endcode + * + * You can mix lines that do not use \\t or \\v with those that do. The plain + * lines will not mess up the table layout. Alignment of the table columns will + * be maintained even across these interjections. + * + * @code + * const option::Descriptor usage[] = { + * {..., "-c, --create \tCreates something." }, + * {..., "----------------------------------" }, + * {..., "-k, --kill \tDestroys something." }, ... + * + * // results in + * + * -c, --create Creates something. + * ---------------------------------- + * -k, --kill Destroys something. + * @endcode + * + * You can have multiple tables within the same usage whose columns are + * aligned independently. Simply insert a dummy Descriptor with @c help==0. + * + * @code + * const option::Descriptor usage[] = { + * {..., "Long options:" }, + * {..., "--very-long-option \tDoes something long." }, + * {..., "--ultra-super-mega-long-option \tTakes forever to complete." }, + * {..., 0 }, // ---------- table break ----------- + * {..., "Short options:" }, + * {..., "-s \tShort." }, + * {..., "-q \tQuick." }, ... + * + * // results in + * + * Long options: + * --very-long-option Does something long. + * --ultra-super-mega-long-option Takes forever to complete. + * Short options: + * -s Short. + * -q Quick. + * + * // Without the table break it would be + * + * Long options: + * --very-long-option Does something long. + * --ultra-super-mega-long-option Takes forever to complete. + * Short options: + * -s Short. + * -q Quick. + * @endcode + * + * Output methods: + * + * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for + * output in the first argument(s) to printUsage(). Because printUsage() is implemented as + * a set of template functions, you have great flexibility in your choice of output + * method. The following example demonstrates typical uses. Anything that's similar enough + * will work. + * + * @code + * #include // write() + * #include // cout + * #include // ostringstream + * #include // fwrite() + * using namespace std; + * + * void my_write(const char* str, int size) { + * fwrite(str, size, 1, stdout); + * } + * + * struct MyWriter { + * void write(const char* buf, size_t size) const { + * fwrite(str, size, 1, stdout); + * } + * }; + * + * struct MyWriteFunctor { + * void operator()(const char* buf, size_t size) { + * fwrite(str, size, 1, stdout); + * } + * }; + * ... + * printUsage(my_write, usage); // custom write function + * printUsage(MyWriter(), usage); // temporary of a custom class + * MyWriter writer; + * printUsage(writer, usage); // custom class object + * MyWriteFunctor wfunctor; + * printUsage(&wfunctor, usage); // custom functor + * printUsage(write, 1, usage); // write() to file descriptor 1 + * printUsage(cout, usage); // an ostream& + * printUsage(fwrite, stdout, usage); // fwrite() to stdout + * ostringstream sstr; + * printUsage(sstr, usage); // an ostringstream& + * + * @endcode + * + * @par Notes: + * @li the @c write() method of a class that is to be passed as a temporary + * as @c MyWriter() is in the example, must be a @c const method, because + * temporary objects are passed as const reference. This only applies to + * temporary objects that are created and destroyed in the same statement. + * If you create an object like @c writer in the example, this restriction + * does not apply. + * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer. + * This differs from the way functors are passed to e.g. the STL algorithms. + * @li All printUsage() templates are tiny wrappers around a shared non-template implementation. + * So there's no penalty for using different versions in the same program. + * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded + * output. If your system uses a different charset, you must do your own conversion. You + * may also need to change the font of the console to see non-ASCII characters properly. + * This is particularly true for Windows. + * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments) + * into the usage. printUsage() has no protection against malicious UTF-8 sequences. + * + * @param prn The output method to use. See the examples above. + * @param usage the Descriptor[] array whose @c help texts will be formatted. + * @param width the maximum number of characters per output line. Note that this number is + * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will + * count multi-byte UTF-8 sequences properly. Asian wide characters are counted + * as 2 characters. + * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available + * for the last column (which typically contains the textual explanation of an option). + * If less space is available, the last column will be printed on its own line, indented + * according to @c last_column_own_line_max_percent. + * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to + * less than @c last_column_min_percent of the width being available, then only + * @c last_column_own_line_max_percent of the extra line(s) will be used for the + * last column's text. This ensures an indentation. See example below. + * + * @code + * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10) + * --3456789 1234567890 + * 1234567890 + * + * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) + * // last_column_own_line_max_percent=75 + * --3456789 + * 123456789012345 + * 67890 + * + * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) + * // last_column_own_line_max_percent=33 (i.e. max. 5) + * --3456789 + * 12345 + * 67890 + * 12345 + * 67890 + * @endcode + */ +template +void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::OStreamWriter write(prn); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::FunctionWriter write(prn); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::TemporaryWriter write(prn); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::SyscallWriter write(prn, fd); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent = + 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::StreamWriter write(prn, stream); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +} +// namespace option + +#endif /* OPTIONPARSER_H_ */ diff --git a/external/CppMicroServices/third_party/patches/civetweb_v1.8.patch b/external/CppMicroServices/third_party/patches/civetweb_v1.8.patch new file mode 100644 index 00000000..53b52c91 --- /dev/null +++ b/external/CppMicroServices/third_party/patches/civetweb_v1.8.patch @@ -0,0 +1,41 @@ +diff --git a/third_party/civetweb/civetweb.c b/third_party/civetweb/civetweb.c +index 98130f5..cc25d9d 100644 +--- a/third_party/civetweb/civetweb.c ++++ b/third_party/civetweb/civetweb.c +@@ -129,8 +129,11 @@ mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); + + #ifdef __MACH__ + +-#define CLOCK_MONOTONIC (1) +-#define CLOCK_REALTIME (2) ++#include ++#if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 ++// define this macro to ensure system functions are used for 10.12 and beyond ++#define _DARWIN_FEATURE_CLOCK_GETTIME 0 ++#endif + + #include + #include +@@ -138,7 +141,14 @@ mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); + #include + #include + ++#ifndef CLOCK_MONOTONIC ++#define CLOCK_MONOTONIC (1) ++#endif ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME (2) ++#endif + ++#if defined(_DARWIN_FEATURE_CLOCK_GETTIME) && (_DARWIN_FEATURE_CLOCK_GETTIME == 0) + /* clock_gettime is not implemented on OSX */ + int clock_gettime(int clk_id, struct timespec *t); + +@@ -183,6 +193,7 @@ clock_gettime(int clk_id, struct timespec *t) + } + return -1; /* EINVAL - Clock ID is unknown */ + } ++#endif // defined(_DARWIN_FEATURE_CLOCK_GETTIME) && (_DARWIN_FEATURE_CLOCK_GETTIME == 0) + #endif + + diff --git a/external/CppMicroServices/third_party/patches/dirent_v1.20.1.patch b/external/CppMicroServices/third_party/patches/dirent_v1.20.1.patch new file mode 100644 index 00000000..a6cdd108 --- /dev/null +++ b/external/CppMicroServices/third_party/patches/dirent_v1.20.1.patch @@ -0,0 +1,26 @@ +diff --git a/third_party/dirent_win32.h b/third_party/dirent_win32.h +index 9b8f1d30..e459f904 +--- a/third_party/dirent_win32.h ++++ b/third_party/dirent_win32.h +@@ -531,14 +531,19 @@ opendir( + return NULL; + } + ++ if (strlen(dirname) > PATH_MAX) { ++ dirent_set_errno (ENAMETOOLONG); ++ return NULL; ++ } ++ + /* Allocate memory for DIR structure */ + dirp = (DIR*) malloc (sizeof (struct DIR)); + if (dirp) { +- wchar_t wname[PATH_MAX]; ++ wchar_t wname[PATH_MAX + 1]; + size_t n; + + /* Convert directory name to wide-character string */ +- error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX); ++ error = dirent_mbstowcs_s (&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); + if (!error) { + + /* Open directory stream using wide-character name */ diff --git a/external/CppMicroServices/third_party/patches/googletest_1.8.0.patch b/external/CppMicroServices/third_party/patches/googletest_1.8.0.patch new file mode 100644 index 00000000..4ed8ee10 --- /dev/null +++ b/external/CppMicroServices/third_party/patches/googletest_1.8.0.patch @@ -0,0 +1,14 @@ +diff --git a/third_party/googletest/CMakeLists.txt b/third_party/googletest/CMakeLists.txt +index 8d2b552e..21c3effb 100644 +--- a/third_party/googletest/CMakeLists.txt ++++ b/third_party/googletest/CMakeLists.txt +@@ -1,5 +1,9 @@ + cmake_minimum_required(VERSION 2.6.2) + ++cmake_policy(SET CMP0048 NEW) ++if(MSVC) ++ add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) ++endif() + project( googletest-distribution ) + + enable_testing() diff --git a/external/CppMicroServices/third_party/patches/jsoncpp_0.10.6.patch b/external/CppMicroServices/third_party/patches/jsoncpp_0.10.6.patch new file mode 100644 index 00000000..f12dfeb4 --- /dev/null +++ b/external/CppMicroServices/third_party/patches/jsoncpp_0.10.6.patch @@ -0,0 +1,13 @@ +diff --git a/third_party/jsoncpp.cpp b/third_party/jsoncpp.cpp +index 60c7a44..d827863 100644 +--- a/third_party/jsoncpp.cpp ++++ b/third_party/jsoncpp.cpp +@@ -1307,7 +1307,7 @@ bool OurReader::readToken(Token& token) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; +- } // else continue ++ } // else fall through + case '/': + token.type_ = tokenComment; + ok = readComment(); diff --git a/external/CppMicroServices/third_party/patches/linenoise_0f2343d2.patch b/external/CppMicroServices/third_party/patches/linenoise_0f2343d2.patch new file mode 100644 index 00000000..08808871 --- /dev/null +++ b/external/CppMicroServices/third_party/patches/linenoise_0f2343d2.patch @@ -0,0 +1,28 @@ +diff --git a/third_party/linenoise.c b/third_party/linenoise.c +index 71df27b..cefe0e0 100644 +--- a/third_party/linenoise.c ++++ b/third_party/linenoise.c +@@ -113,6 +113,7 @@ + #define strdup _strdup + #define snprintf _snprintf + #endif ++#pragma warning( disable : 4244 4267 ) + #else + #include + #include +@@ -133,7 +134,14 @@ + #include + + #include "linenoise.h" +-#include "utf8.h" ++ ++/* No utf-8 support. 1 byte = 1 char */ ++#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B)) ++#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1) ++#define utf8_index(C, I) (I) ++#define utf8_charlen(C) 1 ++ ++//#include "utf8.h" + + #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 + #define LINENOISE_MAX_LINE 4096 diff --git a/external/CppMicroServices/third_party/patches/miniz_v115_r4.patch b/external/CppMicroServices/third_party/patches/miniz_v115_r4.patch new file mode 100644 index 00000000..ddb26876 --- /dev/null +++ b/external/CppMicroServices/third_party/patches/miniz_v115_r4.patch @@ -0,0 +1,160 @@ +--- /miniz-master/miniz.c 2017-05-23 10:34:00.008406900 -0400 ++++ ./miniz.c 2017-05-23 07:44:53.641154800 -0400 +@@ -535,6 +535,7 @@ + typedef struct mz_zip_archive_tag + { + mz_uint64 m_archive_size; ++ mz_uint64 m_archive_file_ofs; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; +@@ -821,7 +822,7 @@ + + // Compresses an image to a compressed PNG file in memory. + // On entry: +-// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. ++// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. + // The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. + // level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL + // If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). +@@ -2849,17 +2850,44 @@ + #include + + #if defined(_MSC_VER) || defined(__MINGW64__) ++ #include ++ #include ++ #include ++ static wchar_t* utf8_to_wchar(const char* inStr) ++ { ++ if (inStr == NULL) ++ return NULL; ++ int wchars_count = MultiByteToWideChar(CP_UTF8, 0, inStr, -1, NULL, 0); ++ wchar_t* wstr = malloc(sizeof(wchar_t)*wchars_count); ++ if (MultiByteToWideChar(CP_UTF8, 0, inStr, -1, wstr, wchars_count) == 0) ++ { ++ wstr[0] = L'\0'; ++ } ++ return wstr; ++ } ++ + static FILE *mz_fopen(const char *pFilename, const char *pMode) + { + FILE* pFile = NULL; +- fopen_s(&pFile, pFilename, pMode); ++ wchar_t* pFilenameW = utf8_to_wchar(pFilename); ++ wchar_t* pModeW = utf8_to_wchar(pMode); ++ (void)_wfopen_s(&pFile, pFilenameW, pModeW); ++ free(pFilenameW); ++ free(pModeW); + return pFile; + } ++ + static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) + { + FILE* pFile = NULL; +- if (freopen_s(&pFile, pPath, pMode, pStream)) +- return NULL; ++ wchar_t* pFilenameW = utf8_to_wchar(pPath); ++ wchar_t* pModeW = utf8_to_wchar(pMode); ++ if (_wfreopen_s(&pFile, pFilenameW, pModeW, pStream)) ++ { ++ pFile = NULL; ++ } ++ free(pFilenameW); ++ free(pModeW); + return pFile; + } + #ifndef MINIZ_NO_TIME +@@ -3173,6 +3201,7 @@ + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); ++ mz_bool zip_signature_found = 0; + // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; +@@ -3184,23 +3213,30 @@ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) ++ { + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ++ { ++ // Read and verify the end of central directory record. ++ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs + i, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) ++ continue; ++ if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || ++ ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) ++ continue; ++ zip_signature_found = 1; + break; +- if (i >= 0) ++ } ++ } ++ ++ if (zip_signature_found) + { + cur_file_ofs += i; + break; + } +- if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) ++ if ((!cur_file_ofs) || (cur_file_ofs < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; +- cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); ++ ++ cur_file_ofs = MZ_MAX(cur_file_ofs - (mz_int64)(sizeof(buf_u32) - 3), 0); + } +- // Read and verify the end of central directory record. +- if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) +- return MZ_FALSE; +- if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || +- ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) +- return MZ_FALSE; + + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); +@@ -3210,12 +3246,16 @@ + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + +- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); ++ cdir_ofs = cur_file_ofs - cdir_size; + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return MZ_FALSE; + + pZip->m_central_directory_file_ofs = cdir_ofs; + ++ pZip->m_archive_file_ofs = cdir_ofs - MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); ++ if (pZip->m_archive_file_ofs > pZip->m_archive_size) ++ return MZ_FALSE; ++ + if (pZip->m_total_files) + { + mz_uint i, n; +@@ -3573,7 +3613,7 @@ + return MZ_FALSE; + + // Read and parse the local directory entry. +- cur_file_ofs = file_stat.m_local_header_ofs; ++ cur_file_ofs = pZip->m_archive_file_ofs + file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) +@@ -4441,7 +4481,7 @@ + + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; +- ++ + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return MZ_FALSE; +@@ -4610,7 +4650,7 @@ + if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + +- cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); ++ cur_src_file_ofs = pSource_zip->m_archive_file_ofs + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) \ No newline at end of file diff --git a/external/CppMicroServices/third_party/patches/mustache_2.0.patch b/external/CppMicroServices/third_party/patches/mustache_2.0.patch new file mode 100644 index 00000000..f98a33ec --- /dev/null +++ b/external/CppMicroServices/third_party/patches/mustache_2.0.patch @@ -0,0 +1,130 @@ +diff --git a/third_party/mustache.hpp b/third_party/mustache.hpp +index a59bb20..63b83dc 100644 +--- a/third_party/mustache.hpp ++++ b/third_party/mustache.hpp +@@ -95,13 +95,13 @@ public: + Invalid, + }; + +- using ObjectType = std::unordered_map; +- using ListType = std::vector; +- using PartialType = std::function; +- using LambdaType = std::function; ++ typedef std::unordered_map ObjectType; ++ typedef std::vector ListType; ++ typedef std::function PartialType; ++ typedef std::function LambdaType; + + // Construction +- Data() : Data(Type::Object) { ++ Data() : type_{Type::Object}, obj_(new ObjectType) { + } + Data(const StringType& string) : type_{Type::String} { + str_.reset(new StringType(string)); +@@ -127,7 +127,7 @@ public: + break; + } + } +- Data(const StringType& name, const Data& var) : Data{} { ++ Data(const StringType& name, const Data& var) : type_{Type::Object}, obj_(new ObjectType) { + set(name, var); + } + Data(const PartialType& partial) : type_{Type::Partial} { +@@ -316,7 +316,7 @@ public: + return render(data, ss).str(); + } + +- using RenderHandler = std::function; ++ typedef std::function RenderHandler; + void render(const Data& data, const RenderHandler& handler) { + if (!isValid()) { + return; +@@ -326,7 +326,7 @@ public: + } + + private: +- using StringSizeType = typename StringType::size_type; ++ typedef typename StringType::size_type StringSizeType; + + class DelimiterSet { + public: +@@ -362,7 +362,7 @@ private: + SetDelimiter, + }; + StringType name; +- Type type = Type::Invalid; ++ Type type; + std::shared_ptr sectionText; + std::shared_ptr delimiterSet; + bool isSectionBegin() const { +@@ -371,6 +371,7 @@ private: + bool isSectionEnd() const { + return type == Type::SectionEnd; + } ++ Tag() : type(Type::Invalid) {} + }; + + class Component { +@@ -378,11 +379,11 @@ private: + StringType text; + Tag tag; + std::vector children; +- StringSizeType position = StringType::npos; ++ StringSizeType position; + bool isText() const { + return tag.type == Tag::Type::Invalid; + } +- Component() {} ++ Component() : position(StringType::npos) {} + Component(const StringType& t, StringSizeType p) : text(t), position(p) {} + }; + +@@ -477,7 +478,7 @@ private: + } + + void parse(const StringType& input, Context& ctx) { +- using streamstring = std::basic_ostringstream; ++ typedef std::basic_ostringstream streamstring; + + const StringType braceDelimiterEndUnescaped(3, '}'); + const StringSizeType inputSize{input.size()}; +@@ -583,7 +584,7 @@ private: + Stop, + Skip, + }; +- using WalkCallback = std::function; ++ typedef std::function WalkCallback; + + void walk(const WalkCallback& callback) const { + walkChildren(callback, rootComponent_); +@@ -688,8 +689,8 @@ private: + } + + void render(const RenderHandler& handler, Context& ctx) { +- walk([&handler, &ctx, this](Component& comp) -> WalkControl { +- return renderComponent(handler, ctx, comp); ++ walk([&handler, &ctx, this](Component& comp) { ++ return BasicMustache::renderComponent(handler, ctx, comp); + }); + } + +@@ -790,7 +791,7 @@ private: + + void renderSection(const RenderHandler& handler, Context& ctx, Component& incomp, const Data* var) { + const auto callback = [&handler, &ctx, this](Component& comp) -> WalkControl { +- return renderComponent(handler, ctx, comp); ++ return BasicMustache::renderComponent(handler, ctx, comp); + }; + if (var && var->isNonEmptyList()) { + for (const auto& item : var->list()) { +@@ -810,8 +811,8 @@ private: + Component rootComponent_; + }; + +-using Mustache = Kainjow::BasicMustache; +-using MustacheW = Kainjow::BasicMustache; ++typedef Kainjow::BasicMustache Mustache; ++typedef Kainjow::BasicMustache MustacheW; + + } // Kainjow + diff --git a/external/CppMicroServices/third_party/patches/optionparser_1.7.patch b/external/CppMicroServices/third_party/patches/optionparser_1.7.patch new file mode 100644 index 00000000..5e4a2460 --- /dev/null +++ b/external/CppMicroServices/third_party/patches/optionparser_1.7.patch @@ -0,0 +1,165 @@ +--- optionparser-1.3/src/optionparser.h 2015-09-23 10:18:26.000000000 +0200 ++++ optionparser.h 2015-10-07 07:19:39.331265462 +0200 +@@ -535,7 +535,7 @@ + */ + int index() const + { +- return desc == 0 ? -1 : (int)desc->index; ++ return desc == 0 ? -1 : static_cast( desc->index ); + } + + /** +@@ -814,17 +814,17 @@ + + static Option* tag(Option* ptr) + { +- return (Option*) ((unsigned long long) ptr | 1); ++ return reinterpret_cast( reinterpret_cast( ptr ) | 1 ); + } + + static Option* untag(Option* ptr) + { +- return (Option*) ((unsigned long long) ptr & ~1ull); ++ return reinterpret_cast( reinterpret_cast( ptr ) & ~1ull); + } + + static bool isTagged(Option* ptr) + { +- return ((unsigned long long) ptr & 1); ++ return (reinterpret_cast( ptr ) & 1); + } + }; + +@@ -964,7 +964,7 @@ + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { +- add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); ++ add(gnu, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX Stats(...) (gnu==false). +@@ -980,7 +980,7 @@ + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { +- add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); ++ add(false, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } + + /** +@@ -999,7 +999,7 @@ + void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { +- add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); ++ add(gnu, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX add() (gnu==false). +@@ -1013,7 +1013,7 @@ + void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { +- add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); ++ add(false, usage, argc, const_cast( argv ), min_abbr_len, single_minus_longopt); + } + private: + class CountOptionsAction; +@@ -1071,7 +1071,7 @@ + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { +- parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); ++ parse(gnu, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX Parser(...) (gnu==false). +@@ -1087,7 +1087,7 @@ + bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { +- parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); ++ parse(false, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + /** +@@ -1153,7 +1153,7 @@ + void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) + { +- parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); ++ parse(gnu, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX parse() (gnu==false). +@@ -1167,7 +1167,7 @@ + void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, + bool single_minus_longopt = false, int bufmax = -1) + { +- parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); ++ parse(false, usage, argc, const_cast( argv ), options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + /** +@@ -1354,6 +1354,9 @@ + */ + struct Parser::Action + { ++ ++ virtual ~Action() {} ++ + /** + * @brief Called by Parser::workhorse() for each Option that has been successfully + * parsed (including unknown +@@ -1691,6 +1694,7 @@ + */ + struct IStringWriter + { ++ virtual ~IStringWriter() {} + /** + * @brief Writes the given number of chars beginning at the given pointer somewhere. + */ +@@ -1933,16 +1937,16 @@ + for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len) + { + ++screenlen; +- unsigned ch = (unsigned char) ptr[len]; ++ unsigned ch = static_cast( ptr[len] ); + if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte + { + // int __builtin_clz (unsigned int x) + // Returns the number of leading 0-bits in x, starting at the most significant bit +- unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); ++ unsigned mask = static_cast( -1 ) >> __builtin_clz(ch ^ 0xff); + ch = ch & mask; // mask out length bits, we don't verify their correctness +- while (((unsigned char) ptr[len + 1] ^ 0x80) <= 0x3F) // while next byte is continuation byte ++ while ((static_cast( ptr[len + 1] ) ^ 0x80) <= 0x3F) // while next byte is continuation byte + { +- ch = (ch << 6) ^ (unsigned char) ptr[len + 1] ^ 0x80; // add continuation to char code ++ ch = (ch << 6) ^ static_cast( ptr[len + 1] ) ^ 0x80; // add continuation to char code + ++len; + } + // ch is the decoded unicode code point +@@ -2328,17 +2332,17 @@ + while (maxi < len && utf8width < width) + { + int charbytes = 1; +- unsigned ch = (unsigned char) data[maxi]; ++ unsigned ch = static_cast( data[maxi] ); + if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte + { + // int __builtin_clz (unsigned int x) + // Returns the number of leading 0-bits in x, starting at the most significant bit +- unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); ++ unsigned mask = static_cast( -1 ) >> __builtin_clz(ch ^ 0xff); + ch = ch & mask; // mask out length bits, we don't verify their correctness + while ((maxi + charbytes < len) && // +- (((unsigned char) data[maxi + charbytes] ^ 0x80) <= 0x3F)) // while next byte is continuation byte ++ ((static_cast( data[maxi + charbytes] ) ^ 0x80) <= 0x3F)) // while next byte is continuation byte + { +- ch = (ch << 6) ^ (unsigned char) data[maxi + charbytes] ^ 0x80; // add continuation to char code ++ ch = (ch << 6) ^ static_cast( data[maxi + charbytes] ) ^ 0x80; // add continuation to char code + ++charbytes; + } + // ch is the decoded unicode code point diff --git a/external/CppMicroServices/third_party/patches/tinyscheme_v1.41.patch b/external/CppMicroServices/third_party/patches/tinyscheme_v1.41.patch new file mode 100644 index 00000000..4b549f7b --- /dev/null +++ b/external/CppMicroServices/third_party/patches/tinyscheme_v1.41.patch @@ -0,0 +1,14 @@ +diff --git a/third_party/tinyscheme/scheme.c b/third_party/tinyscheme/scheme.c +index 99f9106..59921e4 100644 +--- a/third_party/tinyscheme/scheme.c ++++ b/third_party/tinyscheme/scheme.c +@@ -18,7 +18,9 @@ + # include + #endif + #ifdef WIN32 ++#include + #define snprintf _snprintf ++#pragma warning( disable : 4244 4267) + #endif + #if USE_DL + # include "dynload.h" diff --git a/external/CppMicroServices/third_party/tinyscheme/BUILDING b/external/CppMicroServices/third_party/tinyscheme/BUILDING new file mode 100644 index 00000000..78812bba --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/BUILDING @@ -0,0 +1,139 @@ + Building TinyScheme + ------------------- + +The included makefile includes logic for Linux, Solaris and Win32, and can +readily serve as an example for other OSes, especially Unixes. There are +a lot of compile-time flags in TinyScheme (preprocessor defines) that can trim +unwanted features. See next section. 'make all' and 'make clean' function as +expected. + +Autoconfing TinyScheme was once proposed, but the distribution would not be +so small anymore. There are few platform dependencies in TinyScheme, and in +general compiles out of the box. + + Customizing + ----------- + + The following symbols are defined to default values in scheme.h. + Use the -D flag of cc to set to either 1 or 0. + + STANDALONE + Define this to produce a standalone interpreter. + + USE_MATH + Includes math routines. + + USE_CHAR_CLASSIFIERS + Includes character classifier procedures. + + USE_ASCII_NAMES + Enable extended character notation based on ASCII names. + + USE_STRING_PORTS + Enables string ports. + + USE_ERROR_HOOK + To force system errors through user-defined error handling. + (see "Error handling") + + USE_TRACING + To enable use of TRACING. + + USE_COLON_HOOK + Enable use of qualified identifiers. (see "Colon Qualifiers - Packages") + Defining this as 0 has the rather drastic consequence that any code using + packages will stop working, and will have to be modified. It should only + be used if you *absolutely* need to use '::' in identifiers. + + USE_STRCASECMP + Defines stricmp as strcasecmp, for Unix. + + STDIO_ADDS_CR + Informs TinyScheme that stdio translates "\n" to "\r\n". For DOS/Windows. + + USE_DL + Enables dynamically loaded routines. If you define this symbol, you + should also include dynload.c in your compile. + + USE_PLIST + Enables property lists (not Standard Scheme stuff). Off by default. + + USE_NO_FEATURES + Shortcut to disable USE_MATH, USE_CHAR_CLASSIFIERS, USE_ASCII_NAMES, + USE_STRING_PORTS, USE_ERROR_HOOK, USE_TRACING, USE_COLON_HOOK, + USE_DL. + + USE_SCHEME_STACK + Enables 'cons' stack (the alternative is a faster calling scheme, which + breaks continuations). Undefine it if you don't care about strict compatibility + but you do care about faster execution. + + + OS-X tip + -------- + I don't have access to OS-X, but Brian Maher submitted the following tip: + +[1] Download and install fink (I installed fink in +/usr/local/fink) +[2] Install the 'dlcompat' package using fink as such: +> fink install dlcompat +[3] Make the following changes to the +tinyscheme-1.32.tar.gz + +diff -r tinyscheme-1.32/dynload.c +tinyscheme-1.32-new/dynload.c +24c24 +< #define SUN_DL +--- +> +Only in tinyscheme-1.32-new/: dynload.o +Only in tinyscheme-1.32-new/: libtinyscheme.a Only in tinyscheme-1.32-new/: libtinyscheme.so diff -r tinyscheme-1.32/makefile tinyscheme-1.32-new/makefile +33,34c33,43 +< LD = gcc +< LDFLAGS = -shared +--- +> #LD = gcc +> #LDFLAGS = -shared +> #DEBUG=-g -Wno-char-subscripts -O +> #SYS_LIBS= -ldl +> #PLATFORM_FEATURES= -DSUN_DL=1 +> +> # Mac OS X +> CC = gcc +> CFLAGS = -I/usr/local/fink/include +> LD = gcc +> LDFLAGS = -L/usr/local/fink/lib +37c46 +< PLATFORM_FEATURES= -DSUN_DL=1 +--- +> PLATFORM_FEATURES= -DSUN_DL=1 -DOSX +60c69 +< $(CC) -I. -c $(DEBUG) $(FEATURES) +$(DL_FLAGS) $< +--- +> $(CC) $(CFLAGS) -I. -c $(DEBUG) +$(FEATURES) $(DL_FLAGS) $< +66c75 +< $(CC) -o $@ $(DEBUG) $(OBJS) $(SYS_LIBS) +--- +> $(CC) $(LDFLAGS) -o $@ $(DEBUG) $(OBJS) +$(SYS_LIBS) +Only in tinyscheme-1.32-new/: scheme +diff -r tinyscheme-1.32/scheme.c +tinyscheme-1.32-new/scheme.c +60,61c60,61 +< #ifndef macintosh +< # include +--- +> #ifdef OSX +> /* Do nothing */ +62a63,65 +> # ifndef macintosh +> # include +> # else +77c80,81 +< #endif /* macintosh */ +--- +> # endif /* macintosh */ +> #endif /* !OSX */ +Only in tinyscheme-1.32-new/: scheme.o diff --git a/external/CppMicroServices/third_party/tinyscheme/COPYING b/external/CppMicroServices/third_party/tinyscheme/COPYING new file mode 100644 index 00000000..23a7e85a --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/COPYING @@ -0,0 +1,31 @@ + LICENSE TERMS + +Copyright (c) 2000, Dimitrios Souflis +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +Neither the name of Dimitrios Souflis nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/external/CppMicroServices/third_party/tinyscheme/Manual.txt b/external/CppMicroServices/third_party/tinyscheme/Manual.txt new file mode 100644 index 00000000..ccfc4c17 --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/Manual.txt @@ -0,0 +1,444 @@ + + + TinySCHEME Version 1.41 + + "Safe if used as prescribed" + -- Philip K. Dick, "Ubik" + +This software is open source, covered by a BSD-style license. +Please read accompanying file COPYING. +------------------------------------------------------------------------------- + + This Scheme interpreter is based on MiniSCHEME version 0.85k4 + (see miniscm.tar.gz in the Scheme Repository) + Original credits in file MiniSCHEMETribute.txt. + + D. Souflis (dsouflis@acm.org) + +------------------------------------------------------------------------------- + What is TinyScheme? + ------------------- + + TinyScheme is a lightweight Scheme interpreter that implements as large + a subset of R5RS as was possible without getting very large and + complicated. It is meant to be used as an embedded scripting interpreter + for other programs. As such, it does not offer IDEs or extensive toolkits + although it does sport a small top-level loop, included conditionally. + A lot of functionality in TinyScheme is included conditionally, to allow + developers freedom in balancing features and footprint. + + As an embedded interpreter, it allows multiple interpreter states to + coexist in the same program, without any interference between them. + Programmatically, foreign functions in C can be added and values + can be defined in the Scheme environment. Being a quite small program, + it is easy to comprehend, get to grips with, and use. + + Known bugs + ---------- + + TinyScheme is known to misbehave when memory is exhausted. + + + Things that keep missing, or that need fixing + --------------------------------------------- + + There are no hygienic macros. No rational or + complex numbers. No unwind-protect and call-with-values. + + Maybe (a subset of) SLIB will work with TinySCHEME... + + Decent debugging facilities are missing. Only tracing is supported + natively. + + + Scheme Reference + ---------------- + + If something seems to be missing, please refer to the code and + "init.scm", since some are library functions. Refer to the MiniSCHEME + readme as a last resort. + + Environments + (interaction-environment) + See R5RS. In TinySCHEME, immutable list of association lists. + + (current-environment) + The environment in effect at the time of the call. An example of its + use and its utility can be found in the sample code that implements + packages in "init.scm": + + (macro (package form) + `(apply (lambda () + ,@(cdr form) + (current-environment)))) + + The environment containing the (local) definitions inside the closure + is returned as an immutable value. + + (defined? ) (defined? ) + Checks whether the given symbol is defined in the current (or given) + environment. + + Symbols + (gensym) + Returns a new interned symbol each time. Will probably move to the + library when string->symbol is implemented. + + Directives + (gc) + Performs garbage collection immediatelly. + + (gcverbose) (gcverbose ) + The argument (defaulting to #t) controls whether GC produces + visible outcome. + + (quit) (quit ) + Stops the interpreter and sets the 'retcode' internal field (defaults + to 0). When standalone, 'retcode' is returned as exit code to the OS. + + (tracing ) + 1, turns on tracing. 0 turns it off. (Only when USE_TRACING is 1). + + Mathematical functions + Since rationals and complexes are absent, the respective functions + are also missing. + Supported: exp, log, sin, cos, tan, asin, acos, atan, floor, ceiling, + trunc, round and also sqrt and expt when USE_MATH=1. + Number-theoretical quotient, remainder and modulo, gcd, lcm. + Library: exact?, inexact?, odd?, even?, zero?, positive?, negative?, + exact->inexact. inexact->exact is a core function. + + Type predicates + boolean?,eof-object?,symbol?,number?,string?,integer?,real?,list?,null?, + char?,port?,input-port?,output-port?,procedure?,pair?,environment?', + vector?. Also closure?, macro?. + + Types + Types supported: + + Numbers (integers and reals) + Symbols + Pairs + Strings + Characters + Ports + Eof object + Environments + Vectors + + Literals + String literals can contain escaped quotes \" as usual, but also + \n, \r, \t, \xDD (hex representations) and \DDD (octal representations). + Note also that it is possible to include literal newlines in string + literals, e.g. + + (define s "String with newline here + and here + that can function like a HERE-string") + + Character literals contain #\space and #\newline and are supplemented + with #\return and #\tab, with obvious meanings. Hex character + representations are allowed (e.g. #\x20 is #\space). + When USE_ASCII_NAMES is defined, various control characters can be + referred to by their ASCII name. + 0 #\nul 17 #\dc1 + 1 #\soh 18 #\dc2 + 2 #\stx 19 #\dc3 + 3 #\etx 20 #\dc4 + 4 #\eot 21 #\nak + 5 #\enq 22 #\syn + 6 #\ack 23 #\etv + 7 #\bel 24 #\can + 8 #\bs 25 #\em + 9 #\ht 26 #\sub + 10 #\lf 27 #\esc + 11 #\vt 28 #\fs + 12 #\ff 29 #\gs + 13 #\cr 30 #\rs + 14 #\so 31 #\us + 15 #\si + 16 #\dle 127 #\del + + Numeric literals support #x #o #b and #d. Flonums are currently read only + in decimal notation. Full grammar will be supported soon. + + Quote, quasiquote etc. + As usual. + + Immutable values + Immutable pairs cannot be modified by set-car! and set-cdr!. + Immutable strings cannot be modified via string-set! + + I/O + As per R5RS, plus String Ports (see below). + current-input-port, current-output-port, + close-input-port, close-output-port, input-port?, output-port?, + open-input-file, open-output-file. + read, write, display, newline, write-char, read-char, peek-char. + char-ready? returns #t only for string ports, because there is no + portable way in stdio to determine if a character is available. + Also open-input-output-file, set-input-port, set-output-port (not R5RS) + Library: call-with-input-file, call-with-output-file, + with-input-from-file, with-output-from-file and + with-input-output-from-to-files, close-port and input-output-port? + (not R5RS). + String Ports: open-input-string, open-output-string, get-output-string, + open-input-output-string. Strings can be used with I/O routines. + + Vectors + make-vector, vector, vector-length, vector-ref, vector-set!, list->vector, + vector-fill!, vector->list, vector-equal? (auxiliary function, not R5RS) + + Strings + string, make-string, list->string, string-length, string-ref, string-set!, + substring, string->list, string-fill!, string-append, string-copy. + string=?, string?, string>?, string<=?, string>=?. + (No string-ci*? yet). string->number, number->string. Also atom->string, + string->atom (not R5RS). + + Symbols + symbol->string, string->symbol + + Characters + integer->char, char->integer. + char=?, char?, char<=?, char>=?. + (No char-ci*?) + + Pairs & Lists + cons, car, cdr, list, length, map, for-each, foldr, list-tail, + list-ref, last-pair, reverse, append. + Also member, memq, memv, based on generic-member, assoc, assq, assv + based on generic-assoc. + + Streams + head, tail, cons-stream + + Control features + Apart from procedure?, also macro? and closure? + map, for-each, force, delay, call-with-current-continuation (or call/cc), + eval, apply. 'Forcing' a value that is not a promise produces the value. + There is no call-with-values, values, nor dynamic-wind. Dynamic-wind in + the presence of continuations would require support from the abstract + machine itself. + + Property lists + TinyScheme inherited from MiniScheme property lists for symbols. + put, get. + + Dynamically-loaded extensions + (load-extension ) + Loads a DLL declaring foreign procedures. On Unix/Linux, one can make use + of the ld.so.conf file or the LD_RUN_PATH system variable in order to place + the library in a directory other than the current one. Please refer to the + appropriate 'man' page. + + Esoteric procedures + (oblist) + Returns the oblist, an immutable list of all the symbols. + + (macro-expand
) + Returns the expanded form of the macro call denoted by the argument + + (define-with-return ( ...) ) + Like plain 'define', but makes the continuation available as 'return' + inside the procedure. Handy for imperative programs. + + (new-segment ) + Allocates more memory segments. + + defined? + See "Environments" + + (get-closure-code ) + Gets the code as scheme data. + + (make-closure ) + Makes a new closure in the given environment. + + Obsolete procedures + (print-width ) + + Programmer's Reference + ---------------------- + + The interpreter state is initialized with "scheme_init". + Custom memory allocation routines can be installed with an alternate + initialization function: "scheme_init_custom_alloc". + Files can be loaded with "scheme_load_file". Strings containing Scheme + code can be loaded with "scheme_load_string". It is a good idea to + "scheme_load" init.scm before anything else. + + External data for keeping external state (of use to foreign functions) + can be installed with "scheme_set_external_data". + Foreign functions are installed with "assign_foreign". Additional + definitions can be added to the interpreter state, with "scheme_define" + (this is the way HTTP header data and HTML form data are passed to the + Scheme script in the Altera SQL Server). If you wish to define the + foreign function in a specific environment (to enhance modularity), + use "assign_foreign_env". + + The procedure "scheme_apply0" has been added with persistent scripts in + mind. Persistent scripts are loaded once, and every time they are needed + to produce HTTP output, appropriate data are passed through global + definitions and function "main" is called to do the job. One could + add easily "scheme_apply1" etc. + + The interpreter state should be deinitialized with "scheme_deinit". + + DLLs containing foreign functions should define a function named + init_. E.g. foo.dll should define init_foo, and bar.so + should define init_bar. This function should assign_foreign any foreign + function contained in the DLL. + + The first dynamically loaded extension available for TinyScheme is + a regular expression library. Although it's by no means an + established standard, this library is supposed to be installed in + a directory mirroring its name under the TinyScheme location. + + + Foreign Functions + ----------------- + + The user can add foreign functions in C. For example, a function + that squares its argument: + + pointer square(scheme *sc, pointer args) { + if(args!=sc->NIL) { + if(sc->isnumber(sc->pair_car(args))) { + double v=sc->rvalue(sc->pair_car(args)); + return sc->mk_real(sc,v*v); + } + } + return sc->NIL; + } + + Foreign functions are now defined as closures: + + sc->interface->scheme_define( + sc, + sc->global_env, + sc->interface->mk_symbol(sc,"square"), + sc->interface->mk_foreign_func(sc, square)); + + + Foreign functions can use the external data in the "scheme" struct + to implement any kind of external state. + + External data are set with the following function: + void scheme_set_external_data(scheme *sc, void *p); + + As of v.1.17, the canonical way for a foreign function in a DLL to + manipulate Scheme data is using the function pointers in sc->interface. + + Standalone + ---------- + + Usage: tinyscheme -? + or: tinyscheme [ ...] + followed by + -1 [ ...] + -c [ ...] + assuming that the executable is named tinyscheme. + + Use - in the place of a filename to denote stdin. + The -1 flag is meant for #! usage in shell scripts. If you specify + #! /somewhere/tinyscheme -1 + then tinyscheme will be called to process the file. For example, the + following script echoes the Scheme list of its arguments. + + #! /somewhere/tinyscheme -1 + (display *args*) + + The -c flag permits execution of arbitrary Scheme code. + + + Error Handling + -------------- + + Errors are recovered from without damage. The user can install his + own handler for system errors, by defining *error-hook*. Defining + to '() gives the default behavior, which is equivalent to "error". + USE_ERROR_HOOK must be defined. + + A simple exception handling mechanism can be found in "init.scm". + A new syntactic form is introduced: + + (catch + ... ) + + "Catch" establishes a scope spanning multiple call-frames + until another "catch" is encountered. + + Exceptions are thrown with: + + (throw "message") + + If used outside a (catch ...), reverts to (error "message"). + + Example of use: + + (define (foo x) (write x) (newline) (/ x 0)) + + (catch (begin (display "Error!\n") 0) + (write "Before foo ... ") + (foo 5) + (write "After foo")) + + The exception mechanism can be used even by system errors, by + + (define *error-hook* throw) + + which makes use of the error hook described above. + + If necessary, the user can devise his own exception mechanism with + tagged exceptions etc. + + + Reader extensions + ----------------- + + When encountering an unknown character after '#', the user-specified + procedure *sharp-hook* (if any), is called to read the expression. + This can be used to extend the reader to handle user-defined constants + or whatever. It should be a procedure without arguments, reading from + the current input port (which will be the load-port). + + + Colon Qualifiers - Packages + --------------------------- + + When USE_COLON_HOOK=1: + The lexer now recognizes the construction :: and + transforms it in the following manner (T is the transformation function): + + T(::) = (*colon-hook* 'T() ) + + where is a symbol not containing any double-colons. + + As the definition is recursive, qualifiers can be nested. + The user can define his own *colon-hook*, to handle qualified names. + By default, "init.scm" defines *colon-hook* as EVAL. Consequently, + the qualifier must denote a Scheme environment, such as one returned + by (interaction-environment). "Init.scm" defines a new syntantic form, + PACKAGE, as a simple example. It is used like this: + + (define toto + (package + (define foo 1) + (define bar +))) + + foo ==> Error, "foo" undefined + (eval 'foo) ==> Error, "foo" undefined + (eval 'foo toto) ==> 1 + toto::foo ==> 1 + ((eval 'bar toto) 2 (eval 'foo toto)) ==> 3 + (toto::bar 2 toto::foo) ==> 3 + (eval (bar 2 foo) toto) ==> 3 + + If the user installs another package infrastructure, he must define + a new 'package' procedure or macro to retain compatibility with supplied + code. + + Note: Older versions used ':' as a qualifier. Unfortunately, the use + of ':' as a pseudo-qualifier in existing code (i.e. SLIB) essentially + precludes its use as a real qualifier. diff --git a/external/CppMicroServices/third_party/tinyscheme/MiniSCHEMETribute.txt b/external/CppMicroServices/third_party/tinyscheme/MiniSCHEMETribute.txt new file mode 100644 index 00000000..a031f57d --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/MiniSCHEMETribute.txt @@ -0,0 +1,88 @@ + TinyScheme would not exist if it wasn't for MiniScheme. I had just + written the HTTP server for Ovrimos SQL Server, and I was lamenting the + lack of a scripting language. Server-side Javascript would have been the + preferred solution, had there been a Javascript interpreter I could + lay my hands on. But there weren't. Perl would have been another solution, + but it was probably ten times bigger that the program it was supposed to + be embedded in. There would also be thorny licencing issues. + + So, the obvious thing to do was find a trully small interpreter. Forth + was a language I had once quasi-implemented, but the difficulty of + handling dynamic data and the weirdness of the language put me off. I then + looked around for a LISP interpreter, the next thing I knew was easy to + implement. Alas, the LeLisp I knew from my days in UPMC (Universite Pierre + et Marie Curie) had given way to Common Lisp, a megalith of a language! + Then my search lead me to Scheme, a language I knew was very orthogonal + and clean. When I found Mini-Scheme, a single C file of some 2400 loc, I + fell in love with it! What if it lacked floating-point numbers and + strings! The rest, as they say, is history. + + Below are the original credits. Don't email Akira KIDA, the address has + changed. + + ---------- Mini-Scheme Interpreter Version 0.85 ---------- + + coded by Atsushi Moriwaki (11/5/1989) + + E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp + + THIS SOFTWARE IS IN THE PUBLIC DOMAIN + ------------------------------------ + This software is completely free to copy, modify and/or re-distribute. + But I would appreciate it if you left my name on the code as the author. + + This version has been modified by R.C. Secrist. + + Mini-Scheme is now maintained by Akira KIDA. + + This is a revised and modified version by Akira KIDA. + current version is 0.85k4 (15 May 1994) + + Please send suggestions, bug reports and/or requests to: + + + + Features compared to MiniSCHEME + ------------------------------- + + All code is now reentrant. Interpreter state is held in a 'scheme' + struct, and many interpreters can coexist in the same program, possibly + in different threads. The user can specify user-defined memory allocation + primitives. (see "Programmer's Reference") + + The reader is more consistent. + + Strings, characters and flonums are supported. (see "Types") + + Files being loaded can be nested up to some depth. + + R5RS I/O is there, plus String Ports. (see "Scheme Reference","I/O") + + Vectors exist. + + As a standalone application, it supports command-line arguments. + (see "Standalone") + + Running out of memory is now handled. + + The user can add foreign functions in C. (see "Foreign Functions") + + The code has been changed slightly, core functions have been moved + to the library, behavior has been aligned with R5RS etc. + + Support has been added for user-defined error recovery. + (see "Error Handling") + + Support has been added for modular programming. + (see "Colon Qualifiers - Packages") + + To enable this, EVAL has changed internally, and can + now take two arguments, as per R5RS. Environments are supported. + (see "Colon Qualifiers - Packages") + + Promises are now evaluated once only. + + (macro (foo form) ...) is now equivalent to (macro foo (lambda(form) ...)) + + The reader can be extended using new #-expressions + (see "Reader extensions") diff --git a/external/CppMicroServices/third_party/tinyscheme/dynload.c b/external/CppMicroServices/third_party/tinyscheme/dynload.c new file mode 100644 index 00000000..3ad3ace2 --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/dynload.c @@ -0,0 +1,146 @@ +/* dynload.c Dynamic Loader for TinyScheme */ +/* Original Copyright (c) 1999 Alexander Shendi */ +/* Modifications for NT and dl_* interface, scm_load_ext: D. Souflis */ +/* Refurbished by Stephen Gildea */ + +#define _SCHEME_SOURCE +#include "dynload.h" +#include +#include +#include + +#ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +#endif + +static void make_filename(const char *name, char *filename); +static void make_init_fn(const char *name, char *init_fn); + +#ifdef _WIN32 +# include +#else +typedef void *HMODULE; +typedef void (*FARPROC)(); +#define SUN_DL +#include +#endif + +#ifdef _WIN32 + +#define PREFIX "" +#define SUFFIX ".dll" + + static void display_w32_error_msg(const char *additional_message) + { + LPVOID msg_buf; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, GetLastError(), 0, + (LPTSTR)&msg_buf, 0, NULL); + fprintf(stderr, "scheme load-extension: %s: %s", additional_message, msg_buf); + LocalFree(msg_buf); + } + +static HMODULE dl_attach(const char *module) { + HMODULE dll = LoadLibrary(module); + if (!dll) display_w32_error_msg(module); + return dll; +} + +static FARPROC dl_proc(HMODULE mo, const char *proc) { + FARPROC procedure = GetProcAddress(mo,proc); + if (!procedure) display_w32_error_msg(proc); + return procedure; +} + +static void dl_detach(HMODULE mo) { + (void)FreeLibrary(mo); +} + +#elif defined(SUN_DL) + +#include + +#define PREFIX "lib" +#define SUFFIX ".so" + +static HMODULE dl_attach(const char *module) { + HMODULE so=dlopen(module,RTLD_LAZY); + if(!so) { + fprintf(stderr, "Error loading scheme extension \"%s\": %s\n", module, dlerror()); + } + return so; +} + +static FARPROC dl_proc(HMODULE mo, const char *proc) { + const char *errmsg; + FARPROC fp=(FARPROC)dlsym(mo,proc); + if ((errmsg = dlerror()) == 0) { + return fp; + } + fprintf(stderr, "Error initializing scheme module \"%s\": %s\n", proc, errmsg); + return 0; +} + +static void dl_detach(HMODULE mo) { + (void)dlclose(mo); +} +#endif + +pointer scm_load_ext(scheme *sc, pointer args) +{ + pointer first_arg; + pointer retval; + char filename[MAXPATHLEN], init_fn[MAXPATHLEN+6]; + char *name; + HMODULE dll_handle; + void (*module_init)(scheme *sc); + + if ((args != sc->NIL) && is_string((first_arg = pair_car(args)))) { + name = string_value(first_arg); + make_filename(name,filename); + make_init_fn(name,init_fn); + dll_handle = dl_attach(filename); + if (dll_handle == 0) { + retval = sc -> F; + } + else { + module_init = (void(*)(scheme *))dl_proc(dll_handle, init_fn); + if (module_init != 0) { + (*module_init)(sc); + retval = sc -> T; + } + else { + retval = sc->F; + } + } + } + else { + retval = sc -> F; + } + + return(retval); +} + +static void make_filename(const char *name, char *filename) { + strcpy(filename,name); + strcat(filename,SUFFIX); +} + +static void make_init_fn(const char *name, char *init_fn) { + const char *p=strrchr(name,'/'); + if(p==0) { + p=name; + } else { + p++; + } + strcpy(init_fn,"init_"); + strcat(init_fn,p); +} + + +/* +Local variables: +c-file-style: "k&r" +End: +*/ diff --git a/external/CppMicroServices/third_party/tinyscheme/dynload.h b/external/CppMicroServices/third_party/tinyscheme/dynload.h new file mode 100644 index 00000000..069dae3e --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/dynload.h @@ -0,0 +1,12 @@ +/* dynload.h */ +/* Original Copyright (c) 1999 Alexander Shendi */ +/* Modifications for NT and dl_* interface: D. Souflis */ + +#ifndef DYNLOAD_H +#define DYNLOAD_H + +#include "scheme-private.h" + +SCHEME_EXPORT pointer scm_load_ext(scheme *sc, pointer arglist); + +#endif diff --git a/external/CppMicroServices/third_party/tinyscheme/hack.txt b/external/CppMicroServices/third_party/tinyscheme/hack.txt new file mode 100644 index 00000000..3beb6cf1 --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/hack.txt @@ -0,0 +1,244 @@ + + How to hack TinyScheme + ---------------------- + + TinyScheme is easy to learn and modify. It is structured like a + meta-interpreter, only it is written in C. All data are Scheme + objects, which facilitates both understanding/modifying the + code and reifying the interpreter workings. + + In place of a dry description, we will pace through the addition + of a useful new datatype: garbage-collected memory blocks. + The interface will be: + + (make-block []) makes a new block of the specified size + optionally filling it with a specified byte + (block? ) + (block-length ) + (block-ref ) retrieves byte at location + (block-set! ) modifies byte at location + + In the sequel, lines that begin with '>' denote lines to add to the + code. Lines that begin with '|' are just citations of existing code. + Lines that begin with X denote lines to be removed from the code. + + First of all, we need to assign a typeid to our new type. Typeids + in TinyScheme are small integers declared in the scheme_types enum + located near the top of the scheme.c file; it begins with T_STRING. + Add a new entry at the end, say T_MEMBLOCK. Remember to adjust the + value of T_LAST_SYTEM_TYPE when adding new entries. There can be at + most 31 types, but you don't have to worry about that limit yet. + +| T_ENVIRONMENT=14, +X T_LAST_SYSTEM_TYPE=14 +> T_MEMBLOCK=15, +> T_LAST_SYSTEM_TYPE=15 +| }; + + + Then, some helper macros would be useful. Go to where is_string() + and the rest are defined and add: + +> INTERFACE INLINE int is_memblock(pointer p) { return (type(p)==T_MEMBLOCK); } + + This actually is a function, because it is meant to be exported by + scheme.h. If no foreign function will ever manipulate a memory block, + you can instead define it as a macro: + +> #define is_memblock(p) (type(p)==T_MEMBLOCK) + + Then we make space for the new type in the main data structure: + struct cell. As it happens, the _string part of the union _object + (that is used to hold character strings) has two fields that suit us: + +| struct { +| char *_svalue; +| int _keynum; +| } _string; + + We can use _svalue to hold the actual pointer and _keynum to hold its + length. If we couln't reuse existing fields, we could always add other + alternatives in union _object. + + We then proceed to write the function that actually makes a new block. + For conformance reasons, we name it mk_memblock + +> static pointer mk_memblock(scheme *sc, int len, char fill) { +> pointer x; +> char *p=(char*)sc->malloc(len); +> +> if(p==0) { +> return sc->NIL; +> } +> x = get_cell(sc, sc->NIL, sc->NIL); +> +> typeflag(x) = T_MEMBLOCK|T_ATOM; +> strvalue(x)=p; +> keynum(x)=len; +> memset(p,fill,len); +> return (x); +> } + + The memory used by the MEMBLOCK will have to be freed when the cell + is reclaimed during garbage collection. There is a placeholder for + that staff, function finalize_cell(), currently handling strings only. + +| static void finalize_cell(scheme *sc, pointer a) { +| if(is_string(a)) { +| sc->free(strvalue(a)); +> } else if(is_memblock(a)) { +> sc->free(strvalue(a)); +| } else if(is_port(a)) { + + There are no MEMBLOCK literals, so we don't concern ourselves with + the READER part (yet!). We must cater to the PRINTER, though. We + add one case more in atom2str(). + +| } else if (iscontinuation(l)) { +| p = "#"; +> } else if (is_memblock(l)) { +> p = "#"; +| } else { + + Whenever a MEMBLOCK is displayed, it will look like that. + Now, we must add the interface functions: constructor, predicate, + accessor, modifier. We must in fact create new op-codes for the virtual + machine underlying TinyScheme. Since version 1.30, TinyScheme uses + macros and a single source text to keep the enums and the dispatch table + in sync. The op-codes are defined in the opdefines.h file with one line + for each op-code. The lines in the file have six columns between the + starting _OPDEF( and ending ): A, B, C, D, E, and OP. + Note that this file uses unusually long lines to accomodate all the + information; adjust your editor to handle this. + + The purpose of the columns is: + - Column A is the name of the subroutine that handles the op-code. + - Column B is the name of the op-code function. + - Columns C and D are the minimum and maximum number of arguments + that are accepted by the op-code. + - Column E is a set of flags that tells the interpreter the type of + each of the arguments expected by the op-code. + - Column OP is used in the scheme_opcodes enum located in the + scheme-private.h file. + + Op-codes are really just tags for a huge C switch, only this switch + is broken up in to a number of different opexe_X functions. The + correspondence is made in table "dispatch_table". There, we assign + the new op-codes to opexe_2, where the equivalent ones for vectors + are situated. We also assign a name for them, and specify the minimum + and maximum arity (number of expected arguments). INF_ARG as a maximum + arity means "unlimited". + + For reasons of consistency, we add the new op-codes right after those + for vectors: + +| _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET ) +> _OP_DEF(opexe_2, "make-block", 1, 2, TST_NATURAL TST_CHAR, OP_MKBLOCK ) +> _OP_DEF(opexe_2, "block-length", 1, 1, T_MEMBLOCK, OP_BLOCKLEN ) +> _OP_DEF(opexe_2, "block-ref", 2, 2, T_MEMBLOCK TST_NATURAL, OP_BLOCKREF ) +> _OP_DEF(opexe_2, "block-set!", 1, 1, T_MEMBLOCK TST_NATURAL TST_CHAR, OP_BLOCKSET ) +| _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT ) + + We add the predicate along with the other predicates in opexe_3: + +| _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP ) +> _OP_DEF(opexe_3, "block?", 1, 1, TST_ANY, OP_BLOCKP ) +| _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ ) + + All that remains is to write the actual code to do the processing and + add it to the switch statement in opexe_2, after the OP_VECSET case. + +> case OP_MKBLOCK: { /* make-block */ +> int fill=0; +> int len; +> +> if(!isnumber(car(sc->args))) { +> Error_1(sc,"make-block: not a number:",car(sc->args)); +> } +> len=ivalue(car(sc->args)); +> if(len<=0) { +> Error_1(sc,"make-block: not positive:",car(sc->args)); +> } +> +> if(cdr(sc->args)!=sc->NIL) { +> if(!isnumber(cadr(sc->args)) || ivalue(cadr(sc->args))<0) { +> Error_1(sc,"make-block: not a positive number:",cadr(sc->args)); +> } +> fill=charvalue(cadr(sc->args))%255; +> } +> s_return(sc,mk_memblock(sc,len,(char)fill)); +> } +> +> case OP_BLOCKLEN: /* block-length */ +> if(!ismemblock(car(sc->args))) { +> Error_1(sc,"block-length: not a memory block:",car(sc->args)); +> } +> s_return(sc,mk_integer(sc,keynum(car(sc->args)))); +> +> case OP_BLOCKREF: { /* block-ref */ +> char *str; +> int index; +> +> if(!ismemblock(car(sc->args))) { +> Error_1(sc,"block-ref: not a memory block:",car(sc->args)); +> } +> str=strvalue(car(sc->args)); +> +> if(cdr(sc->args)==sc->NIL) { +> Error_0(sc,"block-ref: needs two arguments"); +> } +> if(!isnumber(cadr(sc->args))) { +> Error_1(sc,"block-ref: not a number:",cadr(sc->args)); +> } +> index=ivalue(cadr(sc->args)); +> +> if(index<0 || index>=keynum(car(sc->args))) { +> Error_1(sc,"block-ref: out of bounds:",cadr(sc->args)); +> } +> +> s_return(sc,mk_integer(sc,str[index])); +> } +> +> case OP_BLOCKSET: { /* block-set! */ +> char *str; +> int index; +> int c; +> +> if(!ismemblock(car(sc->args))) { +> Error_1(sc,"block-set!: not a memory block:",car(sc->args)); +> } +> if(isimmutable(car(sc->args))) { +> Error_1(sc,"block-set!: unable to alter immutable memory block:",car(sc->args)); +> } +> str=strvalue(car(sc->args)); +> +> if(cdr(sc->args)==sc->NIL) { +> Error_0(sc,"block-set!: needs three arguments"); +> } +> if(!isnumber(cadr(sc->args))) { +> Error_1(sc,"block-set!: not a number:",cadr(sc->args)); +> } +> index=ivalue(cadr(sc->args)); +> if(index<0 || index>=keynum(car(sc->args))) { +> Error_1(sc,"block-set!: out of bounds:",cadr(sc->args)); +> } +> +> if(cddr(sc->args)==sc->NIL) { +> Error_0(sc,"block-set!: needs three arguments"); +> } +> if(!isinteger(caddr(sc->args))) { +> Error_1(sc,"block-set!: not an integer:",caddr(sc->args)); +> } +> c=ivalue(caddr(sc->args))%255; +> +> str[index]=(char)c; +> s_return(sc,car(sc->args)); +> } + + Finally, do the same for the predicate in opexe_3. + +| case OP_VECTORP: /* vector? */ +| s_retbool(is_vector(car(sc->args))); +> case OP_BLOCKP: /* block? */ +> s_retbool(is_memblock(car(sc->args))); +| case OP_EQ: /* eq? */ diff --git a/external/CppMicroServices/third_party/tinyscheme/init.scm b/external/CppMicroServices/third_party/tinyscheme/init.scm new file mode 100644 index 00000000..223e4219 --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/init.scm @@ -0,0 +1,716 @@ +; Initialization file for TinySCHEME 1.41 + +; Per R5RS, up to four deep compositions should be defined +(define (caar x) (car (car x))) +(define (cadr x) (car (cdr x))) +(define (cdar x) (cdr (car x))) +(define (cddr x) (cdr (cdr x))) +(define (caaar x) (car (car (car x)))) +(define (caadr x) (car (car (cdr x)))) +(define (cadar x) (car (cdr (car x)))) +(define (caddr x) (car (cdr (cdr x)))) +(define (cdaar x) (cdr (car (car x)))) +(define (cdadr x) (cdr (car (cdr x)))) +(define (cddar x) (cdr (cdr (car x)))) +(define (cdddr x) (cdr (cdr (cdr x)))) +(define (caaaar x) (car (car (car (car x))))) +(define (caaadr x) (car (car (car (cdr x))))) +(define (caadar x) (car (car (cdr (car x))))) +(define (caaddr x) (car (car (cdr (cdr x))))) +(define (cadaar x) (car (cdr (car (car x))))) +(define (cadadr x) (car (cdr (car (cdr x))))) +(define (caddar x) (car (cdr (cdr (car x))))) +(define (cadddr x) (car (cdr (cdr (cdr x))))) +(define (cdaaar x) (cdr (car (car (car x))))) +(define (cdaadr x) (cdr (car (car (cdr x))))) +(define (cdadar x) (cdr (car (cdr (car x))))) +(define (cdaddr x) (cdr (car (cdr (cdr x))))) +(define (cddaar x) (cdr (cdr (car (car x))))) +(define (cddadr x) (cdr (cdr (car (cdr x))))) +(define (cdddar x) (cdr (cdr (cdr (car x))))) +(define (cddddr x) (cdr (cdr (cdr (cdr x))))) + +;;;; Utility to ease macro creation +(define (macro-expand form) + ((eval (get-closure-code (eval (car form)))) form)) + +(define (macro-expand-all form) + (if (macro? form) + (macro-expand-all (macro-expand form)) + form)) + +(define *compile-hook* macro-expand-all) + + +(macro (unless form) + `(if (not ,(cadr form)) (begin ,@(cddr form)))) + +(macro (when form) + `(if ,(cadr form) (begin ,@(cddr form)))) + +; DEFINE-MACRO Contributed by Andy Gaynor +(macro (define-macro dform) + (if (symbol? (cadr dform)) + `(macro ,@(cdr dform)) + (let ((form (gensym))) + `(macro (,(caadr dform) ,form) + (apply (lambda ,(cdadr dform) ,@(cddr dform)) (cdr ,form)))))) + +; Utilities for math. Notice that inexact->exact is primitive, +; but exact->inexact is not. +(define exact? integer?) +(define (inexact? x) (and (real? x) (not (integer? x)))) +(define (even? n) (= (remainder n 2) 0)) +(define (odd? n) (not (= (remainder n 2) 0))) +(define (zero? n) (= n 0)) +(define (positive? n) (> n 0)) +(define (negative? n) (< n 0)) +(define complex? number?) +(define rational? real?) +(define (abs n) (if (>= n 0) n (- n))) +(define (exact->inexact n) (* n 1.0)) +(define (<> n1 n2) (not (= n1 n2))) + +; min and max must return inexact if any arg is inexact; use (+ n 0.0) +(define (max . lst) + (foldr (lambda (a b) + (if (> a b) + (if (exact? b) a (+ a 0.0)) + (if (exact? a) b (+ b 0.0)))) + (car lst) (cdr lst))) +(define (min . lst) + (foldr (lambda (a b) + (if (< a b) + (if (exact? b) a (+ a 0.0)) + (if (exact? a) b (+ b 0.0)))) + (car lst) (cdr lst))) + +(define (succ x) (+ x 1)) +(define (pred x) (- x 1)) +(define gcd + (lambda a + (if (null? a) + 0 + (let ((aa (abs (car a))) + (bb (abs (cadr a)))) + (if (= bb 0) + aa + (gcd bb (remainder aa bb))))))) +(define lcm + (lambda a + (if (null? a) + 1 + (let ((aa (abs (car a))) + (bb (abs (cadr a)))) + (if (or (= aa 0) (= bb 0)) + 0 + (abs (* (quotient aa (gcd aa bb)) bb))))))) + + +(define (string . charlist) + (list->string charlist)) + +(define (list->string charlist) + (let* ((len (length charlist)) + (newstr (make-string len)) + (fill-string! + (lambda (str i len charlist) + (if (= i len) + str + (begin (string-set! str i (car charlist)) + (fill-string! str (+ i 1) len (cdr charlist))))))) + (fill-string! newstr 0 len charlist))) + +(define (string-fill! s e) + (let ((n (string-length s))) + (let loop ((i 0)) + (if (= i n) + s + (begin (string-set! s i e) (loop (succ i))))))) + +(define (string->list s) + (let loop ((n (pred (string-length s))) (l '())) + (if (= n -1) + l + (loop (pred n) (cons (string-ref s n) l))))) + +(define (string-copy str) + (string-append str)) + +(define (string->anyatom str pred) + (let* ((a (string->atom str))) + (if (pred a) a + (error "string->xxx: not a xxx" a)))) + +(define (string->number str . base) + (let ((n (string->atom str (if (null? base) 10 (car base))))) + (if (number? n) n #f))) + +(define (anyatom->string n pred) + (if (pred n) + (atom->string n) + (error "xxx->string: not a xxx" n))) + +(define (number->string n . base) + (atom->string n (if (null? base) 10 (car base)))) + + +(define (char-cmp? cmp a b) + (cmp (char->integer a) (char->integer b))) +(define (char-ci-cmp? cmp a b) + (cmp (char->integer (char-downcase a)) (char->integer (char-downcase b)))) + +(define (char=? a b) (char-cmp? = a b)) +(define (char? a b) (char-cmp? > a b)) +(define (char<=? a b) (char-cmp? <= a b)) +(define (char>=? a b) (char-cmp? >= a b)) + +(define (char-ci=? a b) (char-ci-cmp? = a b)) +(define (char-ci? a b) (char-ci-cmp? > a b)) +(define (char-ci<=? a b) (char-ci-cmp? <= a b)) +(define (char-ci>=? a b) (char-ci-cmp? >= a b)) + +; Note the trick of returning (cmp x y) +(define (string-cmp? chcmp cmp a b) + (let ((na (string-length a)) (nb (string-length b))) + (let loop ((i 0)) + (cond + ((= i na) + (if (= i nb) (cmp 0 0) (cmp 0 1))) + ((= i nb) + (cmp 1 0)) + ((chcmp = (string-ref a i) (string-ref b i)) + (loop (succ i))) + (else + (chcmp cmp (string-ref a i) (string-ref b i))))))) + + +(define (string=? a b) (string-cmp? char-cmp? = a b)) +(define (string? a b) (string-cmp? char-cmp? > a b)) +(define (string<=? a b) (string-cmp? char-cmp? <= a b)) +(define (string>=? a b) (string-cmp? char-cmp? >= a b)) + +(define (string-ci=? a b) (string-cmp? char-ci-cmp? = a b)) +(define (string-ci? a b) (string-cmp? char-ci-cmp? > a b)) +(define (string-ci<=? a b) (string-cmp? char-ci-cmp? <= a b)) +(define (string-ci>=? a b) (string-cmp? char-ci-cmp? >= a b)) + +(define (list . x) x) + +(define (foldr f x lst) + (if (null? lst) + x + (foldr f (f x (car lst)) (cdr lst)))) + +(define (unzip1-with-cdr . lists) + (unzip1-with-cdr-iterative lists '() '())) + +(define (unzip1-with-cdr-iterative lists cars cdrs) + (if (null? lists) + (cons cars cdrs) + (let ((car1 (caar lists)) + (cdr1 (cdar lists))) + (unzip1-with-cdr-iterative + (cdr lists) + (append cars (list car1)) + (append cdrs (list cdr1)))))) + +(define (map proc . lists) + (if (null? lists) + (apply proc) + (if (null? (car lists)) + '() + (let* ((unz (apply unzip1-with-cdr lists)) + (cars (car unz)) + (cdrs (cdr unz))) + (cons (apply proc cars) (apply map (cons proc cdrs))))))) + +(define (for-each proc . lists) + (if (null? lists) + (apply proc) + (if (null? (car lists)) + #t + (let* ((unz (apply unzip1-with-cdr lists)) + (cars (car unz)) + (cdrs (cdr unz))) + (apply proc cars) (apply map (cons proc cdrs)))))) + +(define (list-tail x k) + (if (zero? k) + x + (list-tail (cdr x) (- k 1)))) + +(define (list-ref x k) + (car (list-tail x k))) + +(define (last-pair x) + (if (pair? (cdr x)) + (last-pair (cdr x)) + x)) + +(define (head stream) (car stream)) + +(define (tail stream) (force (cdr stream))) + +(define (vector-equal? x y) + (and (vector? x) (vector? y) (= (vector-length x) (vector-length y)) + (let ((n (vector-length x))) + (let loop ((i 0)) + (if (= i n) + #t + (and (equal? (vector-ref x i) (vector-ref y i)) + (loop (succ i)))))))) + +(define (list->vector x) + (apply vector x)) + +(define (vector-fill! v e) + (let ((n (vector-length v))) + (let loop ((i 0)) + (if (= i n) + v + (begin (vector-set! v i e) (loop (succ i))))))) + +(define (vector->list v) + (let loop ((n (pred (vector-length v))) (l '())) + (if (= n -1) + l + (loop (pred n) (cons (vector-ref v n) l))))) + +;; The following quasiquote macro is due to Eric S. Tiedemann. +;; Copyright 1988 by Eric S. Tiedemann; all rights reserved. +;; +;; Subsequently modified to handle vectors: D. Souflis + +(macro + quasiquote + (lambda (l) + (define (mcons f l r) + (if (and (pair? r) + (eq? (car r) 'quote) + (eq? (car (cdr r)) (cdr f)) + (pair? l) + (eq? (car l) 'quote) + (eq? (car (cdr l)) (car f))) + (if (or (procedure? f) (number? f) (string? f)) + f + (list 'quote f)) + (if (eqv? l vector) + (apply l (eval r)) + (list 'cons l r) + ))) + (define (mappend f l r) + (if (or (null? (cdr f)) + (and (pair? r) + (eq? (car r) 'quote) + (eq? (car (cdr r)) '()))) + l + (list 'append l r))) + (define (foo level form) + (cond ((not (pair? form)) + (if (or (procedure? form) (number? form) (string? form)) + form + (list 'quote form)) + ) + ((eq? 'quasiquote (car form)) + (mcons form ''quasiquote (foo (+ level 1) (cdr form)))) + (#t (if (zero? level) + (cond ((eq? (car form) 'unquote) (car (cdr form))) + ((eq? (car form) 'unquote-splicing) + (error "Unquote-splicing wasn't in a list:" + form)) + ((and (pair? (car form)) + (eq? (car (car form)) 'unquote-splicing)) + (mappend form (car (cdr (car form))) + (foo level (cdr form)))) + (#t (mcons form (foo level (car form)) + (foo level (cdr form))))) + (cond ((eq? (car form) 'unquote) + (mcons form ''unquote (foo (- level 1) + (cdr form)))) + ((eq? (car form) 'unquote-splicing) + (mcons form ''unquote-splicing + (foo (- level 1) (cdr form)))) + (#t (mcons form (foo level (car form)) + (foo level (cdr form))))))))) + (foo 0 (car (cdr l))))) + +;;;;;Helper for the dynamic-wind definition. By Tom Breton (Tehom) +(define (shared-tail x y) + (let ((len-x (length x)) + (len-y (length y))) + (define (shared-tail-helper x y) + (if + (eq? x y) + x + (shared-tail-helper (cdr x) (cdr y)))) + + (cond + ((> len-x len-y) + (shared-tail-helper + (list-tail x (- len-x len-y)) + y)) + ((< len-x len-y) + (shared-tail-helper + x + (list-tail y (- len-y len-x)))) + (#t (shared-tail-helper x y))))) + +;;;;;Dynamic-wind by Tom Breton (Tehom) + +;;Guarded because we must only eval this once, because doing so +;;redefines call/cc in terms of old call/cc +(unless (defined? 'dynamic-wind) + (let + ;;These functions are defined in the context of a private list of + ;;pairs of before/after procs. + ( (*active-windings* '()) + ;;We'll define some functions into the larger environment, so + ;;we need to know it. + (outer-env (current-environment))) + + ;;Poor-man's structure operations + (define before-func car) + (define after-func cdr) + (define make-winding cons) + + ;;Manage active windings + (define (activate-winding! new) + ((before-func new)) + (set! *active-windings* (cons new *active-windings*))) + (define (deactivate-top-winding!) + (let ((old-top (car *active-windings*))) + ;;Remove it from the list first so it's not active during its + ;;own exit. + (set! *active-windings* (cdr *active-windings*)) + ((after-func old-top)))) + + (define (set-active-windings! new-ws) + (unless (eq? new-ws *active-windings*) + (let ((shared (shared-tail new-ws *active-windings*))) + + ;;Define the looping functions. + ;;Exit the old list. Do deeper ones last. Don't do + ;;any shared ones. + (define (pop-many) + (unless (eq? *active-windings* shared) + (deactivate-top-winding!) + (pop-many))) + ;;Enter the new list. Do deeper ones first so that the + ;;deeper windings will already be active. Don't do any + ;;shared ones. + (define (push-many new-ws) + (unless (eq? new-ws shared) + (push-many (cdr new-ws)) + (activate-winding! (car new-ws)))) + + ;;Do it. + (pop-many) + (push-many new-ws)))) + + ;;The definitions themselves. + (eval + `(define call-with-current-continuation + ;;It internally uses the built-in call/cc, so capture it. + ,(let ((old-c/cc call-with-current-continuation)) + (lambda (func) + ;;Use old call/cc to get the continuation. + (old-c/cc + (lambda (continuation) + ;;Call func with not the continuation itself + ;;but a procedure that adjusts the active + ;;windings to what they were when we made + ;;this, and only then calls the + ;;continuation. + (func + (let ((current-ws *active-windings*)) + (lambda (x) + (set-active-windings! current-ws) + (continuation x))))))))) + outer-env) + ;;We can't just say "define (dynamic-wind before thunk after)" + ;;because the lambda it's defined to lives in this environment, + ;;not in the global environment. + (eval + `(define dynamic-wind + ,(lambda (before thunk after) + ;;Make a new winding + (activate-winding! (make-winding before after)) + (let ((result (thunk))) + ;;Get rid of the new winding. + (deactivate-top-winding!) + ;;The return value is that of thunk. + result))) + outer-env))) + +(define call/cc call-with-current-continuation) + + +;;;;; atom? and equal? written by a.k + +;;;; atom? +(define (atom? x) + (not (pair? x))) + +;;;; equal? +(define (equal? x y) + (cond + ((pair? x) + (and (pair? y) + (equal? (car x) (car y)) + (equal? (cdr x) (cdr y)))) + ((vector? x) + (and (vector? y) (vector-equal? x y))) + ((string? x) + (and (string? y) (string=? x y))) + (else (eqv? x y)))) + +;;;; (do ((var init inc) ...) (endtest result ...) body ...) +;; +(macro do + (lambda (do-macro) + (apply (lambda (do vars endtest . body) + (let ((do-loop (gensym))) + `(letrec ((,do-loop + (lambda ,(map (lambda (x) + (if (pair? x) (car x) x)) + `,vars) + (if ,(car endtest) + (begin ,@(cdr endtest)) + (begin + ,@body + (,do-loop + ,@(map (lambda (x) + (cond + ((not (pair? x)) x) + ((< (length x) 3) (car x)) + (else (car (cdr (cdr x)))))) + `,vars))))))) + (,do-loop + ,@(map (lambda (x) + (if (and (pair? x) (cdr x)) + (car (cdr x)) + '())) + `,vars))))) + do-macro))) + +;;;; generic-member +(define (generic-member cmp obj lst) + (cond + ((null? lst) #f) + ((cmp obj (car lst)) lst) + (else (generic-member cmp obj (cdr lst))))) + +(define (memq obj lst) + (generic-member eq? obj lst)) +(define (memv obj lst) + (generic-member eqv? obj lst)) +(define (member obj lst) + (generic-member equal? obj lst)) + +;;;; generic-assoc +(define (generic-assoc cmp obj alst) + (cond + ((null? alst) #f) + ((cmp obj (caar alst)) (car alst)) + (else (generic-assoc cmp obj (cdr alst))))) + +(define (assq obj alst) + (generic-assoc eq? obj alst)) +(define (assv obj alst) + (generic-assoc eqv? obj alst)) +(define (assoc obj alst) + (generic-assoc equal? obj alst)) + +(define (acons x y z) (cons (cons x y) z)) + +;;;; Handy for imperative programs +;;;; Used as: (define-with-return (foo x y) .... (return z) ...) +(macro (define-with-return form) + `(define ,(cadr form) + (call/cc (lambda (return) ,@(cddr form))))) + +;;;; Simple exception handling +; +; Exceptions are caught as follows: +; +; (catch (do-something to-recover and-return meaningful-value) +; (if-something goes-wrong) +; (with-these calls)) +; +; "Catch" establishes a scope spanning multiple call-frames +; until another "catch" is encountered. +; +; Exceptions are thrown with: +; +; (throw "message") +; +; If used outside a (catch ...), reverts to (error "message) + +(define *handlers* (list)) + +(define (push-handler proc) + (set! *handlers* (cons proc *handlers*))) + +(define (pop-handler) + (let ((h (car *handlers*))) + (set! *handlers* (cdr *handlers*)) + h)) + +(define (more-handlers?) + (pair? *handlers*)) + +(define (throw . x) + (if (more-handlers?) + (apply (pop-handler)) + (apply error x))) + +(macro (catch form) + (let ((label (gensym))) + `(call/cc (lambda (exit) + (push-handler (lambda () (exit ,(cadr form)))) + (let ((,label (begin ,@(cddr form)))) + (pop-handler) + ,label))))) + +(define *error-hook* throw) + + +;;;;; Definition of MAKE-ENVIRONMENT, to be used with two-argument EVAL + +(macro (make-environment form) + `(apply (lambda () + ,@(cdr form) + (current-environment)))) + +(define-macro (eval-polymorphic x . envl) + (display envl) + (let* ((env (if (null? envl) (current-environment) (eval (car envl)))) + (xval (eval x env))) + (if (closure? xval) + (make-closure (get-closure-code xval) env) + xval))) + +; Redefine this if you install another package infrastructure +; Also redefine 'package' +(define *colon-hook* eval) + +;;;;; I/O + +(define (input-output-port? p) + (and (input-port? p) (output-port? p))) + +(define (close-port p) + (cond + ((input-output-port? p) (close-input-port (close-output-port p))) + ((input-port? p) (close-input-port p)) + ((output-port? p) (close-output-port p)) + (else (throw "Not a port" p)))) + +(define (call-with-input-file s p) + (let ((inport (open-input-file s))) + (if (eq? inport #f) + #f + (let ((res (p inport))) + (close-input-port inport) + res)))) + +(define (call-with-output-file s p) + (let ((outport (open-output-file s))) + (if (eq? outport #f) + #f + (let ((res (p outport))) + (close-output-port outport) + res)))) + +(define (with-input-from-file s p) + (let ((inport (open-input-file s))) + (if (eq? inport #f) + #f + (let ((prev-inport (current-input-port))) + (set-input-port inport) + (let ((res (p))) + (close-input-port inport) + (set-input-port prev-inport) + res))))) + +(define (with-output-to-file s p) + (let ((outport (open-output-file s))) + (if (eq? outport #f) + #f + (let ((prev-outport (current-output-port))) + (set-output-port outport) + (let ((res (p))) + (close-output-port outport) + (set-output-port prev-outport) + res))))) + +(define (with-input-output-from-to-files si so p) + (let ((inport (open-input-file si)) + (outport (open-input-file so))) + (if (not (and inport outport)) + (begin + (close-input-port inport) + (close-output-port outport) + #f) + (let ((prev-inport (current-input-port)) + (prev-outport (current-output-port))) + (set-input-port inport) + (set-output-port outport) + (let ((res (p))) + (close-input-port inport) + (close-output-port outport) + (set-input-port prev-inport) + (set-output-port prev-outport) + res))))) + +; Random number generator (maximum cycle) +(define *seed* 1) +(define (random-next) + (let* ((a 16807) (m 2147483647) (q (quotient m a)) (r (modulo m a))) + (set! *seed* + (- (* a (- *seed* + (* (quotient *seed* q) q))) + (* (quotient *seed* q) r))) + (if (< *seed* 0) (set! *seed* (+ *seed* m))) + *seed*)) +;; SRFI-0 +;; COND-EXPAND +;; Implemented as a macro +(define *features* '(srfi-0)) + +(define-macro (cond-expand . cond-action-list) + (cond-expand-runtime cond-action-list)) + +(define (cond-expand-runtime cond-action-list) + (if (null? cond-action-list) + #t + (if (cond-eval (caar cond-action-list)) + `(begin ,@(cdar cond-action-list)) + (cond-expand-runtime (cdr cond-action-list))))) + +(define (cond-eval-and cond-list) + (foldr (lambda (x y) (and (cond-eval x) (cond-eval y))) #t cond-list)) + +(define (cond-eval-or cond-list) + (foldr (lambda (x y) (or (cond-eval x) (cond-eval y))) #f cond-list)) + +(define (cond-eval condition) + (cond + ((symbol? condition) + (if (member condition *features*) #t #f)) + ((eq? condition #t) #t) + ((eq? condition #f) #f) + (else (case (car condition) + ((and) (cond-eval-and (cdr condition))) + ((or) (cond-eval-or (cdr condition))) + ((not) (if (not (null? (cddr condition))) + (error "cond-expand : 'not' takes 1 argument") + (not (cond-eval (cadr condition))))) + (else (error "cond-expand : unknown operator" (car condition))))))) + +(gc-verbose #f) diff --git a/external/CppMicroServices/third_party/tinyscheme/opdefines.h b/external/CppMicroServices/third_party/tinyscheme/opdefines.h new file mode 100644 index 00000000..ceb4d0e3 --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/opdefines.h @@ -0,0 +1,195 @@ + _OP_DEF(opexe_0, "load", 1, 1, TST_STRING, OP_LOAD ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T0LVL ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T1LVL ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_READ_INTERNAL ) + _OP_DEF(opexe_0, "gensym", 0, 0, 0, OP_GENSYM ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_VALUEPRINT ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_EVAL ) +#if USE_TRACING + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_EVAL ) +#endif + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E0ARGS ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E1ARGS ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_APPLY ) +#if USE_TRACING + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_APPLY ) + _OP_DEF(opexe_0, "tracing", 1, 1, TST_NATURAL, OP_TRACING ) +#endif + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DOMACRO ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA1 ) + _OP_DEF(opexe_0, "make-closure", 1, 2, TST_PAIR TST_ENVIRONMENT, OP_MKCLOSURE ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_QUOTE ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF0 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF1 ) + _OP_DEF(opexe_0, "defined?", 1, 2, TST_SYMBOL TST_ENVIRONMENT, OP_DEFP ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_BEGIN ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF0 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF1 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET0 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET1 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2 ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0AST ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1AST ) + _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2AST ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET0REC ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET1REC ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET2REC ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND0 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND1 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_DELAY ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND0 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND1 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR0 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR1 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C0STREAM ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C1STREAM ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO0 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO1 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE0 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE1 ) + _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE2 ) + _OP_DEF(opexe_1, "eval", 1, 2, TST_ANY TST_ENVIRONMENT, OP_PEVAL ) + _OP_DEF(opexe_1, "apply", 1, INF_ARG, TST_NONE, OP_PAPPLY ) + _OP_DEF(opexe_1, "call-with-current-continuation", 1, 1, TST_NONE, OP_CONTINUATION ) +#if USE_MATH + _OP_DEF(opexe_2, "inexact->exact", 1, 1, TST_NUMBER, OP_INEX2EX ) + _OP_DEF(opexe_2, "exp", 1, 1, TST_NUMBER, OP_EXP ) + _OP_DEF(opexe_2, "log", 1, 1, TST_NUMBER, OP_LOG ) + _OP_DEF(opexe_2, "sin", 1, 1, TST_NUMBER, OP_SIN ) + _OP_DEF(opexe_2, "cos", 1, 1, TST_NUMBER, OP_COS ) + _OP_DEF(opexe_2, "tan", 1, 1, TST_NUMBER, OP_TAN ) + _OP_DEF(opexe_2, "asin", 1, 1, TST_NUMBER, OP_ASIN ) + _OP_DEF(opexe_2, "acos", 1, 1, TST_NUMBER, OP_ACOS ) + _OP_DEF(opexe_2, "atan", 1, 2, TST_NUMBER, OP_ATAN ) + _OP_DEF(opexe_2, "sqrt", 1, 1, TST_NUMBER, OP_SQRT ) + _OP_DEF(opexe_2, "expt", 2, 2, TST_NUMBER, OP_EXPT ) + _OP_DEF(opexe_2, "floor", 1, 1, TST_NUMBER, OP_FLOOR ) + _OP_DEF(opexe_2, "ceiling", 1, 1, TST_NUMBER, OP_CEILING ) + _OP_DEF(opexe_2, "truncate", 1, 1, TST_NUMBER, OP_TRUNCATE ) + _OP_DEF(opexe_2, "round", 1, 1, TST_NUMBER, OP_ROUND ) +#endif + _OP_DEF(opexe_2, "+", 0, INF_ARG, TST_NUMBER, OP_ADD ) + _OP_DEF(opexe_2, "-", 1, INF_ARG, TST_NUMBER, OP_SUB ) + _OP_DEF(opexe_2, "*", 0, INF_ARG, TST_NUMBER, OP_MUL ) + _OP_DEF(opexe_2, "/", 1, INF_ARG, TST_NUMBER, OP_DIV ) + _OP_DEF(opexe_2, "quotient", 1, INF_ARG, TST_INTEGER, OP_INTDIV ) + _OP_DEF(opexe_2, "remainder", 2, 2, TST_INTEGER, OP_REM ) + _OP_DEF(opexe_2, "modulo", 2, 2, TST_INTEGER, OP_MOD ) + _OP_DEF(opexe_2, "car", 1, 1, TST_PAIR, OP_CAR ) + _OP_DEF(opexe_2, "cdr", 1, 1, TST_PAIR, OP_CDR ) + _OP_DEF(opexe_2, "cons", 2, 2, TST_NONE, OP_CONS ) + _OP_DEF(opexe_2, "set-car!", 2, 2, TST_PAIR TST_ANY, OP_SETCAR ) + _OP_DEF(opexe_2, "set-cdr!", 2, 2, TST_PAIR TST_ANY, OP_SETCDR ) + _OP_DEF(opexe_2, "char->integer", 1, 1, TST_CHAR, OP_CHAR2INT ) + _OP_DEF(opexe_2, "integer->char", 1, 1, TST_NATURAL, OP_INT2CHAR ) + _OP_DEF(opexe_2, "char-upcase", 1, 1, TST_CHAR, OP_CHARUPCASE ) + _OP_DEF(opexe_2, "char-downcase", 1, 1, TST_CHAR, OP_CHARDNCASE ) + _OP_DEF(opexe_2, "symbol->string", 1, 1, TST_SYMBOL, OP_SYM2STR ) + _OP_DEF(opexe_2, "atom->string", 1, 2, TST_ANY TST_NATURAL, OP_ATOM2STR ) + _OP_DEF(opexe_2, "string->symbol", 1, 1, TST_STRING, OP_STR2SYM ) + _OP_DEF(opexe_2, "string->atom", 1, 2, TST_STRING TST_NATURAL, OP_STR2ATOM ) + _OP_DEF(opexe_2, "make-string", 1, 2, TST_NATURAL TST_CHAR, OP_MKSTRING ) + _OP_DEF(opexe_2, "string-length", 1, 1, TST_STRING, OP_STRLEN ) + _OP_DEF(opexe_2, "string-ref", 2, 2, TST_STRING TST_NATURAL, OP_STRREF ) + _OP_DEF(opexe_2, "string-set!", 3, 3, TST_STRING TST_NATURAL TST_CHAR, OP_STRSET ) + _OP_DEF(opexe_2, "string-append", 0, INF_ARG, TST_STRING, OP_STRAPPEND ) + _OP_DEF(opexe_2, "substring", 2, 3, TST_STRING TST_NATURAL, OP_SUBSTR ) + _OP_DEF(opexe_2, "vector", 0, INF_ARG, TST_NONE, OP_VECTOR ) + _OP_DEF(opexe_2, "make-vector", 1, 2, TST_NATURAL TST_ANY, OP_MKVECTOR ) + _OP_DEF(opexe_2, "vector-length", 1, 1, TST_VECTOR, OP_VECLEN ) + _OP_DEF(opexe_2, "vector-ref", 2, 2, TST_VECTOR TST_NATURAL, OP_VECREF ) + _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET ) + _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT ) + _OP_DEF(opexe_3, "boolean?", 1, 1, TST_NONE, OP_BOOLP ) + _OP_DEF(opexe_3, "eof-object?", 1, 1, TST_NONE, OP_EOFOBJP ) + _OP_DEF(opexe_3, "null?", 1, 1, TST_NONE, OP_NULLP ) + _OP_DEF(opexe_3, "=", 2, INF_ARG, TST_NUMBER, OP_NUMEQ ) + _OP_DEF(opexe_3, "<", 2, INF_ARG, TST_NUMBER, OP_LESS ) + _OP_DEF(opexe_3, ">", 2, INF_ARG, TST_NUMBER, OP_GRE ) + _OP_DEF(opexe_3, "<=", 2, INF_ARG, TST_NUMBER, OP_LEQ ) + _OP_DEF(opexe_3, ">=", 2, INF_ARG, TST_NUMBER, OP_GEQ ) + _OP_DEF(opexe_3, "symbol?", 1, 1, TST_ANY, OP_SYMBOLP ) + _OP_DEF(opexe_3, "number?", 1, 1, TST_ANY, OP_NUMBERP ) + _OP_DEF(opexe_3, "string?", 1, 1, TST_ANY, OP_STRINGP ) + _OP_DEF(opexe_3, "integer?", 1, 1, TST_ANY, OP_INTEGERP ) + _OP_DEF(opexe_3, "real?", 1, 1, TST_ANY, OP_REALP ) + _OP_DEF(opexe_3, "char?", 1, 1, TST_ANY, OP_CHARP ) +#if USE_CHAR_CLASSIFIERS + _OP_DEF(opexe_3, "char-alphabetic?", 1, 1, TST_CHAR, OP_CHARAP ) + _OP_DEF(opexe_3, "char-numeric?", 1, 1, TST_CHAR, OP_CHARNP ) + _OP_DEF(opexe_3, "char-whitespace?", 1, 1, TST_CHAR, OP_CHARWP ) + _OP_DEF(opexe_3, "char-upper-case?", 1, 1, TST_CHAR, OP_CHARUP ) + _OP_DEF(opexe_3, "char-lower-case?", 1, 1, TST_CHAR, OP_CHARLP ) +#endif + _OP_DEF(opexe_3, "port?", 1, 1, TST_ANY, OP_PORTP ) + _OP_DEF(opexe_3, "input-port?", 1, 1, TST_ANY, OP_INPORTP ) + _OP_DEF(opexe_3, "output-port?", 1, 1, TST_ANY, OP_OUTPORTP ) + _OP_DEF(opexe_3, "procedure?", 1, 1, TST_ANY, OP_PROCP ) + _OP_DEF(opexe_3, "pair?", 1, 1, TST_ANY, OP_PAIRP ) + _OP_DEF(opexe_3, "list?", 1, 1, TST_ANY, OP_LISTP ) + _OP_DEF(opexe_3, "environment?", 1, 1, TST_ANY, OP_ENVP ) + _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP ) + _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ ) + _OP_DEF(opexe_3, "eqv?", 2, 2, TST_ANY, OP_EQV ) + _OP_DEF(opexe_4, "force", 1, 1, TST_ANY, OP_FORCE ) + _OP_DEF(opexe_4, 0, 0, 0, 0, OP_SAVE_FORCED ) + _OP_DEF(opexe_4, "write", 1, 2, TST_ANY TST_OUTPORT, OP_WRITE ) + _OP_DEF(opexe_4, "write-char", 1, 2, TST_CHAR TST_OUTPORT, OP_WRITE_CHAR ) + _OP_DEF(opexe_4, "display", 1, 2, TST_ANY TST_OUTPORT, OP_DISPLAY ) + _OP_DEF(opexe_4, "newline", 0, 1, TST_OUTPORT, OP_NEWLINE ) + _OP_DEF(opexe_4, "error", 1, INF_ARG, TST_NONE, OP_ERR0 ) + _OP_DEF(opexe_4, 0, 0, 0, 0, OP_ERR1 ) + _OP_DEF(opexe_4, "reverse", 1, 1, TST_LIST, OP_REVERSE ) + _OP_DEF(opexe_4, "list*", 1, INF_ARG, TST_NONE, OP_LIST_STAR ) + _OP_DEF(opexe_4, "append", 0, INF_ARG, TST_NONE, OP_APPEND ) +#if USE_PLIST + _OP_DEF(opexe_4, "put", 3, 3, TST_NONE, OP_PUT ) + _OP_DEF(opexe_4, "get", 2, 2, TST_NONE, OP_GET ) +#endif + _OP_DEF(opexe_4, "quit", 0, 1, TST_NUMBER, OP_QUIT ) + _OP_DEF(opexe_4, "gc", 0, 0, 0, OP_GC ) + _OP_DEF(opexe_4, "gc-verbose", 0, 1, TST_NONE, OP_GCVERB ) + _OP_DEF(opexe_4, "new-segment", 0, 1, TST_NUMBER, OP_NEWSEGMENT ) + _OP_DEF(opexe_4, "oblist", 0, 0, 0, OP_OBLIST ) + _OP_DEF(opexe_4, "current-input-port", 0, 0, 0, OP_CURR_INPORT ) + _OP_DEF(opexe_4, "current-output-port", 0, 0, 0, OP_CURR_OUTPORT ) + _OP_DEF(opexe_4, "open-input-file", 1, 1, TST_STRING, OP_OPEN_INFILE ) + _OP_DEF(opexe_4, "open-output-file", 1, 1, TST_STRING, OP_OPEN_OUTFILE ) + _OP_DEF(opexe_4, "open-input-output-file", 1, 1, TST_STRING, OP_OPEN_INOUTFILE ) +#if USE_STRING_PORTS + _OP_DEF(opexe_4, "open-input-string", 1, 1, TST_STRING, OP_OPEN_INSTRING ) + _OP_DEF(opexe_4, "open-input-output-string", 1, 1, TST_STRING, OP_OPEN_INOUTSTRING ) + _OP_DEF(opexe_4, "open-output-string", 0, 1, TST_STRING, OP_OPEN_OUTSTRING ) + _OP_DEF(opexe_4, "get-output-string", 1, 1, TST_OUTPORT, OP_GET_OUTSTRING ) +#endif + _OP_DEF(opexe_4, "close-input-port", 1, 1, TST_INPORT, OP_CLOSE_INPORT ) + _OP_DEF(opexe_4, "close-output-port", 1, 1, TST_OUTPORT, OP_CLOSE_OUTPORT ) + _OP_DEF(opexe_4, "interaction-environment", 0, 0, 0, OP_INT_ENV ) + _OP_DEF(opexe_4, "current-environment", 0, 0, 0, OP_CURR_ENV ) + _OP_DEF(opexe_5, "read", 0, 1, TST_INPORT, OP_READ ) + _OP_DEF(opexe_5, "read-char", 0, 1, TST_INPORT, OP_READ_CHAR ) + _OP_DEF(opexe_5, "peek-char", 0, 1, TST_INPORT, OP_PEEK_CHAR ) + _OP_DEF(opexe_5, "char-ready?", 0, 1, TST_INPORT, OP_CHAR_READY ) + _OP_DEF(opexe_5, "set-input-port", 1, 1, TST_INPORT, OP_SET_INPORT ) + _OP_DEF(opexe_5, "set-output-port", 1, 1, TST_OUTPORT, OP_SET_OUTPORT ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDSEXPR ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDLIST ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDDOT ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQUOTE ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTE ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTEVEC ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUNQUOTE ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUQTSP ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDVEC ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P0LIST ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P1LIST ) + _OP_DEF(opexe_5, 0, 0, 0, 0, OP_PVECFROM ) + _OP_DEF(opexe_6, "length", 1, 1, TST_LIST, OP_LIST_LENGTH ) + _OP_DEF(opexe_6, "assq", 2, 2, TST_NONE, OP_ASSQ ) + _OP_DEF(opexe_6, "get-closure-code", 1, 1, TST_NONE, OP_GET_CLOSURE ) + _OP_DEF(opexe_6, "closure?", 1, 1, TST_NONE, OP_CLOSUREP ) + _OP_DEF(opexe_6, "macro?", 1, 1, TST_NONE, OP_MACROP ) +#undef _OP_DEF diff --git a/external/CppMicroServices/third_party/tinyscheme/scheme-private.h b/external/CppMicroServices/third_party/tinyscheme/scheme-private.h new file mode 100644 index 00000000..33953288 --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/scheme-private.h @@ -0,0 +1,210 @@ +/* scheme-private.h */ + +#ifndef _SCHEME_PRIVATE_H +#define _SCHEME_PRIVATE_H + +#include "scheme.h" +/*------------------ Ugly internals -----------------------------------*/ +/*------------------ Of interest only to FFI users --------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +enum scheme_port_kind { + port_free=0, + port_file=1, + port_string=2, + port_srfi6=4, + port_input=16, + port_output=32, + port_saw_EOF=64 +}; + +typedef struct port { + unsigned char kind; + union { + struct { + FILE *file; + int closeit; +#if SHOW_ERROR_LINE + int curr_line; + char *filename; +#endif + } stdio; + struct { + char *start; + char *past_the_end; + char *curr; + } string; + } rep; +} port; + +/* cell structure */ +struct cell { + unsigned int _flag; + union { + struct { + char *_svalue; + int _length; + } _string; + num _number; + port *_port; + foreign_func _ff; + struct { + struct cell *_car; + struct cell *_cdr; + } _cons; + } _object; +}; + +struct scheme { +/* arrays for segments */ +func_alloc malloc; +func_dealloc free; + +/* return code */ +int retcode; +int tracing; + + +#define CELL_SEGSIZE 5000 /* # of cells in one segment */ +#define CELL_NSEGMENT 10 /* # of segments for cells */ +char *alloc_seg[CELL_NSEGMENT]; +pointer cell_seg[CELL_NSEGMENT]; +int last_cell_seg; + +/* We use 4 registers. */ +pointer args; /* register for arguments of function */ +pointer envir; /* stack register for current environment */ +pointer code; /* register for current code */ +pointer dump; /* stack register for next evaluation */ + +int interactive_repl; /* are we in an interactive REPL? */ + +struct cell _sink; +pointer sink; /* when mem. alloc. fails */ +struct cell _NIL; +pointer NIL; /* special cell representing empty cell */ +struct cell _HASHT; +pointer T; /* special cell representing #t */ +struct cell _HASHF; +pointer F; /* special cell representing #f */ +struct cell _EOF_OBJ; +pointer EOF_OBJ; /* special cell representing end-of-file object */ +pointer oblist; /* pointer to symbol table */ +pointer global_env; /* pointer to global environment */ +pointer c_nest; /* stack for nested calls from C */ + +/* global pointers to special symbols */ +pointer LAMBDA; /* pointer to syntax lambda */ +pointer QUOTE; /* pointer to syntax quote */ + +pointer QQUOTE; /* pointer to symbol quasiquote */ +pointer UNQUOTE; /* pointer to symbol unquote */ +pointer UNQUOTESP; /* pointer to symbol unquote-splicing */ +pointer FEED_TO; /* => */ +pointer COLON_HOOK; /* *colon-hook* */ +pointer ERROR_HOOK; /* *error-hook* */ +pointer SHARP_HOOK; /* *sharp-hook* */ +pointer COMPILE_HOOK; /* *compile-hook* */ + +pointer free_cell; /* pointer to top of free cells */ +long fcells; /* # of free cells */ + +pointer inport; +pointer outport; +pointer save_inport; +pointer loadport; + +#define MAXFIL 64 +port load_stack[MAXFIL]; /* Stack of open files for port -1 (LOADing) */ +int nesting_stack[MAXFIL]; +int file_i; +int nesting; + +char gc_verbose; /* if gc_verbose is not zero, print gc status */ +char no_memory; /* Whether mem. alloc. has failed */ + +#define LINESIZE 1024 +char linebuff[LINESIZE]; +#define STRBUFFSIZE 256 +char strbuff[STRBUFFSIZE]; + +FILE *tmpfp; +int tok; +int print_flag; +pointer value; +int op; + +void *ext_data; /* For the benefit of foreign functions */ +long gensym_cnt; + +struct scheme_interface *vptr; +void *dump_base; /* pointer to base of allocated dump stack */ +int dump_size; /* number of frames allocated for dump stack */ +}; + +/* operator code */ +enum scheme_opcodes { +#define _OP_DEF(A,B,C,D,E,OP) OP, +#include "opdefines.h" + OP_MAXDEFINED +}; + + +#define cons(sc,a,b) _cons(sc,a,b,0) +#define immutable_cons(sc,a,b) _cons(sc,a,b,1) + +int is_string(pointer p); +char *string_value(pointer p); +int is_number(pointer p); +num nvalue(pointer p); +long ivalue(pointer p); +double rvalue(pointer p); +int is_integer(pointer p); +int is_real(pointer p); +int is_character(pointer p); +long charvalue(pointer p); +int is_vector(pointer p); + +int is_port(pointer p); + +int is_pair(pointer p); +pointer pair_car(pointer p); +pointer pair_cdr(pointer p); +pointer set_car(pointer p, pointer q); +pointer set_cdr(pointer p, pointer q); + +int is_symbol(pointer p); +char *symname(pointer p); +int hasprop(pointer p); + +int is_syntax(pointer p); +int is_proc(pointer p); +int is_foreign(pointer p); +char *syntaxname(pointer p); +int is_closure(pointer p); +#ifdef USE_MACRO +int is_macro(pointer p); +#endif +pointer closure_code(pointer p); +pointer closure_env(pointer p); + +int is_continuation(pointer p); +int is_promise(pointer p); +int is_environment(pointer p); +int is_immutable(pointer p); +void setimmutable(pointer p); + +#ifdef __cplusplus +} +#endif + +#endif + +/* +Local variables: +c-file-style: "k&r" +End: +*/ diff --git a/external/CppMicroServices/third_party/tinyscheme/scheme.c b/external/CppMicroServices/third_party/tinyscheme/scheme.c new file mode 100644 index 00000000..59921e48 --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/scheme.c @@ -0,0 +1,5053 @@ +/* T I N Y S C H E M E 1 . 4 1 + * Dimitrios Souflis (dsouflis@acm.org) + * Based on MiniScheme (original credits follow) + * (MINISCM) coded by Atsushi Moriwaki (11/5/1989) + * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp + * (MINISCM) This version has been modified by R.C. Secrist. + * (MINISCM) + * (MINISCM) Mini-Scheme is now maintained by Akira KIDA. + * (MINISCM) + * (MINISCM) This is a revised and modified version by Akira KIDA. + * (MINISCM) current version is 0.85k4 (15 May 1994) + * + */ + +#define _SCHEME_SOURCE +#include "scheme-private.h" +#ifndef WIN32 +# include +#endif +#ifdef WIN32 +#include +#define snprintf _snprintf +#pragma warning( disable : 4244 4267) +#endif +#if USE_DL +# include "dynload.h" +#endif +#if USE_MATH +# include +#endif + +#include +#include +#include + +#if USE_STRCASECMP +#include +# ifndef __APPLE__ +# define stricmp strcasecmp +# endif +#endif + +/* Used for documentation purposes, to signal functions in 'interface' */ +#define INTERFACE + +#define TOK_EOF (-1) +#define TOK_LPAREN 0 +#define TOK_RPAREN 1 +#define TOK_DOT 2 +#define TOK_ATOM 3 +#define TOK_QUOTE 4 +#define TOK_COMMENT 5 +#define TOK_DQUOTE 6 +#define TOK_BQUOTE 7 +#define TOK_COMMA 8 +#define TOK_ATMARK 9 +#define TOK_SHARP 10 +#define TOK_SHARP_CONST 11 +#define TOK_VEC 12 + +#define BACKQUOTE '`' +#define DELIMITERS "()\";\f\t\v\n\r " + +/* + * Basic memory allocation units + */ + +#define banner "TinyScheme 1.41" + +#include +#include + +#ifdef __APPLE__ +static int stricmp(const char *s1, const char *s2) +{ + unsigned char c1, c2; + do { + c1 = tolower(*s1); + c2 = tolower(*s2); + if (c1 < c2) + return -1; + else if (c1 > c2) + return 1; + s1++, s2++; + } while (c1 != 0); + return 0; +} +#endif /* __APPLE__ */ + +#if USE_STRLWR +static const char *strlwr(char *s) { + const char *p=s; + while(*s) { + *s=tolower(*s); + s++; + } + return p; +} +#endif + +#ifndef prompt +# define prompt "ts> " +#endif + +#ifndef InitFile +# define InitFile "init.scm" +#endif + +#ifndef FIRST_CELLSEGS +# define FIRST_CELLSEGS 3 +#endif + +enum scheme_types { + T_STRING=1, + T_NUMBER=2, + T_SYMBOL=3, + T_PROC=4, + T_PAIR=5, + T_CLOSURE=6, + T_CONTINUATION=7, + T_FOREIGN=8, + T_CHARACTER=9, + T_PORT=10, + T_VECTOR=11, + T_MACRO=12, + T_PROMISE=13, + T_ENVIRONMENT=14, + T_LAST_SYSTEM_TYPE=14 +}; + +/* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */ +#define ADJ 32 +#define TYPE_BITS 5 +#define T_MASKTYPE 31 /* 0000000000011111 */ +#define T_SYNTAX 4096 /* 0001000000000000 */ +#define T_IMMUTABLE 8192 /* 0010000000000000 */ +#define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */ +#define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */ +#define MARK 32768 /* 1000000000000000 */ +#define UNMARK 32767 /* 0111111111111111 */ + + +static num num_add(num a, num b); +static num num_mul(num a, num b); +static num num_div(num a, num b); +static num num_intdiv(num a, num b); +static num num_sub(num a, num b); +static num num_rem(num a, num b); +static num num_mod(num a, num b); +static int num_eq(num a, num b); +static int num_gt(num a, num b); +static int num_ge(num a, num b); +static int num_lt(num a, num b); +static int num_le(num a, num b); + +#if USE_MATH +static double round_per_R5RS(double x); +#endif +static int is_zero_double(double x); +static INLINE int num_is_integer(pointer p) { + return ((p)->_object._number.is_fixnum); +} + +static num num_zero; +static num num_one; + +/* macros for cell operations */ +#define typeflag(p) ((p)->_flag) +#define type(p) (typeflag(p)&T_MASKTYPE) + +INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); } +#define strvalue(p) ((p)->_object._string._svalue) +#define strlength(p) ((p)->_object._string._length) + +INTERFACE static int is_list(scheme *sc, pointer p); +INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); } +INTERFACE static void fill_vector(pointer vec, pointer obj); +INTERFACE static pointer vector_elem(pointer vec, int ielem); +INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a); +INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); } +INTERFACE INLINE int is_integer(pointer p) { + if (!is_number(p)) + return 0; + if (num_is_integer(p) || (double)ivalue(p) == rvalue(p)) + return 1; + return 0; +} + +INTERFACE INLINE int is_real(pointer p) { + return is_number(p) && (!(p)->_object._number.is_fixnum); +} + +INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); } +INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); } +INLINE num nvalue(pointer p) { return ((p)->_object._number); } +INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); } +INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); } +#define ivalue_unchecked(p) ((p)->_object._number.value.ivalue) +#define rvalue_unchecked(p) ((p)->_object._number.value.rvalue) +#define set_num_integer(p) (p)->_object._number.is_fixnum=1; +#define set_num_real(p) (p)->_object._number.is_fixnum=0; +INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); } + +INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); } +INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; } +INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; } + +INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); } +#define car(p) ((p)->_object._cons._car) +#define cdr(p) ((p)->_object._cons._cdr) +INTERFACE pointer pair_car(pointer p) { return car(p); } +INTERFACE pointer pair_cdr(pointer p) { return cdr(p); } +INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; } +INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; } + +INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); } +INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); } +#if USE_PLIST +SCHEME_EXPORT INLINE int hasprop(pointer p) { return (typeflag(p)&T_SYMBOL); } +#define symprop(p) cdr(p) +#endif + +INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); } +INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); } +INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); } +INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); } +#define procnum(p) ivalue(p) +static const char *procname(pointer x); + +INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); } +INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); } +INTERFACE INLINE pointer closure_code(pointer p) { return car(p); } +INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); } + +INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); } +#define cont_dump(p) cdr(p) + +/* To do: promise should be forced ONCE only */ +INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); } + +INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); } +#define setenvironment(p) typeflag(p) = T_ENVIRONMENT + +#define is_atom(p) (typeflag(p)&T_ATOM) +#define setatom(p) typeflag(p) |= T_ATOM +#define clratom(p) typeflag(p) &= CLRATOM + +#define is_mark(p) (typeflag(p)&MARK) +#define setmark(p) typeflag(p) |= MARK +#define clrmark(p) typeflag(p) &= UNMARK + +INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); } +/*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/ +INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; } + +#define caar(p) car(car(p)) +#define cadr(p) car(cdr(p)) +#define cdar(p) cdr(car(p)) +#define cddr(p) cdr(cdr(p)) +#define cadar(p) car(cdr(car(p))) +#define caddr(p) car(cdr(cdr(p))) +#define cdaar(p) cdr(car(car(p))) +#define cadaar(p) car(cdr(car(car(p)))) +#define cadddr(p) car(cdr(cdr(cdr(p)))) +#define cddddr(p) cdr(cdr(cdr(cdr(p)))) + +#if USE_CHAR_CLASSIFIERS +static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); } +static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); } +static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); } +static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); } +static INLINE int Cislower(int c) { return isascii(c) && islower(c); } +#endif + +#if USE_ASCII_NAMES +static const char *charnames[32]={ + "nul", + "soh", + "stx", + "etx", + "eot", + "enq", + "ack", + "bel", + "bs", + "ht", + "lf", + "vt", + "ff", + "cr", + "so", + "si", + "dle", + "dc1", + "dc2", + "dc3", + "dc4", + "nak", + "syn", + "etb", + "can", + "em", + "sub", + "esc", + "fs", + "gs", + "rs", + "us" +}; + +static int is_ascii_name(const char *name, int *pc) { + int i; + for(i=0; i<32; i++) { + if(stricmp(name,charnames[i])==0) { + *pc=i; + return 1; + } + } + if(stricmp(name,"del")==0) { + *pc=127; + return 1; + } + return 0; +} + +#endif + +static int file_push(scheme *sc, const char *fname); +static void file_pop(scheme *sc); +static int file_interactive(scheme *sc); +static INLINE int is_one_of(char *s, int c); +static int alloc_cellseg(scheme *sc, int n); +static long binary_decode(const char *s); +static INLINE pointer get_cell(scheme *sc, pointer a, pointer b); +static pointer _get_cell(scheme *sc, pointer a, pointer b); +static pointer reserve_cells(scheme *sc, int n); +static pointer get_consecutive_cells(scheme *sc, int n); +static pointer find_consecutive_cells(scheme *sc, int n); +static void finalize_cell(scheme *sc, pointer a); +static int count_consecutive_cells(pointer x, int needed); +static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all); +static pointer mk_number(scheme *sc, num n); +static char *store_string(scheme *sc, int len, const char *str, char fill); +static pointer mk_vector(scheme *sc, int len); +static pointer mk_atom(scheme *sc, char *q); +static pointer mk_sharp_const(scheme *sc, char *name); +static pointer mk_port(scheme *sc, port *p); +static pointer port_from_filename(scheme *sc, const char *fn, int prop); +static pointer port_from_file(scheme *sc, FILE *, int prop); +static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop); +static port *port_rep_from_filename(scheme *sc, const char *fn, int prop); +static port *port_rep_from_file(scheme *sc, FILE *, int prop); +static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop); +static void port_close(scheme *sc, pointer p, int flag); +static void mark(pointer a); +static void gc(scheme *sc, pointer a, pointer b); +static int basic_inchar(port *pt); +static int inchar(scheme *sc); +static void backchar(scheme *sc, int c); +static char *readstr_upto(scheme *sc, char *delim); +static pointer readstrexp(scheme *sc); +static INLINE int skipspace(scheme *sc); +static int token(scheme *sc); +static void printslashstring(scheme *sc, char *s, int len); +static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen); +static void printatom(scheme *sc, pointer l, int f); +static pointer mk_proc(scheme *sc, enum scheme_opcodes op); +static pointer mk_closure(scheme *sc, pointer c, pointer e); +static pointer mk_continuation(scheme *sc, pointer d); +static pointer reverse(scheme *sc, pointer a); +static pointer reverse_in_place(scheme *sc, pointer term, pointer list); +static pointer revappend(scheme *sc, pointer a, pointer b); +static void dump_stack_mark(scheme *); +static pointer opexe_0(scheme *sc, enum scheme_opcodes op); +static pointer opexe_1(scheme *sc, enum scheme_opcodes op); +static pointer opexe_2(scheme *sc, enum scheme_opcodes op); +static pointer opexe_3(scheme *sc, enum scheme_opcodes op); +static pointer opexe_4(scheme *sc, enum scheme_opcodes op); +static pointer opexe_5(scheme *sc, enum scheme_opcodes op); +static pointer opexe_6(scheme *sc, enum scheme_opcodes op); +static void Eval_Cycle(scheme *sc, enum scheme_opcodes op); +static void assign_syntax(scheme *sc, char *name); +static int syntaxnum(pointer p); +static void assign_proc(scheme *sc, enum scheme_opcodes, char *name); + +#define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue) +#define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue) + +static num num_add(num a, num b) { + num ret; + ret.is_fixnum=a.is_fixnum && b.is_fixnum; + if(ret.is_fixnum) { + ret.value.ivalue= a.value.ivalue+b.value.ivalue; + } else { + ret.value.rvalue=num_rvalue(a)+num_rvalue(b); + } + return ret; +} + +static num num_mul(num a, num b) { + num ret; + ret.is_fixnum=a.is_fixnum && b.is_fixnum; + if(ret.is_fixnum) { + ret.value.ivalue= a.value.ivalue*b.value.ivalue; + } else { + ret.value.rvalue=num_rvalue(a)*num_rvalue(b); + } + return ret; +} + +static num num_div(num a, num b) { + num ret; + ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0; + if(ret.is_fixnum) { + ret.value.ivalue= a.value.ivalue/b.value.ivalue; + } else { + ret.value.rvalue=num_rvalue(a)/num_rvalue(b); + } + return ret; +} + +static num num_intdiv(num a, num b) { + num ret; + ret.is_fixnum=a.is_fixnum && b.is_fixnum; + if(ret.is_fixnum) { + ret.value.ivalue= a.value.ivalue/b.value.ivalue; + } else { + ret.value.rvalue=num_rvalue(a)/num_rvalue(b); + } + return ret; +} + +static num num_sub(num a, num b) { + num ret; + ret.is_fixnum=a.is_fixnum && b.is_fixnum; + if(ret.is_fixnum) { + ret.value.ivalue= a.value.ivalue-b.value.ivalue; + } else { + ret.value.rvalue=num_rvalue(a)-num_rvalue(b); + } + return ret; +} + +static num num_rem(num a, num b) { + num ret; + long e1, e2, res; + ret.is_fixnum=a.is_fixnum && b.is_fixnum; + e1=num_ivalue(a); + e2=num_ivalue(b); + res=e1%e2; + /* remainder should have same sign as second operand */ + if (res > 0) { + if (e1 < 0) { + res -= labs(e2); + } + } else if (res < 0) { + if (e1 > 0) { + res += labs(e2); + } + } + ret.value.ivalue=res; + return ret; +} + +static num num_mod(num a, num b) { + num ret; + long e1, e2, res; + ret.is_fixnum=a.is_fixnum && b.is_fixnum; + e1=num_ivalue(a); + e2=num_ivalue(b); + res=e1%e2; + /* modulo should have same sign as second operand */ + if (res * e2 < 0) { + res += e2; + } + ret.value.ivalue=res; + return ret; +} + +static int num_eq(num a, num b) { + int ret; + int is_fixnum=a.is_fixnum && b.is_fixnum; + if(is_fixnum) { + ret= a.value.ivalue==b.value.ivalue; + } else { + ret=num_rvalue(a)==num_rvalue(b); + } + return ret; +} + + +static int num_gt(num a, num b) { + int ret; + int is_fixnum=a.is_fixnum && b.is_fixnum; + if(is_fixnum) { + ret= a.value.ivalue>b.value.ivalue; + } else { + ret=num_rvalue(a)>num_rvalue(b); + } + return ret; +} + +static int num_ge(num a, num b) { + return !num_lt(a,b); +} + +static int num_lt(num a, num b) { + int ret; + int is_fixnum=a.is_fixnum && b.is_fixnum; + if(is_fixnum) { + ret= a.value.ivaluedce) { + return ce; + } else if(dfl-DBL_MIN; +} + +static long binary_decode(const char *s) { + long x=0; + + while(*s!=0 && (*s=='1' || *s=='0')) { + x<<=1; + x+=*s-'0'; + s++; + } + + return x; +} + +/* allocate new cell segment */ +static int alloc_cellseg(scheme *sc, int n) { + pointer newp; + pointer last; + pointer p; + char *cp; + long i; + int k; + int adj=ADJ; + + if(adjlast_cell_seg >= CELL_NSEGMENT - 1) + return k; + cp = (char*) sc->malloc(CELL_SEGSIZE * sizeof(struct cell)+adj); + if (cp == 0) + return k; + i = ++sc->last_cell_seg ; + sc->alloc_seg[i] = cp; + /* adjust in TYPE_BITS-bit boundary */ + if(((unsigned long)cp)%adj!=0) { + cp=(char*)(adj*((unsigned long)cp/adj+1)); + } + /* insert new segment in address order */ + newp=(pointer)cp; + sc->cell_seg[i] = newp; + while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) { + p = sc->cell_seg[i]; + sc->cell_seg[i] = sc->cell_seg[i - 1]; + sc->cell_seg[--i] = p; + } + sc->fcells += CELL_SEGSIZE; + last = newp + CELL_SEGSIZE - 1; + for (p = newp; p <= last; p++) { + typeflag(p) = 0; + cdr(p) = p + 1; + car(p) = sc->NIL; + } + /* insert new cells in address order on free list */ + if (sc->free_cell == sc->NIL || p < sc->free_cell) { + cdr(last) = sc->free_cell; + sc->free_cell = newp; + } else { + p = sc->free_cell; + while (cdr(p) != sc->NIL && newp > cdr(p)) + p = cdr(p); + cdr(last) = cdr(p); + cdr(p) = newp; + } + } + return n; +} + +static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) { + if (sc->free_cell != sc->NIL) { + pointer x = sc->free_cell; + sc->free_cell = cdr(x); + --sc->fcells; + return (x); + } + return _get_cell (sc, a, b); +} + + +/* get new cell. parameter a, b is marked by gc. */ +static pointer _get_cell(scheme *sc, pointer a, pointer b) { + pointer x; + + if(sc->no_memory) { + return sc->sink; + } + + if (sc->free_cell == sc->NIL) { + const int min_to_be_recovered = sc->last_cell_seg*8; + gc(sc,a, b); + if (sc->fcells < min_to_be_recovered + || sc->free_cell == sc->NIL) { + /* if only a few recovered, get more to avoid fruitless gc's */ + if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) { + sc->no_memory=1; + return sc->sink; + } + } + } + x = sc->free_cell; + sc->free_cell = cdr(x); + --sc->fcells; + return (x); +} + +/* make sure that there is a given number of cells free */ +static pointer reserve_cells(scheme *sc, int n) { + if(sc->no_memory) { + return sc->NIL; + } + + /* Are there enough cells available? */ + if (sc->fcells < n) { + /* If not, try gc'ing some */ + gc(sc, sc->NIL, sc->NIL); + if (sc->fcells < n) { + /* If there still aren't, try getting more heap */ + if (!alloc_cellseg(sc,1)) { + sc->no_memory=1; + return sc->NIL; + } + } + if (sc->fcells < n) { + /* If all fail, report failure */ + sc->no_memory=1; + return sc->NIL; + } + } + return (sc->T); +} + +static pointer get_consecutive_cells(scheme *sc, int n) { + pointer x; + + if(sc->no_memory) { return sc->sink; } + + /* Are there any cells available? */ + x=find_consecutive_cells(sc,n); + if (x != sc->NIL) { return x; } + + /* If not, try gc'ing some */ + gc(sc, sc->NIL, sc->NIL); + x=find_consecutive_cells(sc,n); + if (x != sc->NIL) { return x; } + + /* If there still aren't, try getting more heap */ + if (!alloc_cellseg(sc,1)) + { + sc->no_memory=1; + return sc->sink; + } + + x=find_consecutive_cells(sc,n); + if (x != sc->NIL) { return x; } + + /* If all fail, report failure */ + sc->no_memory=1; + return sc->sink; +} + +static int count_consecutive_cells(pointer x, int needed) { + int n=1; + while(cdr(x)==x+1) { + x=cdr(x); + n++; + if(n>needed) return n; + } + return n; +} + +static pointer find_consecutive_cells(scheme *sc, int n) { + pointer *pp; + int cnt; + + pp=&sc->free_cell; + while(*pp!=sc->NIL) { + cnt=count_consecutive_cells(*pp,n); + if(cnt>=n) { + pointer x=*pp; + *pp=cdr(*pp+n-1); + sc->fcells -= n; + return x; + } + pp=&cdr(*pp+cnt-1); + } + return sc->NIL; +} + +/* To retain recent allocs before interpreter knows about them - + Tehom */ + +static void push_recent_alloc(scheme *sc, pointer recent, pointer extra) +{ + pointer holder = get_cell_x(sc, recent, extra); + typeflag(holder) = T_PAIR | T_IMMUTABLE; + car(holder) = recent; + cdr(holder) = car(sc->sink); + car(sc->sink) = holder; +} + + +static pointer get_cell(scheme *sc, pointer a, pointer b) +{ + pointer cell = get_cell_x(sc, a, b); + /* For right now, include "a" and "b" in "cell" so that gc doesn't + think they are garbage. */ + /* Tentatively record it as a pair so gc understands it. */ + typeflag(cell) = T_PAIR; + car(cell) = a; + cdr(cell) = b; + push_recent_alloc(sc, cell, sc->NIL); + return cell; +} + +static pointer get_vector_object(scheme *sc, int len, pointer init) +{ + pointer cells = get_consecutive_cells(sc,len/2+len%2+1); + if(sc->no_memory) { return sc->sink; } + /* Record it as a vector so that gc understands it. */ + typeflag(cells) = (T_VECTOR | T_ATOM); + ivalue_unchecked(cells)=len; + set_num_integer(cells); + fill_vector(cells,init); + push_recent_alloc(sc, cells, sc->NIL); + return cells; +} + +static INLINE void ok_to_freely_gc(scheme *sc) +{ + car(sc->sink) = sc->NIL; +} + + +#if defined TSGRIND +static void check_cell_alloced(pointer p, int expect_alloced) +{ + /* Can't use putstr(sc,str) because callers have no access to + sc. */ + if(typeflag(p) & !expect_alloced) + { + fprintf(stderr,"Cell is already allocated!\n"); + } + if(!(typeflag(p)) & expect_alloced) + { + fprintf(stderr,"Cell is not allocated!\n"); + } + +} +static void check_range_alloced(pointer p, int n, int expect_alloced) +{ + int i; + for(i = 0;iNIL); + typeflag(x) = T_SYMBOL; + setimmutable(car(x)); + + location = hash_fn(name, ivalue_unchecked(sc->oblist)); + set_vector_elem(sc->oblist, location, + immutable_cons(sc, x, vector_elem(sc->oblist, location))); + return x; +} + +static INLINE pointer oblist_find_by_name(scheme *sc, const char *name) +{ + int location; + pointer x; + char *s; + + location = hash_fn(name, ivalue_unchecked(sc->oblist)); + for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) { + s = symname(car(x)); + /* case-insensitive, per R5RS section 2. */ + if(stricmp(name, s) == 0) { + return car(x); + } + } + return sc->NIL; +} + +static pointer oblist_all_symbols(scheme *sc) +{ + int i; + pointer x; + pointer ob_list = sc->NIL; + + for (i = 0; i < ivalue_unchecked(sc->oblist); i++) { + for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) { + ob_list = cons(sc, x, ob_list); + } + } + return ob_list; +} + +#else + +static pointer oblist_initial_value(scheme *sc) +{ + return sc->NIL; +} + +static INLINE pointer oblist_find_by_name(scheme *sc, const char *name) +{ + pointer x; + char *s; + + for (x = sc->oblist; x != sc->NIL; x = cdr(x)) { + s = symname(car(x)); + /* case-insensitive, per R5RS section 2. */ + if(stricmp(name, s) == 0) { + return car(x); + } + } + return sc->NIL; +} + +/* returns the new symbol */ +static pointer oblist_add_by_name(scheme *sc, const char *name) +{ + pointer x; + + x = immutable_cons(sc, mk_string(sc, name), sc->NIL); + typeflag(x) = T_SYMBOL; + setimmutable(car(x)); + sc->oblist = immutable_cons(sc, x, sc->oblist); + return x; +} +static pointer oblist_all_symbols(scheme *sc) +{ + return sc->oblist; +} + +#endif + +static pointer mk_port(scheme *sc, port *p) { + pointer x = get_cell(sc, sc->NIL, sc->NIL); + + typeflag(x) = T_PORT|T_ATOM; + x->_object._port=p; + return (x); +} + +pointer mk_foreign_func(scheme *sc, foreign_func f) { + pointer x = get_cell(sc, sc->NIL, sc->NIL); + + typeflag(x) = (T_FOREIGN | T_ATOM); + x->_object._ff=f; + return (x); +} + +INTERFACE pointer mk_character(scheme *sc, int c) { + pointer x = get_cell(sc,sc->NIL, sc->NIL); + + typeflag(x) = (T_CHARACTER | T_ATOM); + ivalue_unchecked(x)= c; + set_num_integer(x); + return (x); +} + +/* get number atom (integer) */ +INTERFACE pointer mk_integer(scheme *sc, long num) { + pointer x = get_cell(sc,sc->NIL, sc->NIL); + + typeflag(x) = (T_NUMBER | T_ATOM); + ivalue_unchecked(x)= num; + set_num_integer(x); + return (x); +} + +INTERFACE pointer mk_real(scheme *sc, double n) { + pointer x = get_cell(sc,sc->NIL, sc->NIL); + + typeflag(x) = (T_NUMBER | T_ATOM); + rvalue_unchecked(x)= n; + set_num_real(x); + return (x); +} + +static pointer mk_number(scheme *sc, num n) { + if(n.is_fixnum) { + return mk_integer(sc,n.value.ivalue); + } else { + return mk_real(sc,n.value.rvalue); + } +} + +/* allocate name to string area */ +static char *store_string(scheme *sc, int len_str, const char *str, char fill) { + char *q; + + q=(char*)sc->malloc(len_str+1); + if(q==0) { + sc->no_memory=1; + return sc->strbuff; + } + if(str!=0) { + snprintf(q, len_str+1, "%s", str); + } else { + memset(q, fill, len_str); + q[len_str]=0; + } + return (q); +} + +/* get new string */ +INTERFACE pointer mk_string(scheme *sc, const char *str) { + return mk_counted_string(sc,str,strlen(str)); +} + +INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) { + pointer x = get_cell(sc, sc->NIL, sc->NIL); + typeflag(x) = (T_STRING | T_ATOM); + strvalue(x) = store_string(sc,len,str,0); + strlength(x) = len; + return (x); +} + +INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) { + pointer x = get_cell(sc, sc->NIL, sc->NIL); + typeflag(x) = (T_STRING | T_ATOM); + strvalue(x) = store_string(sc,len,0,fill); + strlength(x) = len; + return (x); +} + +INTERFACE static pointer mk_vector(scheme *sc, int len) +{ return get_vector_object(sc,len,sc->NIL); } + +INTERFACE static void fill_vector(pointer vec, pointer obj) { + int i; + int num=ivalue(vec)/2+ivalue(vec)%2; + for(i=0; iNIL) { + return (x); + } else { + x = oblist_add_by_name(sc, name); + return (x); + } +} + +INTERFACE pointer gensym(scheme *sc) { + pointer x; + char name[40]; + + for(; sc->gensym_cntgensym_cnt++) { + snprintf(name,40,"gensym-%ld",sc->gensym_cnt); + + /* first check oblist */ + x = oblist_find_by_name(sc, name); + + if (x != sc->NIL) { + continue; + } else { + x = oblist_add_by_name(sc, name); + return (x); + } + } + + return sc->NIL; +} + +/* make symbol or number atom from string */ +static pointer mk_atom(scheme *sc, char *q) { + char c, *p; + int has_dec_point=0; + int has_fp_exp = 0; + +#if USE_COLON_HOOK + if((p=strstr(q,"::"))!=0) { + *p=0; + return cons(sc, sc->COLON_HOOK, + cons(sc, + cons(sc, + sc->QUOTE, + cons(sc, mk_atom(sc,p+2), sc->NIL)), + cons(sc, mk_symbol(sc,strlwr(q)), sc->NIL))); + } +#endif + + p = q; + c = *p++; + if ((c == '+') || (c == '-')) { + c = *p++; + if (c == '.') { + has_dec_point=1; + c = *p++; + } + if (!isdigit(c)) { + return (mk_symbol(sc, strlwr(q))); + } + } else if (c == '.') { + has_dec_point=1; + c = *p++; + if (!isdigit(c)) { + return (mk_symbol(sc, strlwr(q))); + } + } else if (!isdigit(c)) { + return (mk_symbol(sc, strlwr(q))); + } + + for ( ; (c = *p) != 0; ++p) { + if (!isdigit(c)) { + if(c=='.') { + if(!has_dec_point) { + has_dec_point=1; + continue; + } + } + else if ((c == 'e') || (c == 'E')) { + if(!has_fp_exp) { + has_dec_point = 1; /* decimal point illegal + from now on */ + p++; + if ((*p == '-') || (*p == '+') || isdigit(*p)) { + continue; + } + } + } + return (mk_symbol(sc, strlwr(q))); + } + } + if(has_dec_point) { + return mk_real(sc,atof(q)); + } + return (mk_integer(sc, atol(q))); +} + +/* make constant */ +static pointer mk_sharp_const(scheme *sc, char *name) { + long x; + char tmp[STRBUFFSIZE]; + + if (!strcmp(name, "t")) + return (sc->T); + else if (!strcmp(name, "f")) + return (sc->F); + else if (*name == 'o') {/* #o (octal) */ + snprintf(tmp, STRBUFFSIZE, "0%s", name+1); + sscanf(tmp, "%lo", (long unsigned *)&x); + return (mk_integer(sc, x)); + } else if (*name == 'd') { /* #d (decimal) */ + sscanf(name+1, "%ld", (long int *)&x); + return (mk_integer(sc, x)); + } else if (*name == 'x') { /* #x (hex) */ + snprintf(tmp, STRBUFFSIZE, "0x%s", name+1); + sscanf(tmp, "%lx", (long unsigned *)&x); + return (mk_integer(sc, x)); + } else if (*name == 'b') { /* #b (binary) */ + x = binary_decode(name+1); + return (mk_integer(sc, x)); + } else if (*name == '\\') { /* #\w (character) */ + int c=0; + if(stricmp(name+1,"space")==0) { + c=' '; + } else if(stricmp(name+1,"newline")==0) { + c='\n'; + } else if(stricmp(name+1,"return")==0) { + c='\r'; + } else if(stricmp(name+1,"tab")==0) { + c='\t'; + } else if(name[1]=='x' && name[2]!=0) { + int c1=0; + if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) { + c=c1; + } else { + return sc->NIL; + } +#if USE_ASCII_NAMES + } else if(is_ascii_name(name+1,&c)) { + /* nothing */ +#endif + } else if(name[2]==0) { + c=name[1]; + } else { + return sc->NIL; + } + return mk_character(sc,c); + } else + return (sc->NIL); +} + +/* ========== garbage collector ========== */ + +/*-- + * We use algorithm E (Knuth, The Art of Computer Programming Vol.1, + * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm, + * for marking. + */ +static void mark(pointer a) { + pointer t, q, p; + + t = (pointer) 0; + p = a; +E2: setmark(p); + if(is_vector(p)) { + int i; + int num=ivalue_unchecked(p)/2+ivalue_unchecked(p)%2; + for(i=0; igc_verbose) { + putstr(sc, "gc..."); + } + + /* mark system globals */ + mark(sc->oblist); + mark(sc->global_env); + + /* mark current registers */ + mark(sc->args); + mark(sc->envir); + mark(sc->code); + dump_stack_mark(sc); + mark(sc->value); + mark(sc->inport); + mark(sc->save_inport); + mark(sc->outport); + mark(sc->loadport); + + /* Mark recent objects the interpreter doesn't know about yet. */ + mark(car(sc->sink)); + /* Mark any older stuff above nested C calls */ + mark(sc->c_nest); + + /* mark variables a, b */ + mark(a); + mark(b); + + /* garbage collect */ + clrmark(sc->NIL); + sc->fcells = 0; + sc->free_cell = sc->NIL; + /* free-list is kept sorted by address so as to maintain consecutive + ranges, if possible, for use with vectors. Here we scan the cells + (which are also kept sorted by address) downwards to build the + free-list in sorted order. + */ + for (i = sc->last_cell_seg; i >= 0; i--) { + p = sc->cell_seg[i] + CELL_SEGSIZE; + while (--p >= sc->cell_seg[i]) { + if (is_mark(p)) { + clrmark(p); + } else { + /* reclaim cell */ + if (typeflag(p) != 0) { + finalize_cell(sc, p); + typeflag(p) = 0; + car(p) = sc->NIL; + } + ++sc->fcells; + cdr(p) = sc->free_cell; + sc->free_cell = p; + } + } + } + + if (sc->gc_verbose) { + char msg[80]; + snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells); + putstr(sc,msg); + } +} + +static void finalize_cell(scheme *sc, pointer a) { + if(is_string(a)) { + sc->free(strvalue(a)); + } else if(is_port(a)) { + if(a->_object._port->kind&port_file + && a->_object._port->rep.stdio.closeit) { + port_close(sc,a,port_input|port_output); + } + sc->free(a->_object._port); + } +} + +/* ========== Routines for Reading ========== */ + +static int file_push(scheme *sc, const char *fname) { + FILE *fin = NULL; + + if (sc->file_i == MAXFIL-1) + return 0; + fin=fopen(fname,"r"); + if(fin!=0) { + sc->file_i++; + sc->load_stack[sc->file_i].kind=port_file|port_input; + sc->load_stack[sc->file_i].rep.stdio.file=fin; + sc->load_stack[sc->file_i].rep.stdio.closeit=1; + sc->nesting_stack[sc->file_i]=0; + sc->loadport->_object._port=sc->load_stack+sc->file_i; + +#if SHOW_ERROR_LINE + sc->load_stack[sc->file_i].rep.stdio.curr_line = 0; + if(fname) + sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0); +#endif + } + return fin!=0; +} + +static void file_pop(scheme *sc) { + if(sc->file_i != 0) { + sc->nesting=sc->nesting_stack[sc->file_i]; + port_close(sc,sc->loadport,port_input); + sc->file_i--; + sc->loadport->_object._port=sc->load_stack+sc->file_i; + } +} + +static int file_interactive(scheme *sc) { + return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin + && sc->inport->_object._port->kind&port_file; +} + +static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) { + FILE *f; + char *rw; + port *pt; + if(prop==(port_input|port_output)) { + rw="a+"; + } else if(prop==port_output) { + rw="w"; + } else { + rw="r"; + } + f=fopen(fn,rw); + if(f==0) { + return 0; + } + pt=port_rep_from_file(sc,f,prop); + pt->rep.stdio.closeit=1; + +#if SHOW_ERROR_LINE + if(fn) + pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0); + + pt->rep.stdio.curr_line = 0; +#endif + return pt; +} + +static pointer port_from_filename(scheme *sc, const char *fn, int prop) { + port *pt; + pt=port_rep_from_filename(sc,fn,prop); + if(pt==0) { + return sc->NIL; + } + return mk_port(sc,pt); +} + +static port *port_rep_from_file(scheme *sc, FILE *f, int prop) +{ + port *pt; + + pt = (port *)sc->malloc(sizeof *pt); + if (pt == NULL) { + return NULL; + } + pt->kind = port_file | prop; + pt->rep.stdio.file = f; + pt->rep.stdio.closeit = 0; + return pt; +} + +static pointer port_from_file(scheme *sc, FILE *f, int prop) { + port *pt; + pt=port_rep_from_file(sc,f,prop); + if(pt==0) { + return sc->NIL; + } + return mk_port(sc,pt); +} + +static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) { + port *pt; + pt=(port*)sc->malloc(sizeof(port)); + if(pt==0) { + return 0; + } + pt->kind=port_string|prop; + pt->rep.string.start=start; + pt->rep.string.curr=start; + pt->rep.string.past_the_end=past_the_end; + return pt; +} + +static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) { + port *pt; + pt=port_rep_from_string(sc,start,past_the_end,prop); + if(pt==0) { + return sc->NIL; + } + return mk_port(sc,pt); +} + +#define BLOCK_SIZE 256 + +static port *port_rep_from_scratch(scheme *sc) { + port *pt; + char *start; + pt=(port*)sc->malloc(sizeof(port)); + if(pt==0) { + return 0; + } + start=sc->malloc(BLOCK_SIZE); + if(start==0) { + return 0; + } + memset(start,' ',BLOCK_SIZE-1); + start[BLOCK_SIZE-1]='\0'; + pt->kind=port_string|port_output|port_srfi6; + pt->rep.string.start=start; + pt->rep.string.curr=start; + pt->rep.string.past_the_end=start+BLOCK_SIZE-1; + return pt; +} + +static pointer port_from_scratch(scheme *sc) { + port *pt; + pt=port_rep_from_scratch(sc); + if(pt==0) { + return sc->NIL; + } + return mk_port(sc,pt); +} + +static void port_close(scheme *sc, pointer p, int flag) { + port *pt=p->_object._port; + pt->kind&=~flag; + if((pt->kind & (port_input|port_output))==0) { + if(pt->kind&port_file) { + +#if SHOW_ERROR_LINE + /* Cleanup is here so (close-*-port) functions could work too */ + pt->rep.stdio.curr_line = 0; + + if(pt->rep.stdio.filename) + sc->free(pt->rep.stdio.filename); +#endif + + fclose(pt->rep.stdio.file); + } + pt->kind=port_free; + } +} + +/* get new character from input file */ +static int inchar(scheme *sc) { + int c; + port *pt; + + pt = sc->inport->_object._port; + if(pt->kind & port_saw_EOF) + { return EOF; } + c = basic_inchar(pt); + if(c == EOF && sc->inport == sc->loadport) { + /* Instead, set port_saw_EOF */ + pt->kind |= port_saw_EOF; + + /* file_pop(sc); */ + return EOF; + /* NOTREACHED */ + } + return c; +} + +static int basic_inchar(port *pt) { + if(pt->kind & port_file) { + return fgetc(pt->rep.stdio.file); + } else { + if(*pt->rep.string.curr == 0 || + pt->rep.string.curr == pt->rep.string.past_the_end) { + return EOF; + } else { + return *pt->rep.string.curr++; + } + } +} + +/* back character to input buffer */ +static void backchar(scheme *sc, int c) { + port *pt; + if(c==EOF) return; + pt=sc->inport->_object._port; + if(pt->kind&port_file) { + ungetc(c,pt->rep.stdio.file); + } else { + if(pt->rep.string.curr!=pt->rep.string.start) { + --pt->rep.string.curr; + } + } +} + +static int realloc_port_string(scheme *sc, port *p) +{ + char *start=p->rep.string.start; + size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE; + char *str=sc->malloc(new_size); + if(str) { + memset(str,' ',new_size-1); + str[new_size-1]='\0'; + strcpy(str,start); + p->rep.string.start=str; + p->rep.string.past_the_end=str+new_size-1; + p->rep.string.curr-=start-str; + sc->free(start); + return 1; + } else { + return 0; + } +} + +INTERFACE void putstr(scheme *sc, const char *s) { + port *pt=sc->outport->_object._port; + if(pt->kind&port_file) { + fputs(s,pt->rep.stdio.file); + } else { + for(;*s;s++) { + if(pt->rep.string.curr!=pt->rep.string.past_the_end) { + *pt->rep.string.curr++=*s; + } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) { + *pt->rep.string.curr++=*s; + } + } + } +} + +static void putchars(scheme *sc, const char *s, int len) { + port *pt=sc->outport->_object._port; + if(pt->kind&port_file) { + fwrite(s,1,len,pt->rep.stdio.file); + } else { + for(;len;len--) { + if(pt->rep.string.curr!=pt->rep.string.past_the_end) { + *pt->rep.string.curr++=*s++; + } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) { + *pt->rep.string.curr++=*s++; + } + } + } +} + +INTERFACE void putcharacter(scheme *sc, int c) { + port *pt=sc->outport->_object._port; + if(pt->kind&port_file) { + fputc(c,pt->rep.stdio.file); + } else { + if(pt->rep.string.curr!=pt->rep.string.past_the_end) { + *pt->rep.string.curr++=c; + } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) { + *pt->rep.string.curr++=c; + } + } +} + +/* read characters up to delimiter, but cater to character constants */ +static char *readstr_upto(scheme *sc, char *delim) { + char *p = sc->strbuff; + + while ((p - sc->strbuff < sizeof(sc->strbuff)) && + !is_one_of(delim, (*p++ = inchar(sc)))); + + if(p == sc->strbuff+2 && p[-2] == '\\') { + *p=0; + } else { + backchar(sc,p[-1]); + *--p = '\0'; + } + return sc->strbuff; +} + +/* read string expression "xxx...xxx" */ +static pointer readstrexp(scheme *sc) { + char *p = sc->strbuff; + int c; + int c1=0; + enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok; + + for (;;) { + c=inchar(sc); + if(c == EOF || p-sc->strbuff > sizeof(sc->strbuff)-1) { + return sc->F; + } + switch(state) { + case st_ok: + switch(c) { + case '\\': + state=st_bsl; + break; + case '"': + *p=0; + return mk_counted_string(sc,sc->strbuff,p-sc->strbuff); + default: + *p++=c; + break; + } + break; + case st_bsl: + switch(c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + state=st_oct1; + c1=c-'0'; + break; + case 'x': + case 'X': + state=st_x1; + c1=0; + break; + case 'n': + *p++='\n'; + state=st_ok; + break; + case 't': + *p++='\t'; + state=st_ok; + break; + case 'r': + *p++='\r'; + state=st_ok; + break; + case '"': + *p++='"'; + state=st_ok; + break; + default: + *p++=c; + state=st_ok; + break; + } + break; + case st_x1: + case st_x2: + c=toupper(c); + if(c>='0' && c<='F') { + if(c<='9') { + c1=(c1<<4)+c-'0'; + } else { + c1=(c1<<4)+c-'A'+10; + } + if(state==st_x1) { + state=st_x2; + } else { + *p++=c1; + state=st_ok; + } + } else { + return sc->F; + } + break; + case st_oct1: + case st_oct2: + if (c < '0' || c > '7') + { + *p++=c1; + backchar(sc, c); + state=st_ok; + } + else + { + if (state==st_oct2 && c1 >= 32) + return sc->F; + + c1=(c1<<3)+(c-'0'); + + if (state == st_oct1) + state=st_oct2; + else + { + *p++=c1; + state=st_ok; + } + } + break; + + } + } +} + +/* check c is in chars */ +static INLINE int is_one_of(char *s, int c) { + if(c==EOF) return 1; + while (*s) + if (*s++ == c) + return (1); + return (0); +} + +/* skip white characters */ +static INLINE int skipspace(scheme *sc) { + int c = 0, curr_line = 0; + + do { + c=inchar(sc); +#if SHOW_ERROR_LINE + if(c=='\n') + curr_line++; +#endif + } while (isspace(c)); + +/* record it */ +#if SHOW_ERROR_LINE + if (sc->load_stack[sc->file_i].kind & port_file) + sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line; +#endif + + if(c!=EOF) { + backchar(sc,c); + return 1; + } + else + { return EOF; } +} + +/* get token */ +static int token(scheme *sc) { + int c; + c = skipspace(sc); + if(c == EOF) { return (TOK_EOF); } + switch (c=inchar(sc)) { + case EOF: + return (TOK_EOF); + case '(': + return (TOK_LPAREN); + case ')': + return (TOK_RPAREN); + case '.': + c=inchar(sc); + if(is_one_of(" \n\t",c)) { + return (TOK_DOT); + } else { + backchar(sc,c); + backchar(sc,'.'); + return TOK_ATOM; + } + case '\'': + return (TOK_QUOTE); + case ';': + while ((c=inchar(sc)) != '\n' && c!=EOF) + ; + +#if SHOW_ERROR_LINE + if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file) + sc->load_stack[sc->file_i].rep.stdio.curr_line++; +#endif + + if(c == EOF) + { return (TOK_EOF); } + else + { return (token(sc));} + case '"': + return (TOK_DQUOTE); + case BACKQUOTE: + return (TOK_BQUOTE); + case ',': + if ((c=inchar(sc)) == '@') { + return (TOK_ATMARK); + } else { + backchar(sc,c); + return (TOK_COMMA); + } + case '#': + c=inchar(sc); + if (c == '(') { + return (TOK_VEC); + } else if(c == '!') { + while ((c=inchar(sc)) != '\n' && c!=EOF) + ; + +#if SHOW_ERROR_LINE + if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file) + sc->load_stack[sc->file_i].rep.stdio.curr_line++; +#endif + + if(c == EOF) + { return (TOK_EOF); } + else + { return (token(sc));} + } else { + backchar(sc,c); + if(is_one_of(" tfodxb\\",c)) { + return TOK_SHARP_CONST; + } else { + return (TOK_SHARP); + } + } + default: + backchar(sc,c); + return (TOK_ATOM); + } +} + +/* ========== Routines for Printing ========== */ +#define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL) + +static void printslashstring(scheme *sc, char *p, int len) { + int i; + unsigned char *s=(unsigned char*)p; + putcharacter(sc,'"'); + for ( i=0; iNIL) { + p = "()"; + } else if (l == sc->T) { + p = "#t"; + } else if (l == sc->F) { + p = "#f"; + } else if (l == sc->EOF_OBJ) { + p = "#"; + } else if (is_port(l)) { + p = sc->strbuff; + snprintf(p, STRBUFFSIZE, "#"); + } else if (is_number(l)) { + p = sc->strbuff; + if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ { + if(num_is_integer(l)) { + snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l)); + } else { + snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l)); + /* r5rs says there must be a '.' (unless 'e'?) */ + f = strcspn(p, ".e"); + if (p[f] == 0) { + p[f] = '.'; /* not found, so add '.0' at the end */ + p[f+1] = '0'; + p[f+2] = 0; + } + } + } else { + long v = ivalue(l); + if (f == 16) { + if (v >= 0) + snprintf(p, STRBUFFSIZE, "%lx", v); + else + snprintf(p, STRBUFFSIZE, "-%lx", -v); + } else if (f == 8) { + if (v >= 0) + snprintf(p, STRBUFFSIZE, "%lo", v); + else + snprintf(p, STRBUFFSIZE, "-%lo", -v); + } else if (f == 2) { + unsigned long b = (v < 0) ? -v : v; + p = &p[STRBUFFSIZE-1]; + *p = 0; + do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0); + if (v < 0) *--p = '-'; + } + } + } else if (is_string(l)) { + if (!f) { + p = strvalue(l); + } else { /* Hack, uses the fact that printing is needed */ + *pp=sc->strbuff; + *plen=0; + printslashstring(sc, strvalue(l), strlength(l)); + return; + } + } else if (is_character(l)) { + int c=charvalue(l); + p = sc->strbuff; + if (!f) { + p[0]=c; + p[1]=0; + } else { + switch(c) { + case ' ': + snprintf(p,STRBUFFSIZE,"#\\space"); break; + case '\n': + snprintf(p,STRBUFFSIZE,"#\\newline"); break; + case '\r': + snprintf(p,STRBUFFSIZE,"#\\return"); break; + case '\t': + snprintf(p,STRBUFFSIZE,"#\\tab"); break; + default: +#if USE_ASCII_NAMES + if(c==127) { + snprintf(p,STRBUFFSIZE, "#\\del"); + break; + } else if(c<32) { + snprintf(p, STRBUFFSIZE, "#\\%s", charnames[c]); + break; + } +#else + if(c<32) { + snprintf(p,STRBUFFSIZE,"#\\x%x",c); break; + break; + } +#endif + snprintf(p,STRBUFFSIZE,"#\\%c",c); break; + break; + } + } + } else if (is_symbol(l)) { + p = symname(l); + } else if (is_proc(l)) { + p = sc->strbuff; + snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l)); + } else if (is_macro(l)) { + p = "#"; + } else if (is_closure(l)) { + p = "#"; + } else if (is_promise(l)) { + p = "#"; + } else if (is_foreign(l)) { + p = sc->strbuff; + snprintf(p,STRBUFFSIZE,"#", procnum(l)); + } else if (is_continuation(l)) { + p = "#"; + } else { + p = "#"; + } + *pp=p; + *plen=strlen(p); +} +/* ========== Routines for Evaluation Cycle ========== */ + +/* make closure. c is code. e is environment */ +static pointer mk_closure(scheme *sc, pointer c, pointer e) { + pointer x = get_cell(sc, c, e); + + typeflag(x) = T_CLOSURE; + car(x) = c; + cdr(x) = e; + return (x); +} + +/* make continuation. */ +static pointer mk_continuation(scheme *sc, pointer d) { + pointer x = get_cell(sc, sc->NIL, d); + + typeflag(x) = T_CONTINUATION; + cont_dump(x) = d; + return (x); +} + +static pointer list_star(scheme *sc, pointer d) { + pointer p, q; + if(cdr(d)==sc->NIL) { + return car(d); + } + p=cons(sc,car(d),cdr(d)); + q=p; + while(cdr(cdr(p))!=sc->NIL) { + d=cons(sc,car(p),cdr(p)); + if(cdr(cdr(p))!=sc->NIL) { + p=cdr(d); + } + } + cdr(p)=car(cdr(p)); + return q; +} + +/* reverse list -- produce new list */ +static pointer reverse(scheme *sc, pointer a) { +/* a must be checked by gc */ + pointer p = sc->NIL; + + for ( ; is_pair(a); a = cdr(a)) { + p = cons(sc, car(a), p); + } + return (p); +} + +/* reverse list --- in-place */ +static pointer reverse_in_place(scheme *sc, pointer term, pointer list) { + pointer p = list, result = term, q; + + while (p != sc->NIL) { + q = cdr(p); + cdr(p) = result; + result = p; + p = q; + } + return (result); +} + +/* append list -- produce new list (in reverse order) */ +static pointer revappend(scheme *sc, pointer a, pointer b) { + pointer result = a; + pointer p = b; + + while (is_pair(p)) { + result = cons(sc, car(p), result); + p = cdr(p); + } + + if (p == sc->NIL) { + return result; + } + + return sc->F; /* signal an error */ +} + +/* equivalence of atoms */ +int eqv(pointer a, pointer b) { + if (is_string(a)) { + if (is_string(b)) + return (strvalue(a) == strvalue(b)); + else + return (0); + } else if (is_number(a)) { + if (is_number(b)) { + if (num_is_integer(a) == num_is_integer(b)) + return num_eq(nvalue(a),nvalue(b)); + } + return (0); + } else if (is_character(a)) { + if (is_character(b)) + return charvalue(a)==charvalue(b); + else + return (0); + } else if (is_port(a)) { + if (is_port(b)) + return a==b; + else + return (0); + } else if (is_proc(a)) { + if (is_proc(b)) + return procnum(a)==procnum(b); + else + return (0); + } else { + return (a == b); + } +} + +/* true or false value macro */ +/* () is #t in R5RS */ +#define is_true(p) ((p) != sc->F) +#define is_false(p) ((p) == sc->F) + +/* ========== Environment implementation ========== */ + +#if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST) + +static int hash_fn(const char *key, int table_size) +{ + unsigned int hashed = 0; + const char *c; + int bits_per_int = sizeof(unsigned int)*8; + + for (c = key; *c; c++) { + /* letters have about 5 bits in them */ + hashed = (hashed<<5) | (hashed>>(bits_per_int-5)); + hashed ^= *c; + } + return hashed % table_size; +} +#endif + +#ifndef USE_ALIST_ENV + +/* + * In this implementation, each frame of the environment may be + * a hash table: a vector of alists hashed by variable name. + * In practice, we use a vector only for the initial frame; + * subsequent frames are too small and transient for the lookup + * speed to out-weigh the cost of making a new vector. + */ + +static void new_frame_in_env(scheme *sc, pointer old_env) +{ + pointer new_frame; + + /* The interaction-environment has about 300 variables in it. */ + if (old_env == sc->NIL) { + new_frame = mk_vector(sc, 461); + } else { + new_frame = sc->NIL; + } + + sc->envir = immutable_cons(sc, new_frame, old_env); + setenvironment(sc->envir); +} + +static INLINE void new_slot_spec_in_env(scheme *sc, pointer env, + pointer variable, pointer value) +{ + pointer slot = immutable_cons(sc, variable, value); + + if (is_vector(car(env))) { + int location = hash_fn(symname(variable), ivalue_unchecked(car(env))); + + set_vector_elem(car(env), location, + immutable_cons(sc, slot, vector_elem(car(env), location))); + } else { + car(env) = immutable_cons(sc, slot, car(env)); + } +} + +static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all) +{ + pointer x,y; + int location; + + for (x = env; x != sc->NIL; x = cdr(x)) { + if (is_vector(car(x))) { + location = hash_fn(symname(hdl), ivalue_unchecked(car(x))); + y = vector_elem(car(x), location); + } else { + y = car(x); + } + for ( ; y != sc->NIL; y = cdr(y)) { + if (caar(y) == hdl) { + break; + } + } + if (y != sc->NIL) { + break; + } + if(!all) { + return sc->NIL; + } + } + if (x != sc->NIL) { + return car(y); + } + return sc->NIL; +} + +#else /* USE_ALIST_ENV */ + +static INLINE void new_frame_in_env(scheme *sc, pointer old_env) +{ + sc->envir = immutable_cons(sc, sc->NIL, old_env); + setenvironment(sc->envir); +} + +static INLINE void new_slot_spec_in_env(scheme *sc, pointer env, + pointer variable, pointer value) +{ + car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env)); +} + +static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all) +{ + pointer x,y; + for (x = env; x != sc->NIL; x = cdr(x)) { + for (y = car(x); y != sc->NIL; y = cdr(y)) { + if (caar(y) == hdl) { + break; + } + } + if (y != sc->NIL) { + break; + } + if(!all) { + return sc->NIL; + } + } + if (x != sc->NIL) { + return car(y); + } + return sc->NIL; +} + +#endif /* USE_ALIST_ENV else */ + +static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value) +{ + new_slot_spec_in_env(sc, sc->envir, variable, value); +} + +static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value) +{ + cdr(slot) = value; +} + +static INLINE pointer slot_value_in_env(pointer slot) +{ + return cdr(slot); +} + +/* ========== Evaluation Cycle ========== */ + + +static pointer _Error_1(scheme *sc, const char *s, pointer a) { + const char *str = s; +#if USE_ERROR_HOOK + pointer x; + pointer hdl=sc->ERROR_HOOK; +#endif + +#if SHOW_ERROR_LINE + char sbuf[STRBUFFSIZE]; + + /* make sure error is not in REPL */ + if (sc->load_stack[sc->file_i].kind & port_file && + sc->load_stack[sc->file_i].rep.stdio.file != stdin) { + int ln = sc->load_stack[sc->file_i].rep.stdio.curr_line; + const char *fname = sc->load_stack[sc->file_i].rep.stdio.filename; + + /* should never happen */ + if(!fname) fname = ""; + + /* we started from 0 */ + ln++; + snprintf(sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s); + + str = (const char*)sbuf; + } +#endif + +#if USE_ERROR_HOOK + x=find_slot_in_env(sc,sc->envir,hdl,1); + if (x != sc->NIL) { + if(a!=0) { + sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc,(a), sc->NIL)), sc->NIL); + } else { + sc->code = sc->NIL; + } + sc->code = cons(sc, mk_string(sc, str), sc->code); + setimmutable(car(sc->code)); + sc->code = cons(sc, slot_value_in_env(x), sc->code); + sc->op = (int)OP_EVAL; + return sc->T; + } +#endif + + if(a!=0) { + sc->args = cons(sc, (a), sc->NIL); + } else { + sc->args = sc->NIL; + } + sc->args = cons(sc, mk_string(sc, str), sc->args); + setimmutable(car(sc->args)); + sc->op = (int)OP_ERR0; + return sc->T; +} +#define Error_1(sc,s, a) return _Error_1(sc,s,a) +#define Error_0(sc,s) return _Error_1(sc,s,0) + +/* Too small to turn into function */ +# define BEGIN do { +# define END } while (0) +#define s_goto(sc,a) BEGIN \ + sc->op = (int)(a); \ + return sc->T; END + +#define s_return(sc,a) return _s_return(sc,a) + +#ifndef USE_SCHEME_STACK + +/* this structure holds all the interpreter's registers */ +struct dump_stack_frame { + enum scheme_opcodes op; + pointer args; + pointer envir; + pointer code; +}; + +#define STACK_GROWTH 3 + +static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) +{ + int nframes = (int)sc->dump; + struct dump_stack_frame *next_frame; + + /* enough room for the next frame? */ + if (nframes >= sc->dump_size) { + sc->dump_size += STACK_GROWTH; + /* alas there is no sc->realloc */ + sc->dump_base = realloc(sc->dump_base, + sizeof(struct dump_stack_frame) * sc->dump_size); + } + next_frame = (struct dump_stack_frame *)sc->dump_base + nframes; + next_frame->op = op; + next_frame->args = args; + next_frame->envir = sc->envir; + next_frame->code = code; + sc->dump = (pointer)(nframes+1); +} + +static pointer _s_return(scheme *sc, pointer a) +{ + int nframes = (int)sc->dump; + struct dump_stack_frame *frame; + + sc->value = (a); + if (nframes <= 0) { + return sc->NIL; + } + nframes--; + frame = (struct dump_stack_frame *)sc->dump_base + nframes; + sc->op = frame->op; + sc->args = frame->args; + sc->envir = frame->envir; + sc->code = frame->code; + sc->dump = (pointer)nframes; + return sc->T; +} + +static INLINE void dump_stack_reset(scheme *sc) +{ + /* in this implementation, sc->dump is the number of frames on the stack */ + sc->dump = (pointer)0; +} + +static INLINE void dump_stack_initialize(scheme *sc) +{ + sc->dump_size = 0; + sc->dump_base = NULL; + dump_stack_reset(sc); +} + +static void dump_stack_free(scheme *sc) +{ + free(sc->dump_base); + sc->dump_base = NULL; + sc->dump = (pointer)0; + sc->dump_size = 0; +} + +static INLINE void dump_stack_mark(scheme *sc) +{ + int nframes = (int)sc->dump; + int i; + for(i=0; idump_base + i; + mark(frame->args); + mark(frame->envir); + mark(frame->code); + } +} + +#else + +static INLINE void dump_stack_reset(scheme *sc) +{ + sc->dump = sc->NIL; +} + +static INLINE void dump_stack_initialize(scheme *sc) +{ + dump_stack_reset(sc); +} + +static void dump_stack_free(scheme *sc) +{ + sc->dump = sc->NIL; +} + +static pointer _s_return(scheme *sc, pointer a) { + sc->value = (a); + if(sc->dump==sc->NIL) return sc->NIL; + sc->op = ivalue(car(sc->dump)); + sc->args = cadr(sc->dump); + sc->envir = caddr(sc->dump); + sc->code = cadddr(sc->dump); + sc->dump = cddddr(sc->dump); + return sc->T; +} + +static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) { + sc->dump = cons(sc, sc->envir, cons(sc, (code), sc->dump)); + sc->dump = cons(sc, (args), sc->dump); + sc->dump = cons(sc, mk_integer(sc, (long)(op)), sc->dump); +} + +static INLINE void dump_stack_mark(scheme *sc) +{ + mark(sc->dump); +} +#endif + +#define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F) + +static pointer opexe_0(scheme *sc, enum scheme_opcodes op) { + pointer x, y; + + switch (op) { + case OP_LOAD: /* load */ + if(file_interactive(sc)) { + fprintf(sc->outport->_object._port->rep.stdio.file, + "Loading %s\n", strvalue(car(sc->args))); + } + if (!file_push(sc,strvalue(car(sc->args)))) { + Error_1(sc,"unable to open", car(sc->args)); + } + else + { + sc->args = mk_integer(sc,sc->file_i); + s_goto(sc,OP_T0LVL); + } + + case OP_T0LVL: /* top level */ + /* If we reached the end of file, this loop is done. */ + if(sc->loadport->_object._port->kind & port_saw_EOF) + { + if(sc->file_i == 0) + { + sc->args=sc->NIL; + s_goto(sc,OP_QUIT); + } + else + { + file_pop(sc); + s_return(sc,sc->value); + } + /* NOTREACHED */ + } + + /* If interactive, be nice to user. */ + if(file_interactive(sc)) + { + sc->envir = sc->global_env; + dump_stack_reset(sc); + putstr(sc,"\n"); + putstr(sc,prompt); + } + + /* Set up another iteration of REPL */ + sc->nesting=0; + sc->save_inport=sc->inport; + sc->inport = sc->loadport; + s_save(sc,OP_T0LVL, sc->NIL, sc->NIL); + s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL); + s_save(sc,OP_T1LVL, sc->NIL, sc->NIL); + s_goto(sc,OP_READ_INTERNAL); + + case OP_T1LVL: /* top level */ + sc->code = sc->value; + sc->inport=sc->save_inport; + s_goto(sc,OP_EVAL); + + case OP_READ_INTERNAL: /* internal read */ + sc->tok = token(sc); + if(sc->tok==TOK_EOF) + { s_return(sc,sc->EOF_OBJ); } + s_goto(sc,OP_RDSEXPR); + + case OP_GENSYM: + s_return(sc, gensym(sc)); + + case OP_VALUEPRINT: /* print evaluation result */ + /* OP_VALUEPRINT is always pushed, because when changing from + non-interactive to interactive mode, it needs to be + already on the stack */ + if(sc->tracing) { + putstr(sc,"\nGives: "); + } + if(file_interactive(sc)) { + sc->print_flag = 1; + sc->args = sc->value; + s_goto(sc,OP_P0LIST); + } else { + s_return(sc,sc->value); + } + + case OP_EVAL: /* main part of evaluation */ +#if USE_TRACING + if(sc->tracing) { + /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/ + s_save(sc,OP_REAL_EVAL,sc->args,sc->code); + sc->args=sc->code; + putstr(sc,"\nEval: "); + s_goto(sc,OP_P0LIST); + } + /* fall through */ + case OP_REAL_EVAL: +#endif + if (is_symbol(sc->code)) { /* symbol */ + x=find_slot_in_env(sc,sc->envir,sc->code,1); + if (x != sc->NIL) { + s_return(sc,slot_value_in_env(x)); + } else { + Error_1(sc,"eval: unbound variable:", sc->code); + } + } else if (is_pair(sc->code)) { + if (is_syntax(x = car(sc->code))) { /* SYNTAX */ + sc->code = cdr(sc->code); + s_goto(sc,syntaxnum(x)); + } else {/* first, eval top element and eval arguments */ + s_save(sc,OP_E0ARGS, sc->NIL, sc->code); + /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/ + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + } + } else { + s_return(sc,sc->code); + } + + case OP_E0ARGS: /* eval arguments */ + if (is_macro(sc->value)) { /* macro expansion */ + s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL); + sc->args = cons(sc,sc->code, sc->NIL); + sc->code = sc->value; + s_goto(sc,OP_APPLY); + } else { + sc->code = cdr(sc->code); + s_goto(sc,OP_E1ARGS); + } + + case OP_E1ARGS: /* eval arguments */ + sc->args = cons(sc, sc->value, sc->args); + if (is_pair(sc->code)) { /* continue */ + s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code)); + sc->code = car(sc->code); + sc->args = sc->NIL; + s_goto(sc,OP_EVAL); + } else { /* end */ + sc->args = reverse_in_place(sc, sc->NIL, sc->args); + sc->code = car(sc->args); + sc->args = cdr(sc->args); + s_goto(sc,OP_APPLY); + } + +#if USE_TRACING + case OP_TRACING: { + int tr=sc->tracing; + sc->tracing=ivalue(car(sc->args)); + s_return(sc,mk_integer(sc,tr)); + } +#endif + + case OP_APPLY: /* apply 'code' to 'args' */ +#if USE_TRACING + if(sc->tracing) { + s_save(sc,OP_REAL_APPLY,sc->args,sc->code); + sc->print_flag = 1; + /* sc->args=cons(sc,sc->code,sc->args);*/ + putstr(sc,"\nApply to: "); + s_goto(sc,OP_P0LIST); + } + /* fall through */ + case OP_REAL_APPLY: +#endif + if (is_proc(sc->code)) { + s_goto(sc,procnum(sc->code)); /* PROCEDURE */ + } else if (is_foreign(sc->code)) + { + /* Keep nested calls from GC'ing the arglist */ + push_recent_alloc(sc,sc->args,sc->NIL); + x=sc->code->_object._ff(sc,sc->args); + s_return(sc,x); + } else if (is_closure(sc->code) || is_macro(sc->code) + || is_promise(sc->code)) { /* CLOSURE */ + /* Should not accept promise */ + /* make environment */ + new_frame_in_env(sc, closure_env(sc->code)); + for (x = car(closure_code(sc->code)), y = sc->args; + is_pair(x); x = cdr(x), y = cdr(y)) { + if (y == sc->NIL) { + Error_0(sc,"not enough arguments"); + } else { + new_slot_in_env(sc, car(x), car(y)); + } + } + if (x == sc->NIL) { + /*-- + * if (y != sc->NIL) { + * Error_0(sc,"too many arguments"); + * } + */ + } else if (is_symbol(x)) + new_slot_in_env(sc, x, y); + else { + Error_1(sc,"syntax error in closure: not a symbol:", x); + } + sc->code = cdr(closure_code(sc->code)); + sc->args = sc->NIL; + s_goto(sc,OP_BEGIN); + } else if (is_continuation(sc->code)) { /* CONTINUATION */ + sc->dump = cont_dump(sc->code); + s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL); + } else { + Error_0(sc,"illegal function"); + } + + case OP_DOMACRO: /* do macro */ + sc->code = sc->value; + s_goto(sc,OP_EVAL); + +#if 1 + case OP_LAMBDA: /* lambda */ + /* If the hook is defined, apply it to sc->code, otherwise + set sc->value fall thru */ + { + pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1); + if(f==sc->NIL) { + sc->value = sc->code; + /* Fallthru */ + } else { + s_save(sc,OP_LAMBDA1,sc->args,sc->code); + sc->args=cons(sc,sc->code,sc->NIL); + sc->code=slot_value_in_env(f); + s_goto(sc,OP_APPLY); + } + } + + case OP_LAMBDA1: + s_return(sc,mk_closure(sc, sc->value, sc->envir)); + +#else + case OP_LAMBDA: /* lambda */ + s_return(sc,mk_closure(sc, sc->code, sc->envir)); + +#endif + + case OP_MKCLOSURE: /* make-closure */ + x=car(sc->args); + if(car(x)==sc->LAMBDA) { + x=cdr(x); + } + if(cdr(sc->args)==sc->NIL) { + y=sc->envir; + } else { + y=cadr(sc->args); + } + s_return(sc,mk_closure(sc, x, y)); + + case OP_QUOTE: /* quote */ + s_return(sc,car(sc->code)); + + case OP_DEF0: /* define */ + if(is_immutable(car(sc->code))) + Error_1(sc,"define: unable to alter immutable", car(sc->code)); + + if (is_pair(car(sc->code))) { + x = caar(sc->code); + sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code))); + } else { + x = car(sc->code); + sc->code = cadr(sc->code); + } + if (!is_symbol(x)) { + Error_0(sc,"variable is not a symbol"); + } + s_save(sc,OP_DEF1, sc->NIL, x); + s_goto(sc,OP_EVAL); + + case OP_DEF1: /* define */ + x=find_slot_in_env(sc,sc->envir,sc->code,0); + if (x != sc->NIL) { + set_slot_in_env(sc, x, sc->value); + } else { + new_slot_in_env(sc, sc->code, sc->value); + } + s_return(sc,sc->code); + + + case OP_DEFP: /* defined? */ + x=sc->envir; + if(cdr(sc->args)!=sc->NIL) { + x=cadr(sc->args); + } + s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL); + + case OP_SET0: /* set! */ + if(is_immutable(car(sc->code))) + Error_1(sc,"set!: unable to alter immutable variable",car(sc->code)); + s_save(sc,OP_SET1, sc->NIL, car(sc->code)); + sc->code = cadr(sc->code); + s_goto(sc,OP_EVAL); + + case OP_SET1: /* set! */ + y=find_slot_in_env(sc,sc->envir,sc->code,1); + if (y != sc->NIL) { + set_slot_in_env(sc, y, sc->value); + s_return(sc,sc->value); + } else { + Error_1(sc,"set!: unbound variable:", sc->code); + } + + + case OP_BEGIN: /* begin */ + if (!is_pair(sc->code)) { + s_return(sc,sc->code); + } + if (cdr(sc->code) != sc->NIL) { + s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code)); + } + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + + case OP_IF0: /* if */ + s_save(sc,OP_IF1, sc->NIL, cdr(sc->code)); + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + + case OP_IF1: /* if */ + if (is_true(sc->value)) + sc->code = car(sc->code); + else + sc->code = cadr(sc->code); /* (if #f 1) ==> () because + * car(sc->NIL) = sc->NIL */ + s_goto(sc,OP_EVAL); + + case OP_LET0: /* let */ + sc->args = sc->NIL; + sc->value = sc->code; + sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code); + s_goto(sc,OP_LET1); + + case OP_LET1: /* let (calculate parameters) */ + sc->args = cons(sc, sc->value, sc->args); + if (is_pair(sc->code)) { /* continue */ + if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) { + Error_1(sc, "Bad syntax of binding spec in let :", + car(sc->code)); + } + s_save(sc,OP_LET1, sc->args, cdr(sc->code)); + sc->code = cadar(sc->code); + sc->args = sc->NIL; + s_goto(sc,OP_EVAL); + } else { /* end */ + sc->args = reverse_in_place(sc, sc->NIL, sc->args); + sc->code = car(sc->args); + sc->args = cdr(sc->args); + s_goto(sc,OP_LET2); + } + + case OP_LET2: /* let */ + new_frame_in_env(sc, sc->envir); + for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args; + y != sc->NIL; x = cdr(x), y = cdr(y)) { + new_slot_in_env(sc, caar(x), car(y)); + } + if (is_symbol(car(sc->code))) { /* named let */ + for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) { + if (!is_pair(x)) + Error_1(sc, "Bad syntax of binding in let :", x); + if (!is_list(sc, car(x))) + Error_1(sc, "Bad syntax of binding in let :", car(x)); + sc->args = cons(sc, caar(x), sc->args); + } + x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir); + new_slot_in_env(sc, car(sc->code), x); + sc->code = cddr(sc->code); + sc->args = sc->NIL; + } else { + sc->code = cdr(sc->code); + sc->args = sc->NIL; + } + s_goto(sc,OP_BEGIN); + + case OP_LET0AST: /* let* */ + if (car(sc->code) == sc->NIL) { + new_frame_in_env(sc, sc->envir); + sc->code = cdr(sc->code); + s_goto(sc,OP_BEGIN); + } + if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) { + Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code)); + } + s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code)); + sc->code = cadaar(sc->code); + s_goto(sc,OP_EVAL); + + case OP_LET1AST: /* let* (make new frame) */ + new_frame_in_env(sc, sc->envir); + s_goto(sc,OP_LET2AST); + + case OP_LET2AST: /* let* (calculate parameters) */ + new_slot_in_env(sc, caar(sc->code), sc->value); + sc->code = cdr(sc->code); + if (is_pair(sc->code)) { /* continue */ + s_save(sc,OP_LET2AST, sc->args, sc->code); + sc->code = cadar(sc->code); + sc->args = sc->NIL; + s_goto(sc,OP_EVAL); + } else { /* end */ + sc->code = sc->args; + sc->args = sc->NIL; + s_goto(sc,OP_BEGIN); + } + default: + snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op); + Error_0(sc,sc->strbuff); + } + return sc->T; +} + +static pointer opexe_1(scheme *sc, enum scheme_opcodes op) { + pointer x, y; + + switch (op) { + case OP_LET0REC: /* letrec */ + new_frame_in_env(sc, sc->envir); + sc->args = sc->NIL; + sc->value = sc->code; + sc->code = car(sc->code); + s_goto(sc,OP_LET1REC); + + case OP_LET1REC: /* letrec (calculate parameters) */ + sc->args = cons(sc, sc->value, sc->args); + if (is_pair(sc->code)) { /* continue */ + if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) { + Error_1(sc, "Bad syntax of binding spec in letrec :", + car(sc->code)); + } + s_save(sc,OP_LET1REC, sc->args, cdr(sc->code)); + sc->code = cadar(sc->code); + sc->args = sc->NIL; + s_goto(sc,OP_EVAL); + } else { /* end */ + sc->args = reverse_in_place(sc, sc->NIL, sc->args); + sc->code = car(sc->args); + sc->args = cdr(sc->args); + s_goto(sc,OP_LET2REC); + } + + case OP_LET2REC: /* letrec */ + for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) { + new_slot_in_env(sc, caar(x), car(y)); + } + sc->code = cdr(sc->code); + sc->args = sc->NIL; + s_goto(sc,OP_BEGIN); + + case OP_COND0: /* cond */ + if (!is_pair(sc->code)) { + Error_0(sc,"syntax error in cond"); + } + s_save(sc,OP_COND1, sc->NIL, sc->code); + sc->code = caar(sc->code); + s_goto(sc,OP_EVAL); + + case OP_COND1: /* cond */ + if (is_true(sc->value)) { + if ((sc->code = cdar(sc->code)) == sc->NIL) { + s_return(sc,sc->value); + } + if(car(sc->code)==sc->FEED_TO) { + if(!is_pair(cdr(sc->code))) { + Error_0(sc,"syntax error in cond"); + } + x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL)); + sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL)); + s_goto(sc,OP_EVAL); + } + s_goto(sc,OP_BEGIN); + } else { + if ((sc->code = cdr(sc->code)) == sc->NIL) { + s_return(sc,sc->NIL); + } else { + s_save(sc,OP_COND1, sc->NIL, sc->code); + sc->code = caar(sc->code); + s_goto(sc,OP_EVAL); + } + } + + case OP_DELAY: /* delay */ + x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir); + typeflag(x)=T_PROMISE; + s_return(sc,x); + + case OP_AND0: /* and */ + if (sc->code == sc->NIL) { + s_return(sc,sc->T); + } + s_save(sc,OP_AND1, sc->NIL, cdr(sc->code)); + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + + case OP_AND1: /* and */ + if (is_false(sc->value)) { + s_return(sc,sc->value); + } else if (sc->code == sc->NIL) { + s_return(sc,sc->value); + } else { + s_save(sc,OP_AND1, sc->NIL, cdr(sc->code)); + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + } + + case OP_OR0: /* or */ + if (sc->code == sc->NIL) { + s_return(sc,sc->F); + } + s_save(sc,OP_OR1, sc->NIL, cdr(sc->code)); + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + + case OP_OR1: /* or */ + if (is_true(sc->value)) { + s_return(sc,sc->value); + } else if (sc->code == sc->NIL) { + s_return(sc,sc->value); + } else { + s_save(sc,OP_OR1, sc->NIL, cdr(sc->code)); + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + } + + case OP_C0STREAM: /* cons-stream */ + s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code)); + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + + case OP_C1STREAM: /* cons-stream */ + sc->args = sc->value; /* save sc->value to register sc->args for gc */ + x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir); + typeflag(x)=T_PROMISE; + s_return(sc,cons(sc, sc->args, x)); + + case OP_MACRO0: /* macro */ + if (is_pair(car(sc->code))) { + x = caar(sc->code); + sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code))); + } else { + x = car(sc->code); + sc->code = cadr(sc->code); + } + if (!is_symbol(x)) { + Error_0(sc,"variable is not a symbol"); + } + s_save(sc,OP_MACRO1, sc->NIL, x); + s_goto(sc,OP_EVAL); + + case OP_MACRO1: /* macro */ + typeflag(sc->value) = T_MACRO; + x = find_slot_in_env(sc, sc->envir, sc->code, 0); + if (x != sc->NIL) { + set_slot_in_env(sc, x, sc->value); + } else { + new_slot_in_env(sc, sc->code, sc->value); + } + s_return(sc,sc->code); + + case OP_CASE0: /* case */ + s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code)); + sc->code = car(sc->code); + s_goto(sc,OP_EVAL); + + case OP_CASE1: /* case */ + for (x = sc->code; x != sc->NIL; x = cdr(x)) { + if (!is_pair(y = caar(x))) { + break; + } + for ( ; y != sc->NIL; y = cdr(y)) { + if (eqv(car(y), sc->value)) { + break; + } + } + if (y != sc->NIL) { + break; + } + } + if (x != sc->NIL) { + if (is_pair(caar(x))) { + sc->code = cdar(x); + s_goto(sc,OP_BEGIN); + } else {/* else */ + s_save(sc,OP_CASE2, sc->NIL, cdar(x)); + sc->code = caar(x); + s_goto(sc,OP_EVAL); + } + } else { + s_return(sc,sc->NIL); + } + + case OP_CASE2: /* case */ + if (is_true(sc->value)) { + s_goto(sc,OP_BEGIN); + } else { + s_return(sc,sc->NIL); + } + + case OP_PAPPLY: /* apply */ + sc->code = car(sc->args); + sc->args = list_star(sc,cdr(sc->args)); + /*sc->args = cadr(sc->args);*/ + s_goto(sc,OP_APPLY); + + case OP_PEVAL: /* eval */ + if(cdr(sc->args)!=sc->NIL) { + sc->envir=cadr(sc->args); + } + sc->code = car(sc->args); + s_goto(sc,OP_EVAL); + + case OP_CONTINUATION: /* call-with-current-continuation */ + sc->code = car(sc->args); + sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL); + s_goto(sc,OP_APPLY); + + default: + snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op); + Error_0(sc,sc->strbuff); + } + return sc->T; +} + +static pointer opexe_2(scheme *sc, enum scheme_opcodes op) { + pointer x; + num v; +#if USE_MATH + double dd; +#endif + + switch (op) { +#if USE_MATH + case OP_INEX2EX: /* inexact->exact */ + x=car(sc->args); + if(num_is_integer(x)) { + s_return(sc,x); + } else if(modf(rvalue_unchecked(x),&dd)==0.0) { + s_return(sc,mk_integer(sc,ivalue(x))); + } else { + Error_1(sc,"inexact->exact: not integral:",x); + } + + case OP_EXP: + x=car(sc->args); + s_return(sc, mk_real(sc, exp(rvalue(x)))); + + case OP_LOG: + x=car(sc->args); + s_return(sc, mk_real(sc, log(rvalue(x)))); + + case OP_SIN: + x=car(sc->args); + s_return(sc, mk_real(sc, sin(rvalue(x)))); + + case OP_COS: + x=car(sc->args); + s_return(sc, mk_real(sc, cos(rvalue(x)))); + + case OP_TAN: + x=car(sc->args); + s_return(sc, mk_real(sc, tan(rvalue(x)))); + + case OP_ASIN: + x=car(sc->args); + s_return(sc, mk_real(sc, asin(rvalue(x)))); + + case OP_ACOS: + x=car(sc->args); + s_return(sc, mk_real(sc, acos(rvalue(x)))); + + case OP_ATAN: + x=car(sc->args); + if(cdr(sc->args)==sc->NIL) { + s_return(sc, mk_real(sc, atan(rvalue(x)))); + } else { + pointer y=cadr(sc->args); + s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y)))); + } + + case OP_SQRT: + x=car(sc->args); + s_return(sc, mk_real(sc, sqrt(rvalue(x)))); + + case OP_EXPT: { + double result; + int real_result=1; + pointer y=cadr(sc->args); + x=car(sc->args); + if (num_is_integer(x) && num_is_integer(y)) + real_result=0; + /* This 'if' is an R5RS compatibility fix. */ + /* NOTE: Remove this 'if' fix for R6RS. */ + if (rvalue(x) == 0 && rvalue(y) < 0) { + result = 0.0; + } else { + result = pow(rvalue(x),rvalue(y)); + } + /* Before returning integer result make sure we can. */ + /* If the test fails, result is too big for integer. */ + if (!real_result) + { + long result_as_long = (long)result; + if (result != (double)result_as_long) + real_result = 1; + } + if (real_result) { + s_return(sc, mk_real(sc, result)); + } else { + s_return(sc, mk_integer(sc, result)); + } + } + + case OP_FLOOR: + x=car(sc->args); + s_return(sc, mk_real(sc, floor(rvalue(x)))); + + case OP_CEILING: + x=car(sc->args); + s_return(sc, mk_real(sc, ceil(rvalue(x)))); + + case OP_TRUNCATE : { + double rvalue_of_x ; + x=car(sc->args); + rvalue_of_x = rvalue(x) ; + if (rvalue_of_x > 0) { + s_return(sc, mk_real(sc, floor(rvalue_of_x))); + } else { + s_return(sc, mk_real(sc, ceil(rvalue_of_x))); + } + } + + case OP_ROUND: + x=car(sc->args); + if (num_is_integer(x)) + s_return(sc, x); + s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x)))); +#endif + + case OP_ADD: /* + */ + v=num_zero; + for (x = sc->args; x != sc->NIL; x = cdr(x)) { + v=num_add(v,nvalue(car(x))); + } + s_return(sc,mk_number(sc, v)); + + case OP_MUL: /* * */ + v=num_one; + for (x = sc->args; x != sc->NIL; x = cdr(x)) { + v=num_mul(v,nvalue(car(x))); + } + s_return(sc,mk_number(sc, v)); + + case OP_SUB: /* - */ + if(cdr(sc->args)==sc->NIL) { + x=sc->args; + v=num_zero; + } else { + x = cdr(sc->args); + v = nvalue(car(sc->args)); + } + for (; x != sc->NIL; x = cdr(x)) { + v=num_sub(v,nvalue(car(x))); + } + s_return(sc,mk_number(sc, v)); + + case OP_DIV: /* / */ + if(cdr(sc->args)==sc->NIL) { + x=sc->args; + v=num_one; + } else { + x = cdr(sc->args); + v = nvalue(car(sc->args)); + } + for (; x != sc->NIL; x = cdr(x)) { + if (!is_zero_double(rvalue(car(x)))) + v=num_div(v,nvalue(car(x))); + else { + Error_0(sc,"/: division by zero"); + } + } + s_return(sc,mk_number(sc, v)); + + case OP_INTDIV: /* quotient */ + if(cdr(sc->args)==sc->NIL) { + x=sc->args; + v=num_one; + } else { + x = cdr(sc->args); + v = nvalue(car(sc->args)); + } + for (; x != sc->NIL; x = cdr(x)) { + if (ivalue(car(x)) != 0) + v=num_intdiv(v,nvalue(car(x))); + else { + Error_0(sc,"quotient: division by zero"); + } + } + s_return(sc,mk_number(sc, v)); + + case OP_REM: /* remainder */ + v = nvalue(car(sc->args)); + if (ivalue(cadr(sc->args)) != 0) + v=num_rem(v,nvalue(cadr(sc->args))); + else { + Error_0(sc,"remainder: division by zero"); + } + s_return(sc,mk_number(sc, v)); + + case OP_MOD: /* modulo */ + v = nvalue(car(sc->args)); + if (ivalue(cadr(sc->args)) != 0) + v=num_mod(v,nvalue(cadr(sc->args))); + else { + Error_0(sc,"modulo: division by zero"); + } + s_return(sc,mk_number(sc, v)); + + case OP_CAR: /* car */ + s_return(sc,caar(sc->args)); + + case OP_CDR: /* cdr */ + s_return(sc,cdar(sc->args)); + + case OP_CONS: /* cons */ + cdr(sc->args) = cadr(sc->args); + s_return(sc,sc->args); + + case OP_SETCAR: /* set-car! */ + if(!is_immutable(car(sc->args))) { + caar(sc->args) = cadr(sc->args); + s_return(sc,car(sc->args)); + } else { + Error_0(sc,"set-car!: unable to alter immutable pair"); + } + + case OP_SETCDR: /* set-cdr! */ + if(!is_immutable(car(sc->args))) { + cdar(sc->args) = cadr(sc->args); + s_return(sc,car(sc->args)); + } else { + Error_0(sc,"set-cdr!: unable to alter immutable pair"); + } + + case OP_CHAR2INT: { /* char->integer */ + char c; + c=(char)ivalue(car(sc->args)); + s_return(sc,mk_integer(sc,(unsigned char)c)); + } + + case OP_INT2CHAR: { /* integer->char */ + unsigned char c; + c=(unsigned char)ivalue(car(sc->args)); + s_return(sc,mk_character(sc,(char)c)); + } + + case OP_CHARUPCASE: { + unsigned char c; + c=(unsigned char)ivalue(car(sc->args)); + c=toupper(c); + s_return(sc,mk_character(sc,(char)c)); + } + + case OP_CHARDNCASE: { + unsigned char c; + c=(unsigned char)ivalue(car(sc->args)); + c=tolower(c); + s_return(sc,mk_character(sc,(char)c)); + } + + case OP_STR2SYM: /* string->symbol */ + s_return(sc,mk_symbol(sc,strvalue(car(sc->args)))); + + case OP_STR2ATOM: /* string->atom */ { + char *s=strvalue(car(sc->args)); + long pf = 0; + if(cdr(sc->args)!=sc->NIL) { + /* we know cadr(sc->args) is a natural number */ + /* see if it is 2, 8, 10, or 16, or error */ + pf = ivalue_unchecked(cadr(sc->args)); + if(pf == 16 || pf == 10 || pf == 8 || pf == 2) { + /* base is OK */ + } + else { + pf = -1; + } + } + if (pf < 0) { + Error_1(sc, "string->atom: bad base:", cadr(sc->args)); + } else if(*s=='#') /* no use of base! */ { + s_return(sc, mk_sharp_const(sc, s+1)); + } else { + if (pf == 0 || pf == 10) { + s_return(sc, mk_atom(sc, s)); + } + else { + char *ep; + long iv = strtol(s,&ep,(int )pf); + if (*ep == 0) { + s_return(sc, mk_integer(sc, iv)); + } + else { + s_return(sc, sc->F); + } + } + } + } + + case OP_SYM2STR: /* symbol->string */ + x=mk_string(sc,symname(car(sc->args))); + setimmutable(x); + s_return(sc,x); + + case OP_ATOM2STR: /* atom->string */ { + long pf = 0; + x=car(sc->args); + if(cdr(sc->args)!=sc->NIL) { + /* we know cadr(sc->args) is a natural number */ + /* see if it is 2, 8, 10, or 16, or error */ + pf = ivalue_unchecked(cadr(sc->args)); + if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) { + /* base is OK */ + } + else { + pf = -1; + } + } + if (pf < 0) { + Error_1(sc, "atom->string: bad base:", cadr(sc->args)); + } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) { + char *p; + int len; + atom2str(sc,x,(int )pf,&p,&len); + s_return(sc,mk_counted_string(sc,p,len)); + } else { + Error_1(sc, "atom->string: not an atom:", x); + } + } + + case OP_MKSTRING: { /* make-string */ + int fill=' '; + int len; + + len=ivalue(car(sc->args)); + + if(cdr(sc->args)!=sc->NIL) { + fill=charvalue(cadr(sc->args)); + } + s_return(sc,mk_empty_string(sc,len,(char)fill)); + } + + case OP_STRLEN: /* string-length */ + s_return(sc,mk_integer(sc,strlength(car(sc->args)))); + + case OP_STRREF: { /* string-ref */ + char *str; + int index; + + str=strvalue(car(sc->args)); + + index=ivalue(cadr(sc->args)); + + if(index>=strlength(car(sc->args))) { + Error_1(sc,"string-ref: out of bounds:",cadr(sc->args)); + } + + s_return(sc,mk_character(sc,((unsigned char*)str)[index])); + } + + case OP_STRSET: { /* string-set! */ + char *str; + int index; + int c; + + if(is_immutable(car(sc->args))) { + Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args)); + } + str=strvalue(car(sc->args)); + + index=ivalue(cadr(sc->args)); + if(index>=strlength(car(sc->args))) { + Error_1(sc,"string-set!: out of bounds:",cadr(sc->args)); + } + + c=charvalue(caddr(sc->args)); + + str[index]=(char)c; + s_return(sc,car(sc->args)); + } + + case OP_STRAPPEND: { /* string-append */ + /* in 1.29 string-append was in Scheme in init.scm but was too slow */ + int len = 0; + pointer newstr; + char *pos; + + /* compute needed length for new string */ + for (x = sc->args; x != sc->NIL; x = cdr(x)) { + len += strlength(car(x)); + } + newstr = mk_empty_string(sc, len, ' '); + /* store the contents of the argument strings into the new string */ + for (pos = strvalue(newstr), x = sc->args; x != sc->NIL; + pos += strlength(car(x)), x = cdr(x)) { + memcpy(pos, strvalue(car(x)), strlength(car(x))); + } + s_return(sc, newstr); + } + + case OP_SUBSTR: { /* substring */ + char *str; + int index0; + int index1; + int len; + + str=strvalue(car(sc->args)); + + index0=ivalue(cadr(sc->args)); + + if(index0>strlength(car(sc->args))) { + Error_1(sc,"substring: start out of bounds:",cadr(sc->args)); + } + + if(cddr(sc->args)!=sc->NIL) { + index1=ivalue(caddr(sc->args)); + if(index1>strlength(car(sc->args)) || index1args)); + } + } else { + index1=strlength(car(sc->args)); + } + + len=index1-index0; + x=mk_empty_string(sc,len,' '); + memcpy(strvalue(x),str+index0,len); + strvalue(x)[len]=0; + + s_return(sc,x); + } + + case OP_VECTOR: { /* vector */ + int i; + pointer vec; + int len=list_length(sc,sc->args); + if(len<0) { + Error_1(sc,"vector: not a proper list:",sc->args); + } + vec=mk_vector(sc,len); + if(sc->no_memory) { s_return(sc, sc->sink); } + for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) { + set_vector_elem(vec,i,car(x)); + } + s_return(sc,vec); + } + + case OP_MKVECTOR: { /* make-vector */ + pointer fill=sc->NIL; + int len; + pointer vec; + + len=ivalue(car(sc->args)); + + if(cdr(sc->args)!=sc->NIL) { + fill=cadr(sc->args); + } + vec=mk_vector(sc,len); + if(sc->no_memory) { s_return(sc, sc->sink); } + if(fill!=sc->NIL) { + fill_vector(vec,fill); + } + s_return(sc,vec); + } + + case OP_VECLEN: /* vector-length */ + s_return(sc,mk_integer(sc,ivalue(car(sc->args)))); + + case OP_VECREF: { /* vector-ref */ + int index; + + index=ivalue(cadr(sc->args)); + + if(index>=ivalue(car(sc->args))) { + Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args)); + } + + s_return(sc,vector_elem(car(sc->args),index)); + } + + case OP_VECSET: { /* vector-set! */ + int index; + + if(is_immutable(car(sc->args))) { + Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args)); + } + + index=ivalue(cadr(sc->args)); + if(index>=ivalue(car(sc->args))) { + Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args)); + } + + set_vector_elem(car(sc->args),index,caddr(sc->args)); + s_return(sc,car(sc->args)); + } + + default: + snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op); + Error_0(sc,sc->strbuff); + } + return sc->T; +} + +static int is_list(scheme *sc, pointer a) +{ return list_length(sc,a) >= 0; } + +/* Result is: + proper list: length + circular list: -1 + not even a pair: -2 + dotted list: -2 minus length before dot +*/ +int list_length(scheme *sc, pointer a) { + int i=0; + pointer slow, fast; + + slow = fast = a; + while (1) + { + if (fast == sc->NIL) + return i; + if (!is_pair(fast)) + return -2 - i; + fast = cdr(fast); + ++i; + if (fast == sc->NIL) + return i; + if (!is_pair(fast)) + return -2 - i; + ++i; + fast = cdr(fast); + + /* Safe because we would have already returned if `fast' + encountered a non-pair. */ + slow = cdr(slow); + if (fast == slow) + { + /* the fast pointer has looped back around and caught up + with the slow pointer, hence the structure is circular, + not of finite length, and therefore not a list */ + return -1; + } + } +} + +static pointer opexe_3(scheme *sc, enum scheme_opcodes op) { + pointer x; + num v; + int (*comp_func)(num,num)=0; + + switch (op) { + case OP_NOT: /* not */ + s_retbool(is_false(car(sc->args))); + case OP_BOOLP: /* boolean? */ + s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T); + case OP_EOFOBJP: /* boolean? */ + s_retbool(car(sc->args) == sc->EOF_OBJ); + case OP_NULLP: /* null? */ + s_retbool(car(sc->args) == sc->NIL); + case OP_NUMEQ: /* = */ + case OP_LESS: /* < */ + case OP_GRE: /* > */ + case OP_LEQ: /* <= */ + case OP_GEQ: /* >= */ + switch(op) { + case OP_NUMEQ: comp_func=num_eq; break; + case OP_LESS: comp_func=num_lt; break; + case OP_GRE: comp_func=num_gt; break; + case OP_LEQ: comp_func=num_le; break; + case OP_GEQ: comp_func=num_ge; break; + } + x=sc->args; + v=nvalue(car(x)); + x=cdr(x); + + for (; x != sc->NIL; x = cdr(x)) { + if(!comp_func(v,nvalue(car(x)))) { + s_retbool(0); + } + v=nvalue(car(x)); + } + s_retbool(1); + case OP_SYMBOLP: /* symbol? */ + s_retbool(is_symbol(car(sc->args))); + case OP_NUMBERP: /* number? */ + s_retbool(is_number(car(sc->args))); + case OP_STRINGP: /* string? */ + s_retbool(is_string(car(sc->args))); + case OP_INTEGERP: /* integer? */ + s_retbool(is_integer(car(sc->args))); + case OP_REALP: /* real? */ + s_retbool(is_number(car(sc->args))); /* All numbers are real */ + case OP_CHARP: /* char? */ + s_retbool(is_character(car(sc->args))); +#if USE_CHAR_CLASSIFIERS + case OP_CHARAP: /* char-alphabetic? */ + s_retbool(Cisalpha(ivalue(car(sc->args)))); + case OP_CHARNP: /* char-numeric? */ + s_retbool(Cisdigit(ivalue(car(sc->args)))); + case OP_CHARWP: /* char-whitespace? */ + s_retbool(Cisspace(ivalue(car(sc->args)))); + case OP_CHARUP: /* char-upper-case? */ + s_retbool(Cisupper(ivalue(car(sc->args)))); + case OP_CHARLP: /* char-lower-case? */ + s_retbool(Cislower(ivalue(car(sc->args)))); +#endif + case OP_PORTP: /* port? */ + s_retbool(is_port(car(sc->args))); + case OP_INPORTP: /* input-port? */ + s_retbool(is_inport(car(sc->args))); + case OP_OUTPORTP: /* output-port? */ + s_retbool(is_outport(car(sc->args))); + case OP_PROCP: /* procedure? */ + /*-- + * continuation should be procedure by the example + * (call-with-current-continuation procedure?) ==> #t + * in R^3 report sec. 6.9 + */ + s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args)) + || is_continuation(car(sc->args)) || is_foreign(car(sc->args))); + case OP_PAIRP: /* pair? */ + s_retbool(is_pair(car(sc->args))); + case OP_LISTP: /* list? */ + s_retbool(list_length(sc,car(sc->args)) >= 0); + + case OP_ENVP: /* environment? */ + s_retbool(is_environment(car(sc->args))); + case OP_VECTORP: /* vector? */ + s_retbool(is_vector(car(sc->args))); + case OP_EQ: /* eq? */ + s_retbool(car(sc->args) == cadr(sc->args)); + case OP_EQV: /* eqv? */ + s_retbool(eqv(car(sc->args), cadr(sc->args))); + default: + snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op); + Error_0(sc,sc->strbuff); + } + return sc->T; +} + +static pointer opexe_4(scheme *sc, enum scheme_opcodes op) { + pointer x, y; + + switch (op) { + case OP_FORCE: /* force */ + sc->code = car(sc->args); + if (is_promise(sc->code)) { + /* Should change type to closure here */ + s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code); + sc->args = sc->NIL; + s_goto(sc,OP_APPLY); + } else { + s_return(sc,sc->code); + } + + case OP_SAVE_FORCED: /* Save forced value replacing promise */ + memcpy(sc->code,sc->value,sizeof(struct cell)); + s_return(sc,sc->value); + + case OP_WRITE: /* write */ + case OP_DISPLAY: /* display */ + case OP_WRITE_CHAR: /* write-char */ + if(is_pair(cdr(sc->args))) { + if(cadr(sc->args)!=sc->outport) { + x=cons(sc,sc->outport,sc->NIL); + s_save(sc,OP_SET_OUTPORT, x, sc->NIL); + sc->outport=cadr(sc->args); + } + } + sc->args = car(sc->args); + if(op==OP_WRITE) { + sc->print_flag = 1; + } else { + sc->print_flag = 0; + } + s_goto(sc,OP_P0LIST); + + case OP_NEWLINE: /* newline */ + if(is_pair(sc->args)) { + if(car(sc->args)!=sc->outport) { + x=cons(sc,sc->outport,sc->NIL); + s_save(sc,OP_SET_OUTPORT, x, sc->NIL); + sc->outport=car(sc->args); + } + } + putstr(sc, "\n"); + s_return(sc,sc->T); + + case OP_ERR0: /* error */ + sc->retcode=-1; + if (!is_string(car(sc->args))) { + sc->args=cons(sc,mk_string(sc," -- "),sc->args); + setimmutable(car(sc->args)); + } + putstr(sc, "Error: "); + putstr(sc, strvalue(car(sc->args))); + sc->args = cdr(sc->args); + s_goto(sc,OP_ERR1); + + case OP_ERR1: /* error */ + putstr(sc, " "); + if (sc->args != sc->NIL) { + s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL); + sc->args = car(sc->args); + sc->print_flag = 1; + s_goto(sc,OP_P0LIST); + } else { + putstr(sc, "\n"); + if(sc->interactive_repl) { + s_goto(sc,OP_T0LVL); + } else { + return sc->NIL; + } + } + + case OP_REVERSE: /* reverse */ + s_return(sc,reverse(sc, car(sc->args))); + + case OP_LIST_STAR: /* list* */ + s_return(sc,list_star(sc,sc->args)); + + case OP_APPEND: /* append */ + x = sc->NIL; + y = sc->args; + if (y == x) { + s_return(sc, x); + } + + /* cdr() in the while condition is not a typo. If car() */ + /* is used (append '() 'a) will return the wrong result.*/ + while (cdr(y) != sc->NIL) { + x = revappend(sc, x, car(y)); + y = cdr(y); + if (x == sc->F) { + Error_0(sc, "non-list argument to append"); + } + } + + s_return(sc, reverse_in_place(sc, car(y), x)); + +#if USE_PLIST + case OP_PUT: /* put */ + if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) { + Error_0(sc,"illegal use of put"); + } + for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) { + if (caar(x) == y) { + break; + } + } + if (x != sc->NIL) + cdar(x) = caddr(sc->args); + else + symprop(car(sc->args)) = cons(sc, cons(sc, y, caddr(sc->args)), + symprop(car(sc->args))); + s_return(sc,sc->T); + + case OP_GET: /* get */ + if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) { + Error_0(sc,"illegal use of get"); + } + for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) { + if (caar(x) == y) { + break; + } + } + if (x != sc->NIL) { + s_return(sc,cdar(x)); + } else { + s_return(sc,sc->NIL); + } +#endif /* USE_PLIST */ + case OP_QUIT: /* quit */ + if(is_pair(sc->args)) { + sc->retcode=ivalue(car(sc->args)); + } + return (sc->NIL); + + case OP_GC: /* gc */ + gc(sc, sc->NIL, sc->NIL); + s_return(sc,sc->T); + + case OP_GCVERB: /* gc-verbose */ + { int was = sc->gc_verbose; + + sc->gc_verbose = (car(sc->args) != sc->F); + s_retbool(was); + } + + case OP_NEWSEGMENT: /* new-segment */ + if (!is_pair(sc->args) || !is_number(car(sc->args))) { + Error_0(sc,"new-segment: argument must be a number"); + } + alloc_cellseg(sc, (int) ivalue(car(sc->args))); + s_return(sc,sc->T); + + case OP_OBLIST: /* oblist */ + s_return(sc, oblist_all_symbols(sc)); + + case OP_CURR_INPORT: /* current-input-port */ + s_return(sc,sc->inport); + + case OP_CURR_OUTPORT: /* current-output-port */ + s_return(sc,sc->outport); + + case OP_OPEN_INFILE: /* open-input-file */ + case OP_OPEN_OUTFILE: /* open-output-file */ + case OP_OPEN_INOUTFILE: /* open-input-output-file */ { + int prop=0; + pointer p; + switch(op) { + case OP_OPEN_INFILE: prop=port_input; break; + case OP_OPEN_OUTFILE: prop=port_output; break; + case OP_OPEN_INOUTFILE: prop=port_input|port_output; break; + } + p=port_from_filename(sc,strvalue(car(sc->args)),prop); + if(p==sc->NIL) { + s_return(sc,sc->F); + } + s_return(sc,p); + } + +#if USE_STRING_PORTS + case OP_OPEN_INSTRING: /* open-input-string */ + case OP_OPEN_INOUTSTRING: /* open-input-output-string */ { + int prop=0; + pointer p; + switch(op) { + case OP_OPEN_INSTRING: prop=port_input; break; + case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break; + } + p=port_from_string(sc, strvalue(car(sc->args)), + strvalue(car(sc->args))+strlength(car(sc->args)), prop); + if(p==sc->NIL) { + s_return(sc,sc->F); + } + s_return(sc,p); + } + case OP_OPEN_OUTSTRING: /* open-output-string */ { + pointer p; + if(car(sc->args)==sc->NIL) { + p=port_from_scratch(sc); + if(p==sc->NIL) { + s_return(sc,sc->F); + } + } else { + p=port_from_string(sc, strvalue(car(sc->args)), + strvalue(car(sc->args))+strlength(car(sc->args)), + port_output); + if(p==sc->NIL) { + s_return(sc,sc->F); + } + } + s_return(sc,p); + } + case OP_GET_OUTSTRING: /* get-output-string */ { + port *p; + + if ((p=car(sc->args)->_object._port)->kind&port_string) { + off_t size; + char *str; + + size=p->rep.string.curr-p->rep.string.start+1; + str=sc->malloc(size); + if(str != NULL) { + pointer s; + + memcpy(str,p->rep.string.start,size-1); + str[size-1]='\0'; + s=mk_string(sc,str); + sc->free(str); + s_return(sc,s); + } + } + s_return(sc,sc->F); + } +#endif + + case OP_CLOSE_INPORT: /* close-input-port */ + port_close(sc,car(sc->args),port_input); + s_return(sc,sc->T); + + case OP_CLOSE_OUTPORT: /* close-output-port */ + port_close(sc,car(sc->args),port_output); + s_return(sc,sc->T); + + case OP_INT_ENV: /* interaction-environment */ + s_return(sc,sc->global_env); + + case OP_CURR_ENV: /* current-environment */ + s_return(sc,sc->envir); + + } + return sc->T; +} + +static pointer opexe_5(scheme *sc, enum scheme_opcodes op) { + pointer x; + + if(sc->nesting!=0) { + int n=sc->nesting; + sc->nesting=0; + sc->retcode=-1; + Error_1(sc,"unmatched parentheses:",mk_integer(sc,n)); + } + + switch (op) { + /* ========== reading part ========== */ + case OP_READ: + if(!is_pair(sc->args)) { + s_goto(sc,OP_READ_INTERNAL); + } + if(!is_inport(car(sc->args))) { + Error_1(sc,"read: not an input port:",car(sc->args)); + } + if(car(sc->args)==sc->inport) { + s_goto(sc,OP_READ_INTERNAL); + } + x=sc->inport; + sc->inport=car(sc->args); + x=cons(sc,x,sc->NIL); + s_save(sc,OP_SET_INPORT, x, sc->NIL); + s_goto(sc,OP_READ_INTERNAL); + + case OP_READ_CHAR: /* read-char */ + case OP_PEEK_CHAR: /* peek-char */ { + int c; + if(is_pair(sc->args)) { + if(car(sc->args)!=sc->inport) { + x=sc->inport; + x=cons(sc,x,sc->NIL); + s_save(sc,OP_SET_INPORT, x, sc->NIL); + sc->inport=car(sc->args); + } + } + c=inchar(sc); + if(c==EOF) { + s_return(sc,sc->EOF_OBJ); + } + if(sc->op==OP_PEEK_CHAR) { + backchar(sc,c); + } + s_return(sc,mk_character(sc,c)); + } + + case OP_CHAR_READY: /* char-ready? */ { + pointer p=sc->inport; + int res; + if(is_pair(sc->args)) { + p=car(sc->args); + } + res=p->_object._port->kind&port_string; + s_retbool(res); + } + + case OP_SET_INPORT: /* set-input-port */ + sc->inport=car(sc->args); + s_return(sc,sc->value); + + case OP_SET_OUTPORT: /* set-output-port */ + sc->outport=car(sc->args); + s_return(sc,sc->value); + + case OP_RDSEXPR: + switch (sc->tok) { + case TOK_EOF: + s_return(sc,sc->EOF_OBJ); + /* NOTREACHED */ +/* + * Commented out because we now skip comments in the scanner + * + case TOK_COMMENT: { + int c; + while ((c=inchar(sc)) != '\n' && c!=EOF) + ; + sc->tok = token(sc); + s_goto(sc,OP_RDSEXPR); + } +*/ + case TOK_VEC: + s_save(sc,OP_RDVEC,sc->NIL,sc->NIL); + /* fall through */ + case TOK_LPAREN: + sc->tok = token(sc); + if (sc->tok == TOK_RPAREN) { + s_return(sc,sc->NIL); + } else if (sc->tok == TOK_DOT) { + Error_0(sc,"syntax error: illegal dot expression"); + } else { + sc->nesting_stack[sc->file_i]++; + s_save(sc,OP_RDLIST, sc->NIL, sc->NIL); + s_goto(sc,OP_RDSEXPR); + } + case TOK_QUOTE: + s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL); + sc->tok = token(sc); + s_goto(sc,OP_RDSEXPR); + case TOK_BQUOTE: + sc->tok = token(sc); + if(sc->tok==TOK_VEC) { + s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL); + sc->tok=TOK_LPAREN; + s_goto(sc,OP_RDSEXPR); + } else { + s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL); + } + s_goto(sc,OP_RDSEXPR); + case TOK_COMMA: + s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL); + sc->tok = token(sc); + s_goto(sc,OP_RDSEXPR); + case TOK_ATMARK: + s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL); + sc->tok = token(sc); + s_goto(sc,OP_RDSEXPR); + case TOK_ATOM: + s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS))); + case TOK_DQUOTE: + x=readstrexp(sc); + if(x==sc->F) { + Error_0(sc,"Error reading string"); + } + setimmutable(x); + s_return(sc,x); + case TOK_SHARP: { + pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1); + if(f==sc->NIL) { + Error_0(sc,"undefined sharp expression"); + } else { + sc->code=cons(sc,slot_value_in_env(f),sc->NIL); + s_goto(sc,OP_EVAL); + } + } + case TOK_SHARP_CONST: + if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) { + Error_0(sc,"undefined sharp expression"); + } else { + s_return(sc,x); + } + default: + Error_0(sc,"syntax error: illegal token"); + } + break; + + case OP_RDLIST: { + sc->args = cons(sc, sc->value, sc->args); + sc->tok = token(sc); +/* We now skip comments in the scanner + while (sc->tok == TOK_COMMENT) { + int c; + while ((c=inchar(sc)) != '\n' && c!=EOF) + ; + sc->tok = token(sc); + } +*/ + if (sc->tok == TOK_EOF) + { s_return(sc,sc->EOF_OBJ); } + else if (sc->tok == TOK_RPAREN) { + int c = inchar(sc); + if (c != '\n') + backchar(sc,c); +#if SHOW_ERROR_LINE + else if (sc->load_stack[sc->file_i].kind & port_file) + sc->load_stack[sc->file_i].rep.stdio.curr_line++; +#endif + sc->nesting_stack[sc->file_i]--; + s_return(sc,reverse_in_place(sc, sc->NIL, sc->args)); + } else if (sc->tok == TOK_DOT) { + s_save(sc,OP_RDDOT, sc->args, sc->NIL); + sc->tok = token(sc); + s_goto(sc,OP_RDSEXPR); + } else { + s_save(sc,OP_RDLIST, sc->args, sc->NIL);; + s_goto(sc,OP_RDSEXPR); + } + } + + case OP_RDDOT: + if (token(sc) != TOK_RPAREN) { + Error_0(sc,"syntax error: illegal dot expression"); + } else { + sc->nesting_stack[sc->file_i]--; + s_return(sc,reverse_in_place(sc, sc->value, sc->args)); + } + + case OP_RDQUOTE: + s_return(sc,cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL))); + + case OP_RDQQUOTE: + s_return(sc,cons(sc, sc->QQUOTE, cons(sc, sc->value, sc->NIL))); + + case OP_RDQQUOTEVEC: + s_return(sc,cons(sc, mk_symbol(sc,"apply"), + cons(sc, mk_symbol(sc,"vector"), + cons(sc,cons(sc, sc->QQUOTE, + cons(sc,sc->value,sc->NIL)), + sc->NIL)))); + + case OP_RDUNQUOTE: + s_return(sc,cons(sc, sc->UNQUOTE, cons(sc, sc->value, sc->NIL))); + + case OP_RDUQTSP: + s_return(sc,cons(sc, sc->UNQUOTESP, cons(sc, sc->value, sc->NIL))); + + case OP_RDVEC: + /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value); + s_goto(sc,OP_EVAL); Cannot be quoted*/ + /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value); + s_return(sc,x); Cannot be part of pairs*/ + /*sc->code=mk_proc(sc,OP_VECTOR); + sc->args=sc->value; + s_goto(sc,OP_APPLY);*/ + sc->args=sc->value; + s_goto(sc,OP_VECTOR); + + /* ========== printing part ========== */ + case OP_P0LIST: + if(is_vector(sc->args)) { + putstr(sc,"#("); + sc->args=cons(sc,sc->args,mk_integer(sc,0)); + s_goto(sc,OP_PVECFROM); + } else if(is_environment(sc->args)) { + putstr(sc,"#"); + s_return(sc,sc->T); + } else if (!is_pair(sc->args)) { + printatom(sc, sc->args, sc->print_flag); + s_return(sc,sc->T); + } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) { + putstr(sc, "'"); + sc->args = cadr(sc->args); + s_goto(sc,OP_P0LIST); + } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) { + putstr(sc, "`"); + sc->args = cadr(sc->args); + s_goto(sc,OP_P0LIST); + } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) { + putstr(sc, ","); + sc->args = cadr(sc->args); + s_goto(sc,OP_P0LIST); + } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) { + putstr(sc, ",@"); + sc->args = cadr(sc->args); + s_goto(sc,OP_P0LIST); + } else { + putstr(sc, "("); + s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL); + sc->args = car(sc->args); + s_goto(sc,OP_P0LIST); + } + + case OP_P1LIST: + if (is_pair(sc->args)) { + s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL); + putstr(sc, " "); + sc->args = car(sc->args); + s_goto(sc,OP_P0LIST); + } else if(is_vector(sc->args)) { + s_save(sc,OP_P1LIST,sc->NIL,sc->NIL); + putstr(sc, " . "); + s_goto(sc,OP_P0LIST); + } else { + if (sc->args != sc->NIL) { + putstr(sc, " . "); + printatom(sc, sc->args, sc->print_flag); + } + putstr(sc, ")"); + s_return(sc,sc->T); + } + case OP_PVECFROM: { + int i=ivalue_unchecked(cdr(sc->args)); + pointer vec=car(sc->args); + int len=ivalue_unchecked(vec); + if(i==len) { + putstr(sc,")"); + s_return(sc,sc->T); + } else { + pointer elem=vector_elem(vec,i); + ivalue_unchecked(cdr(sc->args))=i+1; + s_save(sc,OP_PVECFROM, sc->args, sc->NIL); + sc->args=elem; + if (i > 0) + putstr(sc," "); + s_goto(sc,OP_P0LIST); + } + } + + default: + snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op); + Error_0(sc,sc->strbuff); + + } + return sc->T; +} + +static pointer opexe_6(scheme *sc, enum scheme_opcodes op) { + pointer x, y; + long v; + + switch (op) { + case OP_LIST_LENGTH: /* length */ /* a.k */ + v=list_length(sc,car(sc->args)); + if(v<0) { + Error_1(sc,"length: not a list:",car(sc->args)); + } + s_return(sc,mk_integer(sc, v)); + + case OP_ASSQ: /* assq */ /* a.k */ + x = car(sc->args); + for (y = cadr(sc->args); is_pair(y); y = cdr(y)) { + if (!is_pair(car(y))) { + Error_0(sc,"unable to handle non pair element"); + } + if (x == caar(y)) + break; + } + if (is_pair(y)) { + s_return(sc,car(y)); + } else { + s_return(sc,sc->F); + } + + + case OP_GET_CLOSURE: /* get-closure-code */ /* a.k */ + sc->args = car(sc->args); + if (sc->args == sc->NIL) { + s_return(sc,sc->F); + } else if (is_closure(sc->args)) { + s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value))); + } else if (is_macro(sc->args)) { + s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value))); + } else { + s_return(sc,sc->F); + } + case OP_CLOSUREP: /* closure? */ + /* + * Note, macro object is also a closure. + * Therefore, (closure? <#MACRO>) ==> #t + */ + s_retbool(is_closure(car(sc->args))); + case OP_MACROP: /* macro? */ + s_retbool(is_macro(car(sc->args))); + default: + snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op); + Error_0(sc,sc->strbuff); + } + return sc->T; /* NOTREACHED */ +} + +typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes); + +typedef int (*test_predicate)(pointer); +static int is_any(pointer p) { return 1;} + +static int is_nonneg(pointer p) { + return ivalue(p)>=0 && is_integer(p); +} + +/* Correspond carefully with following defines! */ +static struct { + test_predicate fct; + const char *kind; +} tests[]={ + {0,0}, /* unused */ + {is_any, 0}, + {is_string, "string"}, + {is_symbol, "symbol"}, + {is_port, "port"}, + {is_inport,"input port"}, + {is_outport,"output port"}, + {is_environment, "environment"}, + {is_pair, "pair"}, + {0, "pair or '()"}, + {is_character, "character"}, + {is_vector, "vector"}, + {is_number, "number"}, + {is_integer, "integer"}, + {is_nonneg, "non-negative integer"} +}; + +#define TST_NONE 0 +#define TST_ANY "\001" +#define TST_STRING "\002" +#define TST_SYMBOL "\003" +#define TST_PORT "\004" +#define TST_INPORT "\005" +#define TST_OUTPORT "\006" +#define TST_ENVIRONMENT "\007" +#define TST_PAIR "\010" +#define TST_LIST "\011" +#define TST_CHAR "\012" +#define TST_VECTOR "\013" +#define TST_NUMBER "\014" +#define TST_INTEGER "\015" +#define TST_NATURAL "\016" + +typedef struct { + dispatch_func func; + char *name; + int min_arity; + int max_arity; + char *arg_tests_encoding; +} op_code_info; + +#define INF_ARG 0xffff + +static op_code_info dispatch_table[]= { +#define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E}, +#include "opdefines.h" + { 0 } +}; + +static const char *procname(pointer x) { + int n=procnum(x); + const char *name=dispatch_table[n].name; + if(name==0) { + name="ILLEGAL!"; + } + return name; +} + +/* kernel of this interpreter */ +static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) { + sc->op = op; + for (;;) { + op_code_info *pcd=dispatch_table+sc->op; + if (pcd->name!=0) { /* if built-in function, check arguments */ + char msg[STRBUFFSIZE]; + int ok=1; + int n=list_length(sc,sc->args); + + /* Check number of arguments */ + if(nmin_arity) { + ok=0; + snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)", + pcd->name, + pcd->min_arity==pcd->max_arity?"":" at least", + pcd->min_arity); + } + if(ok && n>pcd->max_arity) { + ok=0; + snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)", + pcd->name, + pcd->min_arity==pcd->max_arity?"":" at most", + pcd->max_arity); + } + if(ok) { + if(pcd->arg_tests_encoding!=0) { + int i=0; + int j; + const char *t=pcd->arg_tests_encoding; + pointer arglist=sc->args; + do { + pointer arg=car(arglist); + j=(int)t[0]; + if(j==TST_LIST[0]) { + if(arg!=sc->NIL && !is_pair(arg)) break; + } else { + if(!tests[j].fct(arg)) break; + } + + if(t[1]!=0) {/* last test is replicated as necessary */ + t++; + } + arglist=cdr(arglist); + i++; + } while(iname, + i+1, + tests[j].kind); + } + } + } + if(!ok) { + if(_Error_1(sc,msg,0)==sc->NIL) { + return; + } + pcd=dispatch_table+sc->op; + } + } + ok_to_freely_gc(sc); + if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) { + return; + } + if(sc->no_memory) { + fprintf(stderr,"No memory!\n"); + return; + } + } +} + +/* ========== Initialization of internal keywords ========== */ + +static void assign_syntax(scheme *sc, char *name) { + pointer x; + + x = oblist_add_by_name(sc, name); + typeflag(x) |= T_SYNTAX; +} + +static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) { + pointer x, y; + + x = mk_symbol(sc, name); + y = mk_proc(sc,op); + new_slot_in_env(sc, x, y); +} + +static pointer mk_proc(scheme *sc, enum scheme_opcodes op) { + pointer y; + + y = get_cell(sc, sc->NIL, sc->NIL); + typeflag(y) = (T_PROC | T_ATOM); + ivalue_unchecked(y) = (long) op; + set_num_integer(y); + return y; +} + +/* Hard-coded for the given keywords. Remember to rewrite if more are added! */ +static int syntaxnum(pointer p) { + const char *s=strvalue(car(p)); + switch(strlength(car(p))) { + case 2: + if(s[0]=='i') return OP_IF0; /* if */ + else return OP_OR0; /* or */ + case 3: + if(s[0]=='a') return OP_AND0; /* and */ + else return OP_LET0; /* let */ + case 4: + switch(s[3]) { + case 'e': return OP_CASE0; /* case */ + case 'd': return OP_COND0; /* cond */ + case '*': return OP_LET0AST; /* let* */ + default: return OP_SET0; /* set! */ + } + case 5: + switch(s[2]) { + case 'g': return OP_BEGIN; /* begin */ + case 'l': return OP_DELAY; /* delay */ + case 'c': return OP_MACRO0; /* macro */ + default: return OP_QUOTE; /* quote */ + } + case 6: + switch(s[2]) { + case 'm': return OP_LAMBDA; /* lambda */ + case 'f': return OP_DEF0; /* define */ + default: return OP_LET0REC; /* letrec */ + } + default: + return OP_C0STREAM; /* cons-stream */ + } +} + +/* initialization of TinyScheme */ +#if USE_INTERFACE +INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) { + return cons(sc,a,b); +} +INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) { + return immutable_cons(sc,a,b); +} + +static struct scheme_interface vtbl ={ + scheme_define, + s_cons, + s_immutable_cons, + reserve_cells, + mk_integer, + mk_real, + mk_symbol, + gensym, + mk_string, + mk_counted_string, + mk_character, + mk_vector, + mk_foreign_func, + putstr, + putcharacter, + + is_string, + string_value, + is_number, + nvalue, + ivalue, + rvalue, + is_integer, + is_real, + is_character, + charvalue, + is_list, + is_vector, + list_length, + ivalue, + fill_vector, + vector_elem, + set_vector_elem, + is_port, + is_pair, + pair_car, + pair_cdr, + set_car, + set_cdr, + + is_symbol, + symname, + + is_syntax, + is_proc, + is_foreign, + syntaxname, + is_closure, + is_macro, + closure_code, + closure_env, + + is_continuation, + is_promise, + is_environment, + is_immutable, + setimmutable, + + scheme_load_file, + scheme_load_string +}; +#endif + +scheme *scheme_init_new() { + scheme *sc=(scheme*)malloc(sizeof(scheme)); + if(!scheme_init(sc)) { + free(sc); + return 0; + } else { + return sc; + } +} + +scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) { + scheme *sc=(scheme*)malloc(sizeof(scheme)); + if(!scheme_init_custom_alloc(sc,malloc,free)) { + free(sc); + return 0; + } else { + return sc; + } +} + + +int scheme_init(scheme *sc) { + return scheme_init_custom_alloc(sc,malloc,free); +} + +int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) { + int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]); + pointer x; + + num_zero.is_fixnum=1; + num_zero.value.ivalue=0; + num_one.is_fixnum=1; + num_one.value.ivalue=1; + +#if USE_INTERFACE + sc->vptr=&vtbl; +#endif + sc->gensym_cnt=0; + sc->malloc=malloc; + sc->free=free; + sc->last_cell_seg = -1; + sc->sink = &sc->_sink; + sc->NIL = &sc->_NIL; + sc->T = &sc->_HASHT; + sc->F = &sc->_HASHF; + sc->EOF_OBJ=&sc->_EOF_OBJ; + sc->free_cell = &sc->_NIL; + sc->fcells = 0; + sc->no_memory=0; + sc->inport=sc->NIL; + sc->outport=sc->NIL; + sc->save_inport=sc->NIL; + sc->loadport=sc->NIL; + sc->nesting=0; + sc->interactive_repl=0; + + if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) { + sc->no_memory=1; + return 0; + } + sc->gc_verbose = 0; + dump_stack_initialize(sc); + sc->code = sc->NIL; + sc->tracing=0; + + /* init sc->NIL */ + typeflag(sc->NIL) = (T_ATOM | MARK); + car(sc->NIL) = cdr(sc->NIL) = sc->NIL; + /* init T */ + typeflag(sc->T) = (T_ATOM | MARK); + car(sc->T) = cdr(sc->T) = sc->T; + /* init F */ + typeflag(sc->F) = (T_ATOM | MARK); + car(sc->F) = cdr(sc->F) = sc->F; + /* init sink */ + typeflag(sc->sink) = (T_PAIR | MARK); + car(sc->sink) = sc->NIL; + /* init c_nest */ + sc->c_nest = sc->NIL; + + sc->oblist = oblist_initial_value(sc); + /* init global_env */ + new_frame_in_env(sc, sc->NIL); + sc->global_env = sc->envir; + /* init else */ + x = mk_symbol(sc,"else"); + new_slot_in_env(sc, x, sc->T); + + assign_syntax(sc, "lambda"); + assign_syntax(sc, "quote"); + assign_syntax(sc, "define"); + assign_syntax(sc, "if"); + assign_syntax(sc, "begin"); + assign_syntax(sc, "set!"); + assign_syntax(sc, "let"); + assign_syntax(sc, "let*"); + assign_syntax(sc, "letrec"); + assign_syntax(sc, "cond"); + assign_syntax(sc, "delay"); + assign_syntax(sc, "and"); + assign_syntax(sc, "or"); + assign_syntax(sc, "cons-stream"); + assign_syntax(sc, "macro"); + assign_syntax(sc, "case"); + + for(i=0; iLAMBDA = mk_symbol(sc, "lambda"); + sc->QUOTE = mk_symbol(sc, "quote"); + sc->QQUOTE = mk_symbol(sc, "quasiquote"); + sc->UNQUOTE = mk_symbol(sc, "unquote"); + sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing"); + sc->FEED_TO = mk_symbol(sc, "=>"); + sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*"); + sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*"); + sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*"); + sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*"); + + return !sc->no_memory; +} + +void scheme_set_input_port_file(scheme *sc, FILE *fin) { + sc->inport=port_from_file(sc,fin,port_input); +} + +void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) { + sc->inport=port_from_string(sc,start,past_the_end,port_input); +} + +void scheme_set_output_port_file(scheme *sc, FILE *fout) { + sc->outport=port_from_file(sc,fout,port_output); +} + +void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) { + sc->outport=port_from_string(sc,start,past_the_end,port_output); +} + +void scheme_set_external_data(scheme *sc, void *p) { + sc->ext_data=p; +} + +void scheme_deinit(scheme *sc) { + int i; + +#if SHOW_ERROR_LINE + char *fname; +#endif + + sc->oblist=sc->NIL; + sc->global_env=sc->NIL; + dump_stack_free(sc); + sc->envir=sc->NIL; + sc->code=sc->NIL; + sc->args=sc->NIL; + sc->value=sc->NIL; + if(is_port(sc->inport)) { + typeflag(sc->inport) = T_ATOM; + } + sc->inport=sc->NIL; + sc->outport=sc->NIL; + if(is_port(sc->save_inport)) { + typeflag(sc->save_inport) = T_ATOM; + } + sc->save_inport=sc->NIL; + if(is_port(sc->loadport)) { + typeflag(sc->loadport) = T_ATOM; + } + sc->loadport=sc->NIL; + sc->gc_verbose=0; + gc(sc,sc->NIL,sc->NIL); + + for(i=0; i<=sc->last_cell_seg; i++) { + sc->free(sc->alloc_seg[i]); + } + +#if SHOW_ERROR_LINE + for(i=0; i<=sc->file_i; i++) { + if (sc->load_stack[i].kind & port_file) { + fname = sc->load_stack[i].rep.stdio.filename; + if(fname) + sc->free(fname); + } + } +#endif +} + +void scheme_load_file(scheme *sc, FILE *fin) +{ scheme_load_named_file(sc,fin,0); } + +void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) { + dump_stack_reset(sc); + sc->envir = sc->global_env; + sc->file_i=0; + sc->load_stack[0].kind=port_input|port_file; + sc->load_stack[0].rep.stdio.file=fin; + sc->loadport=mk_port(sc,sc->load_stack); + sc->retcode=0; + if(fin==stdin) { + sc->interactive_repl=1; + } + +#if SHOW_ERROR_LINE + sc->load_stack[0].rep.stdio.curr_line = 0; + if(fin!=stdin && filename) + sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0); +#endif + + sc->inport=sc->loadport; + sc->args = mk_integer(sc,sc->file_i); + Eval_Cycle(sc, OP_T0LVL); + typeflag(sc->loadport)=T_ATOM; + if(sc->retcode==0) { + sc->retcode=sc->nesting!=0; + } +} + +void scheme_load_string(scheme *sc, const char *cmd) { + dump_stack_reset(sc); + sc->envir = sc->global_env; + sc->file_i=0; + sc->load_stack[0].kind=port_input|port_string; + sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */ + sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd); + sc->load_stack[0].rep.string.curr=(char*)cmd; + sc->loadport=mk_port(sc,sc->load_stack); + sc->retcode=0; + sc->interactive_repl=0; + sc->inport=sc->loadport; + sc->args = mk_integer(sc,sc->file_i); + Eval_Cycle(sc, OP_T0LVL); + typeflag(sc->loadport)=T_ATOM; + if(sc->retcode==0) { + sc->retcode=sc->nesting!=0; + } +} + +void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) { + pointer x; + + x=find_slot_in_env(sc,envir,symbol,0); + if (x != sc->NIL) { + set_slot_in_env(sc, x, value); + } else { + new_slot_spec_in_env(sc, envir, symbol, value); + } +} + +#if !STANDALONE +void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr) +{ + scheme_define(sc, + sc->global_env, + mk_symbol(sc,sr->name), + mk_foreign_func(sc, sr->f)); +} + +void scheme_register_foreign_func_list(scheme * sc, + scheme_registerable * list, + int count) +{ + int i; + for(i = 0; i < count; i++) + { + scheme_register_foreign_func(sc, list + i); + } +} + +pointer scheme_apply0(scheme *sc, const char *procname) +{ return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); } + +void save_from_C_call(scheme *sc) +{ + pointer saved_data = + cons(sc, + car(sc->sink), + cons(sc, + sc->envir, + sc->dump)); + /* Push */ + sc->c_nest = cons(sc, saved_data, sc->c_nest); + /* Truncate the dump stack so TS will return here when done, not + directly resume pre-C-call operations. */ + dump_stack_reset(sc); +} +void restore_from_C_call(scheme *sc) +{ + car(sc->sink) = caar(sc->c_nest); + sc->envir = cadar(sc->c_nest); + sc->dump = cdr(cdar(sc->c_nest)); + /* Pop */ + sc->c_nest = cdr(sc->c_nest); +} + +/* "func" and "args" are assumed to be already eval'ed. */ +pointer scheme_call(scheme *sc, pointer func, pointer args) +{ + int old_repl = sc->interactive_repl; + sc->interactive_repl = 0; + save_from_C_call(sc); + sc->envir = sc->global_env; + sc->args = args; + sc->code = func; + sc->retcode = 0; + Eval_Cycle(sc, OP_APPLY); + sc->interactive_repl = old_repl; + restore_from_C_call(sc); + return sc->value; +} + +pointer scheme_eval(scheme *sc, pointer obj) +{ + int old_repl = sc->interactive_repl; + sc->interactive_repl = 0; + save_from_C_call(sc); + sc->args = sc->NIL; + sc->code = obj; + sc->retcode = 0; + Eval_Cycle(sc, OP_EVAL); + sc->interactive_repl = old_repl; + restore_from_C_call(sc); + return sc->value; +} + + +#endif + +/* ========== Main ========== */ + +#if STANDALONE + +#if defined(__APPLE__) && !defined (OSX) +int main() +{ + extern MacTS_main(int argc, char **argv); + char** argv; + int argc = ccommand(&argv); + MacTS_main(argc,argv); + return 0; +} +int MacTS_main(int argc, char **argv) { +#else +int main(int argc, char **argv) { +#endif + scheme sc; + FILE *fin; + char *file_name=InitFile; + int retcode; + int isfile=1; + + if(argc==1) { + printf(banner); + } + if(argc==2 && strcmp(argv[1],"-?")==0) { + printf("Usage: tinyscheme -?\n"); + printf("or: tinyscheme [ ...]\n"); + printf("followed by\n"); + printf(" -1 [ ...]\n"); + printf(" -c [ ...]\n"); + printf("assuming that the executable is named tinyscheme.\n"); + printf("Use - as filename for stdin.\n"); + return 1; + } + if(!scheme_init(&sc)) { + fprintf(stderr,"Could not initialize!\n"); + return 2; + } + scheme_set_input_port_file(&sc, stdin); + scheme_set_output_port_file(&sc, stdout); +#if USE_DL + scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext)); +#endif + argv++; + if(access(file_name,0)!=0) { + char *p=getenv("TINYSCHEMEINIT"); + if(p!=0) { + file_name=p; + } + } + do { + if(strcmp(file_name,"-")==0) { + fin=stdin; + } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) { + pointer args=sc.NIL; + isfile=file_name[1]=='1'; + file_name=*argv++; + if(strcmp(file_name,"-")==0) { + fin=stdin; + } else if(isfile) { + fin=fopen(file_name,"r"); + } + for(;*argv;argv++) { + pointer value=mk_string(&sc,*argv); + args=cons(&sc,value,args); + } + args=reverse_in_place(&sc,sc.NIL,args); + scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args); + + } else { + fin=fopen(file_name,"r"); + } + if(isfile && fin==0) { + fprintf(stderr,"Could not open file %s\n",file_name); + } else { + if(isfile) { + scheme_load_named_file(&sc,fin,file_name); + } else { + scheme_load_string(&sc,file_name); + } + if(!isfile || fin!=stdin) { + if(sc.retcode!=0) { + fprintf(stderr,"Errors encountered reading %s\n",file_name); + } + if(isfile) { + fclose(fin); + } + } + } + file_name=*argv++; + } while(file_name!=0); + if(argc==1) { + scheme_load_named_file(&sc,stdin,0); + } + retcode=sc.retcode; + scheme_deinit(&sc); + + return retcode; +} + +#endif + +/* +Local variables: +c-file-style: "k&r" +End: +*/ diff --git a/external/CppMicroServices/third_party/tinyscheme/scheme.h b/external/CppMicroServices/third_party/tinyscheme/scheme.h new file mode 100644 index 00000000..90c50a0f --- /dev/null +++ b/external/CppMicroServices/third_party/tinyscheme/scheme.h @@ -0,0 +1,259 @@ +/* SCHEME.H */ + +#ifndef _SCHEME_H +#define _SCHEME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default values for #define'd symbols + */ +#ifndef STANDALONE /* If used as standalone interpreter */ +# define STANDALONE 1 +#endif + +#ifndef _MSC_VER +# define USE_STRCASECMP 1 +# ifndef USE_STRLWR +# define USE_STRLWR 1 +# endif +# define SCHEME_EXPORT +#else +# define USE_STRCASECMP 0 +# define USE_STRLWR 0 +# ifdef _SCHEME_DLL +# ifdef _SCHEME_SOURCE +# define SCHEME_EXPORT __declspec(dllexport) +# else +# define SCHEME_EXPORT __declspec(dllimport) +# endif +# else +# define SCHEME_EXPORT +# endif +#endif + +#if USE_NO_FEATURES +# define USE_MATH 0 +# define USE_CHAR_CLASSIFIERS 0 +# define USE_ASCII_NAMES 0 +# define USE_STRING_PORTS 0 +# define USE_ERROR_HOOK 0 +# define USE_TRACING 0 +# define USE_COLON_HOOK 0 +# define USE_DL 0 +# define USE_PLIST 0 +#endif + +/* + * Leave it defined if you want continuations, and also for the Sharp Zaurus. + * Undefine it if you only care about faster speed and not strict Scheme compatibility. + */ +#define USE_SCHEME_STACK + +#if USE_DL +# define USE_INTERFACE 1 +#endif + + +#ifndef USE_MATH /* If math support is needed */ +# define USE_MATH 1 +#endif + +#ifndef USE_CHAR_CLASSIFIERS /* If char classifiers are needed */ +# define USE_CHAR_CLASSIFIERS 1 +#endif + +#ifndef USE_ASCII_NAMES /* If extended escaped characters are needed */ +# define USE_ASCII_NAMES 1 +#endif + +#ifndef USE_STRING_PORTS /* Enable string ports */ +# define USE_STRING_PORTS 1 +#endif + +#ifndef USE_TRACING +# define USE_TRACING 1 +#endif + +#ifndef USE_PLIST +# define USE_PLIST 0 +#endif + +/* To force system errors through user-defined error handling (see *error-hook*) */ +#ifndef USE_ERROR_HOOK +# define USE_ERROR_HOOK 1 +#endif + +#ifndef USE_COLON_HOOK /* Enable qualified qualifier */ +# define USE_COLON_HOOK 1 +#endif + +#ifndef USE_STRCASECMP /* stricmp for Unix */ +# define USE_STRCASECMP 0 +#endif + +#ifndef USE_STRLWR +# define USE_STRLWR 1 +#endif + +#ifndef STDIO_ADDS_CR /* Define if DOS/Windows */ +# define STDIO_ADDS_CR 0 +#endif + +#ifndef INLINE +# define INLINE +#endif + +#ifndef USE_INTERFACE +# define USE_INTERFACE 0 +#endif + +#ifndef SHOW_ERROR_LINE /* Show error line in file */ +# define SHOW_ERROR_LINE 1 +#endif + +typedef struct scheme scheme; +typedef struct cell *pointer; + +typedef void * (*func_alloc)(size_t); +typedef void (*func_dealloc)(void *); + +/* num, for generic arithmetic */ +typedef struct num { + char is_fixnum; + union { + long ivalue; + double rvalue; + } value; +} num; + +SCHEME_EXPORT scheme *scheme_init_new(); +SCHEME_EXPORT scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free); +SCHEME_EXPORT int scheme_init(scheme *sc); +SCHEME_EXPORT int scheme_init_custom_alloc(scheme *sc, func_alloc, func_dealloc); +SCHEME_EXPORT void scheme_deinit(scheme *sc); +void scheme_set_input_port_file(scheme *sc, FILE *fin); +void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end); +SCHEME_EXPORT void scheme_set_output_port_file(scheme *sc, FILE *fin); +void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end); +SCHEME_EXPORT void scheme_load_file(scheme *sc, FILE *fin); +SCHEME_EXPORT void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename); +SCHEME_EXPORT void scheme_load_string(scheme *sc, const char *cmd); +SCHEME_EXPORT pointer scheme_apply0(scheme *sc, const char *procname); +SCHEME_EXPORT pointer scheme_call(scheme *sc, pointer func, pointer args); +SCHEME_EXPORT pointer scheme_eval(scheme *sc, pointer obj); +void scheme_set_external_data(scheme *sc, void *p); +SCHEME_EXPORT void scheme_define(scheme *sc, pointer env, pointer symbol, pointer value); + +typedef pointer (*foreign_func)(scheme *, pointer); + +pointer _cons(scheme *sc, pointer a, pointer b, int immutable); +pointer mk_integer(scheme *sc, long num); +pointer mk_real(scheme *sc, double num); +pointer mk_symbol(scheme *sc, const char *name); +pointer gensym(scheme *sc); +pointer mk_string(scheme *sc, const char *str); +pointer mk_counted_string(scheme *sc, const char *str, int len); +pointer mk_empty_string(scheme *sc, int len, char fill); +pointer mk_character(scheme *sc, int c); +pointer mk_foreign_func(scheme *sc, foreign_func f); +void putstr(scheme *sc, const char *s); +int list_length(scheme *sc, pointer a); +int eqv(pointer a, pointer b); + + +#if USE_INTERFACE +struct scheme_interface { + void (*scheme_define)(scheme *sc, pointer env, pointer symbol, pointer value); + pointer (*cons)(scheme *sc, pointer a, pointer b); + pointer (*immutable_cons)(scheme *sc, pointer a, pointer b); + pointer (*reserve_cells)(scheme *sc, int n); + pointer (*mk_integer)(scheme *sc, long num); + pointer (*mk_real)(scheme *sc, double num); + pointer (*mk_symbol)(scheme *sc, const char *name); + pointer (*gensym)(scheme *sc); + pointer (*mk_string)(scheme *sc, const char *str); + pointer (*mk_counted_string)(scheme *sc, const char *str, int len); + pointer (*mk_character)(scheme *sc, int c); + pointer (*mk_vector)(scheme *sc, int len); + pointer (*mk_foreign_func)(scheme *sc, foreign_func f); + void (*putstr)(scheme *sc, const char *s); + void (*putcharacter)(scheme *sc, int c); + + int (*is_string)(pointer p); + char *(*string_value)(pointer p); + int (*is_number)(pointer p); + num (*nvalue)(pointer p); + long (*ivalue)(pointer p); + double (*rvalue)(pointer p); + int (*is_integer)(pointer p); + int (*is_real)(pointer p); + int (*is_character)(pointer p); + long (*charvalue)(pointer p); + int (*is_list)(scheme *sc, pointer p); + int (*is_vector)(pointer p); + int (*list_length)(scheme *sc, pointer vec); + long (*vector_length)(pointer vec); + void (*fill_vector)(pointer vec, pointer elem); + pointer (*vector_elem)(pointer vec, int ielem); + pointer (*set_vector_elem)(pointer vec, int ielem, pointer newel); + int (*is_port)(pointer p); + + int (*is_pair)(pointer p); + pointer (*pair_car)(pointer p); + pointer (*pair_cdr)(pointer p); + pointer (*set_car)(pointer p, pointer q); + pointer (*set_cdr)(pointer p, pointer q); + + int (*is_symbol)(pointer p); + char *(*symname)(pointer p); + + int (*is_syntax)(pointer p); + int (*is_proc)(pointer p); + int (*is_foreign)(pointer p); + char *(*syntaxname)(pointer p); + int (*is_closure)(pointer p); + int (*is_macro)(pointer p); + pointer (*closure_code)(pointer p); + pointer (*closure_env)(pointer p); + + int (*is_continuation)(pointer p); + int (*is_promise)(pointer p); + int (*is_environment)(pointer p); + int (*is_immutable)(pointer p); + void (*setimmutable)(pointer p); + void (*load_file)(scheme *sc, FILE *fin); + void (*load_string)(scheme *sc, const char *input); +}; +#endif + +#if !STANDALONE +typedef struct scheme_registerable +{ + foreign_func f; + const char * name; +} +scheme_registerable; + +void scheme_register_foreign_func_list(scheme * sc, + scheme_registerable * list, + int n); + +#endif /* !STANDALONE */ + +#ifdef __cplusplus +} +#endif + +#endif + + +/* +Local variables: +c-file-style: "k&r" +End: +*/ diff --git a/external/CppMicroServices/tools/rc/CMakeLists.txt b/external/CppMicroServices/tools/rc/CMakeLists.txt new file mode 100755 index 00000000..1e2f6632 --- /dev/null +++ b/external/CppMicroServices/tools/rc/CMakeLists.txt @@ -0,0 +1,37 @@ + +enable_language(C) + +include_directories(../../third_party) + +add_definitions(-DUS_RCC_EXECUTABLE_NAME=\"${US_RCC_EXECUTABLE_OUTPUT_NAME}\") + +set(srcs ResourceCompiler.cpp ../../third_party/miniz.c ../../third_party/jsoncpp.cpp) + +add_executable(${US_RCC_EXECUTABLE_TARGET} ${srcs}) +set_property(TARGET ${US_RCC_EXECUTABLE_TARGET} PROPERTY OUTPUT_NAME ${US_RCC_EXECUTABLE_OUTPUT_NAME}) +if(WIN32) + target_link_libraries(${US_RCC_EXECUTABLE_TARGET} Shlwapi) +endif() + +set_property(TARGET ${US_RCC_EXECUTABLE_TARGET} APPEND PROPERTY + COMPILE_DEFINITIONS "MINIZ_NO_ARCHIVE_READING_API;MINIZ_NO_ZLIB_COMPATIBLE_NAMES") + +if(NOT US_NO_INSTALL) + install(TARGETS ${US_RCC_EXECUTABLE_TARGET} + EXPORT ${PROJECT_NAME}Targets + FRAMEWORK DESTINATION . ${US_SDK_INSTALL_COMPONENT} + RUNTIME DESTINATION bin ${US_SDK_INSTALL_COMPONENT}) +endif() + +if(CMAKE_CROSSCOMPILING) + # When cross-compiling, import the host machine executable from a file + # See https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/CrossCompiling + include(${IMPORT_EXECUTABLES}) +else() + # Export the host usResourceCompiler target to a file so it can be imported when cross-compiling. + # Use the NAMESPACE option of EXPORT() to get a different target name for ${US_RCC_EXECUTABLE_TARGET} + # when exporting. + # Doing this allows the host built usResourceCompiler to be used when cross-compiling and allows + # the usResourceCompiler to be built and installed for the target machine. + export( TARGETS ${US_RCC_EXECUTABLE_TARGET} FILE ${IMPORT_EXECUTABLES} NAMESPACE native-) +endif() diff --git a/external/CppMicroServices/tools/rc/ResourceCompiler.cpp b/external/CppMicroServices/tools/rc/ResourceCompiler.cpp new file mode 100644 index 00000000..d8b4d5bd --- /dev/null +++ b/external/CppMicroServices/tools/rc/ResourceCompiler.cpp @@ -0,0 +1,939 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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 "miniz.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "optionparser.h" +#include "json/json.h" + +// --------------------------------------------------------------------------------- +// -------------------------- PLATFORM SPECIFIC CODE ------------------------- +// --------------------------------------------------------------------------------- + +#if defined(_WIN32) || defined(_WIN64) + +# define WIN32_LEAN_AND_MEAN +# define VC_EXTRALEAN +# include +# define PATH_SEPARATOR "\\" +static std::string get_error_str() +{ + // Retrieve the system error message for the last-error code + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + std::string errMsg; + DWORD rc = + FormatMessageA((FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS), + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&lpMsgBuf), + 0, + NULL); + // If FormatMessage fails using FORMAT_MESSAGE_ALLOCATE_BUFFER + // it means that the size of the error message exceeds an internal + // buffer limit (128 kb according to MSDN) and lpMsgBuf will be + // uninitialized. + // Inform the caller that the error message couldn't be retrieved. + if (rc == 0) { + errMsg = "Failed to retrieve error message."; + } else { + errMsg = reinterpret_cast(lpMsgBuf); + LocalFree(lpMsgBuf); + } + return errMsg; +} + +std::string us_tempfile() +{ + char szTempFileName[MAX_PATH]; + if (GetTempFileNameA(".", "ZIP", 1, szTempFileName) == 0) { + std::cerr << "Error: " << get_error_str() << std::endl; + exit(EXIT_FAILURE); + } + return std::string(szTempFileName); +} + +#else + +# include +# define PATH_SEPARATOR "/" +static std::string get_error_str() +{ + return strerror(errno); +} + +std::string us_tempfile() +{ + char temppath[] = "./ZIP_XXXXXX"; + if (mkstemp(temppath) == -1) { + std::cerr << "Error: " << get_error_str() << std::endl; + exit(EXIT_FAILURE); + } + return std::string(temppath); +} + +#endif + +// --------------------------------------------------------------------------------- +// ------------------------ END PLATFORM SPECIFIC CODE ------------------------ +// --------------------------------------------------------------------------------- + +namespace { + +class InvalidManifest : public std::runtime_error +{ +public: + InvalidManifest(const std::string& msg) + : std::runtime_error(msg) + {} + InvalidManifest(const char* msg) + : std::runtime_error(msg) + {} +}; + +/* + * @brief parses json content and returns the parsed json or throws. + * @tparam jsonContent json content to parse. The type must be convertible to std::istream. + * @param root The parsed Json root object. + * @throw InvalidManifest if the json is invalid. Parse error information is in the exception. + * If an exception is thrown, the root param is invalid. + */ +template +void parseAndValidateJson(T& jsonContent, Json::Value& root) +{ + Json::CharReaderBuilder rbuilder; + rbuilder["rejectDupKeys"] = true; + rbuilder["allowComments"] = false; + std::string errs; + + if (!Json::parseFromStream(rbuilder, jsonContent, &root, &errs)) { + throw InvalidManifest(errs); + } +} + +/* + * @brief parses json content from a file and returns the parsed json or throws. + * @param jsonFile path to a json file. + * @param root The parsed Json root object. + * @throw InvalidManifest if the json is invalid. Parse error information is in the exception. + * If an exception is thrown, the root param is invalid. + */ +void parseAndValidateJsonFromFile(const std::string& jsonFile, + Json::Value& root) +{ + try { + std::ifstream json(jsonFile); + if (!json.is_open()) { + throw std::runtime_error("Could not open file " + jsonFile); + } + parseAndValidateJson(json, root); + } catch (const InvalidManifest& e) { + std::string exceptionMsg(jsonFile + ": " + e.what()); + throw InvalidManifest(exceptionMsg); + } +} + +/* + * @brief extracts a manifest file from the zip archive and checks for correct JSON syntax. + * @param zipArchive miniz data structure representing the opened zip archive. + * @param archiveFileName file path of the zip archive. + * @param archiveEntry archive entry path of the manifest file. + * @throw InvalidManifest if the json is invalid. Parse error information is in the exception. + * @throw runtime_error if the manifest file could not be read from the archive. + */ +void validateManifestInArchive(mz_zip_archive* zipArchive, + const std::string& archiveFile, + const std::string& archiveEntry) +{ + void* data = mz_zip_reader_extract_file_to_heap( + zipArchive, archiveEntry.c_str(), nullptr, 0); + std::unique_ptr manifestFileContents(data, ::free); + + if (!manifestFileContents) { + throw std::runtime_error("Failed to extract " + archiveEntry + " from " + + archiveFile); + } + + try { + Json::Value root; + std::istringstream json( + reinterpret_cast(manifestFileContents.get())); + parseAndValidateJson(json, root); + } catch (const InvalidManifest& e) { + std::string exceptionMsg(archiveFile); + exceptionMsg += " (" + archiveEntry + ") : " + e.what(); + throw InvalidManifest(exceptionMsg); + } +} + +/* + * @brief Validate manifest files in an archive. + * @param archiveFile archive file path + * @throw InvalidManifest on the first invalid manifest found. + * @throw runtime_error on the first manifest file which could not be read from the archive. + */ +void validateManifestsInArchive(const std::string& archiveFile) +{ + mz_zip_archive currZipArchive; + mz_uint currZipIndex = 0; + memset(&currZipArchive, 0, sizeof(mz_zip_archive)); + std::clog << "Validating manifests in " << archiveFile << " ... " + << std::endl; + if (!mz_zip_reader_init_file(&currZipArchive, archiveFile.c_str(), 0)) { + throw std::runtime_error("Could not initialize zip archive " + archiveFile); + } + char archiveName[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + mz_uint numZipIndices = mz_zip_reader_get_num_files(&currZipArchive); + for (currZipIndex = 0; currZipIndex < numZipIndices; ++currZipIndex) { + mz_uint numBytes = mz_zip_reader_get_filename( + &currZipArchive, currZipIndex, archiveName, sizeof archiveName); + std::clog << "\tValidating: " << archiveName << " (from " << archiveFile + << ") " << std::endl; + try { + if (numBytes > 1 && archiveName[numBytes - 2] != + '/') // The last character is '\0' in the array + { + std::string archiveEntry(archiveName); + if (archiveEntry.find_first_of("/", 0) == + archiveEntry.find_last_of("/") && + std::string::npos != archiveEntry.find("/manifest.json")) { + validateManifestInArchive(&currZipArchive, archiveFile, archiveEntry); + } + } + } catch (const std::exception&) { + mz_zip_reader_end(&currZipArchive); + throw; + } + } + std::clog << "Finished validating manifest files from " << archiveName + << std::endl; + mz_zip_reader_end(&currZipArchive); +} + +/* + * @brief concatenates all manifests checking for invalid syntax and + * duplicate JSON key names. + * @param manifests a map containing manifest file paths and their content. + * @pre-condition each manifest in manifests has already been validated by jsoncpp. + * @throw InvalidManifest if the manifest has inavlid syntax or duplicate key names + * @return valid JSON content + */ +Json::Value AggregateManifestsAndValidate( + std::unordered_map& manifests) +{ + Json::Value root; + + for (auto& manifest : manifests) { + Json::Value jsonRoot(manifest.second); + Json::Value::iterator iter = jsonRoot.begin(); + for (; iter != jsonRoot.end(); ++iter) { + // concatenating all the root objects together means that + // duplicate key names only have to be checked for children of + // each root object. Any other duplicate keys would have been + // detected when validating each individual JSON file. + if (Json::Value{} == root[iter.name()]) { + root[iter.name()] = (*iter); + } else { + throw InvalidManifest(std::string("Duplicate key: '" + iter.name() + + "' found in " + manifest.first)); + } + } + } + + std::clog << "concatenated (pre-validated) json:\n" + << root.toStyledString() << std::endl; + + // Any duplicate keys would have been flagged earlier while concatenating all the manifest files. + // This is a final JSON validation which should only find JSON syntax errors caused by an error in + // concatenation. + Json::Value manifestJson; + std::istringstream json(root.toStyledString()); + parseAndValidateJson(json, manifestJson); + + std::clog << "final (validated) manifest.json:\n" + << manifestJson.toStyledString() << std::endl; + return manifestJson; +} +} + +/* + *@brief class to represent the zip archive for bundles + */ +class ZipArchive +{ +public: + ZipArchive(const std::string& archiveFileName, + int compressionLevel, + const std::string& bundleName); + virtual ~ZipArchive(); + /* + * @brief Add manifest.json to this zip archive + * @param manifest contents of the manifest to add to the zip archive + * @throw std::runtime exception if failed to add manifest.json + * @throw InvalidManifest if manifest.json is invalid + */ + void AddManifestFile(const Json::Value& manifest); + + /* + * @brief Add a file to this zip archive + * @throw std::runtime exception if failed to add the resource file + * @throw InvalidManifest if manifest.json is invalid + * @param resFileName is the path to the resource to be added + * @param isManifest indicates if the file is the bundle's manifest + */ + void AddResourceFile(const std::string& resFileName, bool isManifest = false); + + /* + * @brief Add all files from another zip archive to this zip archive + * @throw std::runtime exception if failed to add any of the resources + * @param archiveFileName is the path to the source archive + */ + void AddResourcesFromArchive(const std::string& archiveFileName); + + // Remove copy constructor and assignment + ZipArchive(const ZipArchive&) = delete; + void operator=(const ZipArchive&) = delete; + // Remove move constructor and assignment + ZipArchive(ZipArchive&&) = delete; + ZipArchive& operator=(ZipArchive&&) = delete; + +private: + /* + * @brief Add a directory entry to the zip archive + * @throw std::runtime exception if failed to add the entry + */ + void AddDirectory(const std::string& dirName); + + /* + * @brief Checks whether the archive file entry already + * exists in the zip archive. If it does, throw an exception. + * @throw std::runtime_error if the archive entry already exists. + */ + void CheckAndAddToArchivedNames(const std::string& archiveEntry); + + void PrintErrorAndExit(const std::string& errorMsg) + { + std::cerr << errorMsg << std::endl; + exit(EXIT_FAILURE); + } + + std::string fileName; + int compressionLevel; + std::string bundleName; + std::unique_ptr writeArchive; + std::set archivedNames; // list of all the file entries + std::set archivedDirs; // list of all directory entries +}; + +ZipArchive::ZipArchive(const std::string& archiveFileName, + int compressionLevel, + const std::string& bName) + : fileName(archiveFileName) + , compressionLevel(compressionLevel) + , bundleName(bName) + , writeArchive(new mz_zip_archive()) +{ + std::clog << "Initializing zip archive " << fileName << " ..." << std::endl; + // clear the contents of a outFile if it exists + std::ofstream ofile(fileName, std::ofstream::trunc); + ofile.close(); + if (!mz_zip_writer_init_file(writeArchive.get(), fileName.c_str(), 0)) { + throw std::runtime_error("Internal error, could not init new zip archive"); + } +} + +void ZipArchive::CheckAndAddToArchivedNames(const std::string& archiveEntry) +{ + std::clog << "Adding file " << archiveEntry << " ..." << std::endl; + // add the current file to the new archive + if (!archivedNames.insert(archiveEntry).second) { + throw std::runtime_error("A file already exists with the name " + + archiveEntry); + } +} + +void ZipArchive::AddManifestFile(const Json::Value& manifest) +{ + std::string styledManifestJson(manifest.toStyledString()); + std::string archiveEntry(bundleName + "/manifest.json"); + + CheckAndAddToArchivedNames(archiveEntry); + + if (MZ_FALSE == mz_zip_writer_add_mem(writeArchive.get(), + archiveEntry.c_str(), + styledManifestJson.c_str(), + styledManifestJson.size(), + compressionLevel)) { + throw std::runtime_error("Error writing manifest.json to archive " + + fileName); + } + AddDirectory(bundleName + "/"); +} + +void ZipArchive::AddResourceFile(const std::string& resFileName, + bool isManifest) +{ + std::string archiveName = resFileName; + + // This check exists solely to maintain a deprecated way of adding manifest.json + // through the --res-add option. + if (isManifest || resFileName == std::string("manifest.json")) { + Json::Value root; + parseAndValidateJsonFromFile(resFileName, root); + } + + // if it is a manifest file, we ignore the parent directory path because the + // manifest file is always placed at the root of the bundle name directory + if (isManifest && + resFileName.find_last_of(PATH_SEPARATOR) != std::string::npos) { + archiveName = + resFileName.substr(resFileName.find_last_of(PATH_SEPARATOR) + 1); + } + + std::string archiveEntry = bundleName + "/" + archiveName; + CheckAndAddToArchivedNames(archiveEntry); + + if (!mz_zip_writer_add_file(writeArchive.get(), + archiveEntry.c_str(), + resFileName.c_str(), + NULL, + 0, + compressionLevel)) { + throw std::runtime_error("Error writing file to archive"); + } + // add a directory entries for the file path + size_t lastPathSeparatorPos = archiveEntry.find("/", 0); + while (lastPathSeparatorPos != std::string::npos) { + AddDirectory(archiveEntry.substr(0, lastPathSeparatorPos + 1)); + lastPathSeparatorPos = archiveEntry.find("/", lastPathSeparatorPos + 1); + } +} + +void ZipArchive::AddDirectory(const std::string& dirName) +{ + assert(dirName[dirName.length() - 1] == '/'); + if (archivedDirs.insert(dirName).second) { + std::clog << "\t new dir entry " << dirName << std::endl; + // The directory entry does not yet exist, so add it + if (!mz_zip_writer_add_mem( + writeArchive.get(), dirName.c_str(), NULL, 0, MZ_NO_COMPRESSION)) { + throw std::runtime_error("zip add_mem error"); + } + } +} + +ZipArchive::~ZipArchive() +{ + assert(writeArchive->m_zip_mode != MZ_ZIP_MODE_INVALID); + std::clog << "Finalizing the zip archive ..." << std::endl; + std::clog << "Archive has the following files" << std::endl; + for (auto fileNameEntry : archivedNames) { + std::clog << "\t " << fileNameEntry << std::endl; + } + std::clog << "and directory entries" << std::endl; + for (auto dirEntry : archivedDirs) { + std::clog << "\t " << dirEntry << std::endl; + } + if (mz_zip_writer_finalize_archive(writeArchive.get()) == MZ_FALSE) { + PrintErrorAndExit("Failed to finalize Zip archive"); + } + // check state after finalizing the archive. + assert(writeArchive->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED); + if (mz_zip_writer_end(writeArchive.get()) == MZ_FALSE) { + PrintErrorAndExit("Failed to close Zip archive"); + } + // check state after closing the archive file. + assert(writeArchive->m_zip_mode == MZ_ZIP_MODE_INVALID); +} + +void ZipArchive::AddResourcesFromArchive(const std::string& archiveFileName) +{ + mz_zip_archive currZipArchive; + mz_uint currZipIndex = 0; + memset(&currZipArchive, 0, sizeof(mz_zip_archive)); + std::clog << "Merging zip file " << archiveFileName << " ... " << std::endl; + if (!mz_zip_reader_init_file(&currZipArchive, archiveFileName.c_str(), 0)) { + throw std::runtime_error("Could not initialize zip archive " + + archiveFileName); + } + char archiveName[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + mz_uint numZipIndices = mz_zip_reader_get_num_files(&currZipArchive); + for (currZipIndex = 0; currZipIndex < numZipIndices; ++currZipIndex) { + mz_uint numBytes = mz_zip_reader_get_filename( + &currZipArchive, currZipIndex, archiveName, sizeof archiveName); + std::clog << "\tmerging: " << archiveName << " (from " << archiveFileName + << ") " << std::endl; + try { + if (numBytes > 1) { + if (archiveName[numBytes - 2] != + '/') // The last character is '\0' in the array + { + if (!archivedNames.insert(archiveName).second) { + throw std::runtime_error("Found duplicate file with name " + + std::string(archiveName)); + } + + std::string archiveEntry(archiveName); + if (archiveEntry.find_first_of("/", 0) == + archiveEntry.find_last_of("/") && + std::string::npos != archiveEntry.find("/manifest.json")) { + validateManifestInArchive( + &currZipArchive, archiveFileName, archiveEntry); + } + + if (!mz_zip_writer_add_from_zip_reader( + writeArchive.get(), &currZipArchive, currZipIndex)) { + throw std::runtime_error("Failed to append file " + + std::string(archiveName) + + " from archive " + archiveFileName); + } + } else { + AddDirectory(std::string(archiveName)); + } + } + } catch (const std::exception&) { + mz_zip_reader_end(&currZipArchive); + throw; + } + } + std::clog << "Finished merging files from " << archiveFileName << std::endl; + mz_zip_reader_end(&currZipArchive); +} + +struct Custom_Arg : public option::Arg +{ + static void printError(const std::string& msg1, + const option::Option& opt, + const std::string& msg2) + { + std::cerr << "ERROR: " << msg1 << opt.name << msg2 << std::endl; + } + + static option::ArgStatus NonEmpty(const option::Option& option, bool msg) + { + if (option.arg != 0 && option.arg[0] != 0) { + return option::ARG_OK; + } + if (msg) { + printError("Option '", option, "' requires a non-empty argument\n"); + } + return option::ARG_ILLEGAL; + } + + static option::ArgStatus Numeric(const option::Option& option, bool msg) + { + char* endptr = nullptr; + if (option.arg != nullptr) { + errno = 0; + // the return value of strtol is misleading since 0 indicates failure and + // we support 0 as a valid command line option argument. Checking errno + // is the correct way to determine if the argument is valid. + long ret = strtol(option.arg, &endptr, 10); + (void)ret; + if (errno != ERANGE) { + errno = 0; + assert(endptr != nullptr); + return option::ARG_OK; + } + } + + if (msg) { + printError("Option '", option, "' requires a numeric argument\n"); + } + return option::ARG_ILLEGAL; + } +}; + +// $TODO We need to get the executable name at runtime +#define US_PROG_NAME "usResourceCompiler3" + +enum OptionIndex +{ + UNKNOWN, + HELP, + VERBOSE, + BUNDLENAME, + COMPRESSIONLEVEL, + OUTFILE, + RESADD, + ZIPADD, + MANIFESTADD, + BUNDLEFILE +}; + +const option::Descriptor usage[] = { + { UNKNOWN, + 0, + "", + "", + Custom_Arg::None, + "\nUSAGE: " US_PROG_NAME " [options]\n\n" + "Options:" }, + { HELP, + 0, + "h", + "help", + Custom_Arg::None, + " --help, -h \tPrint usage and exit." }, + { VERBOSE, + 0, + "V", + "verbose", + Custom_Arg::None, + " --verbose, -V \tRun in verbose mode." }, + { BUNDLENAME, + 0, + "n", + "bundle-name", + Custom_Arg::NonEmpty, + " --bundle-name, -n \tThe bundle name as specified in the US_BUNDLE_NAME " + "compile definition." }, + { COMPRESSIONLEVEL, + 0, + "c", + "compression-level", + Custom_Arg::Numeric, + " --compression-level, -c \tCompression level used for zip. Value range " + "is 0 to 9. Default value is 6." }, + { OUTFILE, + 0, + "o", + "out-file", + Custom_Arg::NonEmpty, + " --out-file, -o \tPath to output zip file. If the file exists it will be " + "overwritten. If this option is not provided, a temporary zip fie will be " + "created." }, + { RESADD, + 0, + "r", + "res-add", + Custom_Arg::NonEmpty, + " --res-add, -r \tPath to a resource file, relative to the current working " + "directory." }, + { ZIPADD, + 0, + "z", + "zip-add", + Custom_Arg::NonEmpty, + " --zip-add, -z \tPath to a file containing a zip archive to be merged " + "into the output zip file. " }, + { MANIFESTADD, + 0, + "m", + "manifest-add", + Custom_Arg::NonEmpty, + " --manifest-add, -m \tPath to a bundle manifest file. Multiple bundle " + "manifests will be concatenated together into one." }, + { BUNDLEFILE, + 0, + "b", + "bundle-file", + Custom_Arg::NonEmpty, + " --bundle-file, -b \tPath to the bundle binary. The resources zip file " + "will be appended to this binary. " }, + { UNKNOWN, + 0, + "", + "", + Custom_Arg::None, + "\nNote:\n1. Only options --res-add and --zip-add can be specified " + "multiple times." }, + { UNKNOWN, + 0, + "", + "", + Custom_Arg::None, + "\n2. If option --manifest-add or --res-add is specified, option " + "--bundle-name must be provided." }, + { UNKNOWN, + 0, + "", + "", + Custom_Arg::None, + "\n3. At-least one of --bundle-file or --out-file options must be " + "provided." }, + { UNKNOWN, + 0, + "", + "", + Custom_Arg::None, + "\nExamples:\n\nCreate a zip file with resources:\n" + " " US_PROG_NAME + " --compression-level 9 --verbose --bundle-name mybundle --out-file " + "Example.zip --manifest-add manifest.json --zip-add filetomerge.zip\n" + "Behavior: Construct a zip blob with contents 'mybundle/manifest.json', " + "merge the contents of zip file 'filetomerge.zip' into it and write the " + "resulting blob into 'Example.zip'\n" }, + { UNKNOWN, + 0, + "", + "", + Custom_Arg::None, + "\nAppend a bundle with resources\n" + " " US_PROG_NAME + " -V -n mybundle -b mybundle.dylib -m manifest.json -z archivetomerge.zip\n" + "Behavior: Construct a zip blob with contents 'mybundle/manifest.json', " + "merge the contents of zip file 'archivetomerge.zip' into it and append " + "the resulting zip blob to 'mybundle.dylib'\n" }, + { UNKNOWN, + 0, + "", + "", + Custom_Arg::None, + "\nAppend a bundle binary with existing zip file\n" + " " US_PROG_NAME ".exe -b mybundle.dll -z archivetoembed.zip\n" + "Behavior: Append the contents of 'archivetoembed.zip' to " + "'mybundle.dll'\n" }, + { 0, 0, 0, 0, 0, 0 } +}; + +// Check invalid invocations and errors +static int checkSanity(option::Parser& parse, option::Option* options) +{ + int return_code = EXIT_SUCCESS; + + // Check if parsing command line resulted in a failure + if (parse.error()) { + std::cerr << "Parsing command line arguments failed. " << std::endl; + return_code = EXIT_FAILURE; + } + + // Check for unrecognized options + if (parse.nonOptionsCount()) { + std::clog << "unrecognized options ..." << std::endl; + for (int i = 0; i < parse.nonOptionsCount(); ++i) { + std::cout << "\t" << parse.nonOption(i) << std::endl; + } + return_code = EXIT_FAILURE; + } + + // Multiple specifications of the following arguments are illegal + auto check_multiple_args = + [&options, &return_code](std::initializer_list optionIndices) { + for (auto optionidx : optionIndices) { + option::Option* opt = options[optionidx]; + if (opt && opt->count() > 1) { + std::cerr << opt->name; + std::cerr << " appears multiple times in the arguments. Check usage." + << std::endl; + return_code = EXIT_FAILURE; + } + } + }; + check_multiple_args({ BUNDLEFILE, OUTFILE, BUNDLENAME }); + + // At-least one of --bundle-file or --out-file is required. + if (!options[BUNDLEFILE] && !options[OUTFILE]) { + std::cerr << "At least one of the options (--bundle-file | --out-file) is " + "required. Check usage." + << std::endl; + return_code = EXIT_FAILURE; + } + + // If either --manifest-add or --res-add is given, --bundle-name must also be given. + if ((options[MANIFESTADD] || options[RESADD]) && !options[BUNDLENAME]) { + std::cerr << "If either --manifest-add or --res-add is provided, " + "--bundle-name must be provided." + << std::endl; + return_code = EXIT_FAILURE; + } + + // Generate a warning that --bundle-name is not necessary in following invocation. + if (options[BUNDLENAME] && !options[MANIFESTADD] && !options[RESADD] && + return_code != EXIT_FAILURE) { + std::clog << "Warning: --bundle-name option is unnecessary here." + << std::endl; + } + + return return_code; +} + +// --------------------------------------------------------------------------------- +// ----------------------------- MAIN ENTRY POINT ---------------------------- +// --------------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + const int BUNDLE_MANIFEST_VALIDATION_ERROR_CODE(2); + + int compressionLevel = MZ_DEFAULT_LEVEL; //default compression level; + int return_code = EXIT_SUCCESS; + std::string bundleName; + + argc -= (argc > 0); + argv += (argc > 0); // skip program name argv[0] + option::Stats stats(usage, argc, argv); + std::unique_ptr options( + new option::Option[stats.options_max]); + std::unique_ptr buffer( + new option::Option[stats.buffer_max]); + option::Parser parse(true, usage, argc, argv, options.get(), buffer.get()); + + if (argc == 0 || options[HELP]) { + option::printUsage(std::clog, usage); + return return_code; + } + + return_code = checkSanity(parse, options.get()); + if (return_code == EXIT_FAILURE) { + return return_code; + } + + if (options[BUNDLENAME]) { + bundleName = options[BUNDLENAME].arg; + } + + if (!options[VERBOSE]) { + // if not in verbose mode, supress the clog stream + std::clog.setstate(std::ios_base::failbit); + } + + if (options[COMPRESSIONLEVEL]) { + char* endptr = nullptr; + compressionLevel = strtol(options[COMPRESSIONLEVEL].arg, &endptr, 10); + } + std::clog << "using compression level " << compressionLevel << std::endl; + + std::string zipFile; + bool deleteTempFile = false; + + option::Option* bundleFileOpt = options[BUNDLEFILE]; + option::Option* outFileOpt = options[OUTFILE]; + + try { + // Append mode only works with one zip-add argument. + if (!options[RESADD] && !options[MANIFESTADD] && + options[ZIPADD].count() == 1 && options[BUNDLEFILE]) { + // jump to append part. + zipFile = options[ZIPADD].arg; + } else { + if (outFileOpt) { + zipFile = outFileOpt->arg; + } else { + zipFile = us_tempfile(); + deleteTempFile = true; + } + + std::unique_ptr zipArchive( + new ZipArchive(zipFile, compressionLevel, bundleName)); + + // map of manifest file to its JSON data + std::unordered_map manifests; + + // Add the manifest file to zip archive + if (options[MANIFESTADD]) { + for (option::Option* opt = options[MANIFESTADD]; opt; + opt = opt->next()) { + Json::Value manifest; + parseAndValidateJsonFromFile(std::string(opt->arg), manifest); + bool result; + std::tie(std::ignore, result) = + manifests.insert(std::make_pair(opt->arg, manifest)); + if (!result) { + std::clog << "Skipping duplicate manifest file " << opt->arg + << std::endl; + } + } + + // concatenate all manifest files into one, validate it and add it to the zip archive. + zipArchive->AddManifestFile(AggregateManifestsAndValidate(manifests)); + } + // Add resource files to the zip archive + for (option::Option* resopt = options[RESADD]; resopt; + resopt = resopt->next()) { + zipArchive->AddResourceFile(resopt->arg); + } + // Merge resources from supplied zip archives + for (option::Option* opt = options[ZIPADD]; opt; opt = opt->next()) { + zipArchive->AddResourcesFromArchive(opt->arg); + } + } + // --------------------------------------------------------------------------------- + // APPEND ZIP to BINARY if bundle-file is specified + // --------------------------------------------------------------------------------- + if (bundleFileOpt) { + validateManifestsInArchive(zipFile); + std::string bundleBinaryFile(bundleFileOpt->arg); + std::ofstream outFileStream( + bundleBinaryFile, std::ios::ate | std::ios::binary | std::ios::app); + std::ifstream zipFileStream(zipFile, std::ios::in | std::ios::binary); + if (outFileStream.is_open() && zipFileStream.is_open()) { + std::clog << "Appending file " << bundleBinaryFile + << " with contents of resources zip file at " << zipFile + << std::endl; + std::clog << " Initial file size : " << outFileStream.tellp() + << std::endl; + outFileStream << zipFileStream.rdbuf(); + std::clog << " Final file size : " << outFileStream.tellp() + << std::endl; + // Depending on the ofstream destructor to close the file may result in a silent + // file write error. Hence the explicit call to close. + outFileStream.close(); + if (outFileStream.rdstate() & std::ofstream::failbit) { + std::cerr << "Failed to write file : " << bundleBinaryFile + << std::endl; + return_code = EXIT_FAILURE; + } + } else { + std::cerr << "Opening file " + << (outFileStream.is_open() ? zipFile : bundleBinaryFile) + << " failed" << std::endl; + return_code = EXIT_FAILURE; + } + } + } catch (const InvalidManifest& ex) { + std::cerr << "JSON Parsing Error: " << ex.what() << std::endl; + return_code = BUNDLE_MANIFEST_VALIDATION_ERROR_CODE; + } catch (const std::exception& ex) { + std::cerr << "Error: " << ex.what() << std::endl; + return_code = EXIT_FAILURE; + } + + // delete temporary file and report error on failure + if (deleteTempFile && (std::remove(zipFile.c_str()) != 0)) { + std::cerr << "Error removing temporary zip archive " << zipFile + << std::endl; + return_code = EXIT_FAILURE; + } + + // clear the failbit set by us + if (!options[VERBOSE]) { + std::clog.clear(); + } + + return return_code; +} diff --git a/external/CppMicroServices/util/CMakeLists.txt b/external/CppMicroServices/util/CMakeLists.txt new file mode 100644 index 00000000..5e68e3cc --- /dev/null +++ b/external/CppMicroServices/util/CMakeLists.txt @@ -0,0 +1,19 @@ +add_library(util OBJECT + include/cppmicroservices/util/Error.h + include/cppmicroservices/util/FileSystem.h + include/cppmicroservices/util/String.h + + src/Error.cpp + src/FileSystem.cpp + src/String.cpp +) + +set_property(TARGET util PROPERTY POSITION_INDEPENDENT_CODE 1) + +target_include_directories(util + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE + ${CMAKE_SOURCE_DIR}/third_party + ${CMAKE_BINARY_DIR}/include +) diff --git a/external/CppMicroServices/util/include/cppmicroservices/util/Error.h b/external/CppMicroServices/util/include/cppmicroservices/util/Error.h new file mode 100644 index 00000000..c6e071bf --- /dev/null +++ b/external/CppMicroServices/util/include/cppmicroservices/util/Error.h @@ -0,0 +1,46 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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. + +=============================================================================*/ + +#ifndef CPPMICROSERVICES_UTIL_ERROR_H +#define CPPMICROSERVICES_UTIL_ERROR_H + +#include + +#include +#include + +namespace cppmicroservices { + +namespace util { + +std::string GetLastCErrorStr(); +#ifdef US_PLATFORM_WINDOWS +std::string GetLastWin32ErrorStr(); +#endif + +std::string GetExceptionStr(const std::exception_ptr& exc); +std::string GetLastExceptionStr(); + +} // namespace util +} // namespace cppmicroservices + +#endif // CPPMICROSERVICES_UTIL_ERROR_H diff --git a/external/CppMicroServices/util/include/cppmicroservices/util/FileSystem.h b/external/CppMicroServices/util/include/cppmicroservices/util/FileSystem.h new file mode 100644 index 00000000..e9f0fede --- /dev/null +++ b/external/CppMicroServices/util/include/cppmicroservices/util/FileSystem.h @@ -0,0 +1,60 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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. + +=============================================================================*/ + +#ifndef CPPMICROSERVICES_UTIL_FILESYSTEM_H +#define CPPMICROSERVICES_UTIL_FILESYSTEM_H + +#include + +namespace cppmicroservices { + +namespace util { + +const char DIR_SEP_WIN32 = '\\'; +const char DIR_SEP_POSIX = '/'; + +extern const char DIR_SEP; + +// Get the path of the calling executable. +// Throws std::runtime_error if the path cannot be +// determined. +std::string GetExecutablePath(); + +// Platform agnostic way to get the current working directory. +// Supports Linux, Mac, and Windows. +std::string GetCurrentWorkingDirectory(); +bool Exists(const std::string& path); + +bool IsDirectory(const std::string& path); +bool IsFile(const std::string& path); +bool IsRelative(const std::string& path); + +std::string GetAbsolute(const std::string& path, const std::string& base); + +void MakePath(const std::string& path); + +void RemoveDirectoryRecursive(const std::string& path); + +} // namespace util +} // namespace cppmicroservices + +#endif // CPPMICROSERVICES_UTIL_FILESYSTEM_H diff --git a/external/CppMicroServices/util/include/cppmicroservices/util/String.h b/external/CppMicroServices/util/include/cppmicroservices/util/String.h new file mode 100644 index 00000000..71937468 --- /dev/null +++ b/external/CppMicroServices/util/include/cppmicroservices/util/String.h @@ -0,0 +1,74 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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. + +=============================================================================*/ + +#ifndef CPPMICROSERVICES_UTIL_STRING_H +#define CPPMICROSERVICES_UTIL_STRING_H + +#include + +#if defined(__ANDROID__) +# include +#endif + +namespace cppmicroservices { + +namespace util { + +//------------------------------------------------------------------- +// Android Compatibility functions +//------------------------------------------------------------------- + +/** + * Compatibility functions to replace "std::to_string(...)" functions + * on Android, since the latest Android NDKs lack "std::to_string(...)" + * support. + */ + +template +std::string ToString(T val) +{ +#if defined(__ANDROID__) + std::ostringstream os; + os << val; + return os.str(); +#else + return std::to_string(val); +#endif +} + +//------------------------------------------------------------------- +// Unicode Utility functions +//------------------------------------------------------------------- + +#ifdef US_PLATFORM_WINDOWS +// method to convert UTF8 std::string to std::wstring +// throws std::invalid_argument if input string contains invalid UTF8 characters +std::wstring ToWString(const std::string& inStr); +// method to convert a std::wstring to UTF8 std::string +// throws std::invalid_argument if input string cannot be converted to UTF8 +std::string ToUTF8String(const std::wstring& inWStr); +#endif + +} // namespace util +} // namespace cppmicroservices + +#endif // CPPMICROSERVICES_UTIL_STRING_H diff --git a/external/CppMicroServices/util/src/Error.cpp b/external/CppMicroServices/util/src/Error.cpp new file mode 100644 index 00000000..6e1feef3 --- /dev/null +++ b/external/CppMicroServices/util/src/Error.cpp @@ -0,0 +1,127 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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 "cppmicroservices/util/Error.h" +#include "cppmicroservices/util/String.h" + +#ifdef US_PLATFORM_POSIX +# include +# include + +#else +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +#endif + +namespace cppmicroservices { + +namespace util { + +#ifdef US_PLATFORM_WINDOWS +std::string GetLastWin32ErrorStr() +{ + // Retrieve the system error message for the last-error code + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + + DWORD rc = + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&lpMsgBuf), + 0, + NULL); + + // If FormatMessage fails using FORMAT_MESSAGE_ALLOCATE_BUFFER + // it means that the size of the error message exceeds an internal + // buffer limit (128 kb according to MSDN) and lpMsgBuf will be + // uninitialized. + // Inform the caller that the error message couldn't be retrieved. + if (rc == 0) { + return std::string("Failed to retrieve error message."); + } + + std::string errMsg( + ToUTF8String(std::wstring(reinterpret_cast(lpMsgBuf)))); + + LocalFree(lpMsgBuf); + return errMsg; +} +#endif + +std::string GetLastCErrorStr() +{ + char errorString[128]; +#if ((_POSIX_C_SOURCE >= 200112L) && !_GNU_SOURCE) || defined(US_PLATFORM_APPLE) + // This is the XSI strerror_r version + int en = errno; + int r = strerror_r(errno, errorString, sizeof errorString); + if (r) { + std::string errMsg = "Unknown error " + util::ToString(en) + + ": strerror_r failed with error code "; + if (r < 0) { + errMsg += util::ToString(static_cast(errno)); + } else { + errMsg += util::ToString(r); + } + return errMsg; + } + return errorString; +#elif defined(US_PLATFORM_WINDOWS) + if (strerror_s(errorString, sizeof errorString, errno)) { + return "Unknown error"; + } + return errorString; +#else + return strerror_r(errno, errorString, sizeof errorString); +#endif +} + +std::string GetExceptionStr(const std::exception_ptr& exc) +{ + std::string excStr; + if (!exc) { + return excStr; + } + + try { + std::rethrow_exception(exc); + } catch (const std::exception& e) { + excStr = e.what(); + } catch (...) { + excStr = "unknown"; + } + return excStr; +} + +std::string GetLastExceptionStr() +{ + return GetExceptionStr(std::current_exception()); +} + +} // namespace util +} // namespace cppmicroservices diff --git a/external/CppMicroServices/util/src/FileSystem.cpp b/external/CppMicroServices/util/src/FileSystem.cpp new file mode 100644 index 00000000..3a3ffab0 --- /dev/null +++ b/external/CppMicroServices/util/src/FileSystem.cpp @@ -0,0 +1,334 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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 "cppmicroservices/util/FileSystem.h" +#include "cppmicroservices/util/Error.h" +#include "cppmicroservices/util/String.h" +#include + +#include +#include +#include + +#ifdef US_PLATFORM_POSIX +# include +# include +# include +# include +# include // getcwd + +# define US_STAT struct stat +# define us_stat stat +# define us_mkdir mkdir +# define us_rmdir rmdir +# define us_unlink unlink +#else +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +# include +# include +# ifdef __MINGW32__ +# include +# else +# include "dirent_win32.h" +# endif + +# define US_STAT struct _stat +# define us_stat _stat +# define us_mkdir _mkdir +# define us_rmdir _rmdir +# define us_unlink _unlink +#endif + +#ifdef US_PLATFORM_APPLE +# include +#endif + +#include +#include + +namespace cppmicroservices { + +namespace util { + +#ifdef US_PLATFORM_WINDOWS +bool not_found_win32_error(int errval) +{ + return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || + errval == ERROR_INVALID_NAME // "//foo" + || + errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted + || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted + || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" + || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64 + || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32 +} +#endif + +#ifdef US_PLATFORM_WINDOWS +const char DIR_SEP = DIR_SEP_WIN32; +#else +const char DIR_SEP = DIR_SEP_POSIX; +#endif + +bool not_found_c_error(int errval) +{ + return errval == ENOENT || errval == ENOTDIR; +} + +std::vector SplitString(const std::string& str, + const std::string& delim) +{ + std::vector token; + std::size_t b = str.find_first_not_of(delim); + std::size_t e = str.find_first_of(delim, b); + while (e > b) { + token.emplace_back(str.substr(b, e - b)); + b = str.find_first_not_of(delim, e); + e = str.find_first_of(delim, b); + } + return token; +} + +#ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +#endif + +std::string GetExecutablePath() +{ + uint32_t bufsize = MAXPATHLEN; +#ifdef US_PLATFORM_WINDOWS + std::vector wbuf(bufsize + 1, '\0'); + if (GetModuleFileNameW(nullptr, wbuf.data(), bufsize) == 0 || + GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + throw std::runtime_error("GetModuleFileName failed" + + GetLastWin32ErrorStr()); + } + return ToUTF8String(wbuf.data()); +#elif defined(US_PLATFORM_APPLE) + std::vector buf(bufsize + 1, '\0'); + int status = _NSGetExecutablePath(buf.data(), &bufsize); + if (status == -1) { + buf.assign(bufsize + 1, '\0'); + status = _NSGetExecutablePath(buf.data(), &bufsize); + } + if (status != 0) { + throw std::runtime_error("_NSGetExecutablePath() failed"); + } + // the returned path may not be an absolute path + return buf.data(); +#elif defined(US_PLATFORM_LINUX) + std::vector buf(bufsize + 1, '\0'); + ssize_t len = ::readlink("/proc/self/exe", buf.data(), bufsize); + if (len == -1 || len == static_cast(bufsize)) { + throw std::runtime_error("Could not read /proc/self/exe into buffer"); + } + return buf.data(); +#else + // 'dlsym' does not work with symbol name 'main' + throw std::runtime_error("GetExecutablePath failed"); + return ""; +#endif +} + +std::string InitCurrentWorkingDirectory() +{ +#ifdef US_PLATFORM_WINDOWS + DWORD bufSize = ::GetCurrentDirectoryW(0, NULL); + if (bufSize == 0) + bufSize = 1; + std::vector buf(bufSize, L'\0'); + if (::GetCurrentDirectoryW(bufSize, buf.data()) != 0) { + return util::ToUTF8String(buf.data()); + } +#else + std::size_t bufSize = PATH_MAX; + for (;; bufSize *= 2) { + std::vector buf(bufSize, '\0'); + errno = 0; + if (getcwd(buf.data(), bufSize) != 0 && errno != ERANGE) { + return std::string(buf.data()); + } + } +#endif + return std::string(); +} + +static const std::string s_CurrWorkingDir = InitCurrentWorkingDirectory(); + +std::string GetCurrentWorkingDirectory() +{ + return s_CurrWorkingDir; +} + +bool Exists(const std::string& path) +{ +#ifdef US_PLATFORM_POSIX + US_STAT s; + errno = 0; + if (us_stat(path.c_str(), &s)) { + if (not_found_c_error(errno)) + return false; + else + throw std::invalid_argument(GetLastCErrorStr()); + } +#else + std::wstring wpath(ToWString(path)); + DWORD attr(::GetFileAttributesW(wpath.c_str())); + if (attr == INVALID_FILE_ATTRIBUTES) { + if (not_found_win32_error(::GetLastError())) + return false; + else + throw std::invalid_argument(GetLastWin32ErrorStr()); + } +#endif + return true; +} + +bool IsDirectory(const std::string& path) +{ + US_STAT s; + errno = 0; + if (us_stat(path.c_str(), &s)) { + if (not_found_c_error(errno)) + return false; + else + throw std::invalid_argument(GetLastCErrorStr()); + } + return S_ISDIR(s.st_mode); +} + +bool IsFile(const std::string& path) +{ + US_STAT s; + errno = 0; + if (us_stat(path.c_str(), &s)) { + if (not_found_c_error(errno)) + return false; + else + throw std::invalid_argument(GetLastCErrorStr()); + } + return S_ISREG(s.st_mode); +} + +bool IsRelative(const std::string& path) +{ +#ifdef US_PLATFORM_WINDOWS + if (path.size() > MAX_PATH) + return false; + std::wstring wpath(ToWString(path)); + return (TRUE == ::PathIsRelativeW(wpath.c_str())) ? true : false; +#else + return path.empty() || path[0] != DIR_SEP; +#endif +} + +std::string GetAbsolute(const std::string& path, const std::string& base) +{ + if (IsRelative(path)) + return base + DIR_SEP + path; + return path; +} + +void MakePath(const std::string& path) +{ + std::string subPath; + auto dirs = SplitString(path, std::string() + DIR_SEP_WIN32 + DIR_SEP_POSIX); + if (dirs.empty()) + return; + + auto iter = dirs.begin(); +#ifdef US_PLATFORM_POSIX + // Start with the root '/' directory + subPath = DIR_SEP; +#else + // Start with the drive letter` + subPath = *iter + DIR_SEP; + ++iter; +#endif + for (; iter != dirs.end(); ++iter) { + subPath += *iter; + errno = 0; +#ifdef US_PLATFORM_WINDOWS + if (us_mkdir(subPath.c_str())) +#else + if (us_mkdir(subPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) +#endif + { + if (errno != EEXIST) + throw std::invalid_argument(GetLastCErrorStr()); + } + subPath += DIR_SEP; + } +} + +void RemoveDirectoryRecursive(const std::string& path) +{ + int res = -1; + errno = 0; + DIR* dir = opendir(path.c_str()); + if (dir != nullptr) { + res = 0; + + struct dirent* ent = nullptr; + while (!res && (ent = readdir(dir)) != nullptr) { + // Skip the names "." and ".." as we don't want to recurse on them. + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { + continue; + } + + std::string child = path + DIR_SEP + ent->d_name; + if +#ifdef _DIRENT_HAVE_D_TYPE + (ent->d_type == DT_DIR) +#else + (IsDirectory(child)) +#endif + { + RemoveDirectoryRecursive(child); + } else { + res = us_unlink(child.c_str()); + } + } + int old_err = errno; + errno = 0; + closedir(dir); // error ignored + if (old_err) { + errno = old_err; + } + } + + if (!res) { + errno = 0; + res = us_rmdir(path.c_str()); + } + + if (res) + throw std::invalid_argument(GetLastCErrorStr()); +} + +} // namespace util +} // namespace cppmicroservices diff --git a/external/CppMicroServices/util/src/String.cpp b/external/CppMicroServices/util/src/String.cpp new file mode 100644 index 00000000..36fc5c7e --- /dev/null +++ b/external/CppMicroServices/util/src/String.cpp @@ -0,0 +1,77 @@ +/*============================================================================= + + Library: CppMicroServices + + Copyright (c) The CppMicroServices developers. See the COPYRIGHT + file at the top-level directory of this distribution and at + https://github.com/CppMicroServices/CppMicroServices/COPYRIGHT . + + 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 "cppmicroservices/util/String.h" +#include "cppmicroservices/util/Error.h" +#include +#include +#include + +#ifdef US_PLATFORM_WINDOWS +# include + +namespace cppmicroservices { +namespace util { +//------------------------------------------------------------------- +// Unicode Utility functions +//------------------------------------------------------------------- + +inline void ThrowInvalidArgument(const std::string& msgprefix) +{ + throw std::invalid_argument(msgprefix + " Error: " + GetLastWin32ErrorStr()); +} + +// function returns empty string if inStr is empty or if the conversion failed +std::wstring ToWString(const std::string& inStr) +{ + if (inStr.empty()) { + return std::wstring(); + } + int wchar_count = MultiByteToWideChar(CP_UTF8, 0, inStr.c_str(), -1, NULL, 0); + std::unique_ptr wBuf(new wchar_t[wchar_count]); + wchar_count = + MultiByteToWideChar(CP_UTF8, 0, inStr.c_str(), -1, wBuf.get(), wchar_count); + if (wchar_count == 0) { + ThrowInvalidArgument("Failed to convert " + inStr + " to UTF16."); + } + return wBuf.get(); +} + +// function return empty string if inWStr is empty or if the conversion failed +std::string ToUTF8String(const std::wstring& inWStr) +{ + if (inWStr.empty()) { + return std::string(); + } + int char_count = + WideCharToMultiByte(CP_UTF8, 0, inWStr.c_str(), -1, NULL, 0, NULL, NULL); + std::unique_ptr str(new char[char_count]); + char_count = WideCharToMultiByte( + CP_UTF8, 0, inWStr.c_str(), -1, str.get(), char_count, NULL, NULL); + if (char_count == 0) { + ThrowInvalidArgument("Failed to convert UTF16 string to UTF8."); + } + return str.get(); +} +} +} +#endif diff --git a/external/CppMicroServices/valgrind_suppressions.txt b/external/CppMicroServices/valgrind_suppressions.txt new file mode 100644 index 00000000..de166f72 --- /dev/null +++ b/external/CppMicroServices/valgrind_suppressions.txt @@ -0,0 +1,267 @@ +{ + + Memcheck:Leak + fun:calloc + fun:_dlerror_run + fun:dlopen* + ... +} + +{ + + Memcheck:Leak + fun:malloc + fun:strdup + fun:_dl_map_object + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen* + ... +} + +{ + + Memcheck:Leak + fun:malloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen* + ... +} + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_check_map_versions + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen* + ... +} + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen* + ... +} + +{ + + Memcheck:Leak + fun:malloc + obj:/usr/*/libstdc++* + fun:call_init.part.0 + fun:_dl_init + obj:/usr/*/ld-*.so + ... +} + +{ + + Helgrind:Race + fun:load + fun:_ZNKSt6atomicIbE4loadESt12memory_order + fun:_ZN2us21TestBundleC1Activator10UnRegisterEv + ... +} + +{ + + Helgrind:Race + fun:load + fun:_ZNKSt13__atomic_baseIPN2us13BundleContextEEcvS2_Ev + fun:_ZNKSt6atomicIPN2us13BundleContextEEcvS2_Ev + ... +} + +{ + + Helgrind:Race + fun:store + fun:_ZNSt13__atomic_baseIPN2us13BundleContextEEaSES2_ + fun:_ZNSt6atomicIPN2us13BundleContextEEaSES2_ + ... +} + +{ + + Helgrind:Race + fun:store + fun:_ZNSt13__atomic_baseIbEaSEb + fun:_ZNSt6atomicIbEaSEb + ... +} + +{ + + Helgrind:Race + fun:load + fun:_ZNKSt6atomicIPN2us13BundleContextEE4loadESt12memory_order + ... +} + +{ + + Helgrind:Race + fun:load + fun:_ZNKSt6atomicIbEcvbEv + fun:_ZNK2us23ServiceRegistrationBase12GetReferenceERKSs + ... +} + +{ + + Helgrind:Race + fun:_ZNSt13__atomic_baseIiEmmEv + fun:_ZN2us20ServiceReferenceBaseD1Ev + ... +} + +{ + + Helgrind:Race + fun:store + fun:_ZNSt13__atomic_baseIPN2us27ServiceReferenceBasePrivateEEaSES2_ + ... +} + +{ + + Helgrind:Race + fun:load + fun:_ZNKSt6atomicIPN2us27ServiceReferenceBasePrivateEE4loadESt12memory_order + ... +} + +{ + + Helgrind:Race + fun:_ZNSt13__atomic_baseIiEppEv + fun:_ZN2us20ServiceReferenceBaseaSERKS0_ + ... +} + +{ + <_us_create_activator> + Helgrind:Race + fun:load + fun:_ZNKSt6atomicIbE4loadESt12memory_order + ... +} + + +{ + + Helgrind:Race + fun:_ZNKSt10unique_ptrINSt13__future_base12_Result_baseENS1_8_DeleterEE3getEv + fun:_ZNKSt10unique_ptrINSt13__future_base12_Result_baseENS1_8_DeleterEEdeEv + fun:_ZNSt13__future_base13_State_baseV24waitEv + fun:_ZNKSt14__basic_futureIvE4waitEv + ... +} + +{ + + Helgrind:Race + fun:_ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE2EED1Ev + fun:_ZNSt12__shared_ptrINSt6thread10_Impl_baseELN9__gnu_cxx12_Lock_policyE2EED1Ev + fun:_ZNSt10shared_ptrINSt6thread10_Impl_baseEED1Ev + ... +} + +{ + + Helgrind:Race + fun:_ZNSt6thread5_ImplISt12_Bind_simple* + ... +} + + +{ + + Helgrind:Race + fun:_ZNSt6thread5_ImplISt12_Bind_result* + ... +} + +{ + + Helgrind:Race + fun:memset + fun:pthread_create* + fun:pthread_create_WRK + ... +} + + +{ + + Helgrind:Misc + obj:/usr/*/valgrind/vgpreload_helgrind* + fun:pthread_cond_broadcast* + ... +} + + +{ + + Memcheck:Cond + fun:tdefl_find_match + fun:tdefl_compress_normal + fun:tdefl_compress + fun:tdefl_compress_buffer + fun:mz_zip_writer_add_mem_ex + fun:mz_zip_writer_add_mem + ... + fun:main +} + + +{ + + Memcheck:Cond + fun:tdefl_compress + ... + fun:mz_zip_writer_add_mem_ex + fun:mz_zip_writer_add_mem + ... + fun:main +} + + +{ + + Memcheck:Cond + fun:tdefl_compress_normal + ... + fun:mz_zip_writer_add_mem + ... + fun:main +} diff --git a/external/CppMicroServices/valgrindrc b/external/CppMicroServices/valgrindrc new file mode 100644 index 00000000..dfd9f691 --- /dev/null +++ b/external/CppMicroServices/valgrindrc @@ -0,0 +1,3 @@ +--memcheck:leak-check=full +--memcheck:show-reachable=yes +--suppressions=@PROJECT_SOURCE_DIR@/valgrind_suppressions.txt diff --git a/external/dcap_source b/external/dcap_source new file mode 160000 index 00000000..009f27a3 --- /dev/null +++ b/external/dcap_source @@ -0,0 +1 @@ +Subproject commit 009f27a3e3e82f5fb7f91329cf30c546c57849cb diff --git a/external/epid-sdk/epid/common/Makefile b/external/epid-sdk/epid/common/Makefile index 0d9d9e31..a318c4cc 100644 --- a/external/epid-sdk/epid/common/Makefile +++ b/external/epid-sdk/epid/common/Makefile @@ -32,12 +32,12 @@ LIB_IPPCP_DIR = ../../ext/ipp/sources/ippcp/src #set flags for linker LDFLAGS += -L$(GTEST_INCLUDE_DIR)/gtest -L$(LIB_COMMON_TESTHELPER_DIR) \ - -L$(LIB_COMMON_DIR) -L$(LIB_IPPCP_DIR) \ + -L$(LIB_COMMON_DIR) \ -lgtest -lcommon-testhelper -lcommon -lippcp #target part $(COMMON_OBJ): %.o: %.c - $(CC) $(CFLAGS) -I$(IPP_INCLUDE_DIR) -I$(COMMON_MATH_INCLUDE_DIR) -I$(COMMON_INCLUDE_DIR) -c $^ -o $@ + $(CC) $(CFLAGS) -I$(COMMON_MATH_INCLUDE_DIR) -I$(COMMON_INCLUDE_DIR) -c $^ -o $@ $(COMMON_LIB): $(COMMON_OBJ) $(AR) rc $(COMMON_LIB) $(COMMON_OBJ) diff --git a/external/epid-sdk/epid/member/Makefile b/external/epid-sdk/epid/member/Makefile index d56e708f..f133bdbc 100644 --- a/external/epid-sdk/epid/member/Makefile +++ b/external/epid-sdk/epid/member/Makefile @@ -63,7 +63,7 @@ LIB_IPPCP_DIR = ../../ext/ipp/sources/ippcp/src #set flags for linker LDFLAGS += -L$(GTEST_INCLUDE_DIR)/gtest -L$(LIB_COMMON_TESTHELPER_DIR) \ -L$(LIB_MEMBER_DIR) -L$(LIB_VERIFIER_DIR) -L$(LIB_COMMON_DIR) \ - -L$(LIB_IPPCP_DIR) -lgtest -lcommon-testhelper \ + -lgtest -lcommon-testhelper \ -lmember -lverifier -lcommon -lippcp ifneq ($(TSS_PATH),) @@ -87,7 +87,7 @@ ifneq ($(TINY),) endif $(MEMBER_OBJ): %.o: %.c - $(CC) $(CFLAGS) -I$(IPP_INCLUDE_DIR) -I$(IPP_SRC_INCLUDE_DIR) \ + $(CC) $(CFLAGS) \ -I$(MEMBER_INCLUDE_DIR) -c $^ -o $@ $(MEMBER_LIB): $(MEMBER_OBJ) diff --git a/external/epid-sdk/epid/verifier/Makefile b/external/epid-sdk/epid/verifier/Makefile index 6f64d67e..c407b15f 100644 --- a/external/epid-sdk/epid/verifier/Makefile +++ b/external/epid-sdk/epid/verifier/Makefile @@ -34,7 +34,7 @@ LIB_IPPCP_DIR = ../../ext/ipp/sources/ippcp/src #set flags for linker LDFLAGS += -L$(GTEST_INCLUDE_DIR)/gtest -L$(LIB_COMMON_TESTHELPER_DIR) \ -L$(LIB_VERIFIER_DIR) -L$(LIB_COMMON_DIR) \ - -L$(LIB_IPPCP_DIR) -lgtest -lcommon-testhelper -lverifier -lcommon \ + -lgtest -lcommon-testhelper -lverifier -lcommon \ -lippcp ifneq ($(TSS_PATH),) @@ -43,7 +43,7 @@ endif #target part $(VERIFIER_OBJ): %.o: %.c - $(CC) $(CFLAGS) -I$(IPP_INCLUDE_DIR) -I$(IPP_SRC_INCLUDE_DIR) \ + $(CC) $(CFLAGS) \ -I$(VERIFIER_INCLUDE_DIR) -I$(VERIFIER_11_INCLUDE_DIR) -c $^ -o $@ $(VERIFIER_LIB): $(VERIFIER_OBJ) diff --git a/external/epid-sdk/ext/ipp/include/sgx_ippcp.h b/external/epid-sdk/ext/ipp/include/sgx_ippcp.h index 91314d52..12e457e7 100644 --- a/external/epid-sdk/ext/ipp/include/sgx_ippcp.h +++ b/external/epid-sdk/ext/ipp/include/sgx_ippcp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/external/sgxssl/prepare_sgxssl.sh b/external/sgxssl/prepare_sgxssl.sh index 9f7cf892..06fd3aca 100755 --- a/external/sgxssl/prepare_sgxssl.sh +++ b/external/sgxssl/prepare_sgxssl.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/external/sqlite/src/sqlite3.c b/external/sqlite/src/sqlite3.c index c49f89c9..d015df2c 100644 --- a/external/sqlite/src/sqlite3.c +++ b/external/sqlite/src/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.23.1. By combining all the individual C code files into this +** version 3.26.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -55,6 +55,12 @@ #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) +/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This +** option requires a separate macro because legal values contain a single +** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ +#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 +#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) + /* ** An array of names of all compile-time options. This array should ** be sorted A-Z. @@ -138,7 +144,7 @@ static const char * const sqlite3azCompileOpt[] = { "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #ifdef SQLITE_DEFAULT_LOOKASIDE - "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE), + "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), #endif #if SQLITE_DEFAULT_MEMSTATUS "DEFAULT_MEMSTATUS", @@ -254,6 +260,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif +#if SQLITE_ENABLE_GEOPOLY + "ENABLE_GEOPOLY", +#endif #if SQLITE_ENABLE_HIDDEN_COLUMNS "ENABLE_HIDDEN_COLUMNS", #endif @@ -284,6 +293,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_MULTIPLEX "ENABLE_MULTIPLEX", #endif +#if SQLITE_ENABLE_NORMALIZE + "ENABLE_NORMALIZE", +#endif #if SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif @@ -311,6 +323,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif +#if SQLITE_ENABLE_SORTER_REFERENCES + "ENABLE_SORTER_REFERENCES", +#endif #if SQLITE_ENABLE_SQLLOG "ENABLE_SQLLOG", #endif @@ -1147,9 +1162,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.23.1" -#define SQLITE_VERSION_NUMBER 3023001 -#define SQLITE_SOURCE_ID "2018-04-10 17:39:29 4bb2294022060e61de7da5c227a69ccd846ba330e31626ebcd59a94efd148b3b" +#define SQLITE_VERSION "3.26.0" +#define SQLITE_VERSION_NUMBER 3026000 +#define SQLITE_SOURCE_ID "2018-12-01 12:34:55 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238b4f9" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1496,6 +1511,7 @@ SQLITE_API int sqlite3_exec( */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) +#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) @@ -1528,13 +1544,16 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) +#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) +#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) @@ -1908,7 +1927,8 @@ struct sqlite3_io_methods { **
  • [[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary -** write ahead log and shared memory files used for transaction control +** write ahead log ([WAL file]) and shared memory +** files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not @@ -2094,6 +2114,26 @@ struct sqlite3_io_methods { ** a file lock using the xLock or xShmLock methods of the VFS to wait ** for up to M milliseconds before failing, where M is the single ** unsigned integer parameter. +** +**
  • [[SQLITE_FCNTL_DATA_VERSION]] +** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to +** a database file. The argument is a pointer to a 32-bit unsigned integer. +** The "data version" for the pager is written into the pointer. The +** "data version" changes whenever any change occurs to the corresponding +** database file, either through SQL statements on the same database +** connection or through transactions committed by separate database +** connections possibly in other processes. The [sqlite3_total_changes()] +** interface can be used to find if any database on the connection has changed, +** but that interface responds to changes on TEMP as well as MAIN and does +** not provide a mechanism to detect changes to MAIN only. Also, the +** [sqlite3_total_changes()] interface responds to internal changes only and +** omits changes made by other database connections. The +** [PRAGMA data_version] command provide a mechanism to detect changes to +** a single attached database that occur due to other database connections, +** but omits changes implemented by the database connection on which it is +** called. This file control is the only mechanism to detect changes that +** happen either internally or externally and that are associated with +** a particular attached database. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -2129,6 +2169,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 +#define SQLITE_FCNTL_DATA_VERSION 35 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -2954,6 +2995,22 @@ struct sqlite3_mem_methods { ** I/O required to support statement rollback. ** The default value for this setting is controlled by the ** [SQLITE_STMTJRNL_SPILL] compile-time option. +** +** [[SQLITE_CONFIG_SORTERREF_SIZE]] +**
    SQLITE_CONFIG_SORTERREF_SIZE +**
    The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter +** of type (int) - the new value of the sorter-reference size threshold. +** Usually, when SQLite uses an external sort to order records according +** to an ORDER BY clause, all fields required by the caller are present in the +** sorted records. However, if SQLite determines based on the declared type +** of a table column that its values are likely to be very large - larger +** than the configured sorter-reference size threshold - then a reference +** is stored in each sorted record and the required column values loaded +** from the database as records are returned in sorted order. The default +** value for this option is to never use this optimization. Specifying a +** negative value for this option restores the default behaviour. +** This option is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -2983,6 +3040,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ +#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2998,6 +3056,7 @@ struct sqlite3_mem_methods { ** is invoked. ** **
    +** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. @@ -3020,6 +3079,7 @@ struct sqlite3_mem_methods { ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
    ** +** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. @@ -3030,6 +3090,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]] **
    SQLITE_DBCONFIG_ENABLE_TRIGGER
    **
    ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. @@ -3040,6 +3101,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the trigger setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    **
    ^This option is used to enable or disable the two-argument ** version of the [fts3_tokenizer()] function which is part of the @@ -3053,6 +3115,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the new setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    **
    ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. @@ -3070,7 +3133,7 @@ struct sqlite3_mem_methods { ** be a NULL pointer, in which case the new setting is not reported back. **
    ** -**
    SQLITE_DBCONFIG_MAINDBNAME
    +** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database ** schema. ^The sole argument is a pointer to a constant UTF8 string ** which will become the new schema name in place of "main". ^SQLite @@ -3079,6 +3142,7 @@ struct sqlite3_mem_methods { ** until after the database connection closes. **
    ** +** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    **
    Usually, when a database in wal mode is closed or detached from a ** database handle, SQLite checks if this will mean that there are now no @@ -3092,7 +3156,7 @@ struct sqlite3_mem_methods { ** have been disabled - 0 if they are not disabled, 1 if they are. **
    ** -**
    SQLITE_DBCONFIG_ENABLE_QPSG
    +** [[SQLITE_DBCONFIG_ENABLE_QPSG]]
    SQLITE_DBCONFIG_ENABLE_QPSG
    **
    ^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates ** the [query planner stability guarantee] (QPSG). When the QPSG is active, ** a single SQL query statement will always use the same algorithm regardless @@ -3108,7 +3172,7 @@ struct sqlite3_mem_methods { ** following this call. **
    ** -**
    SQLITE_DBCONFIG_TRIGGER_EQP
    +** [[SQLITE_DBCONFIG_TRIGGER_EQP]]
    SQLITE_DBCONFIG_TRIGGER_EQP
    **
    By default, the output of EXPLAIN QUERY PLAN commands does not ** include output for any operations performed by trigger programs. This ** option is used to set or clear (the default) a flag that governs this @@ -3119,6 +3183,39 @@ struct sqlite3_mem_methods { ** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if ** it is not disabled, 1 if it is. **
    +** +** [[SQLITE_DBCONFIG_RESET_DATABASE]]
    SQLITE_DBCONFIG_RESET_DATABASE
    +**
    Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run +** [VACUUM] in order to reset a database back to an empty database +** with no schema and no content. The following process works even for +** a badly corrupted database file: +**
      +**
    1. If the database connection is newly opened, make sure it has read the +** database schema by preparing then discarding some query against the +** database, or calling sqlite3_table_column_metadata(), ignoring any +** errors. This step is only necessary if the application desires to keep +** the database in WAL mode after the reset if it was in WAL mode before +** the reset. +**
    2. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); +**
    3. [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); +**
    4. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); +**
    +** Because resetting a database is destructive and irreversible, the +** process requires the use of this obscure API and multiple steps to help +** ensure that it does not happen by accident. +** +** [[SQLITE_DBCONFIG_DEFENSIVE]]
    SQLITE_DBCONFIG_DEFENSIVE
    +**
    The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the +** "defensive" flag for a database connection. When the defensive +** flag is enabled, language features that allow ordinary SQL to +** deliberately corrupt the database file are disabled. The disabled +** features include but are not limited to the following: +**
      +**
    • The [PRAGMA writable_schema=ON] statement. +**
    • Writes to the [sqlite_dbpage] virtual table. +**
    • Direct writes to [shadow tables]. +**
    +**
    **
    */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -3130,7 +3227,9 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1008 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ +#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1010 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -3258,12 +3357,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** program, the value returned reflects the number of rows modified by the ** previous INSERT, UPDATE or DELETE statement within the same trigger. ** -** See also the [sqlite3_total_changes()] interface, the -** [count_changes pragma], and the [changes() SQL function]. -** ** If a separate thread makes changes on the same database connection ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. +** +** See also: +**
      +**
    • the [sqlite3_total_changes()] interface +**
    • the [count_changes pragma] +**
    • the [changes() SQL function] +**
    • the [data_version pragma] +**
    */ SQLITE_API int sqlite3_changes(sqlite3*); @@ -3281,13 +3385,26 @@ SQLITE_API int sqlite3_changes(sqlite3*); ** count, but those made as part of REPLACE constraint resolution are ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. -** -** See also the [sqlite3_changes()] interface, the -** [count_changes pragma], and the [total_changes() SQL function]. ** +** This the [sqlite3_total_changes(D)] interface only reports the number +** of rows that changed due to SQL statement run against database +** connection D. Any changes by other database connections are ignored. +** To detect changes against a database file from other database +** connections use the [PRAGMA data_version] command or the +** [SQLITE_FCNTL_DATA_VERSION] [file control]. +** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. +** +** See also: +**
      +**
    • the [sqlite3_changes()] interface +**
    • the [count_changes pragma] +**
    • the [changes() SQL function] +**
    • the [data_version pragma] +**
    • the [SQLITE_FCNTL_DATA_VERSION] [file control] +**
    */ SQLITE_API int sqlite3_total_changes(sqlite3*); @@ -4343,13 +4460,24 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int ** [database connection] D failed, then the sqlite3_errcode(D) interface ** returns the numeric [result code] or [extended result code] for that ** API call. -** If the most recent API call was successful, -** then the return value from sqlite3_errcode() is undefined. ** ^The sqlite3_extended_errcode() ** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. ** +** The values returned by sqlite3_errcode() and/or +** sqlite3_extended_errcode() might change with each API call. +** Except, there are some interfaces that are guaranteed to never +** change the value of the error code. The error-code preserving +** interfaces are: +** +**
      +**
    • sqlite3_errcode() +**
    • sqlite3_extended_errcode() +**
    • sqlite3_errmsg() +**
    • sqlite3_errmsg16() +**
    +** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(Memory to hold the error message string is managed internally. @@ -4539,9 +4667,19 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** on this hint by avoiding the use of [lookaside memory] so as not to ** deplete the limited store of lookaside memory. Future versions of ** SQLite may act on this hint differently. +** +** [[SQLITE_PREPARE_NORMALIZE]] ^(
    SQLITE_PREPARE_NORMALIZE
    +**
    The SQLITE_PREPARE_NORMALIZE flag indicates that a normalized +** representation of the SQL statement should be calculated and then +** associated with the prepared statement, which can be obtained via +** the [sqlite3_normalized_sql()] interface.)^ The semantics used to +** normalize a SQL statement are unspecified and subject to change. +** At a minimum, literal values will be replaced with suitable +** placeholders. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 /* ** CAPI3REF: Compiling An SQL Statement @@ -4699,6 +4837,11 @@ SQLITE_API int sqlite3_prepare16_v3( ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. +** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 +** string containing the normalized SQL text of prepared statement P. The +** semantics used to normalize a SQL statement are unspecified and subject +** to change. At a minimum, literal values will be replaced with suitable +** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 @@ -4714,14 +4857,16 @@ SQLITE_API int sqlite3_prepare16_v3( ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** -** ^The string returned by sqlite3_sql(P) is managed by SQLite and is -** automatically freed when the prepared statement is finalized. +** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) +** are managed by SQLite and are automatically freed when the prepared +** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be free by the application ** by passing it to [sqlite3_free()]. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -5503,11 +5648,25 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** -** ^(If a memory allocation error occurs during the evaluation of any -** of these routines, a default value is returned. The default value -** is either the integer 0, the floating point number 0.0, or a NULL -** pointer. Subsequent calls to [sqlite3_errcode()] will return -** [SQLITE_NOMEM].)^ +** As long as the input parameters are correct, these routines will only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_column_blob() +**
    • sqlite3_column_text() +**
    • sqlite3_column_text16() +**
    • sqlite3_column_bytes() +**
    • sqlite3_column_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); @@ -5584,11 +5743,13 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior -** of existing SQL functions or aggregates. The only differences between -** these routines are the text encoding expected for -** the second parameter (the name of the function being created) -** and the presence or absence of a destructor callback for -** the application data pointer. +** of existing SQL functions or aggregates. The only differences between +** the three "sqlite3_create_function*" routines are the text encoding +** expected for the second parameter (the name of the function being +** created) and the presence or absence of a destructor callback for +** the application data pointer. Function sqlite3_create_window_function() +** is similar, but allows the user to supply the extra callback functions +** needed by [aggregate window functions]. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database @@ -5634,7 +5795,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** -** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are +** ^The sixth, seventh and eighth parameters passed to the three +** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal @@ -5643,15 +5805,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** -** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, -** then it is destructor for the application data pointer. -** The destructor is invoked when the function is deleted, either by being -** overloaded or when the database connection closes.)^ -** ^The destructor is also invoked if the call to -** sqlite3_create_function_v2() fails. -** ^When the destructor callback of the tenth parameter is invoked, it -** is passed a single argument which is a copy of the application data -** pointer which was the fifth parameter to sqlite3_create_function_v2(). +** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue +** and xInverse) passed to sqlite3_create_window_function are pointers to +** C-language callbacks that implement the new function. xStep and xFinal +** must both be non-NULL. xValue and xInverse may either both be NULL, in +** which case a regular aggregate function is created, or must both be +** non-NULL, in which case the new function may be used as either an aggregate +** or aggregate window function. More details regarding the implementation +** of aggregate window functions are +** [user-defined window functions|available here]. +** +** ^(If the final parameter to sqlite3_create_function_v2() or +** sqlite3_create_window_function() is not NULL, then it is destructor for +** the application data pointer. The destructor is invoked when the function +** is deleted, either by being overloaded or when the database connection +** closes.)^ ^The destructor is also invoked if the call to +** sqlite3_create_function_v2() fails. ^When the destructor callback is +** invoked, it is passed a single argument which is a copy of the application +** data pointer which was the fifth parameter to sqlite3_create_function_v2(). ** ** ^It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of @@ -5704,6 +5875,18 @@ SQLITE_API int sqlite3_create_function_v2( void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*) ); +SQLITE_API int sqlite3_create_window_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) +); /* ** CAPI3REF: Text Encodings @@ -5846,6 +6029,28 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. +** +** As long as the input parameter is correct, these routines can only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_value_blob() +**
    • sqlite3_value_text() +**
    • sqlite3_value_text16() +**
    • sqlite3_value_text16le() +**
    • sqlite3_value_text16be() +**
    • sqlite3_value_bytes() +**
    • sqlite3_value_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); @@ -6516,6 +6721,41 @@ SQLITE_API char *sqlite3_temp_directory; */ SQLITE_API char *sqlite3_data_directory; +/* +** CAPI3REF: Win32 Specific Interface +** +** These interfaces are available only on Windows. The +** [sqlite3_win32_set_directory] interface is used to set the value associated +** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to +** zValue, depending on the value of the type parameter. The zValue parameter +** should be NULL to cause the previous value to be freed via [sqlite3_free]; +** a non-NULL value will be copied into memory obtained from [sqlite3_malloc] +** prior to being used. The [sqlite3_win32_set_directory] interface returns +** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported, +** or [SQLITE_NOMEM] if memory could not be allocated. The value of the +** [sqlite3_data_directory] variable is intended to act as a replacement for +** the current directory on the sub-platforms of Win32 where that concept is +** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and +** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the +** sqlite3_win32_set_directory interface except the string parameter must be +** UTF-8 or UTF-16, respectively. +*/ +SQLITE_API int sqlite3_win32_set_directory( + unsigned long type, /* Identifier for directory being set or reset */ + void *zValue /* New value for directory being set or reset */ +); +SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); +SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); + +/* +** CAPI3REF: Win32 Directory Types +** +** These macros are only available on Windows. They define the allowed values +** for the type argument to the [sqlite3_win32_set_directory] interface. +*/ +#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1 +#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2 + /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} @@ -7116,6 +7356,9 @@ struct sqlite3_module { int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); }; /* @@ -7248,6 +7491,10 @@ struct sqlite3_index_info { /* ** CAPI3REF: Virtual Table Scan Flags +** +** Virtual table implementations are allowed to set the +** [sqlite3_index_info].idxFlags field to some combination of +** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ @@ -7273,6 +7520,7 @@ struct sqlite3_index_info { #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_IS 72 +#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation @@ -7949,6 +8197,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** METHOD: sqlite3 +** KEYWORDS: {file control} ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated @@ -7963,11 +8212,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** +** A few opcodes for [sqlite3_file_control()] are handled directly +** by the SQLite core and never invoke the +** sqlite3_io_methods.xFileControl method. ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into -** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER] -** case is a short-circuit path which does not actually invoke the -** underlying sqlite3_io_methods.xFileControl method. +** the space pointed to by the 4th parameter. The +** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns +** the [sqlite3_file] object associated with the journal file instead of +** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns +** a pointer to the underlying [sqlite3_vfs] object for the file. +** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter +** from the pager. ** ** ^If the second parameter (zDbName) does not match the name of any ** open database file, then SQLITE_ERROR is returned. ^This error @@ -8023,8 +8279,9 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 -#define SQLITE_TESTCTRL_ISKEYWORD 16 +#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ +#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -8037,6 +8294,189 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 #define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */ +/* +** CAPI3REF: SQL Keyword Checking +** +** These routines provide access to the set of SQL language keywords +** recognized by SQLite. Applications can uses these routines to determine +** whether or not a specific identifier needs to be escaped (for example, +** by enclosing in double-quotes) so as not to confuse the parser. +** +** The sqlite3_keyword_count() interface returns the number of distinct +** keywords understood by SQLite. +** +** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and +** makes *Z point to that keyword expressed as UTF8 and writes the number +** of bytes in the keyword into *L. The string that *Z points to is not +** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns +** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z +** or L are NULL or invalid pointers then calls to +** sqlite3_keyword_name(N,Z,L) result in undefined behavior. +** +** The sqlite3_keyword_check(Z,L) interface checks to see whether or not +** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero +** if it is and zero if not. +** +** The parser used by SQLite is forgiving. It is often possible to use +** a keyword as an identifier as long as such use does not result in a +** parsing ambiguity. For example, the statement +** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and +** creates a new table named "BEGIN" with three columns named +** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid +** using keywords as identifiers. Common techniques used to avoid keyword +** name collisions include: +**
      +**
    • Put all identifier names inside double-quotes. This is the official +** SQL way to escape identifier names. +**
    • Put identifier names inside [...]. This is not standard SQL, +** but it is what SQL Server does and so lots of programmers use this +** technique. +**
    • Begin every identifier with the letter "Z" as no SQL keywords start +** with "Z". +**
    • Include a digit somewhere in every identifier name. +**
    +** +** Note that the number of keywords understood by SQLite can depend on +** compile-time options. For example, "VACUUM" is not a keyword if +** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also, +** new keywords may be added to future releases of SQLite. +*/ +SQLITE_API int sqlite3_keyword_count(void); +SQLITE_API int sqlite3_keyword_name(int,const char**,int*); +SQLITE_API int sqlite3_keyword_check(const char*,int); + +/* +** CAPI3REF: Dynamic String Object +** KEYWORDS: {dynamic string} +** +** An instance of the sqlite3_str object contains a dynamically-sized +** string under construction. +** +** The lifecycle of an sqlite3_str object is as follows: +**
      +**
    1. ^The sqlite3_str object is created using [sqlite3_str_new()]. +**
    2. ^Text is appended to the sqlite3_str object using various +** methods, such as [sqlite3_str_appendf()]. +**
    3. ^The sqlite3_str object is destroyed and the string it created +** is returned using the [sqlite3_str_finish()] interface. +**
    +*/ +typedef struct sqlite3_str sqlite3_str; + +/* +** CAPI3REF: Create A New Dynamic String Object +** CONSTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_new(D)] interface allocates and initializes +** a new [sqlite3_str] object. To avoid memory leaks, the object returned by +** [sqlite3_str_new()] must be freed by a subsequent call to +** [sqlite3_str_finish(X)]. +** +** ^The [sqlite3_str_new(D)] interface always returns a pointer to a +** valid [sqlite3_str] object, though in the event of an out-of-memory +** error the returned object might be a special singleton that will +** silently reject new text, always return SQLITE_NOMEM from +** [sqlite3_str_errcode()], always return 0 for +** [sqlite3_str_length()], and always return NULL from +** [sqlite3_str_finish(X)]. It is always safe to use the value +** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter +** to any of the other [sqlite3_str] methods. +** +** The D parameter to [sqlite3_str_new(D)] may be NULL. If the +** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum +** length of the string contained in the [sqlite3_str] object will be +** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead +** of [SQLITE_MAX_LENGTH]. +*/ +SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); + +/* +** CAPI3REF: Finalize A Dynamic String +** DESTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X +** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()] +** that contains the constructed string. The calling application should +** pass the returned value to [sqlite3_free()] to avoid a memory leak. +** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any +** errors were encountered during construction of the string. ^The +** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** string in [sqlite3_str] object X is zero bytes long. +*/ +SQLITE_API char *sqlite3_str_finish(sqlite3_str*); + +/* +** CAPI3REF: Add Content To A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces add content to an sqlite3_str object previously obtained +** from [sqlite3_str_new()]. +** +** ^The [sqlite3_str_appendf(X,F,...)] and +** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] +** functionality of SQLite to append formatted text onto the end of +** [sqlite3_str] object X. +** +** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S +** onto the end of the [sqlite3_str] object X. N must be non-negative. +** S must contain at least N non-zero bytes of content. To append a +** zero-terminated string in its entirety, use the [sqlite3_str_appendall()] +** method instead. +** +** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of +** zero-terminated string S onto the end of [sqlite3_str] object X. +** +** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the +** single-byte character C onto the end of [sqlite3_str] object X. +** ^This method can be used, for example, to add whitespace indentation. +** +** ^The [sqlite3_str_reset(X)] method resets the string under construction +** inside [sqlite3_str] object X back to zero bytes in length. +** +** These methods do not return a result code. ^If an error occurs, that fact +** is recorded in the [sqlite3_str] object and can be recovered by a +** subsequent call to [sqlite3_str_errcode(X)]. +*/ +SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); +SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list); +SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); +SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); +SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); +SQLITE_API void sqlite3_str_reset(sqlite3_str*); + +/* +** CAPI3REF: Status Of A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces return the current status of an [sqlite3_str] object. +** +** ^If any prior errors have occurred while constructing the dynamic string +** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return +** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns +** [SQLITE_NOMEM] following any out-of-memory error, or +** [SQLITE_TOOBIG] if the size of the dynamic string exceeds +** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors. +** +** ^The [sqlite3_str_length(X)] method returns the current length, in bytes, +** of the dynamic string under construction in [sqlite3_str] object X. +** ^The length returned by [sqlite3_str_length(X)] does not include the +** zero-termination byte. +** +** ^The [sqlite3_str_value(X)] method returns a pointer to the current +** content of the dynamic string under construction in X. The value +** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X +** and might be freed or altered by any subsequent method on the same +** [sqlite3_str] object. Applications must not used the pointer returned +** [sqlite3_str_value(X)] after any subsequent method call on the same +** object. ^Applications may change the content of the string returned +** by [sqlite3_str_value(X)] as long as they do not write into any bytes +** outside the range of 0 to [sqlite3_str_length(X)] and do not read or +** write any byte after any subsequent sqlite3_str method call. +*/ +SQLITE_API int sqlite3_str_errcode(sqlite3_str*); +SQLITE_API int sqlite3_str_length(sqlite3_str*); +SQLITE_API char *sqlite3_str_value(sqlite3_str*); + /* ** CAPI3REF: SQLite Runtime Status ** @@ -9254,6 +9694,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** can use to customize and optimize their behavior. ** **
    +** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] **
    SQLITE_VTAB_CONSTRAINT_SUPPORT **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, @@ -9306,11 +9747,11 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** method of a [virtual table], then it returns true if and only if the ** column is being fetched as part of an UPDATE operation during which the ** column value will not change. Applications might use this to substitute -** a lighter-weight value to return that the corresponding [xUpdate] method -** understands as a "no-change" value. +** a return value that is less expensive to compute and that the corresponding +** [xUpdate] method understands as a "no-change" value. ** ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that -** the column is not changed by the UPDATE statement, they the xColumn +** the column is not changed by the UPDATE statement, then the xColumn ** method can optionally return without setting a result, without calling ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. ** In that case, [sqlite3_value_nochange(X)] will return true for the @@ -9603,7 +10044,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot ** KEYWORDS: {snapshot} {sqlite3_snapshot} -** EXPERIMENTAL ** ** An instance of the snapshot object records the state of a [WAL mode] ** database for some specific point in history. @@ -9620,11 +10060,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*); ** version of the database file so that it is possible to later open a new read ** transaction that sees that historical version of the database rather than ** the most recent version. -** -** The constructor for this object is [sqlite3_snapshot_get()]. The -** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer -** to an historical snapshot (if possible). The destructor for -** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. */ typedef struct sqlite3_snapshot { unsigned char hidden[48]; @@ -9632,7 +10067,7 @@ typedef struct sqlite3_snapshot { /* ** CAPI3REF: Record A Database Snapshot -** EXPERIMENTAL +** CONSTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of @@ -9648,7 +10083,7 @@ typedef struct sqlite3_snapshot { ** in this case. ** **
      -**
    • The database handle must be in [autocommit mode]. +**
    • The database handle must not be in [autocommit mode]. ** **
    • Schema S of [database connection] D must be a [WAL mode] database. ** @@ -9671,7 +10106,7 @@ typedef struct sqlite3_snapshot { ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, @@ -9681,24 +10116,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( /* ** CAPI3REF: Start a read transaction on an historical snapshot -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** -** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a -** read transaction for schema S of -** [database connection] D such that the read transaction -** refers to historical [snapshot] P, rather than the most -** recent change to the database. -** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success -** or an appropriate [error code] if it fails. +** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read +** transaction or upgrades an existing one for schema S of +** [database connection] D such that the read transaction refers to +** historical [snapshot] P, rather than the most recent change to the +** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK +** on success or an appropriate [error code] if it fails. +** +** ^In order to succeed, the database connection must not be in +** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there +** is already a read transaction open on schema S, then the database handle +** must have no active statements (SELECT statements that have been passed +** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). +** SQLITE_ERROR is returned if either of these conditions is violated, or +** if schema S does not exist, or if the snapshot object is invalid. +** +** ^A call to sqlite3_snapshot_open() will fail to open if the specified +** snapshot has been overwritten by a [checkpoint]. In this case +** SQLITE_ERROR_SNAPSHOT is returned. +** +** If there is already a read transaction open when this function is +** invoked, then the same read transaction remains open (on the same +** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT +** is returned. If another error code - for example SQLITE_PROTOCOL or an +** SQLITE_IOERR error code - is returned, then the final state of the +** read transaction is undefined. If SQLITE_OK is returned, then the +** read transaction is now open on database snapshot P. ** -** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be -** the first operation following the [BEGIN] that takes the schema S -** out of [autocommit mode]. -** ^In other words, schema S must not currently be in -** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the -** database connection D must be out of [autocommit mode]. -** ^A [snapshot] will fail to open if it has been overwritten by a -** [checkpoint]. ** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the ** database connection D does not know that the database file for ** schema S is in [WAL mode]. A database connection might not know @@ -9709,7 +10155,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( ** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, @@ -9719,20 +10165,20 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( /* ** CAPI3REF: Destroy a snapshot -** EXPERIMENTAL +** DESTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. ** The application must eventually free every [sqlite3_snapshot] object ** using this routine to avoid a memory leak. ** ** The [sqlite3_snapshot_free()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages ** of two valid snapshot handles. @@ -9751,6 +10197,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); ** Otherwise, this API returns a negative value if P1 refers to an older ** snapshot than P2, zero if the two handles refer to the same database ** snapshot, and a positive value if P1 is a newer snapshot than P2. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, @@ -9759,23 +10208,26 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( /* ** CAPI3REF: Recover snapshots from a wal file -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** -** If all connections disconnect from a database file but do not perform -** a checkpoint, the existing wal file is opened along with the database -** file the next time the database is opened. At this point it is only -** possible to successfully call sqlite3_snapshot_open() to open the most -** recent snapshot of the database (the one at the head of the wal file), -** even though the wal file may contain other valid snapshots for which -** clients have sqlite3_snapshot handles. +** If a [WAL file] remains on disk after all database connections close +** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] +** or because the last process to have the database opened exited without +** calling [sqlite3_close()]) and a new connection is subsequently opened +** on that database and [WAL file], the [sqlite3_snapshot_open()] interface +** will only be able to open the last transaction added to the WAL file +** even though the WAL file contains other valid transactions. ** -** This function attempts to scan the wal file associated with database zDb +** This function attempts to scan the WAL file associated with database zDb ** of database handle db and make all valid snapshots available to ** sqlite3_snapshot_open(). It is an error if there is already a read -** transaction open on the database, or if the database is not a wal mode +** transaction open on the database, or if the database is not a WAL mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); @@ -9805,7 +10257,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same ** values of D and S. ** The size of the database is written into *P even if the -** SQLITE_SERIALIZE_NOCOPY bit is set but no contigious copy +** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the @@ -9886,7 +10338,7 @@ SQLITE_API int sqlite3_deserialize( ** in the P argument is held in memory obtained from [sqlite3_malloc64()] ** and that SQLite should take ownership of this memory and automatically ** free it when it has finished using it. Without this flag, the caller -** is resposible for freeing any dynamically allocated memory. +** is responsible for freeing any dynamically allocated memory. ** ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to ** grow the size of the database using calls to [sqlite3_realloc64()]. This @@ -10012,7 +10464,7 @@ struct sqlite3_rtree_query_info { sqlite3_int64 iRowid; /* Rowid for current entry */ sqlite3_rtree_dbl rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ + int eWithin; /* OUT: Visibility */ sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ /* The following fields are only available in 3.8.11 and later */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ @@ -10508,12 +10960,38 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); ** consecutively. There is no chance that the iterator will visit a change ** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
      SQLITE_CHANGESETAPPLY_INVERT
      +** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* @@ -11168,7 +11646,7 @@ SQLITE_API int sqlite3changeset_apply_v2( ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* Combination of SESSION_APPLY_* flags */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* @@ -11186,8 +11664,14 @@ SQLITE_API int sqlite3changeset_apply_v2( ** causes the sessions module to omit this savepoint. In this case, if the ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. +** +**
      SQLITE_CHANGESETAPPLY_INVERT
      +** Invert the changeset before applying it. This is equivalent to inverting +** a changeset using sqlite3changeset_invert() before applying it. It is +** an error to specify this flag with a patchset. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -11581,6 +12065,12 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); SQLITE_API int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), @@ -11607,6 +12097,45 @@ SQLITE_API int sqlite3rebaser_rebase_strm( void *pOut ); +/* +** CAPI3REF: Configure global parameters +** +** The sqlite3session_config() interface is used to make global configuration +** changes to the sessions module in order to tune it to the specific needs +** of the application. +** +** The sqlite3session_config() interface is not threadsafe. If it is invoked +** while any other thread is inside any other sessions method then the +** results are undefined. Furthermore, if it is invoked after any sessions +** related objects have been created, the results are also undefined. +** +** The first argument to the sqlite3session_config() function must be one +** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The +** interpretation of the (void*) value passed as the second parameter and +** the effect of calling this function depends on the value of the first +** parameter. +** +**
      +**
      SQLITE_SESSION_CONFIG_STRMSIZE
      +** By default, the sessions module streaming interfaces attempt to input +** and output data in approximately 1 KiB chunks. This operand may be used +** to set and query the value of this configuration setting. The pointer +** passed as the second argument must point to a value of type (int). +** If this value is greater than 0, it is used as the new streaming data +** chunk size for both input and output. Before returning, the (int) value +** pointed to by pArg is set to the final value of the streaming interface +** chunk size. +**
      +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg); + +/* +** CAPI3REF: Values for sqlite3session_config(). +*/ +#define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. @@ -12064,7 +12593,7 @@ struct Fts5ExtensionApi { ** This way, even if the tokenizer does not provide synonyms ** when tokenizing query text (it should not - to do would be ** inefficient), it doesn't matter if the user queries for -** 'first + place' or '1st + place', as there are entires in the +** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. ** ** @@ -12092,7 +12621,7 @@ struct Fts5ExtensionApi { ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the -** token "first" is subsituted for "1st" by the tokenizer, then the query: +** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** ** ... MATCH '1s*' @@ -12941,107 +13470,119 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_ESCAPE 58 #define TK_ID 59 #define TK_COLUMNKW 60 -#define TK_FOR 61 -#define TK_IGNORE 62 -#define TK_INITIALLY 63 -#define TK_INSTEAD 64 -#define TK_NO 65 -#define TK_KEY 66 -#define TK_OF 67 -#define TK_OFFSET 68 -#define TK_PRAGMA 69 -#define TK_RAISE 70 -#define TK_RECURSIVE 71 -#define TK_REPLACE 72 -#define TK_RESTRICT 73 -#define TK_ROW 74 -#define TK_TRIGGER 75 -#define TK_VACUUM 76 -#define TK_VIEW 77 -#define TK_VIRTUAL 78 -#define TK_WITH 79 -#define TK_REINDEX 80 -#define TK_RENAME 81 -#define TK_CTIME_KW 82 -#define TK_ANY 83 -#define TK_BITAND 84 -#define TK_BITOR 85 -#define TK_LSHIFT 86 -#define TK_RSHIFT 87 -#define TK_PLUS 88 -#define TK_MINUS 89 -#define TK_STAR 90 -#define TK_SLASH 91 -#define TK_REM 92 -#define TK_CONCAT 93 -#define TK_COLLATE 94 -#define TK_BITNOT 95 -#define TK_INDEXED 96 -#define TK_STRING 97 -#define TK_JOIN_KW 98 -#define TK_CONSTRAINT 99 -#define TK_DEFAULT 100 -#define TK_NULL 101 -#define TK_PRIMARY 102 -#define TK_UNIQUE 103 -#define TK_CHECK 104 -#define TK_REFERENCES 105 -#define TK_AUTOINCR 106 -#define TK_ON 107 -#define TK_INSERT 108 -#define TK_DELETE 109 -#define TK_UPDATE 110 -#define TK_SET 111 -#define TK_DEFERRABLE 112 -#define TK_FOREIGN 113 -#define TK_DROP 114 -#define TK_UNION 115 -#define TK_ALL 116 -#define TK_EXCEPT 117 -#define TK_INTERSECT 118 -#define TK_SELECT 119 -#define TK_VALUES 120 -#define TK_DISTINCT 121 -#define TK_DOT 122 -#define TK_FROM 123 -#define TK_JOIN 124 -#define TK_USING 125 -#define TK_ORDER 126 -#define TK_GROUP 127 -#define TK_HAVING 128 -#define TK_LIMIT 129 -#define TK_WHERE 130 -#define TK_INTO 131 -#define TK_FLOAT 132 -#define TK_BLOB 133 -#define TK_INTEGER 134 -#define TK_VARIABLE 135 -#define TK_CASE 136 -#define TK_WHEN 137 -#define TK_THEN 138 -#define TK_ELSE 139 -#define TK_INDEX 140 -#define TK_ALTER 141 -#define TK_ADD 142 -#define TK_TRUEFALSE 143 -#define TK_ISNOT 144 -#define TK_FUNCTION 145 -#define TK_COLUMN 146 -#define TK_AGG_FUNCTION 147 -#define TK_AGG_COLUMN 148 -#define TK_UMINUS 149 -#define TK_UPLUS 150 -#define TK_TRUTH 151 -#define TK_REGISTER 152 -#define TK_VECTOR 153 -#define TK_SELECT_COLUMN 154 -#define TK_IF_NULL_ROW 155 -#define TK_ASTERISK 156 -#define TK_SPAN 157 -#define TK_END_OF_FILE 158 -#define TK_UNCLOSED_STRING 159 -#define TK_SPACE 160 -#define TK_ILLEGAL 161 +#define TK_DO 61 +#define TK_FOR 62 +#define TK_IGNORE 63 +#define TK_INITIALLY 64 +#define TK_INSTEAD 65 +#define TK_NO 66 +#define TK_KEY 67 +#define TK_OF 68 +#define TK_OFFSET 69 +#define TK_PRAGMA 70 +#define TK_RAISE 71 +#define TK_RECURSIVE 72 +#define TK_REPLACE 73 +#define TK_RESTRICT 74 +#define TK_ROW 75 +#define TK_ROWS 76 +#define TK_TRIGGER 77 +#define TK_VACUUM 78 +#define TK_VIEW 79 +#define TK_VIRTUAL 80 +#define TK_WITH 81 +#define TK_CURRENT 82 +#define TK_FOLLOWING 83 +#define TK_PARTITION 84 +#define TK_PRECEDING 85 +#define TK_RANGE 86 +#define TK_UNBOUNDED 87 +#define TK_REINDEX 88 +#define TK_RENAME 89 +#define TK_CTIME_KW 90 +#define TK_ANY 91 +#define TK_BITAND 92 +#define TK_BITOR 93 +#define TK_LSHIFT 94 +#define TK_RSHIFT 95 +#define TK_PLUS 96 +#define TK_MINUS 97 +#define TK_STAR 98 +#define TK_SLASH 99 +#define TK_REM 100 +#define TK_CONCAT 101 +#define TK_COLLATE 102 +#define TK_BITNOT 103 +#define TK_ON 104 +#define TK_INDEXED 105 +#define TK_STRING 106 +#define TK_JOIN_KW 107 +#define TK_CONSTRAINT 108 +#define TK_DEFAULT 109 +#define TK_NULL 110 +#define TK_PRIMARY 111 +#define TK_UNIQUE 112 +#define TK_CHECK 113 +#define TK_REFERENCES 114 +#define TK_AUTOINCR 115 +#define TK_INSERT 116 +#define TK_DELETE 117 +#define TK_UPDATE 118 +#define TK_SET 119 +#define TK_DEFERRABLE 120 +#define TK_FOREIGN 121 +#define TK_DROP 122 +#define TK_UNION 123 +#define TK_ALL 124 +#define TK_EXCEPT 125 +#define TK_INTERSECT 126 +#define TK_SELECT 127 +#define TK_VALUES 128 +#define TK_DISTINCT 129 +#define TK_DOT 130 +#define TK_FROM 131 +#define TK_JOIN 132 +#define TK_USING 133 +#define TK_ORDER 134 +#define TK_GROUP 135 +#define TK_HAVING 136 +#define TK_LIMIT 137 +#define TK_WHERE 138 +#define TK_INTO 139 +#define TK_NOTHING 140 +#define TK_FLOAT 141 +#define TK_BLOB 142 +#define TK_INTEGER 143 +#define TK_VARIABLE 144 +#define TK_CASE 145 +#define TK_WHEN 146 +#define TK_THEN 147 +#define TK_ELSE 148 +#define TK_INDEX 149 +#define TK_ALTER 150 +#define TK_ADD 151 +#define TK_WINDOW 152 +#define TK_OVER 153 +#define TK_FILTER 154 +#define TK_TRUEFALSE 155 +#define TK_ISNOT 156 +#define TK_FUNCTION 157 +#define TK_COLUMN 158 +#define TK_AGG_FUNCTION 159 +#define TK_AGG_COLUMN 160 +#define TK_UMINUS 161 +#define TK_UPLUS 162 +#define TK_TRUTH 163 +#define TK_REGISTER 164 +#define TK_VECTOR 165 +#define TK_SELECT_COLUMN 166 +#define TK_IF_NULL_ROW 167 +#define TK_ASTERISK 168 +#define TK_SPAN 169 +#define TK_END_OF_FILE 170 +#define TK_UNCLOSED_STRING 171 +#define TK_SPACE 172 +#define TK_ILLEGAL 173 /* The token codes above must all fit in 8 bits */ #define TKFLG_MASK 0xff @@ -13161,6 +13702,13 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define SQLITE_DEFAULT_PCACHE_INITSZ 20 #endif +/* +** Default value for the SQLITE_CONFIG_SORTERREF_SIZE option. +*/ +#ifndef SQLITE_DEFAULT_SORTERREF_SIZE +# define SQLITE_DEFAULT_SORTERREF_SIZE 0x7fffffff +#endif + /* ** The compile-time options SQLITE_MMAP_READWRITE and ** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another. @@ -13308,7 +13856,8 @@ typedef INT16_TYPE LogEst; # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(_M_ARM) || defined(__arm__) || defined(__x86) + defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ + (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 @@ -13349,7 +13898,7 @@ typedef INT16_TYPE LogEst; # if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) + defined(__arm__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 # elif defined(sparc) || defined(__ppc__) # define SQLITE_BYTEORDER 4321 @@ -13604,13 +14153,14 @@ typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; +typedef struct RenameToken RenameToken; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcList SrcList; -typedef struct StrAccum StrAccum; +typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; @@ -13619,12 +14169,40 @@ typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct UnpackedRecord UnpackedRecord; +typedef struct Upsert Upsert; typedef struct VTable VTable; typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WhereInfo WhereInfo; +typedef struct Window Window; typedef struct With With; + +/* +** The bitmask datatype defined below is used for various optimizations. +** +** Changing this from a 64-bit to a 32-bit type limits the number of +** tables in a join to 32 instead of 64. But it also reduces the size +** of the library by 738 bytes on ix86. +*/ +#ifdef SQLITE_BITMASK_TYPE + typedef SQLITE_BITMASK_TYPE Bitmask; +#else + typedef u64 Bitmask; +#endif + +/* +** The number of bits in a Bitmask. "BMS" means "BitMask Size". +*/ +#define BMS ((int)(sizeof(Bitmask)*8)) + +/* +** A bit in a Bitmask +*/ +#define MASKBIT(n) (((Bitmask)1)<<(n)) +#define MASKBIT32(n) (((unsigned int)1)<<(n)) +#define ALLBITS ((Bitmask)-1) + /* A VList object records a mapping between parameters/variables/wildcards ** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer ** variable number associated with that parameter. See the format description @@ -13720,7 +14298,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*); SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p); SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); -SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int,int*); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); @@ -13901,13 +14479,28 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags); ** entry in either an index or table btree. ** ** Index btrees (used for indexes and also WITHOUT ROWID tables) contain -** an arbitrary key and no data. These btrees have pKey,nKey set to their -** key and pData,nData,nZero set to zero. +** an arbitrary key and no data. These btrees have pKey,nKey set to the +** key and the pData,nData,nZero fields are uninitialized. The aMem,nMem +** fields give an array of Mem objects that are a decomposition of the key. +** The nMem field might be zero, indicating that no decomposition is available. ** ** Table btrees (used for rowid tables) contain an integer rowid used as ** the key and passed in the nKey field. The pKey field is zero. ** pData,nData hold the content of the new entry. nZero extra zero bytes ** are appended to the end of the content when constructing the entry. +** The aMem,nMem fields are uninitialized for table btrees. +** +** Field usage summary: +** +** Table BTrees Index Btrees +** +** pKey always NULL encoded key +** nKey the ROWID length of pKey +** pData data not used +** aMem not used decomposed key value +** nMem not used entries in aMem +** nData length of pData not used +** nZero extra zeros after pData not used ** ** This object is used to pass information into sqlite3BtreeInsert(). The ** same information used to be passed as five separate parameters. But placing @@ -13918,7 +14511,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags); struct BtreePayload { const void *pKey; /* Key content for indexes. NULL for tables */ sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */ - const void *pData; /* Data for tables. NULL for indexes */ + const void *pData; /* Data for tables. */ sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */ u16 nMem; /* Number of aMem[] value. Might be zero */ int nData; /* Size of pData. 0 if none. */ @@ -13928,6 +14521,9 @@ struct BtreePayload { SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor*); +#endif SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); @@ -14095,7 +14691,8 @@ struct VdbeOp { u64 cycles; /* Total time spent executing this instruction */ #endif #ifdef SQLITE_VDBE_COVERAGE - int iSrcLine; /* Source-code line that generated this opcode */ + u32 iSrcLine; /* Source-code line that generated this opcode + ** with flags in the upper 8 bits */ #endif }; typedef struct VdbeOp VdbeOp; @@ -14196,52 +14793,52 @@ typedef struct VdbeOpList VdbeOpList; #define OP_AutoCommit 1 #define OP_Transaction 2 #define OP_SorterNext 3 /* jump */ -#define OP_PrevIfOpen 4 /* jump */ -#define OP_NextIfOpen 5 /* jump */ -#define OP_Prev 6 /* jump */ -#define OP_Next 7 /* jump */ -#define OP_Checkpoint 8 -#define OP_JournalMode 9 -#define OP_Vacuum 10 -#define OP_VFilter 11 /* jump, synopsis: iplan=r[P3] zplan='P4' */ -#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */ -#define OP_Goto 13 /* jump */ -#define OP_Gosub 14 /* jump */ -#define OP_InitCoroutine 15 /* jump */ -#define OP_Yield 16 /* jump */ -#define OP_MustBeInt 17 /* jump */ -#define OP_Jump 18 /* jump */ +#define OP_Prev 4 /* jump */ +#define OP_Next 5 /* jump */ +#define OP_Checkpoint 6 +#define OP_JournalMode 7 +#define OP_Vacuum 8 +#define OP_VFilter 9 /* jump, synopsis: iplan=r[P3] zplan='P4' */ +#define OP_VUpdate 10 /* synopsis: data=r[P3@P2] */ +#define OP_Goto 11 /* jump */ +#define OP_Gosub 12 /* jump */ +#define OP_InitCoroutine 13 /* jump */ +#define OP_Yield 14 /* jump */ +#define OP_MustBeInt 15 /* jump */ +#define OP_Jump 16 /* jump */ +#define OP_Once 17 /* jump */ +#define OP_If 18 /* jump */ #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ -#define OP_Once 20 /* jump */ -#define OP_If 21 /* jump */ -#define OP_IfNot 22 /* jump */ -#define OP_IfNullRow 23 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ -#define OP_SeekLT 24 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekLE 25 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekGE 26 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekGT 27 /* jump, synopsis: key=r[P3@P4] */ -#define OP_NoConflict 28 /* jump, synopsis: key=r[P3@P4] */ -#define OP_NotFound 29 /* jump, synopsis: key=r[P3@P4] */ -#define OP_Found 30 /* jump, synopsis: key=r[P3@P4] */ -#define OP_SeekRowid 31 /* jump, synopsis: intkey=r[P3] */ -#define OP_NotExists 32 /* jump, synopsis: intkey=r[P3] */ -#define OP_Last 33 /* jump */ -#define OP_IfSmaller 34 /* jump */ -#define OP_SorterSort 35 /* jump */ -#define OP_Sort 36 /* jump */ -#define OP_Rewind 37 /* jump */ -#define OP_IdxLE 38 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxGT 39 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxLT 40 /* jump, synopsis: key=r[P3@P4] */ -#define OP_IdxGE 41 /* jump, synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 42 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_IfNot 20 /* jump */ +#define OP_IfNullRow 21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ +#define OP_SeekLT 22 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekLE 23 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGE 24 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGT 25 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */ +#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */ +#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */ +#define OP_Last 32 /* jump */ +#define OP_IfSmaller 33 /* jump */ +#define OP_SorterSort 34 /* jump */ +#define OP_Sort 35 /* jump */ +#define OP_Rewind 36 /* jump */ +#define OP_IdxLE 37 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGT 38 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxLT 39 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGE 40 /* jump, synopsis: key=r[P3@P4] */ +#define OP_RowSetRead 41 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 42 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ #define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ #define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 46 /* jump */ -#define OP_FkIfZero 47 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_IfPos 48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_IfNotZero 49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_Program 45 /* jump */ +#define OP_FkIfZero 46 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 47 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 48 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_DecrJumpZero 49 /* jump, synopsis: if (--r[P1])==0 goto P2 */ #define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ @@ -14251,118 +14848,121 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ #define OP_ElseNotEq 58 /* jump, same as TK_ESCAPE */ -#define OP_DecrJumpZero 59 /* jump, synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 60 /* jump */ -#define OP_VNext 61 /* jump */ -#define OP_Init 62 /* jump, synopsis: Start at P2 */ -#define OP_Return 63 -#define OP_EndCoroutine 64 -#define OP_HaltIfNull 65 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 66 -#define OP_Integer 67 /* synopsis: r[P2]=P1 */ -#define OP_Int64 68 /* synopsis: r[P2]=P4 */ -#define OP_String 69 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 70 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 71 /* synopsis: r[P1]=NULL */ -#define OP_Blob 72 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 73 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 74 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 75 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 76 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 77 /* synopsis: r[P2]=r[P1] */ -#define OP_ResultRow 78 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 79 -#define OP_AddImm 80 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 81 -#define OP_Cast 82 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 83 -#define OP_BitAnd 84 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ -#define OP_BitOr 85 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ -#define OP_ShiftLeft 86 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ -#define OP_Add 88 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ -#define OP_Subtract 89 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ -#define OP_Multiply 90 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ -#define OP_Divide 91 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ -#define OP_Remainder 92 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ -#define OP_Concat 93 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_Compare 94 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_BitNot 95 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ -#define OP_IsTrue 96 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ -#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_Offset 98 /* synopsis: r[P3] = sqlite_offset(P1) */ -#define OP_Column 99 /* synopsis: r[P3]=PX */ -#define OP_Affinity 100 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 101 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 102 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 103 -#define OP_SetCookie 104 -#define OP_ReopenIdx 105 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 106 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 107 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenDup 108 -#define OP_OpenAutoindex 109 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 110 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 111 -#define OP_SequenceTest 112 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ -#define OP_OpenPseudo 113 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 114 -#define OP_ColumnsUsed 115 -#define OP_Sequence 116 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 117 /* synopsis: r[P2]=rowid */ -#define OP_Insert 118 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_InsertInt 119 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 120 -#define OP_ResetCount 121 -#define OP_SorterCompare 122 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 123 /* synopsis: r[P2]=data */ -#define OP_RowData 124 /* synopsis: r[P2]=data */ -#define OP_Rowid 125 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 126 -#define OP_SeekEnd 127 -#define OP_SorterInsert 128 /* synopsis: key=r[P2] */ -#define OP_IdxInsert 129 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 130 /* synopsis: key=r[P2@P3] */ -#define OP_DeferredSeek 131 /* synopsis: Move P3 to P1.rowid if needed */ -#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_IdxRowid 133 /* synopsis: r[P2]=rowid */ -#define OP_Destroy 134 -#define OP_Clear 135 -#define OP_ResetSorter 136 -#define OP_CreateBtree 137 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ -#define OP_SqlExec 138 -#define OP_ParseSchema 139 -#define OP_LoadAnalysis 140 -#define OP_DropTable 141 -#define OP_DropIndex 142 -#define OP_DropTrigger 143 -#define OP_IntegrityCk 144 -#define OP_RowSetAdd 145 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Param 146 -#define OP_FkCounter 147 /* synopsis: fkctr[P1]+=P2 */ -#define OP_MemMax 148 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 149 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggStep0 150 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep 151 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggFinal 152 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 153 -#define OP_TableLock 154 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 155 -#define OP_VCreate 156 -#define OP_VDestroy 157 -#define OP_VOpen 158 -#define OP_VColumn 159 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 160 -#define OP_Pagecount 161 -#define OP_MaxPgcnt 162 -#define OP_PureFunc0 163 -#define OP_Function0 164 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_PureFunc 165 -#define OP_Function 166 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_Trace 167 -#define OP_CursorHint 168 -#define OP_Noop 169 -#define OP_Explain 170 +#define OP_IncrVacuum 59 /* jump */ +#define OP_VNext 60 /* jump */ +#define OP_Init 61 /* jump, synopsis: Start at P2 */ +#define OP_PureFunc0 62 +#define OP_Function0 63 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_PureFunc 64 +#define OP_Function 65 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_Return 66 +#define OP_EndCoroutine 67 +#define OP_HaltIfNull 68 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 69 +#define OP_Integer 70 /* synopsis: r[P2]=P1 */ +#define OP_Int64 71 /* synopsis: r[P2]=P4 */ +#define OP_String 72 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_Null 73 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 74 /* synopsis: r[P1]=NULL */ +#define OP_Blob 75 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 76 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 77 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 78 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 79 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 80 /* synopsis: r[P2]=r[P1] */ +#define OP_ResultRow 81 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 82 +#define OP_AddImm 83 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 84 +#define OP_Cast 85 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 86 +#define OP_Compare 87 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_IsTrue 88 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ +#define OP_Offset 89 /* synopsis: r[P3] = sqlite_offset(P1) */ +#define OP_Column 90 /* synopsis: r[P3]=PX */ +#define OP_Affinity 91 /* synopsis: affinity(r[P1@P2]) */ +#define OP_BitAnd 92 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 93 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 94 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ +#define OP_Add 96 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 97 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 98 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 99 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 100 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 101 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_MakeRecord 102 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_BitNot 103 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ +#define OP_Count 104 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 105 +#define OP_String8 106 /* same as TK_STRING, synopsis: r[P2]='P4' */ +#define OP_SetCookie 107 +#define OP_ReopenIdx 108 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 109 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 110 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenDup 111 +#define OP_OpenAutoindex 112 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 113 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 114 +#define OP_SequenceTest 115 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 116 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 117 +#define OP_ColumnsUsed 118 +#define OP_SeekHit 119 /* synopsis: seekHit=P2 */ +#define OP_Sequence 120 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 121 /* synopsis: r[P2]=rowid */ +#define OP_Insert 122 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 123 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 124 +#define OP_ResetCount 125 +#define OP_SorterCompare 126 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 127 /* synopsis: r[P2]=data */ +#define OP_RowData 128 /* synopsis: r[P2]=data */ +#define OP_Rowid 129 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 130 +#define OP_SeekEnd 131 +#define OP_SorterInsert 132 /* synopsis: key=r[P2] */ +#define OP_IdxInsert 133 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 134 /* synopsis: key=r[P2@P3] */ +#define OP_DeferredSeek 135 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 136 /* synopsis: r[P2]=rowid */ +#define OP_Destroy 137 +#define OP_Clear 138 +#define OP_ResetSorter 139 +#define OP_CreateBtree 140 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_Real 141 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_SqlExec 142 +#define OP_ParseSchema 143 +#define OP_LoadAnalysis 144 +#define OP_DropTable 145 +#define OP_DropIndex 146 +#define OP_DropTrigger 147 +#define OP_IntegrityCk 148 +#define OP_RowSetAdd 149 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 150 +#define OP_FkCounter 151 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 152 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 153 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 154 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 155 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 156 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 157 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 158 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 159 +#define OP_TableLock 160 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 161 +#define OP_VCreate 162 +#define OP_VDestroy 163 +#define OP_VOpen 164 +#define OP_VColumn 165 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 166 +#define OP_Pagecount 167 +#define OP_MaxPgcnt 168 +#define OP_Trace 169 +#define OP_CursorHint 170 +#define OP_Noop 171 +#define OP_Explain 172 +#define OP_Abortable 173 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -14375,28 +14975,28 @@ typedef struct VdbeOpList VdbeOpList; #define OPFLG_OUT2 0x10 /* out2: P2 is an output */ #define OPFLG_OUT3 0x20 /* out3: P3 is an output */ #define OPFLG_INITIALIZER {\ -/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\ -/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\ -/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x01,\ +/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\ +/* 8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\ +/* 16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\ /* 24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\ -/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ -/* 40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\ +/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 40 */ 0x01, 0x23, 0x0b, 0x26, 0x26, 0x01, 0x01, 0x03,\ /* 48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ -/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x02,\ -/* 64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\ -/* 72 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 80 */ 0x02, 0x02, 0x02, 0x00, 0x26, 0x26, 0x26, 0x26,\ -/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\ -/* 96 */ 0x12, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10, 0x10,\ -/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 112 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\ -/* 128 */ 0x04, 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00,\ -/* 136 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 144 */ 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 160 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 168 */ 0x00, 0x00, 0x00,} +/* 56 */ 0x0b, 0x0b, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,\ +/* 64 */ 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10,\ +/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,\ +/* 80 */ 0x10, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\ +/* 88 */ 0x12, 0x20, 0x00, 0x00, 0x26, 0x26, 0x26, 0x26,\ +/* 96 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\ +/* 104 */ 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 128 */ 0x00, 0x10, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,\ +/* 136 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00,\ +/* 152 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ +/* 168 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,} /* The sqlite3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -14404,7 +15004,7 @@ typedef struct VdbeOpList VdbeOpList; ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ -#define SQLITE_MX_JUMP_OPCODE 62 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 61 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ @@ -14438,7 +15038,24 @@ SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p); # define sqlite3VdbeVerifyNoMallocRequired(A,B) # define sqlite3VdbeVerifyNoResultRow(A) #endif -SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int); +#else +# define sqlite3VdbeVerifyAbortable(A,B) +#endif +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); +#ifndef SQLITE_OMIT_EXPLAIN +SQLITE_PRIVATE void sqlite3VdbeExplain(Parse*,u8,const char*,...); +SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse*); +SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*); +# define ExplainQueryPlan(P) sqlite3VdbeExplain P +# define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P) +# define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P) +#else +# define ExplainQueryPlan(P) +# define ExplainQueryPlanPop(P) +# define ExplainQueryPlanParent(P) 0 +#endif SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); @@ -14482,6 +15099,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); +SQLITE_PRIVATE int sqlite3BlobCompare(const Mem*, const Mem*); SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); @@ -14537,23 +15155,52 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); ** ** VdbeCoverageNeverTaken(v) // Previous branch is never taken ** +** VdbeCoverageNeverNull(v) // Previous three-way branch is only +** // taken on the first two ways. The +** // NULL option is not possible +** +** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested +** // in distingishing equal and not-equal. +** ** Every VDBE branch operation must be tagged with one of the macros above. ** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and ** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch() ** routine in vdbe.c, alerting the developer to the missed tag. +** +** During testing, the test application will invoke +** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback +** routine that is invoked as each bytecode branch is taken. The callback +** contains the sqlite3.c source line number ov the VdbeCoverage macro and +** flags to indicate whether or not the branch was taken. The test application +** is responsible for keeping track of this and reporting byte-code branches +** that are never taken. +** +** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the +** vdbe.c source file for additional information. */ #ifdef SQLITE_VDBE_COVERAGE SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int); # define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__) # define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__) -# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2); -# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1); +# define VdbeCoverageAlwaysTaken(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000); +# define VdbeCoverageNeverTaken(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000); +# define VdbeCoverageNeverNull(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); +# define VdbeCoverageNeverNullIf(v,x) \ + if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); +# define VdbeCoverageEqNe(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000); # define VDBE_OFFSET_LINENO(x) (__LINE__+x) #else # define VdbeCoverage(v) # define VdbeCoverageIf(v,x) # define VdbeCoverageAlwaysTaken(v) # define VdbeCoverageNeverTaken(v) +# define VdbeCoverageNeverNull(v) +# define VdbeCoverageNeverNullIf(v,x) +# define VdbeCoverageEqNe(v) # define VDBE_OFFSET_LINENO(x) 0 #endif @@ -14563,6 +15210,10 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) +SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); +#endif + #endif /* SQLITE_VDBE_H */ /************** End of vdbe.h ************************************************/ @@ -14750,16 +15401,17 @@ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); -# ifdef SQLITE_DIRECT_OVERFLOW_READ -SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno); -# endif # ifdef SQLITE_ENABLE_SNAPSHOT SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot); SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager); # endif -#else -# define sqlite3PagerUseWal(x,y) 0 +#endif + +#ifdef SQLITE_DIRECT_OVERFLOW_READ +SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno); #endif #ifdef SQLITE_ENABLE_ZIPVFS @@ -15004,6 +15656,10 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); /* Number of dirty pages as a percentage of the configured cache size */ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); +#ifdef SQLITE_DIRECT_OVERFLOW_READ +SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache); +#endif + #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ @@ -15509,12 +16165,14 @@ struct LookasideSlot { ** functions use a regular table table from hash.h.) ** ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. -** Collisions are on the FuncDef.u.pHash chain. +** Collisions are on the FuncDef.u.pHash chain. Use the SQLITE_FUNC_HASH() +** macro to compute a hash on the function name. */ #define SQLITE_FUNC_HASH_SZ 23 struct FuncDefHash { FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ }; +#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) #ifdef SQLITE_USER_AUTHENTICATION /* @@ -15575,7 +16233,7 @@ struct sqlite3 { Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ u32 mDbFlags; /* flags recording internal state */ - u32 flags; /* flags settable by pragmas. See below */ + u64 flags; /* flags settable by pragmas. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ u32 nSchemaLock; /* Do not reset the schema when non-zero */ @@ -15595,7 +16253,7 @@ struct sqlite3 { u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ u8 mTrace; /* zero or more SQLITE_TRACE flags */ - u8 skipBtreeMutex; /* True if no shared-cache backends */ + u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ int nextPagesize; /* Pagesize after VACUUM if >0 */ u32 magic; /* Magic number for detect library misuse */ @@ -15739,14 +16397,19 @@ struct sqlite3 { #define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ #define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/ #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ +#define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ +#define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ +#define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ +#define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */ /* Flags used only if debugging */ +#define HI(X) ((u64)(X)<<32) #ifdef SQLITE_DEBUG -#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */ -#define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */ -#define SQLITE_VdbeAddopTrace 0x40000000 /* Trace sqlite3VdbeAddOp() calls */ -#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_SqlTrace HI(0x0001) /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing HI(0x0002) /* Debug listings of VDBE progs */ +#define SQLITE_VdbeTrace HI(0x0004) /* True to trace VDBE execution */ +#define SQLITE_VdbeAddopTrace HI(0x0008) /* Trace sqlite3VdbeAddOp() calls */ +#define SQLITE_VdbeEQP HI(0x0010) /* Debug EXPLAIN QUERY PLAN */ #endif /* @@ -15755,6 +16418,7 @@ struct sqlite3 { #define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */ #define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ +#define DBFLAG_SchemaKnownOk 0x0008 /* Schema is known to be valid */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the @@ -15762,7 +16426,7 @@ struct sqlite3 { ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ -#define SQLITE_ColumnCache 0x0002 /* Column cache */ + /* 0x0002 available for reuse */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */ @@ -15776,6 +16440,8 @@ struct sqlite3 { /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */ #define SQLITE_PushDown 0x1000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */ +#define SQLITE_SkipScan 0x4000 /* Skip-scans */ +#define SQLITE_PropagateConst 0x8000 /* The constant propagation opt */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* @@ -15814,11 +16480,13 @@ struct sqlite3 { */ struct FuncDef { i8 nArg; /* Number of arguments. -1 means unlimited */ - u16 funcFlags; /* Some combination of SQLITE_FUNC_* */ + u32 funcFlags; /* Some combination of SQLITE_FUNC_* */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */ void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ + void (*xValue)(sqlite3_context*); /* Current agg value */ + void (*xInverse)(sqlite3_context*,int,sqlite3_value**); /* inverse agg-step */ const char *zName; /* SQL name of the function. */ union { FuncDef *pHash; /* Next with a different name but the same hash */ @@ -15875,6 +16543,9 @@ struct FuncDestructor { ** single query - might change over time */ #define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */ #define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */ +#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ +#define SQLITE_FUNC_WINDOW_SIZE 0x20000 /* Requires partition size as arg. */ +#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -15909,6 +16580,12 @@ struct FuncDestructor { ** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** +** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse) +** Used to create an aggregate function definition implemented by +** the C functions xStep and xFinal. The first four parameters +** are interpreted in the same way as the first 4 parameters to +** FUNCTION(). +** ** LIKEFUNC(zName, nArg, pArg, flags) ** Used to create a scalar function definition of a function zName ** that accepts nArg arguments and is implemented by a call to C @@ -15919,31 +16596,38 @@ struct FuncDestructor { */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ - 0, 0, xFunc, 0, #zName, {0} } + 0, 0, xFunc, 0, 0, 0, #zName, {0} } #define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ - (void*)&sqlite3Config, 0, xFunc, 0, #zName, {0} } + (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - pArg, 0, xFunc, 0, #zName, } + pArg, 0, xFunc, 0, 0, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ - (void *)arg, 0, likeFunc, 0, #zName, {0} } -#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ + (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } +#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,0,#zName, {0}} #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}} +#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ + {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} +#define INTERNAL_FUNCTION(zName, nArg, xFunc) \ + {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + 0, 0, xFunc, 0, 0, 0, #zName, {0} } + /* ** All current savepoints are stored in a linked list starting at @@ -16000,6 +16684,7 @@ struct Column { #define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ #define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ #define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */ +#define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ /* ** A "Collating Sequence" is defined by an instance of the following @@ -16127,6 +16812,9 @@ struct VTable { struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ +#ifdef SQLITE_ENABLE_NORMALIZE + Hash *pColHash; /* All columns indexed by name */ +#endif Index *pIndex; /* List of SQL indexes on this table. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ FKey *pFKey; /* Linked list of all foreign keys in this table */ @@ -16177,6 +16865,7 @@ struct Table { #define TF_StatsUsed 0x0100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ #define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */ +#define TF_Shadow 0x0400 /* True for a shadow table */ /* ** Test to see whether or not a table is a virtual table. This is @@ -16287,13 +16976,12 @@ struct FKey { #define OE_Fail 3 /* Stop the operation but leave all prior changes */ #define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ #define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ - -#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ -#define OE_SetNull 7 /* Set the foreign key value to NULL */ -#define OE_SetDflt 8 /* Set the foreign key value to its default */ -#define OE_Cascade 9 /* Cascade the changes */ - -#define OE_Default 10 /* Do whatever the default action is */ +#define OE_Update 6 /* Process as a DO UPDATE in an upsert */ +#define OE_Restrict 7 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ +#define OE_SetNull 8 /* Set the foreign key value to NULL */ +#define OE_SetDflt 9 /* Set the foreign key value to its default */ +#define OE_Cascade 10 /* Cascade the changes */ +#define OE_Default 11 /* Do whatever the default action is */ /* @@ -16429,6 +17117,7 @@ struct Index { tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ #endif + Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */ }; /* @@ -16463,13 +17152,21 @@ struct IndexSample { tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ }; +/* +** Possible values to use within the flags argument to sqlite3GetToken(). +*/ +#define SQLITE_TOKEN_QUOTED 0x1 /* Token is a quoted identifier. */ +#define SQLITE_TOKEN_KEYWORD 0x2 /* Token is a keyword. */ + /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** -** Note if Token.z==0 then Token.dyn and Token.n are undefined and -** may contain random values. Do not make any assumptions about Token.dyn -** and Token.n when Token.z==0. +** The memory that "z" points to is owned by other objects. Take care +** that the owner of the "z" string does not deallocate the string before +** the Token goes out of scope! Very often, the "z" points to some place +** in the middle of the Parse.zSql text. But it might also point to a +** static string. */ struct Token { const char *z; /* Text of the token. Not NULL-terminated! */ @@ -16642,8 +17339,11 @@ struct Expr { ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ - Table *pTab; /* Table for TK_COLUMN expressions. Can be NULL - ** for a column of an index on an expression */ + union { + Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL + ** for a column of an index on an expression */ + Window *pWin; /* TK_FUNCTION: Window definition for the func */ + } y; }; /* @@ -16652,7 +17352,7 @@ struct Expr { #define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ #define EP_Agg 0x000002 /* Contains one or more aggregate functions */ #define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ - /* 0x000008 // available for use */ +#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ @@ -16673,6 +17373,7 @@ struct Expr { #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ #define EP_Alias 0x400000 /* Is an alias for a result set column */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ +#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ /* ** The EP_Propagate mask is a set of properties that automatically propagate @@ -16740,6 +17441,7 @@ struct ExprList { unsigned done :1; /* A flag to indicate when processing is finished */ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */ unsigned reusable :1; /* Constant expression is reusable */ + unsigned bSorterRef :1; /* Defer evaluation until after sorting */ union { struct { u16 iOrderByCol; /* For ORDER BY, column number in result set */ @@ -16773,31 +17475,6 @@ struct IdList { int nId; /* Number of identifiers on the list */ }; -/* -** The bitmask datatype defined below is used for various optimizations. -** -** Changing this from a 64-bit to a 32-bit type limits the number of -** tables in a join to 32 instead of 64. But it also reduces the size -** of the library by 738 bytes on ix86. -*/ -#ifdef SQLITE_BITMASK_TYPE - typedef SQLITE_BITMASK_TYPE Bitmask; -#else - typedef u64 Bitmask; -#endif - -/* -** The number of bits in a Bitmask. "BMS" means "BitMask Size". -*/ -#define BMS ((int)(sizeof(Bitmask)*8)) - -/* -** A bit in a Bitmask -*/ -#define MASKBIT(n) (((Bitmask)1)<<(n)) -#define MASKBIT32(n) (((unsigned int)1)<<(n)) -#define ALLBITS ((Bitmask)-1) - /* ** The following structure describes the FROM clause of a SELECT statement. ** Each table or subquery in the FROM clause is a separate element of @@ -16839,9 +17516,6 @@ struct SrcList { unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ } fg; -#ifndef SQLITE_OMIT_EXPLAIN - u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ -#endif int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ @@ -16923,12 +17597,16 @@ struct SrcList { struct NameContext { Parse *pParse; /* The parser */ SrcList *pSrcList; /* One or more tables used to resolve names */ - ExprList *pEList; /* Optional list of result-set columns */ - AggInfo *pAggInfo; /* Information about aggregates at this level */ + union { + ExprList *pEList; /* Optional list of result-set columns */ + AggInfo *pAggInfo; /* Information about aggregates at this level */ + Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */ + } uNC; NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nErr; /* Number of errors encountered while resolving names */ u16 ncFlags; /* Zero or more NC_* flags defined below */ + Select *pWinSelect; /* SELECT statement for any window functions */ }; /* @@ -16946,18 +17624,49 @@ struct NameContext { #define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ #define NC_VarSelect 0x0040 /* A correlated subquery has been seen */ +#define NC_UEList 0x0080 /* True if uNC.pEList is used */ +#define NC_UAggInfo 0x0100 /* True if uNC.pAggInfo is used */ +#define NC_UUpsert 0x0200 /* True if uNC.pUpsert is used */ #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ #define NC_Complex 0x2000 /* True if a function or subquery seen */ +#define NC_AllowWin 0x4000 /* Window functions are allowed here */ + +/* +** An instance of the following object describes a single ON CONFLICT +** clause in an upsert. +** +** The pUpsertTarget field is only set if the ON CONFLICT clause includes +** conflict-target clause. (In "ON CONFLICT(a,b)" the "(a,b)" is the +** conflict-target clause.) The pUpsertTargetWhere is the optional +** WHERE clause used to identify partial unique indexes. +** +** pUpsertSet is the list of column=expr terms of the UPDATE statement. +** The pUpsertSet field is NULL for a ON CONFLICT DO NOTHING. The +** pUpsertWhere is the WHERE clause for the UPDATE and is NULL if the +** WHERE clause is omitted. +*/ +struct Upsert { + ExprList *pUpsertTarget; /* Optional description of conflicting index */ + Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */ + ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */ + Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ + /* The fields above comprise the parse tree for the upsert clause. + ** The fields below are used to transfer information from the INSERT + ** processing down into the UPDATE processing while generating code. + ** Upsert owns the memory allocated above, but not the memory below. */ + Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */ + SrcList *pUpsertSrc; /* Table to be updated */ + int regData; /* First register holding array of VALUES */ + int iDataCur; /* Index of the data cursor */ + int iIdxCur; /* Index of the first index cursor */ +}; /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. ** -** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. -** If there is a LIMIT clause, the parser sets nLimit to the value of the -** limit and nOffset to the value of the offset (or 0 if there is not -** offset). But later on, nLimit and nOffset become the memory locations -** in the VDBE that record the limit and offset counters. +** See the header comment on the computeLimitRegisters() routine for a +** detailed description of the meaning of the iLimit and iOffset fields. ** ** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. ** These addresses must be stored so that we can go back and fill in @@ -16975,9 +17684,7 @@ struct Select { LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ -#if SELECTTRACE_ENABLED - char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ -#endif + u32 selId; /* Unique identifier number for this SELECT */ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ @@ -16988,6 +17695,10 @@ struct Select { Select *pNext; /* Next select to the left in a compound */ Expr *pLimit; /* LIMIT expression. NULL means not used. */ With *pWith; /* WITH clause attached to this select. Or NULL. */ +#ifndef SQLITE_OMIT_WINDOWFUNC + Window *pWin; /* List of window functions */ + Window *pWinDefn; /* List of named window definitions */ +#endif }; /* @@ -17017,8 +17728,7 @@ struct Select { #define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ #define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ -#define SF_ComplexResult 0x40000 /* Result set contains subquery or function */ - +#define SF_ComplexResult 0x40000 /* Result contains subquery or function */ /* ** The results of a SELECT can be distributed in several ways, as defined @@ -17132,13 +17842,6 @@ struct AutoincInfo { int regCtr; /* Memory register holding the rowid counter */ }; -/* -** Size of the column cache -*/ -#ifndef SQLITE_N_COLCACHE -# define SQLITE_N_COLCACHE 10 -#endif - /* ** At least one instance of the following structure is created for each ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE @@ -17214,7 +17917,6 @@ struct Parse { u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ - u8 nColCache; /* Number of entries in aColCache[] */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ @@ -17224,8 +17926,6 @@ struct Parse { int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ - int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ - int iCacheCnt; /* Counter used to generate aColCache[].lru values */ int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ @@ -17235,9 +17935,7 @@ struct Parse { int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ -#if SELECTTRACE_ENABLED - int nSelect; /* Number of SELECT statements seen */ -#endif + int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ @@ -17257,17 +17955,9 @@ struct Parse { ** Fields above must be initialized to zero. The fields that follow, ** down to the beginning of the recursive section, do not need to be ** initialized as they will be set before being used. The boundary is - ** determined by offsetof(Parse,aColCache). + ** determined by offsetof(Parse,aTempReg). **************************************************************************/ - struct yColCache { - int iTable; /* Table cursor number */ - i16 iColumn; /* Table column number */ - u8 tempReg; /* iReg is a temp register that needs to be freed */ - int iLevel; /* Nesting level */ - int iReg; /* Reg with value of this column. 0 means none. */ - int lru; /* Least recently used entry has the smallest value */ - } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ int aTempReg[8]; /* Holding area for temporary registers */ Token sNameToken; /* Token with unqualified schema object name */ @@ -17282,19 +17972,21 @@ struct Parse { ynVar nVar; /* Number of '?' variables seen in the SQL so far */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ +#if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)) + u8 eParseMode; /* PARSE_MODE_XXX constant */ +#endif #ifndef SQLITE_OMIT_VIRTUALTABLE - u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN - int iSelectId; /* ID of current select for EXPLAIN output */ - int iNextSelectId; /* Next available select ID for EXPLAIN output */ + int addrExplain; /* Address of current OP_Explain opcode */ #endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ + Index *pNewIndex; /* An index being constructed by CREATE INDEX */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -17305,12 +17997,20 @@ struct Parse { TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ With *pWithToFree; /* Free this WITH object at the end of the parse */ +#ifndef SQLITE_OMIT_ALTERTABLE + RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ +#endif }; +#define PARSE_MODE_NORMAL 0 +#define PARSE_MODE_DECLARE_VTAB 1 +#define PARSE_MODE_RENAME_COLUMN 2 +#define PARSE_MODE_RENAME_TABLE 3 + /* ** Sizes and pointers of various parts of the Parse object. */ -#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/ +#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/ #define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ #define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ #define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ @@ -17321,7 +18021,19 @@ struct Parse { #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #else - #define IN_DECLARE_VTAB (pParse->declareVtab) + #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB) +#endif + +#if defined(SQLITE_OMIT_ALTERTABLE) + #define IN_RENAME_OBJECT 0 +#else + #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME_COLUMN) +#endif + +#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE) + #define IN_SPECIAL_PARSE 0 +#else + #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL) #endif /* @@ -17347,6 +18059,7 @@ struct AuthContext { */ #define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ /* Also used in P2 (not P5) of OP_Delete */ +#define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ @@ -17448,8 +18161,9 @@ struct TriggerStep { Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ - ExprList *pExprList; /* SET clause for UPDATE. */ + ExprList *pExprList; /* SET clause for UPDATE */ IdList *pIdList; /* Column names for INSERT */ + Upsert *pUpsert; /* Upsert clauses on an INSERT */ char *zSpan; /* Original SQL text of this command */ TriggerStep *pNext; /* Next in the link-list */ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ @@ -17474,17 +18188,15 @@ struct DbFixer { ** An objected used to accumulate the text of a string where we ** do not necessarily know how big the string will be in the end. */ -struct StrAccum { +struct sqlite3_str { sqlite3 *db; /* Optional database for lookaside. Can be NULL */ char *zText; /* The string collected so far */ u32 nAlloc; /* Amount of space allocated in zText */ u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */ u32 nChar; /* Length of the string so far */ - u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */ + u8 accError; /* SQLITE_NOMEM or SQLITE_TOOBIG */ u8 printfFlags; /* SQLITE_PRINTF flags below */ }; -#define STRACCUM_NOMEM 1 -#define STRACCUM_TOOBIG 2 #define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */ #define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */ #define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */ @@ -17501,8 +18213,14 @@ typedef struct { char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ + u32 mInitFlags; /* Flags controlling error messages */ } InitData; +/* +** Allowed values for mInitFlags +*/ +#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */ + /* ** Structure containing global configuration data for the SQLite library. ** @@ -17553,14 +18271,16 @@ struct Sqlite3Config { /* The following callback (if not NULL) is invoked on every VDBE branch ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. */ - void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ + void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ + int bInternalFunctions; /* Internal SQL functions are visible */ int iOnceResetThreshold; /* When to reset OP_Once counters */ + u32 szSorterRef; /* Min size in bytes to use sorter-refs */ }; /* @@ -17603,6 +18323,9 @@ struct Walker { struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */ ExprList *pGroupBy; /* GROUP BY clause */ Select *pSelect; /* HAVING to WHERE clause ctx */ + struct WindowRewrite *pRewrite; /* Window rewrite context */ + struct WhereConst *pConst; /* WHERE clause constants */ + struct RenameCtx *pRename; /* RENAME COLUMN context */ } u; }; @@ -17653,6 +18376,68 @@ struct TreeView { }; #endif /* SQLITE_DEBUG */ +/* +** This object is used in varioius ways, all related to window functions +** +** (1) A single instance of this structure is attached to the +** the Expr.pWin field for each window function in an expression tree. +** This object holds the information contained in the OVER clause, +** plus additional fields used during code generation. +** +** (2) All window functions in a single SELECT form a linked-list +** attached to Select.pWin. The Window.pFunc and Window.pExpr +** fields point back to the expression that is the window function. +** +** (3) The terms of the WINDOW clause of a SELECT are instances of this +** object on a linked list attached to Select.pWinDefn. +** +** The uses (1) and (2) are really the same Window object that just happens +** to be accessible in two different ways. Use (3) is are separate objects. +*/ +struct Window { + char *zName; /* Name of window (may be NULL) */ + ExprList *pPartition; /* PARTITION BY clause */ + ExprList *pOrderBy; /* ORDER BY clause */ + u8 eType; /* TK_RANGE or TK_ROWS */ + u8 eStart; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ + u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ + Expr *pStart; /* Expression for " PRECEDING" */ + Expr *pEnd; /* Expression for " FOLLOWING" */ + Window *pNextWin; /* Next window function belonging to this SELECT */ + Expr *pFilter; /* The FILTER expression */ + FuncDef *pFunc; /* The function */ + int iEphCsr; /* Partition buffer or Peer buffer */ + int regAccum; + int regResult; + int csrApp; /* Function cursor (used by min/max) */ + int regApp; /* Function register (also used by min/max) */ + int regPart; /* First in a set of registers holding PARTITION BY + ** and ORDER BY values for the window */ + Expr *pOwner; /* Expression object this window is attached to */ + int nBufferCol; /* Number of columns in buffer table */ + int iArgCol; /* Offset of first argument for this function */ +}; + +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*); +SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p); +SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*); +SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*); +SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*); +SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Window*); +SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); +SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*); +SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, struct SrcList_item*); +SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); +SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); +SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p); +SQLITE_PRIVATE void sqlite3WindowFunctions(void); +#else +# define sqlite3WindowDelete(a,b) +# define sqlite3WindowFunctions() +# define sqlite3WindowAttach(a,b,c) +#endif + /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. @@ -17740,15 +18525,14 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); # define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') #endif -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_PRIVATE int sqlite3IsIdChar(u8); -#endif /* ** Internal function prototypes */ SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*); SQLITE_PRIVATE int sqlite3Strlen30(const char*); +#define sqlite3Strlen30NN(C) (strlen(C)&0x3fffffff) SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*); #define sqlite3StrNICmp sqlite3_strnicmp @@ -17852,8 +18636,6 @@ struct PrintfArguments { sqlite3_value **apArg; /* The argument values */ }; -SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list); -SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...); SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...); SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list); #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) @@ -17867,8 +18649,13 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*); SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); +SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*); SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8); SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView*, const Window*, u8); +SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); +#endif #endif @@ -17893,7 +18680,7 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); -SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); +SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); @@ -17905,6 +18692,7 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); +SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32); SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); #ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); @@ -17954,8 +18742,9 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); #endif -SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); -SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*); +SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*); +SQLITE_PRIVATE void sqlite3RowSetDelete(void*); +SQLITE_PRIVATE void sqlite3RowSetClear(void*); SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64); SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*); @@ -17974,6 +18763,7 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); +SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); @@ -17981,9 +18771,9 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif -SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int); +SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); -SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); +SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); @@ -18011,13 +18801,14 @@ SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); #endif SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); -SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*); +SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, + Upsert*); SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); -SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); @@ -18027,15 +18818,8 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); -SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(Parse*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); -SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); -SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*); -SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); -SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*); -SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); @@ -18098,13 +18882,17 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3IsRowid(const char*); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE int sqlite3IsRowidN(const char*, int); +#endif SQLITE_PRIVATE void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); +SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int); SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, - u8,u8,int,int*,int*); + u8,u8,int,int*,int*,Upsert*); #ifdef SQLITE_ENABLE_NULL_TRIM SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe*,Table*); #else @@ -18123,10 +18911,8 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); -#if SELECTTRACE_ENABLED -SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*); -#else -# define sqlite3SelectSetName(A,B) +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE FuncDef *sqlite3FunctionSearchN(int,const char*,int); #endif SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); @@ -18156,11 +18942,12 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, i SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*, - Select*,u8,const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, + Select*,u8,Upsert*, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8, + const char*,const char*); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, const char*,const char*); SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); @@ -18275,6 +19062,7 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void); SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); +SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); @@ -18283,6 +19071,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Toke SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); +SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*); SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); @@ -18327,9 +19116,13 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int); SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); SQLITE_PRIVATE void sqlite3AlterFunctions(void); SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); +SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE int sqlite3GetTokenNormalized(const unsigned char *, int *, int *); +#endif SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); -SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*); +SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int); SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); @@ -18342,8 +19135,12 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int); SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); +SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*); +SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); +SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*); SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); -SQLITE_PRIVATE char sqlite3AffinityType(const char*, u8*); +SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*); SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*); SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); @@ -18360,25 +19157,27 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo*); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo*); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); + #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*); #endif SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), - void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), + void (*)(sqlite3_context*,int,sqlite3_value **), + void (*)(sqlite3_context*), + void (*)(sqlite3_context*), + void (*)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ); +SQLITE_PRIVATE void sqlite3NoopDestructor(void*); SQLITE_PRIVATE void sqlite3OomFault(sqlite3*); SQLITE_PRIVATE void sqlite3OomClear(sqlite3*); SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); -SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int); -SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum*,const char*); -SQLITE_PRIVATE void sqlite3AppendChar(StrAccum*,int,char); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); -SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*); SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int); SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); @@ -18405,10 +19204,11 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int); ** The interface to the LEMON-generated parser */ #ifndef SQLITE_AMALGAMATION -SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64)); +SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64), Parse*); SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); #endif -SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*); +SQLITE_PRIVATE void sqlite3Parser(void*, int, Token); +SQLITE_PRIVATE int sqlite3ParserFallback(int); #ifdef YYTRACKMAXSTACKDEPTH SQLITE_PRIVATE int sqlite3ParserStackPeak(void*); #endif @@ -18474,11 +19274,13 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*); SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *); SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); -SQLITE_PRIVATE void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); SQLITE_PRIVATE void sqlite3ParserReset(Parse*); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE void sqlite3Normalize(Vdbe*, const char*, int, u8); +#endif SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*); SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); @@ -18496,6 +19298,18 @@ SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8); #define sqlite3WithPush(x,y,z) #define sqlite3WithDelete(x,y) #endif +#ifndef SQLITE_OMIT_UPSERT +SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*); +SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*); +SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); +SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); +SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); +#else +#define sqlite3UpsertNew(v,w,x,y,z) ((Upsert*)0) +#define sqlite3UpsertDelete(x,y) +#define sqlite3UpsertDup(x,y) ((Upsert*)0) +#endif + /* Declarations for functions in fkey.c. All of these are replaced by ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign @@ -18928,7 +19742,9 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ - 0x7ffffffe /* iOnceResetThreshold */ + 0, /* bInternalFunctions */ + 0x7ffffffe, /* iOnceResetThreshold */ + SQLITE_DEFAULT_SORTERREF_SIZE /* szSorterRef */ }; /* @@ -19097,6 +19913,7 @@ struct VdbeCursor { Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ + Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */ Btree *pBtx; /* Separate file holding temporary table */ i64 seqCount; /* Sequence counter */ int *aAltMap; /* Mapping from table to index column numbers */ @@ -19180,6 +19997,9 @@ struct VdbeFrame { void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ +#if SQLITE_DEBUG + u32 iFrameMagic; /* magic number for sanity checking */ +#endif int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ @@ -19190,6 +20010,13 @@ struct VdbeFrame { int nDbChange; /* Value of db->nChange */ }; +/* Magic number for sanity checking on VdbeFrame objects */ +#define SQLITE_FRAME_MAGIC 0x879fb71e + +/* +** Return a pointer to the array of registers allocated for use +** by a VdbeFrame. +*/ #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* @@ -19204,8 +20031,6 @@ struct sqlite3_value { int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ - RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ - VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ } u; u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ @@ -19220,7 +20045,7 @@ struct sqlite3_value { void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ - void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */ + u16 mScopyFlags; /* flags value immediately after the shallow copy */ #endif }; @@ -19249,8 +20074,8 @@ struct sqlite3_value { #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_AffMask 0x001f /* Mask of affinity bits */ -#define MEM_RowSet 0x0020 /* Value is a RowSet object */ -#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ +/* Available 0x0020 */ +/* Available 0x0040 */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_TypeMask 0xc1ff /* Mask of type bits */ @@ -19277,7 +20102,7 @@ struct sqlite3_value { ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ - (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) + (((X)->flags&(MEM_Agg|MEM_Dyn))!=0) /* ** Clear any existing type flags from a Mem and replace them with f @@ -19391,14 +20216,15 @@ struct Vdbe { int nOp; /* Number of instructions in the program */ #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ + u32 nWrite; /* Number of write operations that have occurred */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ - bft expired:1; /* True if the VM needs to be recompiled */ - bft doingRerun:1; /* True if rerunning after an auto-reprepare */ + bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* True if EXPLAIN present on SQL command */ + bft doingRerun:1; /* True if rerunning after an auto-reprepare */ bft changeCntOn:1; /* True to update the change-counter */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ @@ -19408,6 +20234,9 @@ struct Vdbe { yDbMask lockMask; /* Subset of btreeMask that requires a lock */ u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ +#ifdef SQLITE_ENABLE_NORMALIZE + char *zNormSql; /* Normalization of the associated SQL statement */ +#endif void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ @@ -19459,9 +20288,6 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*); SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); -#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) -SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); -#endif SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8); SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*); @@ -19473,7 +20299,9 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); +#ifndef SQLITE_OMIT_EXPLAIN SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); +#endif SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int); SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*); @@ -19492,7 +20320,10 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(v SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); -SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*); +#endif +SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*); @@ -19506,11 +20337,20 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8); SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*); +#endif +#ifndef SQLITE_OMIT_EXPLAIN SQLITE_PRIVATE const char *sqlite3OpcodeName(int); +#endif SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); -SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame*); +#endif +SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */ +SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int); @@ -19526,6 +20366,14 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*); +SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*); +#else +# define sqlite3VdbeIncrWriteCounter(V,C) +# define sqlite3VdbeAssertAbortable(V) +#endif + #if !defined(SQLITE_OMIT_SHARED_CACHE) SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); #else @@ -21600,9 +22448,12 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ ** Unregister a VFS so that it is no longer accessible. */ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ -#if SQLITE_THREADSAFE - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + MUTEX_LOGIC(sqlite3_mutex *mutex;) +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return rc; #endif + MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); sqlite3_mutex_leave(mutex); @@ -24218,7 +25069,6 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ #endif /* !defined(SQLITE_MUTEX_OMIT) */ - /************** End of mutex.c ***********************************************/ /************** Begin file mutex_noop.c **************************************/ /* @@ -26382,7 +27232,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ ** Set the StrAccum object to an error mode. */ static void setStrAccumError(StrAccum *p, u8 eError){ - assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG ); + assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; p->nAlloc = 0; } @@ -26416,8 +27266,8 @@ static char *getTextArg(PrintfArguments *p){ /* ** Render a string given by "fmt" into the StrAccum object. */ -SQLITE_PRIVATE void sqlite3VXPrintf( - StrAccum *pAccum, /* Accumulate results here */ +SQLITE_API void sqlite3_str_vappendf( + sqlite3_str *pAccum, /* Accumulate results here */ const char *fmt, /* Format string */ va_list ap /* arguments */ ){ @@ -26474,11 +27324,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( #else do{ fmt++; }while( *fmt && *fmt != '%' ); #endif - sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); + sqlite3_str_append(pAccum, bufpt, (int)(fmt - bufpt)); if( *fmt==0 ) break; } if( (c=(*++fmt))==0 ){ - sqlite3StrAccumAppend(pAccum, "%", 1); + sqlite3_str_append(pAccum, "%", 1); break; } /* Find out what flags are present */ @@ -26656,7 +27506,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( u64 n = (u64)precision + 10 + precision/3; zOut = zExtra = sqlite3Malloc( n ); if( zOut==0 ){ - setStrAccumError(pAccum, STRACCUM_NOMEM); + setStrAccumError(pAccum, SQLITE_NOMEM); return; } nOut = (int)n; @@ -26781,7 +27631,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 ); if( bufpt==0 ){ - setStrAccumError(pAccum, STRACCUM_NOMEM); + setStrAccumError(pAccum, SQLITE_NOMEM); return; } } @@ -26913,11 +27763,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( precision>1 ){ width -= precision-1; if( width>1 && !flag_leftjustify ){ - sqlite3AppendChar(pAccum, width-1, ' '); + sqlite3_str_appendchar(pAccum, width-1, ' '); width = 0; } while( precision-- > 1 ){ - sqlite3StrAccumAppend(pAccum, buf, length); + sqlite3_str_append(pAccum, buf, length); } } bufpt = buf; @@ -26934,7 +27784,12 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( bufpt==0 ){ bufpt = ""; }else if( xtype==etDYNSTRING ){ - if( pAccum->nChar==0 && pAccum->mxAlloc && width==0 && precision<0 ){ + if( pAccum->nChar==0 + && pAccum->mxAlloc + && width==0 + && precision<0 + && pAccum->accError==0 + ){ /* Special optimization for sqlite3_mprintf("%z..."): ** Extend an existing memory allocation rather than creating ** a new one. */ @@ -27003,7 +27858,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( n>etBUFSIZE ){ bufpt = zExtra = sqlite3Malloc( n ); if( bufpt==0 ){ - setStrAccumError(pAccum, STRACCUM_NOMEM); + setStrAccumError(pAccum, SQLITE_NOMEM); return; } }else{ @@ -27027,7 +27882,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf( pToken = va_arg(ap, Token*); assert( bArgList==0 ); if( pToken && pToken->n ){ - sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n); + sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); } length = width = 0; break; @@ -27043,10 +27898,10 @@ SQLITE_PRIVATE void sqlite3VXPrintf( assert( bArgList==0 ); assert( k>=0 && knSrc ); if( pItem->zDatabase ){ - sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase); - sqlite3StrAccumAppend(pAccum, ".", 1); + sqlite3_str_appendall(pAccum, pItem->zDatabase); + sqlite3_str_append(pAccum, ".", 1); } - sqlite3StrAccumAppendAll(pAccum, pItem->zName); + sqlite3_str_appendall(pAccum, pItem->zName); length = width = 0; break; } @@ -27065,11 +27920,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( */ width -= length; if( width>0 ){ - if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); - sqlite3StrAccumAppend(pAccum, bufpt, length); - if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); + if( !flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); + sqlite3_str_append(pAccum, bufpt, length); + if( flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); }else{ - sqlite3StrAccumAppend(pAccum, bufpt, length); + sqlite3_str_append(pAccum, bufpt, length); } if( zExtra ){ @@ -27090,13 +27945,13 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zNew; assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ - testcase(p->accError==STRACCUM_TOOBIG); - testcase(p->accError==STRACCUM_NOMEM); + testcase(p->accError==SQLITE_TOOBIG); + testcase(p->accError==SQLITE_NOMEM); return 0; } if( p->mxAlloc==0 ){ N = p->nAlloc - p->nChar - 1; - setStrAccumError(p, STRACCUM_TOOBIG); + setStrAccumError(p, SQLITE_TOOBIG); return N; }else{ char *zOld = isMalloced(p) ? p->zText : 0; @@ -27108,8 +27963,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ szNew += p->nChar; } if( szNew > p->mxAlloc ){ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_TOOBIG); + sqlite3_str_reset(p); + setStrAccumError(p, SQLITE_TOOBIG); return 0; }else{ p->nAlloc = (int)szNew; @@ -27126,8 +27981,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ p->nAlloc = sqlite3DbMallocSize(p->db, zNew); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_NOMEM); + sqlite3_str_reset(p); + setStrAccumError(p, SQLITE_NOMEM); return 0; } } @@ -27137,7 +27992,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ /* ** Append N copies of character c to the given string buffer. */ -SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ +SQLITE_API void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){ testcase( p->nChar + (i64)N > 0x7fffffff ); if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ return; @@ -27149,9 +28004,9 @@ SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ ** The StrAccum "p" is not large enough to accept N new bytes of z[]. ** So enlarge if first, then do the append. ** -** This is a helper routine to sqlite3StrAccumAppend() that does special-case +** This is a helper routine to sqlite3_str_append() that does special-case ** work (enlarging the buffer) using tail recursion, so that the -** sqlite3StrAccumAppend() routine can use fast calling semantics. +** sqlite3_str_append() routine can use fast calling semantics. */ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ N = sqlite3StrAccumEnlarge(p, N); @@ -27165,7 +28020,7 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ ** Append N bytes of text from z to the StrAccum object. Increase the ** size of the memory allocation for StrAccum if necessary. */ -SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ +SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); @@ -27182,8 +28037,8 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ /* ** Append the complete text of zero-terminated string z[] to the p string. */ -SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ - sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z)); +SQLITE_API void sqlite3_str_appendall(sqlite3_str *p, const char *z){ + sqlite3_str_append(p, z, sqlite3Strlen30(z)); } @@ -27200,7 +28055,7 @@ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ - setStrAccumError(p, STRACCUM_NOMEM); + setStrAccumError(p, SQLITE_NOMEM); } p->zText = zText; return zText; @@ -27215,14 +28070,56 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ return p->zText; } +/* +** This singleton is an sqlite3_str object that is returned if +** sqlite3_malloc() fails to provide space for a real one. This +** sqlite3_str object accepts no new text and always returns +** an SQLITE_NOMEM error. +*/ +static sqlite3_str sqlite3OomStr = { + 0, 0, 0, 0, 0, SQLITE_NOMEM, 0 +}; + +/* Finalize a string created using sqlite3_str_new(). +*/ +SQLITE_API char *sqlite3_str_finish(sqlite3_str *p){ + char *z; + if( p!=0 && p!=&sqlite3OomStr ){ + z = sqlite3StrAccumFinish(p); + sqlite3_free(p); + }else{ + z = 0; + } + return z; +} + +/* Return any error code associated with p */ +SQLITE_API int sqlite3_str_errcode(sqlite3_str *p){ + return p ? p->accError : SQLITE_NOMEM; +} + +/* Return the current length of p in bytes */ +SQLITE_API int sqlite3_str_length(sqlite3_str *p){ + return p ? p->nChar : 0; +} + +/* Return the current value for p */ +SQLITE_API char *sqlite3_str_value(sqlite3_str *p){ + if( p==0 || p->nChar==0 ) return 0; + p->zText[p->nChar] = 0; + return p->zText; +} + /* ** Reset an StrAccum string. Reclaim all malloced memory. */ -SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ +SQLITE_API void sqlite3_str_reset(StrAccum *p){ if( isMalloced(p) ){ sqlite3DbFree(p->db, p->zText); p->printfFlags &= ~SQLITE_PRINTF_MALLOCED; } + p->nAlloc = 0; + p->nChar = 0; p->zText = 0; } @@ -27250,6 +28147,18 @@ SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, i p->printfFlags = 0; } +/* Allocate and initialize a new dynamic string object */ +SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3 *db){ + sqlite3_str *p = sqlite3_malloc64(sizeof(*p)); + if( p ){ + sqlite3StrAccumInit(p, 0, 0, 0, + db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH); + }else{ + p = &sqlite3OomStr; + } + return p; +} + /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. @@ -27262,9 +28171,9 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); acc.printfFlags = SQLITE_PRINTF_INTERNAL; - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); - if( acc.accError==STRACCUM_NOMEM ){ + if( acc.accError==SQLITE_NOMEM ){ sqlite3OomFault(db); } return z; @@ -27302,7 +28211,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ if( sqlite3_initialize() ) return 0; #endif sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); return z; } @@ -27347,7 +28256,7 @@ SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_li } #endif sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); zBuf[acc.nChar] = 0; return zBuf; } @@ -27369,7 +28278,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ ** allocate memory because it might be called while the memory allocator ** mutex is held. ** -** sqlite3VXPrintf() might ask for *temporary* memory allocations for +** sqlite3_str_vappendf() might ask for *temporary* memory allocations for ** certain format characters (%q) or for very large precisions or widths. ** Care must be taken that any sqlite3_log() calls that occur while the ** memory mutex is held do not use these mechanisms. @@ -27379,7 +28288,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, sqlite3StrAccumFinish(&acc)); } @@ -27408,7 +28317,7 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ char zBuf[500]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); va_start(ap,zFormat); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); sqlite3StrAccumFinish(&acc); #ifdef SQLITE_OS_TRACE_PROC @@ -27425,13 +28334,13 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ /* -** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument +** variable-argument wrapper around sqlite3_str_vappendf(). The bFlags argument ** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats. */ -SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){ +SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){ va_list ap; va_start(ap,zFormat); - sqlite3VXPrintf(p, zFormat, ap); + sqlite3_str_vappendf(p, zFormat, ap); va_end(ap); } @@ -27497,15 +28406,17 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); if( p ){ for(i=0; iiLevel && ibLine)-1; i++){ - sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); + sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4); } - sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); + sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); + } + if( zFormat!=0 ){ + va_start(ap, zFormat); + sqlite3_str_vappendf(&acc, zFormat, ap); + va_end(ap); + assert( acc.nChar>0 ); + sqlite3_str_append(&acc, "\n", 1); } - va_start(ap, zFormat); - sqlite3VXPrintf(&acc, zFormat, ap); - va_end(ap); - assert( acc.nChar>0 ); - if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); fflush(stdout); @@ -27538,17 +28449,17 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m char zLine[1000]; const struct Cte *pCte = &pWith->a[i]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3XPrintf(&x, "%s", pCte->zName); + sqlite3_str_appendf(&x, "%s", pCte->zName); if( pCte->pCols && pCte->pCols->nExpr>0 ){ char cSep = '('; int j; for(j=0; jpCols->nExpr; j++){ - sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName); + sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zName); cSep = ','; } - sqlite3XPrintf(&x, ")"); + sqlite3_str_appendf(&x, ")"); } - sqlite3XPrintf(&x, " AS"); + sqlite3_str_appendf(&x, " AS"); sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); @@ -27558,6 +28469,42 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m } } +/* +** Generate a human-readable description of a SrcList object. +*/ +SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ + int i; + for(i=0; inSrc; i++){ + const struct SrcList_item *pItem = &pSrc->a[i]; + StrAccum x; + char zLine[100]; + sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); + sqlite3_str_appendf(&x, "{%d,*}", pItem->iCursor); + if( pItem->zDatabase ){ + sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName); + }else if( pItem->zName ){ + sqlite3_str_appendf(&x, " %s", pItem->zName); + } + if( pItem->pTab ){ + sqlite3_str_appendf(&x, " tabname=%Q", pItem->pTab->zName); + } + if( pItem->zAlias ){ + sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias); + } + if( pItem->fg.jointype & JT_LEFT ){ + sqlite3_str_appendf(&x, " LEFT-JOIN"); + } + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, inSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + if( pItem->fg.isTabFunc ){ + sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); + } + sqlite3TreeViewPop(pView); + } +} /* ** Generate a human-readable description of a Select object. @@ -27576,21 +28523,13 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewPush(pView, 1); } do{ -#if SELECTTRACE_ENABLED sqlite3TreeViewLine(pView, - "SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d", + "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), - p->zSelName, p, p->selFlags, + p->selId, p, p->selFlags, (int)p->nSelectRow ); -#else - sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", - ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, - (int)p->nSelectRow - ); -#endif if( cnt++ ) sqlite3TreeViewPop(pView); if( p->pPrior ){ n = 1000; @@ -27602,42 +28541,27 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m if( p->pHaving ) n++; if( p->pOrderBy ) n++; if( p->pLimit ) n++; +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ) n++; + if( p->pWinDefn ) n++; +#endif } sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ){ + Window *pX; + pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewLine(pView, "window-functions"); + for(pX=p->pWin; pX; pX=pX->pNextWin){ + sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0); + } + sqlite3TreeViewPop(pView); + } +#endif if( p->pSrc && p->pSrc->nSrc ){ - int i; pView = sqlite3TreeViewPush(pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); - for(i=0; ipSrc->nSrc; i++){ - struct SrcList_item *pItem = &p->pSrc->a[i]; - StrAccum x; - char zLine[100]; - sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor); - if( pItem->zDatabase ){ - sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName); - }else if( pItem->zName ){ - sqlite3XPrintf(&x, " %s", pItem->zName); - } - if( pItem->pTab ){ - sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName); - } - if( pItem->zAlias ){ - sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias); - } - if( pItem->fg.jointype & JT_LEFT ){ - sqlite3XPrintf(&x, " LEFT-JOIN"); - } - sqlite3StrAccumFinish(&x); - sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); - if( pItem->pSelect ){ - sqlite3TreeViewSelect(pView, pItem->pSelect, 0); - } - if( pItem->fg.isTabFunc ){ - sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); - } - sqlite3TreeViewPop(pView); - } + sqlite3TreeViewSrcList(pView, p->pSrc); sqlite3TreeViewPop(pView); } if( p->pWhere ){ @@ -27653,6 +28577,16 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewExpr(pView, p->pHaving, 0); sqlite3TreeViewPop(pView); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWinDefn ){ + Window *pX; + sqlite3TreeViewItem(pView, "WINDOW", (n--)>0); + for(pX=p->pWinDefn; pX; pX=pX->pNextWin){ + sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0); + } + sqlite3TreeViewPop(pView); + } +#endif if( p->pOrderBy ){ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } @@ -27680,6 +28614,83 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewPop(pView); } +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Generate a description of starting or stopping bounds +*/ +SQLITE_PRIVATE void sqlite3TreeViewBound( + TreeView *pView, /* View context */ + u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */ + Expr *pExpr, /* Value for PRECEDING or FOLLOWING */ + u8 moreToFollow /* True if more to follow */ +){ + switch( eBound ){ + case TK_UNBOUNDED: { + sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow); + sqlite3TreeViewPop(pView); + break; + } + case TK_CURRENT: { + sqlite3TreeViewItem(pView, "CURRENT", moreToFollow); + sqlite3TreeViewPop(pView); + break; + } + case TK_PRECEDING: { + sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow); + sqlite3TreeViewExpr(pView, pExpr, 0); + sqlite3TreeViewPop(pView); + break; + } + case TK_FOLLOWING: { + sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow); + sqlite3TreeViewExpr(pView, pExpr, 0); + sqlite3TreeViewPop(pView); + break; + } + } +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Generate a human-readable explanation for a Window object +*/ +SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ + pView = sqlite3TreeViewPush(pView, more); + if( pWin->zName ){ + sqlite3TreeViewLine(pView, "OVER %s", pWin->zName); + }else{ + sqlite3TreeViewLine(pView, "OVER"); + } + if( pWin->pPartition ){ + sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY"); + } + if( pWin->pOrderBy ){ + sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY"); + } + if( pWin->eType ){ + sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0); + sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); + sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Generate a human-readable explanation for a Window Function object +*/ +SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ + pView = sqlite3TreeViewPush(pView, more); + sqlite3TreeViewLine(pView, "WINFUNC %s(%d)", + pWin->pFunc->zName, pWin->pFunc->nArg); + sqlite3TreeViewWindow(pView, pWin, 0); + sqlite3TreeViewPop(pView); +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + /* ** Generate a human-readable explanation of an expression tree. */ @@ -27717,6 +28728,9 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewLine(pView, "{%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); } + if( ExprHasProperty(pExpr, EP_FixedCol) ){ + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + } break; } case TK_INTEGER: { @@ -27830,10 +28844,17 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m case TK_AGG_FUNCTION: case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ + Window *pWin; if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; + pWin = 0; }else{ pFarg = pExpr->x.pList; +#ifndef SQLITE_OMIT_WINDOWFUNC + pWin = pExpr->y.pWin; +#else + pWin = 0; +#endif } if( pExpr->op==TK_AGG_FUNCTION ){ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", @@ -27842,8 +28863,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); } if( pFarg ){ - sqlite3TreeViewExprList(pView, pFarg, 0, 0); + sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pWin ){ + sqlite3TreeViewWindow(pView, pWin, 0); + } +#endif break; } #ifndef SQLITE_OMIT_SUBQUERY @@ -27975,16 +29001,21 @@ SQLITE_PRIVATE void sqlite3TreeViewBareExprList( for(i=0; inExpr; i++){ int j = pList->a[i].u.x.iOrderByCol; char *zName = pList->a[i].zName; + int moreToFollow = inExpr - 1; if( j || zName ){ - sqlite3TreeViewPush(pView, 0); + sqlite3TreeViewPush(pView, moreToFollow); + moreToFollow = 0; + sqlite3TreeViewLine(pView, 0); + if( zName ){ + fprintf(stdout, "AS %s ", zName); + } + if( j ){ + fprintf(stdout, "iOrderByCol=%d", j); + } + fprintf(stdout, "\n"); + fflush(stdout); } - if( zName ){ - sqlite3TreeViewLine(pView, "AS %s", zName); - } - if( j ){ - sqlite3TreeViewLine(pView, "iOrderByCol=%d", j); - } - sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); + sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); if( j || zName ){ sqlite3TreeViewPop(pView); } @@ -30648,6 +31679,20 @@ static unsigned int strHash(const char *z){ } return h; } +#ifdef SQLITE_ENABLE_NORMALIZE +static unsigned int strHashN(const char *z, int n){ + unsigned int h = 0; + int i; + for(i=0; iht ){ /*OPTIMIZATION-IF-TRUE*/ + struct _ht *pEntry; + h = strHashN(pKey, nKey) % pH->htsize; + pEntry = &pH->ht[h]; + elem = pEntry->chain; + count = pEntry->count; + }else{ + h = 0; + elem = pH->first; + count = pH->count; + } + if( pHash ) *pHash = h; + while( count-- ){ + assert( elem!=0 ); + if( sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){ + return elem; + } + elem = elem->next; + } + return &nullElement; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. @@ -30803,6 +31882,14 @@ SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ assert( pKey!=0 ); return findElementWithHash(pH, pKey, 0)->data; } +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE void *sqlite3HashFindN(const Hash *pH, const char *pKey, int nKey){ + assert( pH!=0 ); + assert( pKey!=0 ); + assert( nKey>=0 ); + return findElementWithHashN(pH, pKey, nKey, 0)->data; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ /* Insert an element into the hash table pH. The key is pKey ** and the data is "data". @@ -30870,52 +31957,52 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 1 */ "AutoCommit" OpHelp(""), /* 2 */ "Transaction" OpHelp(""), /* 3 */ "SorterNext" OpHelp(""), - /* 4 */ "PrevIfOpen" OpHelp(""), - /* 5 */ "NextIfOpen" OpHelp(""), - /* 6 */ "Prev" OpHelp(""), - /* 7 */ "Next" OpHelp(""), - /* 8 */ "Checkpoint" OpHelp(""), - /* 9 */ "JournalMode" OpHelp(""), - /* 10 */ "Vacuum" OpHelp(""), - /* 11 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), - /* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"), - /* 13 */ "Goto" OpHelp(""), - /* 14 */ "Gosub" OpHelp(""), - /* 15 */ "InitCoroutine" OpHelp(""), - /* 16 */ "Yield" OpHelp(""), - /* 17 */ "MustBeInt" OpHelp(""), - /* 18 */ "Jump" OpHelp(""), + /* 4 */ "Prev" OpHelp(""), + /* 5 */ "Next" OpHelp(""), + /* 6 */ "Checkpoint" OpHelp(""), + /* 7 */ "JournalMode" OpHelp(""), + /* 8 */ "Vacuum" OpHelp(""), + /* 9 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), + /* 10 */ "VUpdate" OpHelp("data=r[P3@P2]"), + /* 11 */ "Goto" OpHelp(""), + /* 12 */ "Gosub" OpHelp(""), + /* 13 */ "InitCoroutine" OpHelp(""), + /* 14 */ "Yield" OpHelp(""), + /* 15 */ "MustBeInt" OpHelp(""), + /* 16 */ "Jump" OpHelp(""), + /* 17 */ "Once" OpHelp(""), + /* 18 */ "If" OpHelp(""), /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), - /* 20 */ "Once" OpHelp(""), - /* 21 */ "If" OpHelp(""), - /* 22 */ "IfNot" OpHelp(""), - /* 23 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), - /* 24 */ "SeekLT" OpHelp("key=r[P3@P4]"), - /* 25 */ "SeekLE" OpHelp("key=r[P3@P4]"), - /* 26 */ "SeekGE" OpHelp("key=r[P3@P4]"), - /* 27 */ "SeekGT" OpHelp("key=r[P3@P4]"), - /* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"), - /* 29 */ "NotFound" OpHelp("key=r[P3@P4]"), - /* 30 */ "Found" OpHelp("key=r[P3@P4]"), - /* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"), - /* 32 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 33 */ "Last" OpHelp(""), - /* 34 */ "IfSmaller" OpHelp(""), - /* 35 */ "SorterSort" OpHelp(""), - /* 36 */ "Sort" OpHelp(""), - /* 37 */ "Rewind" OpHelp(""), - /* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"), - /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"), - /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 20 */ "IfNot" OpHelp(""), + /* 21 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), + /* 22 */ "SeekLT" OpHelp("key=r[P3@P4]"), + /* 23 */ "SeekLE" OpHelp("key=r[P3@P4]"), + /* 24 */ "SeekGE" OpHelp("key=r[P3@P4]"), + /* 25 */ "SeekGT" OpHelp("key=r[P3@P4]"), + /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"), + /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"), + /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"), + /* 29 */ "Found" OpHelp("key=r[P3@P4]"), + /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"), + /* 31 */ "NotExists" OpHelp("intkey=r[P3]"), + /* 32 */ "Last" OpHelp(""), + /* 33 */ "IfSmaller" OpHelp(""), + /* 34 */ "SorterSort" OpHelp(""), + /* 35 */ "Sort" OpHelp(""), + /* 36 */ "Rewind" OpHelp(""), + /* 37 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 38 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 39 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 40 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 41 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 42 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), - /* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 46 */ "Program" OpHelp(""), - /* 47 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 48 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 49 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 45 */ "Program" OpHelp(""), + /* 46 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 47 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 48 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 49 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), @@ -30925,118 +32012,121 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 56 */ "Lt" OpHelp("IF r[P3]=r[P1]"), /* 58 */ "ElseNotEq" OpHelp(""), - /* 59 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 60 */ "IncrVacuum" OpHelp(""), - /* 61 */ "VNext" OpHelp(""), - /* 62 */ "Init" OpHelp("Start at P2"), - /* 63 */ "Return" OpHelp(""), - /* 64 */ "EndCoroutine" OpHelp(""), - /* 65 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 66 */ "Halt" OpHelp(""), - /* 67 */ "Integer" OpHelp("r[P2]=P1"), - /* 68 */ "Int64" OpHelp("r[P2]=P4"), - /* 69 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 70 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 71 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 72 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 73 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 74 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 75 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 76 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 77 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 78 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 79 */ "CollSeq" OpHelp(""), - /* 80 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 81 */ "RealAffinity" OpHelp(""), - /* 82 */ "Cast" OpHelp("affinity(r[P1])"), - /* 83 */ "Permutation" OpHelp(""), - /* 84 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), - /* 85 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), - /* 86 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), - /* 88 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), - /* 89 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), - /* 90 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), - /* 91 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), - /* 92 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), - /* 93 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 94 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 95 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), - /* 96 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), - /* 97 */ "String8" OpHelp("r[P2]='P4'"), - /* 98 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), - /* 99 */ "Column" OpHelp("r[P3]=PX"), - /* 100 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 101 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 102 */ "Count" OpHelp("r[P2]=count()"), - /* 103 */ "ReadCookie" OpHelp(""), - /* 104 */ "SetCookie" OpHelp(""), - /* 105 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 106 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 107 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 108 */ "OpenDup" OpHelp(""), - /* 109 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 110 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 111 */ "SorterOpen" OpHelp(""), - /* 112 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), - /* 113 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 114 */ "Close" OpHelp(""), - /* 115 */ "ColumnsUsed" OpHelp(""), - /* 116 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 117 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 118 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 119 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 120 */ "Delete" OpHelp(""), - /* 121 */ "ResetCount" OpHelp(""), - /* 122 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 123 */ "SorterData" OpHelp("r[P2]=data"), - /* 124 */ "RowData" OpHelp("r[P2]=data"), - /* 125 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 126 */ "NullRow" OpHelp(""), - /* 127 */ "SeekEnd" OpHelp(""), - /* 128 */ "SorterInsert" OpHelp("key=r[P2]"), - /* 129 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 130 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 131 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), - /* 132 */ "Real" OpHelp("r[P2]=P4"), - /* 133 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 134 */ "Destroy" OpHelp(""), - /* 135 */ "Clear" OpHelp(""), - /* 136 */ "ResetSorter" OpHelp(""), - /* 137 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), - /* 138 */ "SqlExec" OpHelp(""), - /* 139 */ "ParseSchema" OpHelp(""), - /* 140 */ "LoadAnalysis" OpHelp(""), - /* 141 */ "DropTable" OpHelp(""), - /* 142 */ "DropIndex" OpHelp(""), - /* 143 */ "DropTrigger" OpHelp(""), - /* 144 */ "IntegrityCk" OpHelp(""), - /* 145 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 146 */ "Param" OpHelp(""), - /* 147 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 148 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 149 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 150 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 151 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 152 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 153 */ "Expire" OpHelp(""), - /* 154 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 155 */ "VBegin" OpHelp(""), - /* 156 */ "VCreate" OpHelp(""), - /* 157 */ "VDestroy" OpHelp(""), - /* 158 */ "VOpen" OpHelp(""), - /* 159 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 160 */ "VRename" OpHelp(""), - /* 161 */ "Pagecount" OpHelp(""), - /* 162 */ "MaxPgcnt" OpHelp(""), - /* 163 */ "PureFunc0" OpHelp(""), - /* 164 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), - /* 165 */ "PureFunc" OpHelp(""), - /* 166 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), - /* 167 */ "Trace" OpHelp(""), - /* 168 */ "CursorHint" OpHelp(""), - /* 169 */ "Noop" OpHelp(""), - /* 170 */ "Explain" OpHelp(""), + /* 59 */ "IncrVacuum" OpHelp(""), + /* 60 */ "VNext" OpHelp(""), + /* 61 */ "Init" OpHelp("Start at P2"), + /* 62 */ "PureFunc0" OpHelp(""), + /* 63 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 64 */ "PureFunc" OpHelp(""), + /* 65 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), + /* 66 */ "Return" OpHelp(""), + /* 67 */ "EndCoroutine" OpHelp(""), + /* 68 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 69 */ "Halt" OpHelp(""), + /* 70 */ "Integer" OpHelp("r[P2]=P1"), + /* 71 */ "Int64" OpHelp("r[P2]=P4"), + /* 72 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 73 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 74 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 75 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 76 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 77 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 78 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 79 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 80 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 81 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 82 */ "CollSeq" OpHelp(""), + /* 83 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 84 */ "RealAffinity" OpHelp(""), + /* 85 */ "Cast" OpHelp("affinity(r[P1])"), + /* 86 */ "Permutation" OpHelp(""), + /* 87 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 88 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), + /* 89 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), + /* 90 */ "Column" OpHelp("r[P3]=PX"), + /* 91 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 92 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 93 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 94 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), + /* 96 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 97 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 98 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 99 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 100 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 101 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 102 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 103 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), + /* 104 */ "Count" OpHelp("r[P2]=count()"), + /* 105 */ "ReadCookie" OpHelp(""), + /* 106 */ "String8" OpHelp("r[P2]='P4'"), + /* 107 */ "SetCookie" OpHelp(""), + /* 108 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 109 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 110 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 111 */ "OpenDup" OpHelp(""), + /* 112 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 113 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 114 */ "SorterOpen" OpHelp(""), + /* 115 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 116 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 117 */ "Close" OpHelp(""), + /* 118 */ "ColumnsUsed" OpHelp(""), + /* 119 */ "SeekHit" OpHelp("seekHit=P2"), + /* 120 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 121 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 122 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 123 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 124 */ "Delete" OpHelp(""), + /* 125 */ "ResetCount" OpHelp(""), + /* 126 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 127 */ "SorterData" OpHelp("r[P2]=data"), + /* 128 */ "RowData" OpHelp("r[P2]=data"), + /* 129 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 130 */ "NullRow" OpHelp(""), + /* 131 */ "SeekEnd" OpHelp(""), + /* 132 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 133 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 134 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 135 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), + /* 136 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 137 */ "Destroy" OpHelp(""), + /* 138 */ "Clear" OpHelp(""), + /* 139 */ "ResetSorter" OpHelp(""), + /* 140 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), + /* 141 */ "Real" OpHelp("r[P2]=P4"), + /* 142 */ "SqlExec" OpHelp(""), + /* 143 */ "ParseSchema" OpHelp(""), + /* 144 */ "LoadAnalysis" OpHelp(""), + /* 145 */ "DropTable" OpHelp(""), + /* 146 */ "DropIndex" OpHelp(""), + /* 147 */ "DropTrigger" OpHelp(""), + /* 148 */ "IntegrityCk" OpHelp(""), + /* 149 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 150 */ "Param" OpHelp(""), + /* 151 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 152 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 153 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 154 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 155 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 156 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 157 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 158 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 159 */ "Expire" OpHelp(""), + /* 160 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 161 */ "VBegin" OpHelp(""), + /* 162 */ "VCreate" OpHelp(""), + /* 163 */ "VDestroy" OpHelp(""), + /* 164 */ "VOpen" OpHelp(""), + /* 165 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 166 */ "VRename" OpHelp(""), + /* 167 */ "Pagecount" OpHelp(""), + /* 168 */ "MaxPgcnt" OpHelp(""), + /* 169 */ "Trace" OpHelp(""), + /* 170 */ "CursorHint" OpHelp(""), + /* 171 */ "Noop" OpHelp(""), + /* 172 */ "Explain" OpHelp(""), + /* 173 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -31182,12 +32272,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* -** If we are to be thread-safe, include the pthreads header and define -** the SQLITE_UNIX_THREADS macro. +** If we are to be thread-safe, include the pthreads header. */ #if SQLITE_THREADSAFE /* # include */ -# define SQLITE_UNIX_THREADS 1 #endif /* @@ -31765,7 +32853,11 @@ static struct unix_syscall { #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) +# ifdef __ANDROID__ + { "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 }, +# else { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, +# endif #else { "ioctl", (sqlite3_syscall_ptr)0, 0 }, #endif @@ -31946,12 +33038,25 @@ static int robust_open(const char *z, int f, mode_t m){ ** unixEnterMutex() ** assert( unixMutexHeld() ); ** unixEnterLeave() +** +** To prevent deadlock, the global unixBigLock must must be acquired +** before the unixInodeInfo.pLockMutex mutex, if both are held. It is +** OK to get the pLockMutex without holding unixBigLock first, but if +** that happens, the unixBigLock mutex must not be acquired until after +** pLockMutex is released. +** +** OK: enter(unixBigLock), enter(pLockInfo) +** OK: enter(unixBigLock) +** OK: enter(pLockInfo) +** ERROR: enter(pLockInfo), enter(unixBigLock) */ static sqlite3_mutex *unixBigLock = 0; static void unixEnterMutex(void){ + assert( sqlite3_mutex_notheld(unixBigLock) ); /* Not a recursive mutex */ sqlite3_mutex_enter(unixBigLock); } static void unixLeaveMutex(void){ + assert( sqlite3_mutex_held(unixBigLock) ); sqlite3_mutex_leave(unixBigLock); } #ifdef SQLITE_DEBUG @@ -32346,22 +33451,39 @@ struct unixFileId { /* ** An instance of the following structure is allocated for each open -** inode. Or, on LinuxThreads, there is one of these structures for -** each inode opened by each thread. +** inode. ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this ** object keeps a count of the number of unixFile pointing to it. +** +** Mutex rules: +** +** (1) Only the pLockMutex mutex must be held in order to read or write +** any of the locking fields: +** nShared, nLock, eFileLock, bProcessLock, pUnused +** +** (2) When nRef>0, then the following fields are unchanging and can +** be read (but not written) without holding any mutex: +** fileId, pLockMutex +** +** (3) With the exceptions above, all the fields may only be read +** or written while holding the global unixBigLock mutex. +** +** Deadlock prevention: The global unixBigLock mutex may not +** be acquired while holding the pLockMutex mutex. If both unixBigLock +** and pLockMutex are needed, then unixBigLock must be acquired first. */ struct unixInodeInfo { struct unixFileId fileId; /* The lookup key */ - int nShared; /* Number of SHARED locks held */ - unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ - unsigned char bProcessLock; /* An exclusive process lock is held */ + sqlite3_mutex *pLockMutex; /* Hold this mutex for... */ + int nShared; /* Number of SHARED locks held */ + int nLock; /* Number of outstanding file locks */ + unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ + unsigned char bProcessLock; /* An exclusive process lock is held */ + UnixUnusedFd *pUnused; /* Unused file descriptors to close */ int nRef; /* Number of pointers to this structure */ unixShmNode *pShmNode; /* Shared memory associated with this inode */ - int nLock; /* Number of outstanding file locks */ - UnixUnusedFd *pUnused; /* Unused file descriptors to close */ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ unixInodeInfo *pPrev; /* .... doubly linked */ #if SQLITE_ENABLE_LOCKING_STYLE @@ -32375,9 +33497,26 @@ struct unixInodeInfo { /* ** A lists of all unixInodeInfo objects. +** +** Must hold unixBigLock in order to read or write this variable. */ static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ -static unsigned int nUnusedFd = 0; /* Total unused file descriptors */ + +#ifdef SQLITE_DEBUG +/* +** True if the inode mutex (on the unixFile.pFileMutex field) is held, or not. +** This routine is used only within assert() to help verify correct mutex +** usage. +*/ +int unixFileMutexHeld(unixFile *pFile){ + assert( pFile->pInode ); + return sqlite3_mutex_held(pFile->pInode->pLockMutex); +} +int unixFileMutexNotheld(unixFile *pFile){ + assert( pFile->pInode ); + return sqlite3_mutex_notheld(pFile->pInode->pLockMutex); +} +#endif /* ** @@ -32483,11 +33622,11 @@ static void closePendingFds(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p; UnixUnusedFd *pNext; + assert( unixFileMutexHeld(pFile) ); for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; robust_close(pFile, p->fd, __LINE__); sqlite3_free(p); - nUnusedFd--; } pInode->pUnused = 0; } @@ -32495,17 +33634,20 @@ static void closePendingFds(unixFile *pFile){ /* ** Release a unixInodeInfo structure previously allocated by findInodeInfo(). ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must be held when this routine is called, but the mutex +** on the inode being deleted must NOT be held. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); + assert( unixFileMutexNotheld(pFile) ); if( ALWAYS(pInode) ){ pInode->nRef--; if( pInode->nRef==0 ){ assert( pInode->pShmNode==0 ); + sqlite3_mutex_enter(pInode->pLockMutex); closePendingFds(pFile); + sqlite3_mutex_leave(pInode->pLockMutex); if( pInode->pPrev ){ assert( pInode->pPrev->pNext==pInode ); pInode->pPrev->pNext = pInode->pNext; @@ -32517,10 +33659,10 @@ static void releaseInodeInfo(unixFile *pFile){ assert( pInode->pNext->pPrev==pInode ); pInode->pNext->pPrev = pInode->pPrev; } + sqlite3_mutex_free(pInode->pLockMutex); sqlite3_free(pInode); } } - assert( inodeList!=0 || nUnusedFd==0 ); } /* @@ -32528,8 +33670,7 @@ static void releaseInodeInfo(unixFile *pFile){ ** describes that file descriptor. Create a new one if necessary. The ** return value might be uninitialized if an error occurs. ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must held when calling this routine. ** ** Return an appropriate error code. */ @@ -32590,7 +33731,7 @@ static int findInodeInfo( #else fileId.ino = (u64)statbuf.st_ino; #endif - assert( inodeList!=0 || nUnusedFd==0 ); + assert( unixMutexHeld() ); pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; @@ -32602,7 +33743,15 @@ static int findInodeInfo( } memset(pInode, 0, sizeof(*pInode)); memcpy(&pInode->fileId, &fileId, sizeof(fileId)); + if( sqlite3GlobalConfig.bCoreMutex ){ + pInode->pLockMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pInode->pLockMutex==0 ){ + sqlite3_free(pInode); + return SQLITE_NOMEM_BKPT; + } + } pInode->nRef = 1; + assert( unixMutexHeld() ); pInode->pNext = inodeList; pInode->pPrev = 0; if( inodeList ) inodeList->pPrev = pInode; @@ -32680,7 +33829,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ assert( pFile ); assert( pFile->eFileLock<=SHARED_LOCK ); - unixEnterMutex(); /* Because pFile->pInode is shared across threads */ + sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ @@ -32705,7 +33854,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ } #endif - unixLeaveMutex(); + sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; @@ -32771,8 +33920,8 @@ static int osSetPosixAdvisoryLock( static int unixFileLock(unixFile *pFile, struct flock *pLock){ int rc; unixInodeInfo *pInode = pFile->pInode; - assert( unixMutexHeld() ); assert( pInode!=0 ); + assert( sqlite3_mutex_held(pInode->pLockMutex) ); if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ if( pInode->bProcessLock==0 ){ struct flock lock; @@ -32891,8 +34040,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* This mutex is needed because pFile->pInode is shared across threads */ - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. @@ -33035,7 +34184,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ } end_lock: - unixLeaveMutex(); + sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; @@ -33048,11 +34197,11 @@ end_lock: static void setPendingFd(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p = pFile->pPreallocatedUnused; + assert( unixFileMutexHeld(pFile) ); p->pNext = pInode->pUnused; pInode->pUnused = p; pFile->h = -1; pFile->pPreallocatedUnused = 0; - nUnusedFd++; } /* @@ -33083,8 +34232,8 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); @@ -33210,14 +34359,14 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ */ pInode->nLock--; assert( pInode->nLock>=0 ); - if( pInode->nLock==0 ){ - closePendingFds(pFile); - } + if( pInode->nLock==0 ) closePendingFds(pFile); } end_unlock: - unixLeaveMutex(); - if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; + sqlite3_mutex_leave(pInode->pLockMutex); + if( rc==SQLITE_OK ){ + pFile->eFileLock = eFileLock; + } return rc; } @@ -33288,15 +34437,20 @@ static int closeUnixFile(sqlite3_file *id){ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; unixFile *pFile = (unixFile *)id; + unixInodeInfo *pInode = pFile->pInode; + + assert( pInode!=0 ); verifyDbFile(pFile); unixUnlock(id, NO_LOCK); + assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); /* unixFile.pInode is always valid here. Otherwise, a different close ** routine (e.g. nolockClose()) would be called instead. */ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); - if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){ + sqlite3_mutex_enter(pInode->pLockMutex); + if( pInode->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pInode->pUnused list. It will be automatically closed @@ -33304,6 +34458,7 @@ static int unixClose(sqlite3_file *id){ */ setPendingFd(pFile); } + sqlite3_mutex_leave(pInode->pLockMutex); releaseInodeInfo(pFile); rc = closeUnixFile(id); unixLeaveMutex(); @@ -33901,6 +35056,7 @@ static int semXClose(sqlite3_file *id) { unixFile *pFile = (unixFile*)id; semXUnlock(id, NO_LOCK); assert( pFile ); + assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); releaseInodeInfo(pFile); unixLeaveMutex(); @@ -34015,8 +35171,7 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ *pResOut = 1; return SQLITE_OK; } - unixEnterMutex(); /* Because pFile->pInode is shared across threads */ - + sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; @@ -34040,7 +35195,7 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ } } - unixLeaveMutex(); + sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved)); *pResOut = reserved; @@ -34103,8 +35258,8 @@ static int afpLock(sqlite3_file *id, int eFileLock){ /* This mutex is needed because pFile->pInode is shared across threads */ - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. @@ -34240,7 +35395,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ } afp_end_lock: - unixLeaveMutex(); + sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; @@ -34272,8 +35427,8 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); @@ -34342,14 +35497,14 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { if( rc==SQLITE_OK ){ pInode->nLock--; assert( pInode->nLock>=0 ); - if( pInode->nLock==0 ){ - closePendingFds(pFile); - } + if( pInode->nLock==0 ) closePendingFds(pFile); } } - unixLeaveMutex(); - if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; + sqlite3_mutex_leave(pInode->pLockMutex); + if( rc==SQLITE_OK ){ + pFile->eFileLock = eFileLock; + } return rc; } @@ -34361,14 +35516,20 @@ static int afpClose(sqlite3_file *id) { unixFile *pFile = (unixFile*)id; assert( id!=0 ); afpUnlock(id, NO_LOCK); + assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); - if( pFile->pInode && pFile->pInode->nLock ){ - /* If there are outstanding locks, do not actually close the file just - ** yet because that would clear those locks. Instead, add the file - ** descriptor to pInode->aPending. It will be automatically closed when - ** the last lock is cleared. - */ - setPendingFd(pFile); + if( pFile->pInode ){ + unixInodeInfo *pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); + if( pInode->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pInode->aPending. It will be automatically closed when + ** the last lock is cleared. + */ + setPendingFd(pFile); + } + sqlite3_mutex_leave(pInode->pLockMutex); } releaseInodeInfo(pFile); sqlite3_free(pFile->lockingContext); @@ -35023,7 +36184,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); - if( err ) return SQLITE_IOERR_WRITE; + if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; #else /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely @@ -35388,18 +36549,18 @@ static int unixGetpagesize(void){ ** ** The following fields are read-only after the object is created: ** -** fid +** hShm ** zFilename ** -** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and +** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and ** unixMutexHeld() is true when reading or writing any other field ** in this structure. */ struct unixShmNode { unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ - sqlite3_mutex *mutex; /* Mutex to access this object */ + sqlite3_mutex *pShmMutex; /* Mutex to access this object */ char *zFilename; /* Name of the mmapped file */ - int h; /* Open file descriptor */ + int hShm; /* Open file descriptor */ int szRegion; /* Size of shared-memory regions */ u16 nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ @@ -35421,16 +36582,16 @@ struct unixShmNode { ** The following fields are initialized when this object is created and ** are read-only thereafter: ** -** unixShm.pFile +** unixShm.pShmNode ** unixShm.id ** -** All other fields are read/write. The unixShm.pFile->mutex must be held -** while accessing any read/write fields. +** All other fields are read/write. The unixShm.pShmNode->pShmMutex must +** be held while accessing any read/write fields. */ struct unixShm { unixShmNode *pShmNode; /* The underlying unixShmNode object */ unixShm *pNext; /* Next unixShm with the same unixShmNode */ - u8 hasMutex; /* True if holding the unixShmNode mutex */ + u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */ u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ @@ -35460,7 +36621,8 @@ static int unixShmSystemLock( /* Access to the unixShmNode object is serialized by the caller */ pShmNode = pFile->pInode->pShmNode; - assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) ); + assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); + assert( pShmNode->nRef>0 || unixMutexHeld() ); /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); @@ -35468,13 +36630,13 @@ static int unixShmSystemLock( /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; - rc = osSetPosixAdvisoryLock(pShmNode->h, &f, pFile); + rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; } @@ -35546,18 +36708,18 @@ static void unixShmPurge(unixFile *pFd){ int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); - sqlite3_mutex_free(p->mutex); + sqlite3_mutex_free(p->pShmMutex); for(i=0; inRegion; i+=nShmPerMap){ - if( p->h>=0 ){ + if( p->hShm>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); } } sqlite3_free(p->apRegion); - if( p->h>=0 ){ - robust_close(pFd, p->h, __LINE__); - p->h = -1; + if( p->hShm>=0 ){ + robust_close(pFd, p->hShm, __LINE__); + p->hShm = -1; } p->pInode->pShmNode = 0; sqlite3_free(p); @@ -35599,7 +36761,7 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ lock.l_start = UNIX_SHM_DMS; lock.l_len = 1; lock.l_type = F_WRLCK; - if( osFcntl(pShmNode->h, F_GETLK, &lock)!=0 ) { + if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) { rc = SQLITE_IOERR_LOCK; }else if( lock.l_type==F_UNLCK ){ if( pShmNode->isReadonly ){ @@ -35607,7 +36769,12 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ rc = SQLITE_READONLY_CANTINIT; }else{ rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); - if( rc==SQLITE_OK && robust_ftruncate(pShmNode->h, 0) ){ + /* The first connection to attach must truncate the -shm file. We + ** truncate to 3 bytes (an arbitrary small number, less than the + ** -shm header size) rather than 0 as a system debugging aid, to + ** help detect if a -shm file truncation is legitimate or is the work + ** or a rogue process. */ + if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename); } } @@ -35674,6 +36841,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ /* Check to see if a unixShmNode object already exists. Reuse an existing ** one if present. Create a new one if necessary. */ + assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); pInode = pDbFd->pInode; pShmNode = pInode->pShmNode; @@ -35712,12 +36880,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath); sqlite3FileSuffix3(pDbFd->zPath, zShm); #endif - pShmNode->h = -1; + pShmNode->hShm = -1; pDbFd->pInode->pShmNode = pShmNode; pShmNode->pInode = pDbFd->pInode; if( sqlite3GlobalConfig.bCoreMutex ){ - pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ + pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->pShmMutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } @@ -35725,11 +36893,11 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ - pShmNode->h = robust_open(zShm, O_RDWR|O_CREAT, (sStat.st_mode&0777)); + pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT,(sStat.st_mode&0777)); } - if( pShmNode->h<0 ){ - pShmNode->h = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777)); - if( pShmNode->h<0 ){ + if( pShmNode->hShm<0 ){ + pShmNode->hShm = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777)); + if( pShmNode->hShm<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm); goto shm_open_err; } @@ -35740,7 +36908,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** is owned by the same user that owns the original database. Otherwise, ** the original owner will not be able to connect. */ - robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); + robustFchown(pShmNode->hShm, sStat.st_uid, sStat.st_gid); rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; @@ -35760,13 +36928,13 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** the cover of the unixEnterMutex() mutex and the pointer from the ** new (struct unixShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex - ** mutex. + ** at pShmNode->pFirst. This must be done while holding the + ** pShmNode->pShmMutex. */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; /* Jump here on any error */ @@ -35818,7 +36986,7 @@ static int unixShmMap( p = pDbFd->pShm; pShmNode = p->pShmNode; - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); if( pShmNode->isUnlocked ){ rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK ) goto shmpage_out; @@ -35826,8 +36994,8 @@ static int unixShmMap( } assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); assert( pShmNode->pInode==pDbFd->pInode ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); /* Minimum number of regions required to be mapped. */ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; @@ -35839,12 +37007,12 @@ static int unixShmMap( pShmNode->szRegion = szRegion; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ /* The requested region is not mapped into this processes address space. ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ - if( osFstat(pShmNode->h, &sStat) ){ + if( osFstat(pShmNode->hShm, &sStat) ){ rc = SQLITE_IOERR_SHMSIZE; goto shmpage_out; } @@ -35872,7 +37040,7 @@ static int unixShmMap( assert( (nByte % pgsz)==0 ); for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){ int x = 0; - if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){ + if( seekAndWriteFd(pShmNode->hShm, iPg*pgsz + pgsz-1,"",1,&x)!=1 ){ const char *zFile = pShmNode->zFilename; rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); goto shmpage_out; @@ -35895,22 +37063,22 @@ static int unixShmMap( int nMap = szRegion*nShmPerMap; int i; void *pMem; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ pMem = osMmap(0, nMap, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, - MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion + MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion ); if( pMem==MAP_FAILED ){ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); goto shmpage_out; } }else{ - pMem = sqlite3_malloc64(szRegion); + pMem = sqlite3_malloc64(nMap); if( pMem==0 ){ rc = SQLITE_NOMEM_BKPT; goto shmpage_out; } - memset(pMem, 0, szRegion); + memset(pMem, 0, nMap); } for(i=0; iisReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } @@ -35961,12 +37129,12 @@ static int unixShmLock( || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); mask = (1<<(ofst+n)) - (1<1 || mask==(1<mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); if( flags & SQLITE_SHM_UNLOCK ){ u16 allMask = 0; /* Mask of locks held by siblings */ @@ -36039,7 +37207,7 @@ static int unixShmLock( } } } - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; @@ -36056,6 +37224,9 @@ static void unixShmBarrier( ){ UNUSED_PARAMETER(fd); sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ + assert( fd->pMethods->xLock==nolockLock + || unixFileMutexNotheld((unixFile*)fd) + ); unixEnterMutex(); /* Also mutex, for redundancy */ unixLeaveMutex(); } @@ -36086,22 +37257,23 @@ static int unixShmUnmap( /* Remove connection p from the set of connections associated ** with pShmNode */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} *pp = p->pNext; /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ + assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ - if( deleteFlag && pShmNode->h>=0 ){ + if( deleteFlag && pShmNode->hShm>=0 ){ osUnlink(pShmNode->zFilename); } unixShmPurge(pDbFd); @@ -36423,7 +37595,7 @@ IOMETHODS( IOMETHODS( nolockIoFinder, /* Finder function name */ nolockIoMethods, /* sqlite3_io_methods object name */ - 3, /* shared memory is disabled */ + 3, /* shared memory and mmap are enabled */ nolockClose, /* xClose method */ nolockLock, /* xLock method */ nolockUnlock, /* xUnlock method */ @@ -36919,7 +38091,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a reusable file descriptor are not dire. */ - if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){ + if( inodeList!=0 && 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; pInode = inodeList; @@ -36929,12 +38101,14 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ } if( pInode ){ UnixUnusedFd **pp; + assert( sqlite3_mutex_notheld(pInode->pLockMutex) ); + sqlite3_mutex_enter(pInode->pLockMutex); for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ - nUnusedFd--; *pp = pUnused->pNext; } + sqlite3_mutex_leave(pInode->pLockMutex); } } unixLeaveMutex(); @@ -39517,8 +40691,7 @@ struct winFile { int nFetchOut; /* Number of outstanding xFetch references */ HANDLE hMap; /* Handle for accessing memory mapping */ void *pMapRegion; /* Area memory mapped */ - sqlite3_int64 mmapSize; /* Usable size of mapped region */ - sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ + sqlite3_int64 mmapSize; /* Size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; @@ -39548,22 +40721,6 @@ struct winVfsAppData { # define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD))) #endif -/* - * The value used with sqlite3_win32_set_directory() to specify that - * the data directory should be changed. - */ -#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE -# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1) -#endif - -/* - * The value used with sqlite3_win32_set_directory() to specify that - * the temporary directory should be changed. - */ -#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE -# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2) -#endif - /* * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * various Win32 API heap functions instead of our own. @@ -41160,13 +42317,13 @@ SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){ } /* -** This function sets the data directory or the temporary directory based on -** the provided arguments. The type argument must be 1 in order to set the -** data directory or 2 in order to set the temporary directory. The zValue -** argument is the name of the directory to use. The return value will be -** SQLITE_OK if successful. +** This function is the same as sqlite3_win32_set_directory (below); however, +** it accepts a UTF-8 string. */ -SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ +SQLITE_API int sqlite3_win32_set_directory8( + unsigned long type, /* Identifier for directory being set or reset */ + const char *zValue /* New value for directory being set or reset */ +){ char **ppDirectory = 0; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); @@ -41182,20 +42339,53 @@ SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ ); assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) ); if( ppDirectory ){ - char *zValueUtf8 = 0; + char *zCopy = 0; if( zValue && zValue[0] ){ - zValueUtf8 = winUnicodeToUtf8(zValue); - if ( zValueUtf8==0 ){ + zCopy = sqlite3_mprintf("%s", zValue); + if ( zCopy==0 ){ return SQLITE_NOMEM_BKPT; } } sqlite3_free(*ppDirectory); - *ppDirectory = zValueUtf8; + *ppDirectory = zCopy; return SQLITE_OK; } return SQLITE_ERROR; } +/* +** This function is the same as sqlite3_win32_set_directory (below); however, +** it accepts a UTF-16 string. +*/ +SQLITE_API int sqlite3_win32_set_directory16( + unsigned long type, /* Identifier for directory being set or reset */ + const void *zValue /* New value for directory being set or reset */ +){ + int rc; + char *zUtf8 = 0; + if( zValue ){ + zUtf8 = sqlite3_win32_unicode_to_utf8(zValue); + if( zUtf8==0 ) return SQLITE_NOMEM_BKPT; + } + rc = sqlite3_win32_set_directory8(type, zUtf8); + if( zUtf8 ) sqlite3_free(zUtf8); + return rc; +} + +/* +** This function sets the data directory or the temporary directory based on +** the provided arguments. The type argument must be 1 in order to set the +** data directory or 2 in order to set the temporary directory. The zValue +** argument is the name of the directory to use. The return value will be +** SQLITE_OK if successful. +*/ +SQLITE_API int sqlite3_win32_set_directory( + unsigned long type, /* Identifier for directory being set or reset */ + void *zValue /* New value for directory being set or reset */ +){ + return sqlite3_win32_set_directory16(type, zValue); +} + /* ** The return value of winGetLastErrorMsg ** is zero if the error message fits in the buffer, or non-zero @@ -42120,6 +43310,29 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ winFile *pFile = (winFile*)id; /* File handle object */ int rc = SQLITE_OK; /* Return code for this function */ DWORD lastErrno; +#if SQLITE_MAX_MMAP_SIZE>0 + sqlite3_int64 oldMmapSize; + if( pFile->nFetchOut>0 ){ + /* File truncation is a no-op if there are outstanding memory mapped + ** pages. This is because truncating the file means temporarily unmapping + ** the file, and that might delete memory out from under existing cursors. + ** + ** This can result in incremental vacuum not truncating the file, + ** if there is an active read cursor when the incremental vacuum occurs. + ** No real harm comes of this - the database file is not corrupted, + ** though some folks might complain that the file is bigger than it + ** needs to be. + ** + ** The only feasible work-around is to defer the truncation until after + ** all references to memory-mapped content are closed. That is doable, + ** but involves adding a few branches in the common write code path which + ** could slow down normal operations slightly. Hence, we have decided for + ** now to simply make trancations a no-op if there are pending reads. We + ** can maybe revisit this decision in the future. + */ + return SQLITE_OK; + } +#endif assert( pFile ); SimulateIOError(return SQLITE_IOERR_TRUNCATE); @@ -42135,6 +43348,15 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->pMapRegion ){ + oldMmapSize = pFile->mmapSize; + }else{ + oldMmapSize = 0; + } + winUnmapfile(pFile); +#endif + /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ if( winSeekFile(pFile, nByte) ){ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, @@ -42147,12 +43369,12 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ } #if SQLITE_MAX_MMAP_SIZE>0 - /* If the file was truncated to a size smaller than the currently - ** mapped region, reduce the effective mapping size as well. SQLite will - ** use read() and write() to access data beyond this point from now on. - */ - if( pFile->pMapRegion && nBytemmapSize ){ - pFile->mmapSize = nByte; + if( rc==SQLITE_OK && oldMmapSize>0 ){ + if( oldMmapSize>nByte ){ + winMapfile(pFile, -1); + }else{ + winMapfile(pFile, oldMmapSize); + } } #endif @@ -43538,9 +44760,9 @@ shmpage_out: static int winUnmapfile(winFile *pFile){ assert( pFile!=0 ); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, " - "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n", + "mmapSize=%lld, mmapSizeMax=%lld\n", osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion, - pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax)); + pFile->mmapSize, pFile->mmapSizeMax)); if( pFile->pMapRegion ){ if( !osUnmapViewOfFile(pFile->pMapRegion) ){ pFile->lastErrno = osGetLastError(); @@ -43552,7 +44774,6 @@ static int winUnmapfile(winFile *pFile){ } pFile->pMapRegion = 0; pFile->mmapSize = 0; - pFile->mmapSizeActual = 0; } if( pFile->hMap!=NULL ){ if( !osCloseHandle(pFile->hMap) ){ @@ -43663,7 +44884,6 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ } pFd->pMapRegion = pNew; pFd->mmapSize = nMap; - pFd->mmapSizeActual = nMap; } OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", @@ -44465,7 +45685,6 @@ static int winOpen( pFile->hMap = NULL; pFile->pMapRegion = 0; pFile->mmapSize = 0; - pFile->mmapSizeActual = 0; pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap; #endif @@ -45340,8 +46559,8 @@ SQLITE_API int sqlite3_os_end(void){ ** This file also implements interface sqlite3_serialize() and ** sqlite3_deserialize(). */ -#ifdef SQLITE_ENABLE_DESERIALIZE /* #include "sqliteInt.h" */ +#ifdef SQLITE_ENABLE_DESERIALIZE /* ** Forward declaration of objects used by this utility @@ -46362,7 +47581,7 @@ bitvec_end: ** The PCache.pSynced variable is used to optimize searching for a dirty ** page to eject from the cache mid-transaction. It is better to eject ** a page that does not require a journal sync than one that does. -** Therefore, pSynced is maintained to that it *almost* always points +** Therefore, pSynced is maintained so that it *almost* always points ** to either the oldest page in the pDirty/pDirtyTail list that has a ** clear PGHDR_NEED_SYNC flag or to a page that is older than this one ** (so that the right page to eject can be found by following pDirtyPrev @@ -47186,6 +48405,15 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){ return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; } +#ifdef SQLITE_DIRECT_OVERFLOW_READ +/* +** Return true if there are one or more dirty pages in the cache. Else false. +*/ +SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache){ + return (pCache->pDirty!=0); +} +#endif + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified @@ -47309,7 +48537,8 @@ struct PgHdr1 { }; /* -** A page is pinned if it is no on the LRU list +** A page is pinned if it is not on the LRU list. To be "pinned" means +** that the page is in active use and must not be deallocated. */ #define PAGE_IS_PINNED(p) ((p)->pLruNext==0) #define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0) @@ -48589,30 +49818,23 @@ struct RowSet { #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ /* -** Turn bulk memory into a RowSet object. N bytes of memory -** are available at pSpace. The db pointer is used as a memory context -** for any subsequent allocations that need to occur. -** Return a pointer to the new RowSet object. -** -** It must be the case that N is sufficient to make a Rowset. If not -** an assertion fault occurs. -** -** If N is larger than the minimum, use the surplus as an initial -** allocation of entries available to be filled. +** Allocate a RowSet object. Return NULL if a memory allocation +** error occurs. */ -SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){ - RowSet *p; - assert( N >= ROUND8(sizeof(*p)) ); - p = pSpace; - p->pChunk = 0; - p->db = db; - p->pEntry = 0; - p->pLast = 0; - p->pForest = 0; - p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); - p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); - p->rsFlags = ROWSET_SORTED; - p->iBatch = 0; +SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db){ + RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p)); + if( p ){ + int N = sqlite3DbMallocSize(db, p); + p->pChunk = 0; + p->db = db; + p->pEntry = 0; + p->pLast = 0; + p->pForest = 0; + p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); + p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); + p->rsFlags = ROWSET_SORTED; + p->iBatch = 0; + } return p; } @@ -48621,7 +49843,8 @@ SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int ** the RowSet has allocated over its lifetime. This routine is ** the destructor for the RowSet. */ -SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){ +SQLITE_PRIVATE void sqlite3RowSetClear(void *pArg){ + RowSet *p = (RowSet*)pArg; struct RowSetChunk *pChunk, *pNextChunk; for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ pNextChunk = pChunk->pNextChunk; @@ -48635,6 +49858,16 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){ p->rsFlags = ROWSET_SORTED; } +/* +** Deallocate all chunks from a RowSet. This frees all memory that +** the RowSet has allocated over its lifetime. This routine is +** the destructor for the RowSet. +*/ +SQLITE_PRIVATE void sqlite3RowSetDelete(void *pArg){ + sqlite3RowSetClear(pArg); + sqlite3DbFree(((RowSet*)pArg)->db, pArg); +} + /* ** Allocate a new RowSetEntry object that is associated with the ** given RowSet. Return a pointer to the new and completely uninitialized @@ -49122,6 +50355,8 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal); +SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal); #endif #ifdef SQLITE_ENABLE_ZIPVFS @@ -49943,19 +51178,30 @@ static const unsigned char aJournalMagic[] = { */ #define isOpen(pFd) ((pFd)->pMethods!=0) +#ifdef SQLITE_DIRECT_OVERFLOW_READ /* -** Return true if this pager uses a write-ahead log to read page pgno. -** Return false if the pager reads pgno directly from the database. +** Return true if page pgno can be read directly from the database file +** by the b-tree layer. This is the case if: +** +** * the database file is open, +** * there are no dirty pages in the cache, and +** * the desired page is not currently in the wal file. */ -#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_DIRECT_OVERFLOW_READ) -SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){ - u32 iRead = 0; - int rc; - if( pPager->pWal==0 ) return 0; - rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return rc || iRead; +SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ + if( pPager->fd->pMethods==0 ) return 0; + if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; +#ifndef SQLITE_OMIT_WAL + if( pPager->pWal ){ + u32 iRead = 0; + int rc; + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); + return (rc==SQLITE_OK && iRead==0); + } +#endif + return 1; } #endif + #ifndef SQLITE_OMIT_WAL # define pagerUseWal(x) ((x)->pWal!=0) #else @@ -50115,8 +51361,12 @@ static int assert_pager_state(Pager *p){ ** to "print *pPager" in gdb: ** ** (gdb) printf "%s", print_pager_state(pPager) +** +** This routine has external linkage in order to suppress compiler warnings +** about an unused function. It is enclosed within SQLITE_DEBUG and so does +** not appear in normal builds. */ -static char *print_pager_state(Pager *p){ +char *print_pager_state(Pager *p){ static char zRet[1024]; sqlite3_snprintf(1024, zRet, @@ -50882,7 +52132,6 @@ static void pager_reset(Pager *pPager){ ** Return the pPager->iDataVersion value */ SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){ - assert( pPager->eState>PAGER_OPEN ); return pPager->iDataVersion; } @@ -55500,9 +56749,10 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( ** backup in progress needs to be restarted. */ sqlite3BackupRestart(pPager->pBackup); }else{ + PgHdr *pList; if( pagerUseWal(pPager) ){ - PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); PgHdr *pPageOne = 0; + pList = sqlite3PcacheDirtyList(pPager->pPCache); if( pList==0 ){ /* Must have at least one page for the WAL commit flag. ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ @@ -55523,14 +56773,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( ** should be used. No rollback journal is created if batch-atomic-write ** is enabled. */ - sqlite3_file *fd = pPager->fd; #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE - const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ + sqlite3_file *fd = pPager->fd; + int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) && !pPager->noSync && sqlite3JournalIsInMemory(pPager->jfd); #else -# define bBatch 0 +# define bBatch 0 #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE @@ -55582,15 +56832,16 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( } } } -#else +#else /* SQLITE_ENABLE_ATOMIC_WRITE */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( zMaster ){ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + assert( bBatch==0 ); } #endif rc = pager_incr_changecounter(pPager, 0); -#endif +#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */ if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Write the master journal name into the journal file. If a master @@ -55614,24 +56865,36 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( rc = syncJournal(pPager, 0); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + pList = sqlite3PcacheDirtyList(pPager->pPCache); +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( bBatch ){ - /* The pager is now in DBMOD state. But regardless of what happens - ** next, attempting to play the journal back into the database would - ** be unsafe. Close it now to make sure that does not happen. */ - sqlite3OsClose(pPager->jfd); rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0); - if( rc!=SQLITE_OK ) goto commit_phase_one_exit; - } - rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache)); - if( bBatch ){ if( rc==SQLITE_OK ){ - rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); + rc = pager_write_pagelist(pPager, pList); + if( rc==SQLITE_OK ){ + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); + } + if( rc!=SQLITE_OK ){ + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0); + } } - if( rc!=SQLITE_OK ){ - sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0); + + if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ){ + sqlite3OsClose(pPager->jfd); + goto commit_phase_one_exit; + } + bBatch = 0; + }else{ + sqlite3OsClose(pPager->jfd); } } +#endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + if( bBatch==0 ){ + rc = pager_write_pagelist(pPager, pList); + } if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; @@ -56122,7 +57385,11 @@ SQLITE_PRIVATE void sqlite3PagerSetCodec( void (*xCodecFree)(void*), void *pCodec ){ - if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); + if( pPager->xCodecFree ){ + pPager->xCodecFree(pPager->pCodec); + }else{ + pager_reset(pPager); + } pPager->xCodec = pPager->memDb ? 0 : xCodec; pPager->xCodecSizeChng = xCodecSizeChng; pPager->xCodecFree = xCodecFree; @@ -56383,13 +57650,6 @@ SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ -#ifdef SQLITE_DEBUG - /* The print_pager_state() routine is intended to be used by the debugger - ** only. We invoke it once here to suppress a compiler warning. */ - print_pager_state(pPager); -#endif - - /* The eMode parameter is always valid */ assert( eMode==PAGER_JOURNALMODE_DELETE || eMode==PAGER_JOURNALMODE_TRUNCATE @@ -56758,6 +58018,38 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){ } return rc; } + +/* +** The caller currently has a read transaction open on the database. +** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise, +** this function takes a SHARED lock on the CHECKPOINTER slot and then +** checks if the snapshot passed as the second argument is still +** available. If so, SQLITE_OK is returned. +** +** If the snapshot is not available, SQLITE_ERROR is returned. Or, if +** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error +** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER +** lock is released before returning. +*/ +SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){ + int rc; + if( pPager->pWal ){ + rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot); + }else{ + rc = SQLITE_ERROR; + } + return rc; +} + +/* +** Release a lock obtained by an earlier successful call to +** sqlite3PagerSnapshotCheck(). +*/ +SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){ + assert( pPager->pWal ); + return sqlite3WalSnapshotUnlock(pPager->pWal); +} + #endif /* SQLITE_ENABLE_SNAPSHOT */ #endif /* !SQLITE_OMIT_WAL */ @@ -57039,6 +58331,18 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0; # define WALTRACE(X) #endif +/* +** WAL mode depends on atomic aligned 32-bit loads and stores in a few +** places. The following macros try to make this explicit. +*/ +#if GCC_VESRION>=5004000 +# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) +# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) +#else +# define AtomicLoad(PTR) (*(PTR)) +# define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) +#endif + /* ** The maximum (and only) versions of the wal and wal-index formats ** that may be interpreted by this version of SQLite. @@ -57661,48 +58965,51 @@ static int walNextHash(int iPriorHash){ return (iPriorHash+1)&(HASHTABLE_NSLOT-1); } +/* +** An instance of the WalHashLoc object is used to describe the location +** of a page hash table in the wal-index. This becomes the return value +** from walHashGet(). +*/ +typedef struct WalHashLoc WalHashLoc; +struct WalHashLoc { + volatile ht_slot *aHash; /* Start of the wal-index hash table */ + volatile u32 *aPgno; /* aPgno[1] is the page of first frame indexed */ + u32 iZero; /* One less than the frame number of first indexed*/ +}; + /* ** Return pointers to the hash table and page number array stored on ** page iHash of the wal-index. The wal-index is broken into 32KB pages ** numbered starting from 0. ** -** Set output variable *paHash to point to the start of the hash table -** in the wal-index file. Set *piZero to one less than the frame +** Set output variable pLoc->aHash to point to the start of the hash table +** in the wal-index file. Set pLoc->iZero to one less than the frame ** number of the first frame indexed by this hash table. If a ** slot in the hash table is set to N, it refers to frame number -** (*piZero+N) in the log. +** (pLoc->iZero+N) in the log. ** -** Finally, set *paPgno so that *paPgno[1] is the page number of the -** first frame indexed by the hash table, frame (*piZero+1). +** Finally, set pLoc->aPgno so that pLoc->aPgno[1] is the page number of the +** first frame indexed by the hash table, frame (pLoc->iZero+1). */ static int walHashGet( Wal *pWal, /* WAL handle */ int iHash, /* Find the iHash'th table */ - volatile ht_slot **paHash, /* OUT: Pointer to hash index */ - volatile u32 **paPgno, /* OUT: Pointer to page number array */ - u32 *piZero /* OUT: Frame associated with *paPgno[0] */ + WalHashLoc *pLoc /* OUT: Hash table location */ ){ int rc; /* Return code */ - volatile u32 *aPgno; - rc = walIndexPage(pWal, iHash, &aPgno); + rc = walIndexPage(pWal, iHash, &pLoc->aPgno); assert( rc==SQLITE_OK || iHash>0 ); if( rc==SQLITE_OK ){ - u32 iZero; - volatile ht_slot *aHash; - - aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE]; + pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE]; if( iHash==0 ){ - aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; - iZero = 0; + pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; + pLoc->iZero = 0; }else{ - iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; + pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; } - - *paPgno = &aPgno[-1]; - *paHash = aHash; - *piZero = iZero; + pLoc->aPgno = &pLoc->aPgno[-1]; } return rc; } @@ -57748,9 +59055,7 @@ static u32 walFramePgno(Wal *pWal, u32 iFrame){ ** actually needed. */ static void walCleanupHash(Wal *pWal){ - volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */ - volatile u32 *aPgno = 0; /* Page number array for hash table */ - u32 iZero = 0; /* frame == (aHash[x]+iZero) */ + WalHashLoc sLoc; /* Hash table location */ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ @@ -57768,24 +59073,24 @@ static void walCleanupHash(Wal *pWal){ */ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) ); assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] ); - walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero); + walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); /* Zero all hash-table entries that correspond to frame numbers greater ** than pWal->hdr.mxFrame. */ - iLimit = pWal->hdr.mxFrame - iZero; + iLimit = pWal->hdr.mxFrame - sLoc.iZero; assert( iLimit>0 ); for(i=0; iiLimit ){ - aHash[i] = 0; + if( sLoc.aHash[i]>iLimit ){ + sLoc.aHash[i] = 0; } } /* Zero the entries in the aPgno array that correspond to frames with ** frame numbers greater than pWal->hdr.mxFrame. */ - nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]); - memset((void *)&aPgno[iLimit+1], 0, nByte); + nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]); + memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the every entry in the mapping region is still reachable @@ -57795,10 +59100,10 @@ static void walCleanupHash(Wal *pWal){ int j; /* Loop counter */ int iKey; /* Hash key */ for(j=1; j<=iLimit; j++){ - for(iKey=walHash(aPgno[j]); aHash[iKey]; iKey=walNextHash(iKey)){ - if( aHash[iKey]==j ) break; + for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){ + if( sLoc.aHash[iKey]==j ) break; } - assert( aHash[iKey]==j ); + assert( sLoc.aHash[iKey]==j ); } } #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */ @@ -57811,11 +59116,9 @@ static void walCleanupHash(Wal *pWal){ */ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ int rc; /* Return code */ - u32 iZero = 0; /* One less than frame number of aPgno[1] */ - volatile u32 *aPgno = 0; /* Page number array */ - volatile ht_slot *aHash = 0; /* Hash table */ + WalHashLoc sLoc; /* Wal-index hash table location */ - rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero); + rc = walHashGet(pWal, walFramePage(iFrame), &sLoc); /* Assuming the wal-index file was successfully mapped, populate the ** page number array and hash table entry. @@ -57825,15 +59128,16 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ int idx; /* Value to write to hash-table slot */ int nCollide; /* Number of hash collisions */ - idx = iFrame - iZero; + idx = iFrame - sLoc.iZero; assert( idx <= HASHTABLE_NSLOT/2 + 1 ); /* If this is the first entry to be added to this hash-table, zero the ** entire hash table and aPgno[] array before proceeding. */ if( idx==1 ){ - int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]); - memset((void*)&aPgno[1], 0, nByte); + int nByte = (int)((u8 *)&sLoc.aHash[HASHTABLE_NSLOT] + - (u8 *)&sLoc.aPgno[1]); + memset((void*)&sLoc.aPgno[1], 0, nByte); } /* If the entry in aPgno[] is already set, then the previous writer @@ -57842,18 +59146,18 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ ** Remove the remnants of that writers uncommitted transaction from ** the hash-table before writing any new entries. */ - if( aPgno[idx] ){ + if( sLoc.aPgno[idx] ){ walCleanupHash(pWal); - assert( !aPgno[idx] ); + assert( !sLoc.aPgno[idx] ); } /* Write the aPgno[] array entry and the hash-table slot. */ nCollide = idx; - for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){ + for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } - aPgno[idx] = iPage; - aHash[iKey] = (ht_slot)idx; + sLoc.aPgno[idx] = iPage; + sLoc.aHash[iKey] = (ht_slot)idx; #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the number of entries in the hash table exactly equals @@ -57862,7 +59166,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ { int i; /* Loop counter */ int nEntry = 0; /* Number of entries in the hash table */ - for(i=0; iaSegment[p->nSegment])[iZero]; - iZero++; + aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero]; + sLoc.iZero++; for(j=0; jaSegment[i].iZero = iZero; + walMergesort((u32 *)sLoc.aPgno, aTmp, aIndex, &nEntry); + p->aSegment[i].iZero = sLoc.iZero; p->aSegment[i].nEntry = nEntry; p->aSegment[i].aIndex = aIndex; - p->aSegment[i].aPgno = (u32 *)aPgno; + p->aSegment[i].aPgno = (u32 *)sLoc.aPgno; } } sqlite3_free(aTmp); @@ -58616,7 +59920,6 @@ static int walCheckpoint( if( pIter && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK ){ - i64 nSize; /* Current size of database file */ u32 nBackfill = pInfo->nBackfill; pInfo->nBackfillAttempted = mxSafeFrame; @@ -58629,6 +59932,7 @@ static int walCheckpoint( */ if( rc==SQLITE_OK ){ i64 nReq = ((i64)mxPage * szPage); + i64 nSize; /* Current size of database file */ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); @@ -59336,7 +60640,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ } #endif for(i=1; iaReadMark[i]; + u32 thisMark = AtomicLoad(pInfo->aReadMark+i); if( mxReadMark<=thisMark && thisMark<=mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; @@ -59349,7 +60653,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ for(i=1; iaReadMark[i] = mxFrame; + mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame); mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; @@ -59401,9 +60705,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** we can guarantee that the checkpointer that set nBackfill could not ** see any pages past pWal->hdr.mxFrame, this problem does not come up. */ - pWal->minFrame = pInfo->nBackfill+1; + pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; walShmBarrier(pWal); - if( pInfo->aReadMark[mxI]!=mxReadMark + if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); @@ -59454,16 +60758,14 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ }else{ u32 i = pInfo->nBackfillAttempted; for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){ - volatile ht_slot *dummy; - volatile u32 *aPgno; /* Array of page numbers */ - u32 iZero; /* Frame corresponding to aPgno[0] */ + WalHashLoc sLoc; /* Hash table location */ u32 pgno; /* Page number in db file */ i64 iDbOff; /* Offset of db file entry */ i64 iWalOff; /* Offset of wal file entry */ - rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero); + rc = walHashGet(pWal, walFramePage(i), &sLoc); if( rc!=SQLITE_OK ) break; - pgno = aPgno[i-iZero]; + pgno = sLoc.aPgno[i-sLoc.iZero]; iDbOff = (i64)(pgno-1) * szPage; if( iDbOff+szPage<=szDb ){ @@ -59504,7 +60806,7 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ ** ** If the database contents have changes since the previous read ** transaction, then *pChanged is set to 1 before returning. The -** Pager layer will use this to know that is cache is stale and +** Pager layer will use this to know that its cache is stale and ** needs to be flushed. */ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ @@ -59566,7 +60868,7 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ /* Check that the wal file has not been wrapped. Assuming that it has ** not, also check that no checkpointer has attempted to checkpoint any ** frames beyond pSnapshot->mxFrame. If either of these conditions are - ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr + ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr ** with *pSnapshot and set *pChanged as appropriate for opening the ** snapshot. */ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) @@ -59576,11 +60878,12 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); *pChanged = bChanged; }else{ - rc = SQLITE_BUSY_SNAPSHOT; + rc = SQLITE_ERROR_SNAPSHOT; } /* Release the shared CKPT lock obtained above. */ walUnlockShared(pWal, WAL_CKPT_LOCK); + pWal->minFrame = 1; } @@ -59664,21 +60967,20 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( */ iMinHash = walFramePage(pWal->minFrame); for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){ - volatile ht_slot *aHash; /* Pointer to hash table */ - volatile u32 *aPgno; /* Pointer to array of page numbers */ - u32 iZero; /* Frame number corresponding to aPgno[0] */ + WalHashLoc sLoc; /* Hash table location */ int iKey; /* Hash slot index */ int nCollide; /* Number of hash collisions remaining */ int rc; /* Error code */ - rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero); + rc = walHashGet(pWal, iHash, &sLoc); if( rc!=SQLITE_OK ){ return rc; } nCollide = HASHTABLE_NSLOT; - for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){ - u32 iFrame = aHash[iKey] + iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){ + for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ + u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero; + if( iFrame<=iLast && iFrame>=pWal->minFrame + && sLoc.aPgno[sLoc.aHash[iKey]]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } @@ -60553,6 +61855,43 @@ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){ if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1; return 0; } + +/* +** The caller currently has a read transaction open on the database. +** This function takes a SHARED lock on the CHECKPOINTER slot and then +** checks if the snapshot passed as the second argument is still +** available. If so, SQLITE_OK is returned. +** +** If the snapshot is not available, SQLITE_ERROR is returned. Or, if +** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error +** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER +** lock is released before returning. +*/ +SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){ + int rc; + rc = walLockShared(pWal, WAL_CKPT_LOCK); + if( rc==SQLITE_OK ){ + WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot; + if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) + || pNew->mxFramenBackfillAttempted + ){ + rc = SQLITE_ERROR_SNAPSHOT; + walUnlockShared(pWal, WAL_CKPT_LOCK); + } + } + return rc; +} + +/* +** Release a lock obtained by an earlier successful call to +** sqlite3WalSnapshotCheck(). +*/ +SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal){ + assert( pWal ); + walUnlockShared(pWal, WAL_CKPT_LOCK); +} + + #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_ZIPVFS @@ -61482,10 +62821,10 @@ static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ skipOk = 0; } } - db->skipBtreeMutex = skipOk; + db->noSharedCache = skipOk; } SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ - if( db->skipBtreeMutex==0 ) btreeEnterAll(db); + if( db->noSharedCache==0 ) btreeEnterAll(db); } static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){ int i; @@ -61497,7 +62836,7 @@ static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){ } } SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ - if( db->skipBtreeMutex==0 ) btreeLeaveAll(db); + if( db->noSharedCache==0 ) btreeLeaveAll(db); } #ifndef NDEBUG @@ -62462,7 +63801,11 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ ** back to where it ought to be if this routine returns true. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ - return pCur->eState!=CURSOR_VALID; + assert( EIGHT_BYTE_ALIGNMENT(pCur) + || pCur==sqlite3BtreeFakeValidCursor() ); + assert( offsetof(BtCursor, eState)==0 ); + assert( sizeof(pCur->eState)==1 ); + return CURSOR_VALID != *(u8*)pCur; } /* @@ -64570,6 +65913,10 @@ static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){ # define setDefaultSyncFlag(pBt,safety_level) #endif +/* Forward declaration */ +static int newDatabase(BtShared*); + + /* ** Get a reference to pPage1 of the database file. This will ** also acquire a readlock on that file. @@ -64601,6 +65948,9 @@ static int lockBtree(BtShared *pBt){ if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ nPage = nPageFile; } + if( (pBt->db->flags & SQLITE_ResetDatabase)!=0 ){ + nPage = 0; + } if( nPage>0 ){ u32 pageSize; u32 usableSize; @@ -64699,7 +66049,7 @@ static int lockBtree(BtShared *pBt){ pageSize-usableSize); return rc; } - if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){ + if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } @@ -64887,7 +66237,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ -SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){ BtShared *pBt = p->pBt; int rc = SQLITE_OK; @@ -64903,6 +66253,12 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 ); + if( (p->db->flags & SQLITE_ResetDatabase) + && sqlite3PagerIsreadonly(pBt->pPager)==0 + ){ + pBt->btsFlags &= ~BTS_READ_ONLY; + } + /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; @@ -64962,6 +66318,11 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db)); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); + }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){ + /* if there was no transaction opened when this function was + ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error + ** code to SQLITE_BUSY. */ + rc = SQLITE_BUSY; } } } @@ -65013,14 +66374,18 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } } - trans_begun: - if( rc==SQLITE_OK && wrflag ){ - /* This call makes sure that the pager has the correct number of - ** open savepoints. If the second parameter is greater than 0 and - ** the sub-journal is not already open, then it will be opened here. - */ - rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); + if( rc==SQLITE_OK ){ + if( pSchemaVersion ){ + *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]); + } + if( wrflag ){ + /* This call makes sure that the pager has the correct number of + ** open savepoints. If the second parameter is greater than 0 and + ** the sub-journal is not already open, then it will be opened here. + */ + rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); + } } btreeIntegrity(p); @@ -65158,6 +66523,7 @@ static int relocatePage( eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( pDbPage->pBt==pBt ); + if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT; /* Move page iDbPage from its current location to page number iFreePage */ TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", @@ -66329,9 +67695,6 @@ static int accessPayload( /* Need to read this page properly. It contains some of the ** range of data that is being read (eOp==0) or written (eOp!=0). */ -#ifdef SQLITE_DIRECT_OVERFLOW_READ - sqlite3_file *fd; /* File from which to do direct overflow read */ -#endif int a = amt; if( a + offset > ovflSize ){ a = ovflSize - offset; @@ -66342,7 +67705,7 @@ static int accessPayload( ** ** 1) this is a read operation, and ** 2) data is required from the start of this overflow page, and - ** 3) there is no open write-transaction, and + ** 3) there are no dirty pages in the page-cache ** 4) the database is file-backed, and ** 5) the page is not in the WAL file ** 6) at least 4 bytes have already been read into the output buffer @@ -66353,11 +67716,10 @@ static int accessPayload( */ if( eOp==0 /* (1) */ && offset==0 /* (2) */ - && pBt->inTransaction==TRANS_READ /* (3) */ - && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (4) */ - && 0==sqlite3PagerUseWal(pBt->pPager, nextPage) /* (5) */ + && sqlite3PagerDirectReadOk(pBt->pPager, nextPage) /* (3,4,5) */ && &pBuf[-4]>=pBufStart /* (6) */ ){ + sqlite3_file *fd = sqlite3PagerFile(pBt->pPager); u8 aSave[4]; u8 *aWrite = &pBuf[-4]; assert( aWrite>=pBufStart ); /* due to (6) */ @@ -66767,6 +68129,23 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ return rc; } +/* +** This function is a no-op if cursor pCur does not point to a valid row. +** Otherwise, if pCur is valid, configure it so that the next call to +** sqlite3BtreeNext() is a no-op. +*/ +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor *pCur){ + /* We believe that the cursor must always be in the valid state when + ** this routine is called, but the proof is difficult, so we add an + ** ALWaYS() test just in case we are wrong. */ + if( ALWAYS(pCur->eState==CURSOR_VALID) ){ + pCur->eState = CURSOR_SKIPNEXT; + pCur->skipNext = 1; + } +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + /* Move the cursor to the last entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. @@ -67171,7 +68550,16 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ pPage = pCur->pPage; idx = ++pCur->ix; - assert( pPage->isInit ); + if( !pPage->isInit ){ + /* The only known way for this to happen is for there to be a + ** recursive SQL function that does a DELETE operation as part of a + ** SELECT which deletes content out from under an active cursor + ** in a corrupt database file where the table being DELETE-ed from + ** has pages in common with the table being queried. See TH3 + ** module cov1/btree78.test testcase 220 (2018-06-08) for an + ** example. */ + return SQLITE_CORRUPT_BKPT; + } /* If the database file is corrupt, it is possible for the value of idx ** to be invalid here. This can only occur if a second cursor modifies @@ -67817,7 +69205,9 @@ static int clearCell( if( pInfo->nLocal==pInfo->nPayload ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } - if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){ + testcase( pCell + pInfo->nSize == pPage->aDataEnd ); + testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); + if( pCell + pInfo->nSize > pPage->aDataEnd ){ /* Cell extends past end of page */ return SQLITE_CORRUPT_PAGE(pPage); } @@ -69743,6 +71133,94 @@ static int balance(BtCursor *pCur){ return rc; } +/* Overwrite content from pX into pDest. Only do the write if the +** content is different from what is already there. +*/ +static int btreeOverwriteContent( + MemPage *pPage, /* MemPage on which writing will occur */ + u8 *pDest, /* Pointer to the place to start writing */ + const BtreePayload *pX, /* Source of data to write */ + int iOffset, /* Offset of first byte to write */ + int iAmt /* Number of bytes to be written */ +){ + int nData = pX->nData - iOffset; + if( nData<=0 ){ + /* Overwritting with zeros */ + int i; + for(i=0; ipDbPage); + if( rc ) return rc; + memset(pDest + i, 0, iAmt - i); + } + }else{ + if( nDatapData) + iOffset, iAmt)!=0 ){ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + memcpy(pDest, ((u8*)pX->pData) + iOffset, iAmt); + } + } + return SQLITE_OK; +} + +/* +** Overwrite the cell that cursor pCur is pointing to with fresh content +** contained in pX. +*/ +static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ + int iOffset; /* Next byte of pX->pData to write */ + int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */ + int rc; /* Return code */ + MemPage *pPage = pCur->pPage; /* Page being written */ + BtShared *pBt; /* Btree */ + Pgno ovflPgno; /* Next overflow page to write */ + u32 ovflPageSize; /* Size to write on overflow page */ + + if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd ){ + return SQLITE_CORRUPT_BKPT; + } + /* Overwrite the local portion first */ + rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, + 0, pCur->info.nLocal); + if( rc ) return rc; + if( pCur->info.nLocal==nTotal ) return SQLITE_OK; + + /* Now overwrite the overflow pages */ + iOffset = pCur->info.nLocal; + assert( nTotal>=0 ); + assert( iOffset>=0 ); + ovflPgno = get4byte(pCur->info.pPayload + iOffset); + pBt = pPage->pBt; + ovflPageSize = pBt->usableSize - 4; + do{ + rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); + if( rc ) return rc; + if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + if( iOffset+ovflPageSize<(u32)nTotal ){ + ovflPgno = get4byte(pPage->aData); + }else{ + ovflPageSize = nTotal - iOffset; + } + rc = btreeOverwriteContent(pPage, pPage->aData+4, pX, + iOffset, ovflPageSize); + } + sqlite3PagerUnref(pPage->pDbPage); + if( rc ) return rc; + iOffset += ovflPageSize; + }while( iOffsetpgnoRoot, pX->nKey, 0); /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing - ** to a row with the same key as the new entry being inserted. */ - assert( (flags & BTREE_SAVEPOSITION)==0 || - ((pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey) ); + ** to a row with the same key as the new entry being inserted. + */ +#ifdef SQLITE_DEBUG + if( flags & BTREE_SAVEPOSITION ){ + assert( pCur->curFlags & BTCF_ValidNKey ); + assert( pX->nKey==pCur->info.nKey ); + assert( pCur->info.nSize!=0 ); + assert( loc==0 ); + } +#endif - /* If the cursor is currently on the last row and we are appending a - ** new row onto the end, set the "loc" to avoid an unnecessary - ** btreeMoveto() call */ + /* On the other hand, BTREE_SAVEPOSITION==0 does not imply + ** that the cursor is not pointing to a row to be overwritten. + ** So do a complete check. + */ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){ - loc = 0; + /* The cursor is pointing to the entry that is to be + ** overwritten */ + assert( pX->nData>=0 && pX->nZero>=0 ); + if( pCur->info.nSize!=0 + && pCur->info.nPayload==(u32)pX->nData+pX->nZero + ){ + /* New entry is the same size as the old. Do an overwrite */ + return btreeOverwriteCell(pCur, pX); + } + assert( loc==0 ); }else if( loc==0 ){ + /* The cursor is *not* pointing to the cell to be overwritten, nor + ** to an adjacent cell. Move the cursor so that it is pointing either + ** to the cell to be overwritten or an adjacent cell. + */ rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); if( rc ) return rc; } - }else if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ - if( pX->nMem ){ - UnpackedRecord r; - r.pKeyInfo = pCur->pKeyInfo; - r.aMem = pX->aMem; - r.nField = pX->nMem; - r.default_rc = 0; - r.errCode = 0; - r.r1 = 0; - r.r2 = 0; - r.eqSeen = 0; - rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); - }else{ - rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + }else{ + /* This is an index or a WITHOUT ROWID table */ + + /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing + ** to a row with the same key as the new entry being inserted. + */ + assert( (flags & BTREE_SAVEPOSITION)==0 || loc==0 ); + + /* If the cursor is not already pointing either to the cell to be + ** overwritten, or if a new cell is being inserted, if the cursor is + ** not pointing to an immediately adjacent cell, then move the cursor + ** so that it does. + */ + if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ + if( pX->nMem ){ + UnpackedRecord r; + r.pKeyInfo = pCur->pKeyInfo; + r.aMem = pX->aMem; + r.nField = pX->nMem; + r.default_rc = 0; + r.errCode = 0; + r.r1 = 0; + r.r2 = 0; + r.eqSeen = 0; + rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); + }else{ + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + } + if( rc ) return rc; } - if( rc ) return rc; + + /* If the cursor is currently pointing to an entry to be overwritten + ** and the new content is the same as as the old, then use the + ** overwrite optimization. + */ + if( loc==0 ){ + getCellInfo(pCur); + if( pCur->info.nKey==pX->nKey ){ + BtreePayload x2; + x2.pData = pX->pKey; + x2.nData = pX->nKey; + x2.nZero = 0; + return btreeOverwriteCell(pCur, &x2); + } + } + } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); @@ -70700,14 +72229,14 @@ static void checkAppendMsg( pCheck->nErr++; va_start(ap, zFormat); if( pCheck->errMsg.nChar ){ - sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1); + sqlite3_str_append(&pCheck->errMsg, "\n", 1); } if( pCheck->zPfx ){ - sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); + sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); } - sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap); + sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap); va_end(ap); - if( pCheck->errMsg.accError==STRACCUM_NOMEM ){ + if( pCheck->errMsg.accError==SQLITE_NOMEM ){ pCheck->mallocFailed = 1; } } @@ -70742,8 +72271,7 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ ** Also check that the page number is in bounds. */ static int checkRef(IntegrityCk *pCheck, Pgno iPage){ - if( iPage==0 ) return 1; - if( iPage>pCheck->nPage ){ + if( iPage>pCheck->nPage || iPage==0 ){ checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } @@ -70798,17 +72326,12 @@ static void checkList( ){ int i; int expected = N; - int iFirst = iPage; - while( N-- > 0 && pCheck->mxErr ){ + int nErrAtStart = pCheck->nErr; + while( iPage!=0 && pCheck->mxErr ){ DbPage *pOvflPage; unsigned char *pOvflData; - if( iPage<1 ){ - checkAppendMsg(pCheck, - "%d of %d pages missing from overflow list starting at %d", - N+1, expected, iFirst); - break; - } if( checkRef(pCheck, iPage) ) break; + N--; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ checkAppendMsg(pCheck, "failed to get page %d", iPage); break; @@ -70852,10 +72375,12 @@ static void checkList( #endif iPage = get4byte(pOvflData); sqlite3PagerUnref(pOvflPage); - - if( isFreeList && N<(iPage!=0) ){ - checkAppendMsg(pCheck, "free-page count in header is too small"); - } + } + if( N && nErrAtStart==pCheck->nErr ){ + checkAppendMsg(pCheck, + "%s is %d but should be %d", + isFreeList ? "size" : "overflow list length", + expected-N, expected); } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -71249,6 +72774,24 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( /* Check all the tables. */ +#ifndef SQLITE_OMIT_AUTOVACUUM + if( pBt->autoVacuum ){ + int mx = 0; + int mxInHdr; + for(i=0; (int)ipPage1->aData[52]); + if( mx!=mxInHdr ){ + checkAppendMsg(&sCheck, + "max rootpage (%d) disagrees with header (%d)", + mx, mxInHdr + ); + } + }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){ + checkAppendMsg(&sCheck, + "incremental_vacuum enabled with a max rootpage of zero" + ); + } +#endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); pBt->db->flags &= ~SQLITE_CellSizeCk; for(i=0; (int)ipPager) ); sqlite3BtreeLeave(p); @@ -71530,11 +73073,11 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ pBt->btsFlags &= ~BTS_NO_WAL; if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL; - rc = sqlite3BtreeBeginTrans(pBtree, 0); + rc = sqlite3BtreeBeginTrans(pBtree, 0, 0); if( rc==SQLITE_OK ){ u8 *aData = pBt->pPage1->aData; if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){ - rc = sqlite3BtreeBeginTrans(pBtree, 2); + rc = sqlite3BtreeBeginTrans(pBtree, 2, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc==SQLITE_OK ){ @@ -71974,7 +73517,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** before this function exits. */ if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){ - rc = sqlite3BtreeBeginTrans(p->pSrc, 0); + rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0); bCloseTrans = 1; } @@ -71990,10 +73533,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 - && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2, + (int*)&p->iDestSchema)) ){ p->bDestLocked = 1; - sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); } /* Do not allow backup if the destination database is in WAL mode @@ -72437,8 +73980,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ - assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob - |MEM_RowSet|MEM_Frame|MEM_Agg))==0 ); + assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 ); /* If MEM_Null is set, then either the value is a pure NULL (the usual ** case) or it is a pointer set using sqlite3_bind_pointer() or @@ -72551,7 +74093,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ @@ -72584,7 +74126,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); testcase( pMem->db==0 ); /* If the bPreserve flag is set to true, then the memory cell must already @@ -72672,7 +74214,7 @@ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ */ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ @@ -72697,7 +74239,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem->flags & MEM_Zero ); assert( pMem->flags&MEM_Blob ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ @@ -72752,7 +74294,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -72773,7 +74315,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ assert( fg & MEM_Real ); sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); } - pMem->n = sqlite3Strlen30(pMem->z); + assert( pMem->z!=0 ); + pMem->n = sqlite3Strlen30NN(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); @@ -72810,6 +74353,35 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ return ctx.isError; } +/* +** Memory cell pAccum contains the context of an aggregate function. +** This routine calls the xValue method for that function and stores +** the results in memory cell pMem. +** +** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK +** otherwise. +*/ +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){ + sqlite3_context ctx; + Mem t; + assert( pFunc!=0 ); + assert( pFunc->xValue!=0 ); + assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef ); + assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) ); + memset(&ctx, 0, sizeof(ctx)); + memset(&t, 0, sizeof(t)); + t.flags = MEM_Null; + t.db = pAccum->db; + sqlite3VdbeMemSetNull(pOut); + ctx.pOut = pOut; + ctx.pMem = pAccum; + ctx.pFunc = pFunc; + pFunc->xValue(&ctx); + return ctx.isError; +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + /* ** If the memory cell contains a value that must be freed by ** invoking the external callback in Mem.xDel, then this routine @@ -72828,15 +74400,8 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ testcase( p->flags & MEM_Dyn ); } if( p->flags&MEM_Dyn ){ - assert( (p->flags&MEM_RowSet)==0 ); assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); p->xDel((void *)p->z); - }else if( p->flags&MEM_RowSet ){ - sqlite3RowSetClear(p->u.pRowSet); - }else if( p->flags&MEM_Frame ){ - VdbeFrame *pFrame = p->u.pFrame; - pFrame->pParent = pFrame->v->pDelFrame; - pFrame->v->pDelFrame = pFrame; } p->flags = MEM_Null; } @@ -72984,7 +74549,7 @@ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; assert( pMem->flags & MEM_Real ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -73011,7 +74576,7 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ */ SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.i = sqlite3VdbeIntValue(pMem); @@ -73195,7 +74760,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ } /* A no-op destructor */ -static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } +SQLITE_PRIVATE void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } /* ** Set the value stored in *pMem should already be a NULL. @@ -73229,26 +74794,36 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ } #endif +#ifdef SQLITE_DEBUG +/* +** Return true if the Mem holds a RowSet object. This routine is intended +** for use inside of assert() statements. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem *pMem){ + return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn) + && pMem->xDel==sqlite3RowSetDelete; +} +#endif + /* ** Delete any previous value and set the value of pMem to be an ** empty boolean index. +** +** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation +** error occurs. */ -SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){ +SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem *pMem){ sqlite3 *db = pMem->db; + RowSet *p; assert( db!=0 ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); sqlite3VdbeMemRelease(pMem); - pMem->zMalloc = sqlite3DbMallocRawNN(db, 64); - if( db->mallocFailed ){ - pMem->flags = MEM_Null; - pMem->szMalloc = 0; - }else{ - assert( pMem->zMalloc ); - pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc); - pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc); - assert( pMem->u.pRowSet!=0 ); - pMem->flags = MEM_RowSet; - } + p = sqlite3RowSetInit(db); + if( p==0 ) return SQLITE_NOMEM; + pMem->z = (char*)p; + pMem->flags = MEM_Blob|MEM_Dyn; + pMem->xDel = sqlite3RowSetDelete; + return SQLITE_OK; } /* @@ -73281,7 +74856,21 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ Mem *pX; for(i=0, pX=pVdbe->aMem; inMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ - pX->flags |= MEM_Undefined; + /* If pX is marked as a shallow copy of pMem, then verify that + ** no significant changes have been made to pX since the OP_SCopy. + ** A significant change would indicated a missed call to this + ** function for pX. Minor changes, such as adding or removing a + ** dual type, are allowed, as long as the underlying value is the + ** same. */ + u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags; + assert( (mFlags&MEM_Int)==0 || pMem->u.i==pX->u.i ); + assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r ); + assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) ); + assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 ); + + /* pMem is the register that is changing. But also mark pX as + ** undefined so that we can quickly detect the shallow-copy error */ + pX->flags = MEM_Undefined; pX->pScopyFrom = 0; } } @@ -73302,7 +74891,7 @@ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){ sqlite3VdbeMemShallowCopy(pTo, pFrom, eType); } SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ - assert( (pFrom->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pFrom) ); assert( pTo->db==pFrom->db ); if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; } memcpy(pTo, pFrom, MEMCELLSIZE); @@ -73320,7 +74909,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; - assert( (pFrom->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pFrom) ); if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; @@ -73378,7 +74967,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( u16 flags = 0; /* New value for pMem->flags */ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ @@ -73500,7 +75089,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( zData!=0 ); @@ -73524,7 +75113,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); - assert( (pVal->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pVal) ); assert( (pVal->flags & (MEM_Null))==0 ); if( pVal->flags & (MEM_Blob|MEM_Str) ){ if( ExpandBlob(pVal) ) return 0; @@ -73567,7 +75156,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); - assert( (pVal->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ assert( sqlite3VdbeMemConsistentDualRep(pVal) ); return pVal->z; @@ -73873,12 +75462,16 @@ static int valueFromExpr( 0, SQLITE_DYNAMIC); } #endif - #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 else if( op==TK_FUNCTION && pCtx!=0 ){ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx); } #endif + else if( op==TK_TRUEFALSE ){ + pVal = valueNew(db, pCtx); + pVal->flags = MEM_Int; + pVal->u.i = pExpr->u.zToken[4]==0; + } *ppVal = pVal; return rc; @@ -74130,11 +75723,11 @@ SQLITE_PRIVATE int sqlite3Stat4Column( int iCol, /* Column to extract */ sqlite3_value **ppVal /* OUT: Extracted value */ ){ - u32 t; /* a column type code */ + u32 t = 0; /* a column type code */ int nHdr; /* Size of the header in the record */ int iHdr; /* Next unread header byte */ int iField; /* Next unread data byte */ - int szField; /* Size of the current data field */ + int szField = 0; /* Size of the current data field */ int i; /* Column index */ u8 *a = (u8*)pRec; /* Typecast byte array */ Mem *pMem = *ppVal; /* Write result into this Mem object */ @@ -74298,6 +75891,13 @@ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlag } assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); +#ifdef SQLITE_ENABLE_NORMALIZE + assert( p->zNormSql==0 ); + if( p->zSql && (prepFlags & SQLITE_PREPARE_NORMALIZE)!=0 ){ + sqlite3Normalize(p, p->zSql, n, prepFlags); + assert( p->zNormSql!=0 || p->db->mallocFailed ); + } +#endif } /* @@ -74319,6 +75919,11 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; +#ifdef SQLITE_ENABLE_NORMALIZE + zTmp = pA->zNormSql; + pA->zNormSql = pB->zNormSql; + pB->zNormSql = zTmp; +#endif pB->expmask = pA->expmask; pB->prepFlags = pA->prepFlags; memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); @@ -74427,14 +76032,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ - int jj, kk; - Parse *pParse = p->pParse; - for(jj=kk=0; jjnColCache; jj++){ - struct yColCache *x = pParse->aColCache + jj; - printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn); - kk++; - } - if( kk ) printf("\n"); sqlite3VdbePrintOp(0, i, &p->aOp[i]); test_addop_breakpoint(); } @@ -74537,6 +76134,49 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); } +#ifndef SQLITE_OMIT_EXPLAIN +/* +** Return the address of the current EXPLAIN QUERY PLAN baseline. +** 0 means "none". +*/ +SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse *pParse){ + VdbeOp *pOp; + if( pParse->addrExplain==0 ) return 0; + pOp = sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrExplain); + return pOp->p2; +} + +/* +** Add a new OP_Explain opcode. +** +** If the bPush flag is true, then make this opcode the parent for +** subsequent Explains until sqlite3VdbeExplainPop() is called. +*/ +SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ + if( pParse->explain==2 ){ + char *zMsg; + Vdbe *v; + va_list ap; + int iThis; + va_start(ap, zFmt); + zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap); + va_end(ap); + v = pParse->pVdbe; + iThis = v->nOp; + sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, + zMsg, P4_DYNAMIC); + if( bPush) pParse->addrExplain = iThis; + } +} + +/* +** Pop the EXPLAIN QUERY PLAN stack one level. +*/ +SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse *pParse){ + pParse->addrExplain = sqlite3VdbeExplainParent(pParse); +} +#endif /* SQLITE_OMIT_EXPLAIN */ + /* ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees @@ -74626,6 +76266,12 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ assert( jnLabel ); assert( j>=0 ); if( p->aLabel ){ +#ifdef SQLITE_DEBUG + if( p->db->flags & SQLITE_VdbeAddopTrace ){ + printf("RESOLVE LABEL %d to %d\n", x, v->nOp); + } +#endif + assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */ p->aLabel[j] = v->nOp; } } @@ -74775,6 +76421,32 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ +#ifdef SQLITE_DEBUG +/* +** Increment the nWrite counter in the VDBE if the cursor is not an +** ephemeral cursor, or if the cursor argument is NULL. +*/ +SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe *p, VdbeCursor *pC){ + if( pC==0 + || (pC->eCurType!=CURTYPE_SORTER + && pC->eCurType!=CURTYPE_PSEUDO + && !pC->isEphemeral) + ){ + p->nWrite++; + } +} +#endif + +#ifdef SQLITE_DEBUG +/* +** Assert if an Abort at this point in time might result in a corrupt +** database. +*/ +SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ + assert( p->nWrite==0 || p->usesStmtJournal ); +} +#endif + /* ** This routine is called after all opcodes have been inserted. It loops ** through all the opcodes and fixes up some details. @@ -74835,7 +76507,6 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ break; } case OP_Next: - case OP_NextIfOpen: case OP_SorterNext: { pOp->p4.xAdvance = sqlite3BtreeNext; pOp->p4type = P4_ADVANCE; @@ -74845,8 +76516,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ assert( pOp->p2>=0 ); break; } - case OP_Prev: - case OP_PrevIfOpen: { + case OP_Prev: { pOp->p4.xAdvance = sqlite3BtreePrevious; pOp->p4type = P4_ADVANCE; /* The code generator never codes any of these opcodes as a jump @@ -74934,6 +76604,17 @@ SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){ } #endif +/* +** Generate code (a single OP_Abortable opcode) that will +** verify that the VDBE program can safely call Abort in the current +** context. +*/ +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int onError){ + if( onError==OE_Abort ) sqlite3VdbeAddOp0(p, OP_Abortable); +} +#endif + /* ** This function returns a pointer to the array of opcodes associated with ** the Vdbe passed as the first argument. It is the callers responsibility @@ -75478,23 +77159,23 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){ const char *zOp = 0; switch( pExpr->op ){ case TK_STRING: - sqlite3XPrintf(p, "%Q", pExpr->u.zToken); + sqlite3_str_appendf(p, "%Q", pExpr->u.zToken); break; case TK_INTEGER: - sqlite3XPrintf(p, "%d", pExpr->u.iValue); + sqlite3_str_appendf(p, "%d", pExpr->u.iValue); break; case TK_NULL: - sqlite3XPrintf(p, "NULL"); + sqlite3_str_appendf(p, "NULL"); break; case TK_REGISTER: { - sqlite3XPrintf(p, "r[%d]", pExpr->iTable); + sqlite3_str_appendf(p, "r[%d]", pExpr->iTable); break; } case TK_COLUMN: { if( pExpr->iColumn<0 ){ - sqlite3XPrintf(p, "rowid"); + sqlite3_str_appendf(p, "rowid"); }else{ - sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn); + sqlite3_str_appendf(p, "c%d", (int)pExpr->iColumn); } break; } @@ -75526,18 +77207,18 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){ case TK_NOTNULL: zOp = "NOTNULL"; break; default: - sqlite3XPrintf(p, "%s", "expr"); + sqlite3_str_appendf(p, "%s", "expr"); break; } if( zOp ){ - sqlite3XPrintf(p, "%s(", zOp); + sqlite3_str_appendf(p, "%s(", zOp); displayP4Expr(p, pExpr->pLeft); if( pExpr->pRight ){ - sqlite3StrAccumAppend(p, ",", 1); + sqlite3_str_append(p, ",", 1); displayP4Expr(p, pExpr->pRight); } - sqlite3StrAccumAppend(p, ")", 1); + sqlite3_str_append(p, ")", 1); } } #endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */ @@ -75558,14 +77239,15 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ int j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->aSortOrder!=0 ); - sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField); + sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField); for(j=0; jnKeyField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : ""; if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; - sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl); + sqlite3_str_appendf(&x, ",%s%s", + pKeyInfo->aSortOrder[j] ? "-" : "", zColl); } - sqlite3StrAccumAppend(&x, ")", 1); + sqlite3_str_append(&x, ")", 1); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS @@ -75576,31 +77258,31 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ #endif case P4_COLLSEQ: { CollSeq *pColl = pOp->p4.pColl; - sqlite3XPrintf(&x, "(%.20s)", pColl->zName); + sqlite3_str_appendf(&x, "(%.20s)", pColl->zName); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; - sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); + sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) case P4_FUNCCTX: { FuncDef *pDef = pOp->p4.pCtx->pFunc; - sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); + sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } #endif case P4_INT64: { - sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64); + sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64); break; } case P4_INT32: { - sqlite3XPrintf(&x, "%d", pOp->p4.i); + sqlite3_str_appendf(&x, "%d", pOp->p4.i); break; } case P4_REAL: { - sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal); + sqlite3_str_appendf(&x, "%.16g", *pOp->p4.pReal); break; } case P4_MEM: { @@ -75608,9 +77290,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ if( pMem->flags & MEM_Str ){ zP4 = pMem->z; }else if( pMem->flags & MEM_Int ){ - sqlite3XPrintf(&x, "%lld", pMem->u.i); + sqlite3_str_appendf(&x, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ - sqlite3XPrintf(&x, "%.16g", pMem->u.r); + sqlite3_str_appendf(&x, "%.16g", pMem->u.r); }else if( pMem->flags & MEM_Null ){ zP4 = "NULL"; }else{ @@ -75622,7 +77304,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; - sqlite3XPrintf(&x, "vtab:%p", pVtab); + sqlite3_str_appendf(&x, "vtab:%p", pVtab); break; } #endif @@ -75632,14 +77314,14 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ int n = ai[0]; /* The first element of an INTARRAY is always the ** count of the number of elements to follow */ for(i=1; i<=n; i++){ - sqlite3XPrintf(&x, ",%d", ai[i]); + sqlite3_str_appendf(&x, ",%d", ai[i]); } zTemp[0] = '['; - sqlite3StrAccumAppend(&x, "]", 1); + sqlite3_str_append(&x, "]", 1); break; } case P4_SUBPROGRAM: { - sqlite3XPrintf(&x, "program"); + sqlite3_str_appendf(&x, "program"); break; } case P4_DYNBLOB: @@ -75648,7 +77330,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ break; } case P4_TABLE: { - sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName); + sqlite3_str_appendf(&x, "%s", pOp->p4.pTab->zName); break; } default: { @@ -75749,7 +77431,7 @@ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){ /* ** Print a single opcode. This routine is used for debugging only. */ -SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ +SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){ char *zP4; char zPtr[50]; char zCom[100]; @@ -75818,9 +77500,8 @@ static void releaseMemArray(Mem *p, int N){ */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); - testcase( p->flags & MEM_Frame ); - testcase( p->flags & MEM_RowSet ); - if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ + testcase( p->xDel==sqlite3VdbeFrameMemDel ); + if( p->flags&(MEM_Agg|MEM_Dyn) ){ sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); @@ -75832,6 +77513,35 @@ static void releaseMemArray(Mem *p, int N){ } } +#ifdef SQLITE_DEBUG +/* +** Verify that pFrame is a valid VdbeFrame pointer. Return true if it is +** and false if something is wrong. +** +** This routine is intended for use inside of assert() statements only. +*/ +SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame *pFrame){ + if( pFrame->iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0; + return 1; +} +#endif + + +/* +** This is a destructor on a Mem object (which is really an sqlite3_value) +** that deletes the Frame object that is attached to it as a blob. +** +** This routine does not delete the Frame right away. It merely adds the +** frame to a list of frames to be deleted when the Vdbe halts. +*/ +SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void *pArg){ + VdbeFrame *pFrame = (VdbeFrame*)pArg; + assert( sqlite3VdbeFrameIsValid(pFrame) ); + pFrame->pParent = pFrame->v->pDelFrame; + pFrame->v->pDelFrame = pFrame; +} + + /* ** Delete a VdbeFrame object and its contents. VdbeFrame objects are ** allocated by the OP_Program opcode in sqlite3VdbeExec(). @@ -75840,6 +77550,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){ int i; Mem *aMem = VdbeFrameMem(p); VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem]; + assert( sqlite3VdbeFrameIsValid(p) ); for(i=0; inChildCsr; i++){ sqlite3VdbeFreeCursor(p->v, apCsr[i]); } @@ -75860,6 +77571,9 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){ ** p->explain==2, only OP_Explain instructions are listed and these ** are shown in a different format. p->explain==2 is used to implement ** EXPLAIN QUERY PLAN. +** 2018-04-24: In p->explain==2 mode, the OP_Init opcodes of triggers +** are also shown, so that the boundaries between the main program and +** each trigger are clear. ** ** When p->explain==1, first the main program is listed, then each of ** the trigger subprograms are listed one by one. @@ -75922,7 +77636,7 @@ SQLITE_PRIVATE int sqlite3VdbeList( } } - do{ + while(1){ /* Loop exits via break */ i = p->pc++; if( i>=nRow ){ p->rc = SQLITE_OK; @@ -75968,7 +77682,10 @@ SQLITE_PRIVATE int sqlite3VdbeList( nRow += pOp->p4.pProgram->nOp; } } - }while( p->explain==2 && pOp->opcode!=OP_Explain ); + if( p->explain<2 ) break; + if( pOp->opcode==OP_Explain ) break; + if( pOp->opcode==OP_Init && p->pc>1 ) break; + } if( rc==SQLITE_OK ){ if( db->u1.isInterrupted ){ @@ -77130,7 +78847,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ */ sqlite3VdbeHalt(p); - /* If the VDBE has be run even partially, then transfer the error code + /* If the VDBE has been run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. @@ -77160,6 +78877,9 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; p->pResultSet = 0; +#ifdef SQLITE_DEBUG + p->nWrite = 0; +#endif /* Save profiling information from this VDBE run. */ @@ -77275,6 +78995,9 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3DbFree(db, p->zNormSql); +#endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS { int i; @@ -78039,7 +79762,7 @@ static int isAllZero(const char *z, int n){ ** is less than, equal to, or greater than the second, respectively. ** If one blob is a prefix of the other, then the shorter is the lessor. */ -static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ int c; int n1 = pB1->n; int n2 = pB2->n; @@ -78082,13 +79805,10 @@ static int sqlite3IntFloatCompare(i64 i, double r){ i64 y; double s; if( r<-9223372036854775808.0 ) return +1; - if( r>9223372036854775807.0 ) return -1; + if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( iy ){ - if( y==SMALLEST_INT64 && r>0.0 ) return -1; - return +1; - } + if( i>y ) return +1; s = (double)i; if( sr ) return +1; @@ -78112,7 +79832,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C f1 = pMem1->flags; f2 = pMem2->flags; combined_flags = f1|f2; - assert( (combined_flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) ); /* If one value is NULL, it is less than the other. If both values ** are NULL, return 0. @@ -78257,7 +79977,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( u32 idx1; /* Offset of first type in header */ int rc = 0; /* Return value */ Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */ - KeyInfo *pKeyInfo = pPKey2->pKeyInfo; + KeyInfo *pKeyInfo; const unsigned char *aKey1 = (const unsigned char *)pKey1; Mem mem1; @@ -78352,7 +80072,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( if( (d1+mem1.n) > (unsigned)nKey1 ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ - }else if( pKeyInfo->aColl[i] ){ + }else if( (pKeyInfo = pPKey2->pKeyInfo)->aColl[i] ){ mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; mem1.flags = MEM_Str; @@ -78403,7 +80123,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( } if( rc!=0 ){ - if( pKeyInfo->aSortOrder[i] ){ + if( pPKey2->pKeyInfo->aSortOrder[i] ){ rc = -rc; } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); @@ -78412,10 +80132,11 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( } i++; + if( i==pPKey2->nField ) break; pRhs++; d1 += sqlite3VdbeSerialTypeLen(serial_type); idx1 += sqlite3VarintLen(serial_type); - }while( idx1<(unsigned)szHdr1 && inField && d1<=(unsigned)nKey1 ); + }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 ); /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a @@ -78427,7 +80148,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( ** value. */ assert( CORRUPT_DB || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) - || pKeyInfo->db->mallocFailed + || pPKey2->pKeyInfo->db->mallocFailed ); pPKey2->eqSeen = 1; return pPKey2->default_rc; @@ -78678,7 +80399,9 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ (void)getVarint32((u8*)m.z, szHdr); testcase( szHdr==3 ); testcase( szHdr==m.n ); - if( unlikely(szHdr<3 || (int)szHdr>m.n) ){ + testcase( szHdr>0x7fffffff ); + assert( m.n>=0 ); + if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){ goto idx_rowid_corruption; } @@ -78753,7 +80476,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( if( rc ){ return rc; } - *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); + *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0); sqlite3VdbeMemRelease(&m); return SQLITE_OK; } @@ -78785,11 +80508,19 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){ ** programs obsolete. Removing user-defined functions or collating ** sequences, or changing an authorization function are the types of ** things that make prepared statements obsolete. +** +** If iCode is 1, then expiration is advisory. The statement should +** be reprepared before being restarted, but if it is already running +** it is allowed to run to completion. +** +** Internally, this function just sets the Vdbe.expired flag on all +** prepared statements. The flag is set to 1 for an immediate expiration +** and set to 2 for an advisory expiration. */ -SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db){ +SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){ Vdbe *p; for(p = db->pVdbe; p; p=p->pNext){ - p->expired = 1; + p->expired = iCode+1; } } @@ -79766,28 +81497,6 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ return *piTime; } -/* -** The following is the implementation of an SQL function that always -** fails with an error message stating that the function is used in the -** wrong context. The sqlite3_overload_function() API might construct -** SQL function that use this routine so that the functions will exist -** for name resolution but are actually overloaded by the xFindFunction -** method of virtual tables. -*/ -SQLITE_PRIVATE void sqlite3InvalidFunction( - sqlite3_context *context, /* The function calling context */ - int NotUsed, /* Number of arguments to the function */ - sqlite3_value **NotUsed2 /* Value of each argument */ -){ - const char *zName = context->pFunc->zName; - char *zErr; - UNUSED_PARAMETER2(NotUsed, NotUsed2); - zErr = sqlite3_mprintf( - "unable to use function %s in the requested context", zName); - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); -} - /* ** Create a new aggregate context for p and return a pointer to ** its pMem->z element. @@ -79971,7 +81680,7 @@ static const Mem *columnNullValue(void){ /* .xDel = */ (void(*)(void*))0, #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, - /* .pFiller = */ (void*)0, + /* .mScopyFlags= */ 0, #endif }; return &nullMem; @@ -80703,6 +82412,16 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ #endif } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Return the normalized SQL associated with a prepared statement. +*/ +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + return p ? p->zNormSql : 0; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized @@ -81055,17 +82774,17 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( while( *zRawSql ){ const char *zStart = zRawSql; while( *(zRawSql++)!='\n' && *zRawSql ); - sqlite3StrAccumAppend(&out, "-- ", 3); + sqlite3_str_append(&out, "-- ", 3); assert( (zRawSql - zStart) > 0 ); - sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart)); + sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart)); } }else if( p->nVar==0 ){ - sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql)); + sqlite3_str_append(&out, zRawSql, sqlite3Strlen30(zRawSql)); }else{ while( zRawSql[0] ){ n = findNextHostParameter(zRawSql, &nToken); assert( n>0 ); - sqlite3StrAccumAppend(&out, zRawSql, n); + sqlite3_str_append(&out, zRawSql, n); zRawSql += n; assert( zRawSql[0] || nToken==0 ); if( nToken==0 ) break; @@ -81091,11 +82810,11 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( assert( idx>0 && idx<=p->nVar ); pVar = &p->aVar[idx-1]; if( pVar->flags & MEM_Null ){ - sqlite3StrAccumAppend(&out, "NULL", 4); + sqlite3_str_append(&out, "NULL", 4); }else if( pVar->flags & MEM_Int ){ - sqlite3XPrintf(&out, "%lld", pVar->u.i); + sqlite3_str_appendf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ - sqlite3XPrintf(&out, "%!.15g", pVar->u.r); + sqlite3_str_appendf(&out, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 @@ -81105,7 +82824,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){ - out.accError = STRACCUM_NOMEM; + out.accError = SQLITE_NOMEM; out.nAlloc = 0; } pVar = &utf8; @@ -81118,38 +82837,38 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( while( nOutn && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; } } #endif - sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z); + sqlite3_str_appendf(&out, "'%.*q'", nOut, pVar->z); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ - sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); + sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif #ifndef SQLITE_OMIT_UTF16 if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8); #endif }else if( pVar->flags & MEM_Zero ){ - sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero); + sqlite3_str_appendf(&out, "zeroblob(%d)", pVar->u.nZero); }else{ int nOut; /* Number of bytes of the blob to include in output */ assert( pVar->flags & MEM_Blob ); - sqlite3StrAccumAppend(&out, "x'", 2); + sqlite3_str_append(&out, "x'", 2); nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT; #endif for(i=0; iz[i]&0xff); + sqlite3_str_appendf(&out, "%02x", pVar->z[i]&0xff); } - sqlite3StrAccumAppend(&out, "'", 1); + sqlite3_str_append(&out, "'", 1); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ - sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); + sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif } } } - if( out.accError ) sqlite3StrAccumReset(&out); + if( out.accError ) sqlite3_str_reset(&out); return sqlite3StrAccumFinish(&out); } @@ -81281,32 +83000,56 @@ SQLITE_API int sqlite3_found_count = 0; ** feature is used for test suite validation only and does not appear an ** production builds. ** -** M is an integer, 2 or 3, that indices how many different ways the -** branch can go. It is usually 2. "I" is the direction the branch -** goes. 0 means falls through. 1 means branch is taken. 2 means the -** second alternative branch is taken. +** M is an integer between 2 and 4. 2 indicates a ordinary two-way +** branch (I=0 means fall through and I=1 means taken). 3 indicates +** a 3-way branch where the third way is when one of the operands is +** NULL. 4 indicates the OP_Jump instruction which has three destinations +** depending on whether the first operand is less than, equal to, or greater +** than the second. ** ** iSrcLine is the source code line (from the __LINE__ macro) that -** generated the VDBE instruction. This instrumentation assumes that all -** source code is in a single file (the amalgamation). Special values 1 -** and 2 for the iSrcLine parameter mean that this particular branch is -** always taken or never taken, respectively. +** generated the VDBE instruction combined with flag bits. The source +** code line number is in the lower 24 bits of iSrcLine and the upper +** 8 bytes are flags. The lower three bits of the flags indicate +** values for I that should never occur. For example, if the branch is +** always taken, the flags should be 0x05 since the fall-through and +** alternate branch are never taken. If a branch is never taken then +** flags should be 0x06 since only the fall-through approach is allowed. +** +** Bit 0x04 of the flags indicates an OP_Jump opcode that is only +** interested in equal or not-equal. In other words, I==0 and I==2 +** should be treated the same. +** +** Since only a line number is retained, not the filename, this macro +** only works for amalgamation builds. But that is ok, since these macros +** should be no-ops except for special builds used to measure test coverage. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) #else # define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M) - static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){ - if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){ - M = iSrcLine; - /* Assert the truth of VdbeCoverageAlwaysTaken() and - ** VdbeCoverageNeverTaken() */ - assert( (M & I)==I ); - }else{ - if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ - sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, - iSrcLine,I,M); + static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){ + u8 mNever; + assert( I<=2 ); /* 0: fall through, 1: taken, 2: alternate taken */ + assert( M<=4 ); /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */ + assert( I> 24; + assert( (I & mNever)==0 ); + if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ + I |= mNever; + if( M==2 ) I |= 0x04; + if( M==4 ){ + I |= 0x08; + if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/ } + sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, + iSrcLine&0xffffff, I, M); } #endif @@ -81637,7 +83380,7 @@ static void memTracePrint(Mem *p){ }else if( p->flags & MEM_Real ){ printf(" r:%g", p->u.r); #endif - }else if( p->flags & MEM_RowSet ){ + }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ char zBuf[200]; @@ -82163,6 +83906,9 @@ case OP_Yield: { /* in1, jump */ */ case OP_HaltIfNull: { /* in3 */ pIn3 = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } +#endif if( (pIn3->flags & MEM_Null)==0 ) break; /* Fall through into OP_Halt */ } @@ -82202,6 +83948,9 @@ case OP_Halt: { int pcx; pcx = (int)(pOp - aOp); +#ifdef SQLITE_DEBUG + if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } +#endif if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ pFrame = p->pFrame; @@ -82385,6 +84134,9 @@ case OP_Null: { /* out2 */ assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; pOut->n = 0; +#ifdef SQLITE_DEBUG + pOut->uTemp = 0; +#endif while( cnt>0 ){ pOut++; memAboutToChange(p, pOut); @@ -82506,6 +84258,7 @@ case OP_Copy: { pOut = &aMem[pOp->p2]; assert( pOut!=pIn1 ); while( 1 ){ + memAboutToChange(p, pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); Deephemeralize(pOut); #ifdef SQLITE_DEBUG @@ -82538,7 +84291,8 @@ case OP_SCopy: { /* out2 */ assert( pOut!=pIn1 ); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); #ifdef SQLITE_DEBUG - if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1; + pOut->pScopyFrom = pIn1; + pOut->mScopyFlags = pIn1->flags; #endif break; } @@ -83172,7 +84926,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); - testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */ + assert( flags3==pIn3->flags ); + /* testcase( flags3!=pIn3->flags ); + ** this used to be possible with pIn1==pIn3, but not since + ** the column cache was removed. The following assignment + ** is essentially a no-op. But, it provides defense-in-depth + ** in case our analysis is incorrect, so it is left in. */ flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ @@ -83386,11 +85145,11 @@ case OP_Compare: { */ case OP_Jump: { /* jump */ if( iCompare<0 ){ - VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1]; + VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ - VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1]; + VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1]; }else{ - VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1]; + VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1]; } break; } @@ -83487,7 +85246,7 @@ case OP_Not: { /* same as TK_NOT, in1, out2 */ } /* Opcode: BitNot P1 P2 * * * -** Synopsis: r[P1]= ~r[P1] +** Synopsis: r[P2]= ~r[P1] ** ** Interpret the content of register P1 as an integer. Store the ** ones-complement of the P1 value into register P2. If P1 holds @@ -84102,17 +85861,25 @@ case OP_MakeRecord: { if( nVarintdb->aLimit[SQLITE_LIMIT_LENGTH] ){ - goto too_big; - } /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ - if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ - goto no_mem; + if( nByte+nZero<=pOut->szMalloc ){ + /* The output register is already large enough to hold the record. + ** No error checks or buffer enlargement is required */ + pOut->z = pOut->zMalloc; + }else{ + /* Need to make sure that the output is not too big and then enlarge + ** the output register to hold the full result */ + if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; + } + if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ + goto no_mem; + } } zNewRecord = (u8 *)pOut->z; @@ -84302,7 +86069,7 @@ case OP_Savepoint: { } } if( isSchemaChange ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); db->mDbFlags |= DBFLAG_SchemaChange; } @@ -84444,8 +86211,7 @@ case OP_AutoCommit: { */ case OP_Transaction: { Btree *pBt; - int iMeta; - int iGen; + int iMeta = 0; assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); @@ -84458,7 +86224,7 @@ case OP_Transaction: { pBt = db->aDb[pOp->p1].pBt; if( pBt ){ - rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); + rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta); testcase( rc==SQLITE_BUSY_SNAPSHOT ); testcase( rc==SQLITE_BUSY_RECOVERY ); if( rc!=SQLITE_OK ){ @@ -84491,19 +86257,17 @@ case OP_Transaction: { p->nStmtDefCons = db->nDeferredCons; p->nStmtDefImmCons = db->nDeferredImmCons; } - - /* Gather the schema version number for checking: + } + assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); + if( pOp->p5 + && (iMeta!=pOp->p3 + || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i) + ){ + /* ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema ** version is checked to ensure that the schema has not changed since the ** SQL statement was prepared. */ - sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); - iGen = db->aDb[pOp->p1].pSchema->iGeneration; - }else{ - iGen = iMeta = 0; - } - assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); - if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); /* If the schema-cookie from the database file matches the cookie @@ -84572,6 +86336,8 @@ case OP_ReadCookie: { /* out2 */ */ case OP_SetCookie: { Db *pDb; + + sqlite3VdbeIncrWriteCounter(p, 0); assert( pOp->p2p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); @@ -84592,7 +86358,7 @@ case OP_SetCookie: { if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); p->expired = 0; } if( rc ) goto abort_due_to_error; @@ -84610,59 +86376,78 @@ case OP_SetCookie: { ** values need not be contiguous but all P1 values should be small integers. ** It is an error for P1 to be negative. ** -** If P5!=0 then use the content of register P2 as the root page, not -** the value of P2 itself. -** -** There will be a read lock on the database whenever there is an -** open cursor. If the database was unlocked prior to this instruction -** then a read lock is acquired as part of this instruction. A read -** lock allows other processes to read the database but prohibits -** any other process from modifying the database. The read lock is -** released when all cursors are closed. If this instruction attempts -** to get a read lock but fails, the script terminates with an -** SQLITE_BUSY error code. +** Allowed P5 bits: +**
        +**
      • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for +** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT +** of OP_SeekLE/OP_IdxGT) +**
      ** ** The P4 value may be either an integer (P4_INT32) or a pointer to ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo -** structure, then said structure defines the content and collating -** sequence of the index being opened. Otherwise, if P4 is an integer -** value, it is set to the number of columns in the table. +** object, then table being opened must be an [index b-tree] where the +** KeyInfo object defines the content and collating +** sequence of that index b-tree. Otherwise, if P4 is an integer +** value, then the table being opened must be a [table b-tree] with a +** number of columns no less than the value of P4. ** ** See also: OpenWrite, ReopenIdx */ /* Opcode: ReopenIdx P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** -** The ReopenIdx opcode works exactly like ReadOpen except that it first -** checks to see if the cursor on P1 is already open with a root page -** number of P2 and if it is this opcode becomes a no-op. In other words, +** The ReopenIdx opcode works like OP_OpenRead except that it first +** checks to see if the cursor on P1 is already open on the same +** b-tree and if it is this opcode becomes a no-op. In other words, ** if the cursor is already open, do not reopen it. ** -** The ReopenIdx opcode may only be used with P5==0 and with P4 being -** a P4_KEYINFO object. Furthermore, the P3 value must be the same as -** every other ReopenIdx or OpenRead for the same cursor number. +** The ReopenIdx opcode may only be used with P5==0 or P5==OPFLAG_SEEKEQ +** and with P4 being a P4_KEYINFO object. Furthermore, the P3 value must +** be the same as every other ReopenIdx or OpenRead for the same cursor +** number. ** -** See the OpenRead opcode documentation for additional information. +** Allowed P5 bits: +**
        +**
      • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for +** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT +** of OP_SeekLE/OP_IdxGT) +**
      +** +** See also: OP_OpenRead, OP_OpenWrite */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** Open a read/write cursor named P1 on the table or index whose root -** page is P2. Or if P5!=0 use the content of register P2 to find the -** root page. +** page is P2 (or whose root page is held in register P2 if the +** OPFLAG_P2ISREG bit is set in P5 - see below). ** ** The P4 value may be either an integer (P4_INT32) or a pointer to ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo -** structure, then said structure defines the content and collating -** sequence of the index being opened. Otherwise, if P4 is an integer -** value, it is set to the number of columns in the table, or to the -** largest index of any column of the table that is actually used. +** object, then table being opened must be an [index b-tree] where the +** KeyInfo object defines the content and collating +** sequence of that index b-tree. Otherwise, if P4 is an integer +** value, then the table being opened must be a [table b-tree] with a +** number of columns no less than the value of P4. ** -** This instruction works just like OpenRead except that it opens the cursor -** in read/write mode. For a given table, there can be one or more read-only -** cursors or a single read/write cursor but not both. +** Allowed P5 bits: +**
        +**
      • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for +** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT +** of OP_SeekLE/OP_IdxGT) +**
      • 0x08 OPFLAG_FORDELETE: This cursor is used only to seek +** and subsequently delete entries in an index btree. This is a +** hint to the storage engine that the storage engine is allowed to +** ignore. The hint is not used by the official SQLite b*tree storage +** engine, but is used by COMDB2. +**
      • 0x10 OPFLAG_P2ISREG: Use the content of register P2 +** as the root page, not the value of P2 itself. +**
      ** -** See also OpenRead. +** This instruction works like OpenRead except that it opens the cursor +** in read/write mode. +** +** See also: OP_OpenRead, OP_ReopenIdx */ case OP_ReopenIdx: { int nField; @@ -84691,7 +86476,7 @@ case OP_OpenWrite: assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); - if( p->expired ){ + if( p->expired==1 ){ rc = SQLITE_ABORT_ROLLBACK; goto abort_due_to_error; } @@ -84718,6 +86503,7 @@ case OP_OpenWrite: if( pOp->p5 & OPFLAG_P2ISREG ){ assert( p2>0 ); assert( p2<=(p->nMem+1 - p->nCursor) ); + assert( pOp->opcode==OP_OpenWrite ); pIn2 = &aMem[p2]; assert( memIsValid(pIn2) ); assert( (pIn2->flags & MEM_Int)!=0 ); @@ -84846,7 +86632,7 @@ case OP_OpenEphemeral: { rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1); + rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0); } if( rc==SQLITE_OK ){ /* If a transient index is required, create it by calling @@ -85073,10 +86859,10 @@ case OP_ColumnsUsed: { ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ -case OP_SeekLT: /* jump, in3 */ -case OP_SeekLE: /* jump, in3 */ -case OP_SeekGE: /* jump, in3 */ -case OP_SeekGT: { /* jump, in3 */ +case OP_SeekLT: /* jump, in3, group */ +case OP_SeekLE: /* jump, in3, group */ +case OP_SeekGE: /* jump, in3, group */ +case OP_SeekGT: { /* jump, in3, group */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ @@ -85254,6 +87040,25 @@ seek_not_found: break; } +/* Opcode: SeekHit P1 P2 * * * +** Synopsis: seekHit=P2 +** +** Set the seekHit flag on cursor P1 to the value in P2. +** The seekHit flag is used by the IfNoHope opcode. +** +** P1 must be a valid b-tree cursor. P2 must be a boolean value, +** either 0 or 1. +*/ +case OP_SeekHit: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pOp->p2==0 || pOp->p2==1 ); + pC->seekHit = pOp->p2 & 1; + break; +} + /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** @@ -85288,7 +87093,34 @@ seek_not_found: ** advanced in either direction. In other words, the Next and Prev ** opcodes do not work after this operation. ** -** See also: Found, NotExists, NoConflict +** See also: Found, NotExists, NoConflict, IfNoHope +*/ +/* Opcode: IfNoHope P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** Register P3 is the first of P4 registers that form an unpacked +** record. +** +** Cursor P1 is on an index btree. If the seekHit flag is set on P1, then +** this opcode is a no-op. But if the seekHit flag of P1 is clear, then +** check to see if there is any entry in P1 that matches the +** prefix identified by P3 and P4. If no entry matches the prefix, +** jump to P2. Otherwise fall through. +** +** This opcode behaves like OP_NotFound if the seekHit +** flag is clear and it behaves like OP_Noop if the seekHit flag is set. +** +** This opcode is used in IN clause processing for a multi-column key. +** If an IN clause is attached to an element of the key other than the +** left-most element, and if there are no matches on the most recent +** seek over the whole key, then it might be that one of the key element +** to the left is prohibiting a match, and hence there is "no hope" of +** any match regardless of how many IN clause elements are checked. +** In such a case, we abandon the IN clause search early, using this +** opcode. The opcode name comes from the fact that the +** jump is taken if there is "no hope" of achieving a match. +** +** See also: NotFound, SeekHit */ /* Opcode: NoConflict P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] @@ -85313,6 +87145,14 @@ seek_not_found: ** ** See also: NotFound, Found, NotExists */ +case OP_IfNoHope: { /* jump, in3 */ + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + if( pC->seekHit ) break; + /* Fall through into OP_NotFound */ +} case OP_NoConflict: /* jump, in3 */ case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ @@ -85450,18 +87290,26 @@ case OP_SeekRowid: { /* jump, in3 */ pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & MEM_Int)==0 ){ + /* Make sure pIn3->u.i contains a valid integer representation of + ** the key value, but do not change the datatype of the register, as + ** other parts of the perpared statement might be depending on the + ** current datatype. */ + u16 origFlags = pIn3->flags; + int isNotInt; applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); - if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2; + isNotInt = (pIn3->flags & MEM_Int)==0; + pIn3->flags = origFlags; + if( isNotInt ) goto jump_to_p2; } /* Fall through into OP_NotExists */ case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; - assert( pIn3->flags & MEM_Int ); + assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid ); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG - pC->seekOp = 0; + pC->seekOp = OP_SeekRowid; #endif assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); @@ -85535,11 +87383,8 @@ case OP_NewRowid: { /* out2 */ pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; - if( !pC->isTable ){ - rc = SQLITE_CORRUPT_BKPT; - goto abort_due_to_error; - } assert( pC!=0 ); + assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); { @@ -85708,6 +87553,7 @@ case OP_InsertInt: { assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable ); assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); REGISTER_TRACE(pOp->p2, pData); + sqlite3VdbeIncrWriteCounter(p, pC); if( pOp->opcode==OP_Insert ){ pKey = &aMem[pOp->p3]; @@ -85822,6 +87668,7 @@ case OP_Delete: { assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); + sqlite3VdbeIncrWriteCounter(p, pC); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ @@ -85990,10 +87837,10 @@ case OP_SorterData: { ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. ** -** If P3!=0 then this opcode is allowed to make an ephermeral pointer +** If P3!=0 then this opcode is allowed to make an ephemeral pointer ** into the database page. That means that the content of the output ** register will be invalidated as soon as the cursor moves - including -** moves caused by other cursors that "save" the the current cursors +** moves caused by other cursors that "save" the current cursors ** position in order that they can write to the same table. If P3==0 ** then a copy of the data is made into memory. P3!=0 is faster, but ** P3==0 is safer. @@ -86116,6 +87963,9 @@ case OP_NullRow: { assert( pC->uc.pCursor!=0 ); sqlite3BtreeClearCursor(pC->uc.pCursor); } +#ifdef SQLITE_DEBUG + if( pC->seekOp==0 ) pC->seekOp = OP_NullRow; +#endif break; } @@ -86234,7 +88084,7 @@ case OP_Sort: { /* jump */ p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ } -/* Opcode: Rewind P1 P2 * * * +/* Opcode: Rewind P1 P2 * * P5 ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. @@ -86242,6 +88092,10 @@ case OP_Sort: { /* jump */ ** If the table or index is not empty, fall through to the following ** instruction. ** +** If P5 is non-zero and the table is not empty, then the "skip-next" +** flag is set on the cursor so that the next OP_Next instruction +** executed on it is a no-op. +** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. @@ -86266,6 +88120,9 @@ case OP_Rewind: { /* jump */ pCrsr = pC->uc.pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pOp->p5 ) sqlite3BtreeSkipNext(pCrsr); +#endif pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } @@ -86302,12 +88159,7 @@ case OP_Rewind: { /* jump */ ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** -** See also: Prev, NextIfOpen -*/ -/* Opcode: NextIfOpen P1 P2 P3 P4 P5 -** -** This opcode works just like Next except that if cursor P1 is not -** open it behaves a no-op. +** See also: Prev */ /* Opcode: Prev P1 P2 P3 P4 P5 ** @@ -86335,11 +88187,6 @@ case OP_Rewind: { /* jump */ ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ -/* Opcode: PrevIfOpen P1 P2 P3 P4 P5 -** -** This opcode works just like Prev except that if cursor P1 is not -** open it behaves a no-op. -*/ /* Opcode: SorterNext P1 P2 * * P5 ** ** This opcode works just like OP_Next except that P1 must be a @@ -86354,10 +88201,6 @@ case OP_SorterNext: { /* jump */ assert( isSorter(pC) ); rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; -case OP_PrevIfOpen: /* jump */ -case OP_NextIfOpen: /* jump */ - if( p->apCsr[pOp->p1]==0 ) break; - /* Fall through */ case OP_Prev: /* jump */ case OP_Next: /* jump */ assert( pOp->p1>=0 && pOp->p1nCursor ); @@ -86368,17 +88211,17 @@ case OP_Next: /* jump */ assert( pC->eCurType==CURTYPE_BTREE ); assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); - assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); - assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious); - /* The Next opcode is only used after SeekGT, SeekGE, and Rewind. + /* The Next opcode is only used after SeekGT, SeekGE, Rewind, and Found. ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ - assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen + assert( pOp->opcode!=OP_Next || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE - || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found); - assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen + || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found + || pC->seekOp==OP_NullRow); + assert( pOp->opcode!=OP_Prev || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE - || pC->seekOp==OP_Last ); + || pC->seekOp==OP_Last + || pC->seekOp==OP_NullRow); rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3); next_tail: @@ -86440,6 +88283,7 @@ case OP_IdxInsert: { /* in2 */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; + sqlite3VdbeIncrWriteCounter(p, pC); assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) ); pIn2 = &aMem[pOp->p2]; @@ -86486,6 +88330,7 @@ case OP_IdxDelete: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3VdbeIncrWriteCounter(p, pC); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); assert( pOp->p5==0 ); @@ -86659,7 +88504,13 @@ case OP_IdxGE: { /* jump */ } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG - { int i; for(i=0; ip3+i, &aMem[pOp->p3+i]); + } + } #endif res = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res); @@ -86708,6 +88559,7 @@ case OP_Destroy: { /* out2 */ int iMoved; int iDb; + sqlite3VdbeIncrWriteCounter(p, 0); assert( p->readOnly==0 ); assert( pOp->p1>1 ); pOut = out2Prerelease(p, pOp); @@ -86757,6 +88609,7 @@ case OP_Destroy: { /* out2 */ case OP_Clear: { int nChange; + sqlite3VdbeIncrWriteCounter(p, 0); nChange = 0; assert( p->readOnly==0 ); assert( DbMaskTest(p->btreeMask, pOp->p2) ); @@ -86806,13 +88659,14 @@ case OP_ResetSorter: { ** Allocate a new b-tree in the main database file if P1==0 or in the ** TEMP database file if P1==1 or in an attached database if ** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table -** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table. +** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table. ** The root page number of the new b-tree is stored in register P2. */ case OP_CreateBtree: { /* out2 */ int pgno; Db *pDb; + sqlite3VdbeIncrWriteCounter(p, 0); pOut = out2Prerelease(p, pOp); pgno = 0; assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY ); @@ -86832,6 +88686,7 @@ case OP_CreateBtree: { /* out2 */ ** Run the SQL statement or statements specified in the P4 string. */ case OP_SqlExec: { + sqlite3VdbeIncrWriteCounter(p, 0); db->nSqlExec++; rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); db->nSqlExec--; @@ -86842,7 +88697,8 @@ case OP_SqlExec: { /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the SQLITE_MASTER table of database P1 -** that match the WHERE clause P4. +** that match the WHERE clause P4. If P4 is a NULL pointer, then the +** entire schema for P1 is reparsed. ** ** This opcode invokes the parser to create a new virtual machine, ** then runs the new virtual machine. It is thus a re-entrant opcode. @@ -86866,11 +88722,22 @@ case OP_ParseSchema: { iDb = pOp->p1; assert( iDb>=0 && iDbnDb ); assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); - /* Used to be a conditional */ { + +#ifndef SQLITE_OMIT_ALTERTABLE + if( pOp->p4.z==0 ){ + sqlite3SchemaClear(db->aDb[iDb].pSchema); + db->mDbFlags &= ~DBFLAG_SchemaKnownOk; + rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable); + db->mDbFlags |= DBFLAG_SchemaChange; + p->expired = 0; + }else +#endif + { zMaster = MASTER_NAME; initData.db = db; - initData.iDb = pOp->p1; + initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; + initData.mInitFlags = 0; zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); @@ -86921,6 +88788,7 @@ case OP_LoadAnalysis: { ** schema consistent with what is on disk. */ case OP_DropTable: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z); break; } @@ -86934,6 +88802,7 @@ case OP_DropTable: { ** schema consistent with what is on disk. */ case OP_DropIndex: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z); break; } @@ -86947,6 +88816,7 @@ case OP_DropIndex: { ** schema consistent with what is on disk. */ case OP_DropTrigger: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z); break; } @@ -87020,11 +88890,11 @@ case OP_RowSetAdd: { /* in1, in2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Int)!=0 ); - if( (pIn1->flags & MEM_RowSet)==0 ){ - sqlite3VdbeMemSetRowSet(pIn1); - if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + if( (pIn1->flags & MEM_Blob)==0 ){ + if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } - sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i); + assert( sqlite3VdbeMemIsRowSet(pIn1) ); + sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i); break; } @@ -87040,8 +88910,9 @@ case OP_RowSetRead: { /* jump, in1, out3 */ i64 val; pIn1 = &aMem[pOp->p1]; - if( (pIn1->flags & MEM_RowSet)==0 - || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 + assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) ); + if( (pIn1->flags & MEM_Blob)==0 + || sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); @@ -87090,20 +88961,19 @@ case OP_RowSetTest: { /* jump, in1, in3 */ /* If there is anything other than a rowset object in memory cell P1, ** delete it now and initialize P1 with an empty rowset */ - if( (pIn1->flags & MEM_RowSet)==0 ){ - sqlite3VdbeMemSetRowSet(pIn1); - if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + if( (pIn1->flags & MEM_Blob)==0 ){ + if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } - + assert( sqlite3VdbeMemIsRowSet(pIn1) ); assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ - exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); + exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); if( exists ) goto jump_to_p2; } if( iSet>=0 ){ - sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); + sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i); } break; } @@ -87167,7 +89037,7 @@ case OP_Program: { /* jump */ ** of the current program, and the memory required at runtime to execute ** the trigger program. If this trigger has been fired before, then pRt ** is already allocated. Otherwise, it must be initialized. */ - if( (pRt->flags&MEM_Frame)==0 ){ + if( (pRt->flags&MEM_Blob)==0 ){ /* SubProgram.nMem is set to the number of memory cells used by the ** program stored in SubProgram.aOp. As well as these, one memory ** cell is required for each cursor used by the program. Set local @@ -87185,8 +89055,10 @@ case OP_Program: { /* jump */ goto no_mem; } sqlite3VdbeMemRelease(pRt); - pRt->flags = MEM_Frame; - pRt->u.pFrame = pFrame; + pRt->flags = MEM_Blob|MEM_Dyn; + pRt->z = (char*)pFrame; + pRt->n = nByte; + pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; pFrame->nChildMem = nMem; @@ -87202,6 +89074,9 @@ case OP_Program: { /* jump */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pFrame->anExec = p->anExec; #endif +#ifdef SQLITE_DEBUG + pFrame->iFrameMagic = SQLITE_FRAME_MAGIC; +#endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ @@ -87209,7 +89084,8 @@ case OP_Program: { /* jump */ pMem->db = db; } }else{ - pFrame = pRt->u.pFrame; + pFrame = (VdbeFrame*)pRt->z; + assert( pRt->xDel==sqlite3VdbeFrameMemDel ); assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) ); assert( pProgram->nCsr==pFrame->nChildCsr ); @@ -87438,24 +89314,35 @@ case OP_DecrJumpZero: { /* jump, in1 */ } -/* Opcode: AggStep0 * P2 P3 P4 P5 +/* Opcode: AggStep * P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** -** Execute the step function for an aggregate. The -** function has P5 arguments. P4 is a pointer to the FuncDef -** structure that specifies the function. Register P3 is the +** Execute the xStep function for an aggregate. +** The function has P5 arguments. P4 is a pointer to the +** FuncDef structure that specifies the function. Register P3 is the ** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. */ -/* Opcode: AggStep * P2 P3 P4 P5 +/* Opcode: AggInverse * P2 P3 P4 P5 +** Synopsis: accum=r[P3] inverse(r[P2@P5]) +** +** Execute the xInverse function for an aggregate. +** The function has P5 arguments. P4 is a pointer to the +** FuncDef structure that specifies the function. Register P3 is the +** accumulator. +** +** The P5 arguments are taken from register P2 and its +** successors. +*/ +/* Opcode: AggStep1 P1 P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** -** Execute the step function for an aggregate. The -** function has P5 arguments. P4 is a pointer to an sqlite3_context -** object that is used to run the function. Register P3 is -** as the accumulator. +** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an +** aggregate. The function has P5 arguments. P4 is a pointer to the +** FuncDef structure that specifies the function. Register P3 is the +** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. @@ -87466,7 +89353,8 @@ case OP_DecrJumpZero: { /* jump, in1 */ ** sqlite3_context only happens once, instead of on each call to the ** step function. */ -case OP_AggStep0: { +case OP_AggInverse: +case OP_AggStep: { int n; sqlite3_context *pCtx; @@ -87489,10 +89377,14 @@ case OP_AggStep0: { pCtx->argc = n; pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; - pOp->opcode = OP_AggStep; + + /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */ + assert( pOp->p1==(pOp->opcode==OP_AggInverse) ); + + pOp->opcode = OP_AggStep1; /* Fall through into OP_AggStep */ } -case OP_AggStep: { +case OP_AggStep1: { int i; sqlite3_context *pCtx; Mem *pMem; @@ -87501,6 +89393,17 @@ case OP_AggStep: { pCtx = pOp->p4.pCtx; pMem = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + if( pOp->p1 ){ + /* This is an OP_AggInverse call. Verify that xStep has always + ** been called at least once prior to any xInverse call. */ + assert( pMem->uTemp==0x1122e0e3 ); + }else{ + /* This is an OP_AggStep call. Mark it as such. */ + pMem->uTemp = 0x1122e0e3; + } +#endif + /* If this function is inside of a trigger, the register array in aMem[] ** might change from one evaluation to the next. The next block of code ** checks to see if the register array has changed, and if so it @@ -87521,7 +89424,13 @@ case OP_AggStep: { assert( pCtx->pOut->flags==MEM_Null ); assert( pCtx->isError==0 ); assert( pCtx->skipFlag==0 ); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pOp->p1 ){ + (pCtx->pFunc->xInverse)(pCtx,pCtx->argc,pCtx->argv); + }else +#endif (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ + if( pCtx->isError ){ if( pCtx->isError>0 ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut)); @@ -87546,22 +89455,46 @@ case OP_AggStep: { /* Opcode: AggFinal P1 P2 * P4 * ** Synopsis: accum=r[P1] N=P2 ** -** Execute the finalizer function for an aggregate. P1 is -** the memory location that is the accumulator for the aggregate. +** P1 is the memory location that is the accumulator for an aggregate +** or window function. Execute the finalizer function +** for an aggregate and store the result in P1. ** ** P2 is the number of arguments that the step function takes and ** P4 is a pointer to the FuncDef for this function. The P2 ** argument is not used by this opcode. It is only there to disambiguate ** functions that can take varying numbers of arguments. The -** P4 argument is only needed for the degenerate case where +** P4 argument is only needed for the case where ** the step function was not previously called. */ +/* Opcode: AggValue * P2 P3 P4 * +** Synopsis: r[P3]=value N=P2 +** +** Invoke the xValue() function and store the result in register P3. +** +** P2 is the number of arguments that the step function takes and +** P4 is a pointer to the FuncDef for this function. The P2 +** argument is not used by this opcode. It is only there to disambiguate +** functions that can take varying numbers of arguments. The +** P4 argument is only needed for the case where +** the step function was not previously called. +*/ +case OP_AggValue: case OP_AggFinal: { Mem *pMem; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + assert( pOp->p3==0 || pOp->opcode==OP_AggValue ); pMem = &aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); - rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pOp->p3 ){ + rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); + pMem = &aMem[pOp->p3]; + }else +#endif + { + rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); + } + if( rc ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); goto abort_due_to_error; @@ -87756,7 +89689,7 @@ case OP_IncrVacuum: { /* jump */ } #endif -/* Opcode: Expire P1 * * * * +/* Opcode: Expire P1 P2 * * * ** ** Cause precompiled statements to expire. When an expired statement ** is executed using sqlite3_step() it will either automatically @@ -87765,12 +89698,19 @@ case OP_IncrVacuum: { /* jump */ ** ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, ** then only the currently executing statement is expired. +** +** If P2 is 0, then SQL statements are expired immediately. If P2 is 1, +** then running SQL statements are allowed to continue to run to completion. +** The P2==1 case occurs when a CREATE INDEX or similar schema change happens +** that might help the statement run faster but which does not affect the +** correctness of operation. */ case OP_Expire: { + assert( pOp->p2==0 || pOp->p2==1 ); if( !pOp->p1 ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ - p->expired = 1; + p->expired = pOp->p2+1; } break; } @@ -87992,10 +89932,11 @@ case OP_VFilter: { /* jump */ ** ** If the VColumn opcode is being used to fetch the value of ** an unchanging column during an UPDATE operation, then the P5 -** value is 1. Otherwise, P5 is 0. The P5 value is returned -** by sqlite3_vtab_nochange() routine can can be used -** by virtual table implementations to return special "no-change" -** marks which can be more efficient, depending on the virtual table. +** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange() +** function to return true inside the xColumn method of the virtual +** table implementation. The P5 column might also contain other +** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are +** unused by OP_VColumn. */ case OP_VColumn: { sqlite3_vtab *pVtab; @@ -88017,7 +89958,8 @@ case OP_VColumn: { assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; - if( pOp->p5 ){ + testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && pOp->p5!=0 ); + if( pOp->p5 & OPFLAG_NOCHNG ){ sqlite3VdbeMemSetNull(pDest); pDest->flags = MEM_Null|MEM_Zero; pDest->u.nZero = 0; @@ -88094,7 +90036,10 @@ case OP_VNext: { /* jump */ case OP_VRename: { sqlite3_vtab *pVtab; Mem *pName; - + int isLegacy; + + isLegacy = (db->flags & SQLITE_LegacyAlter); + db->flags |= SQLITE_LegacyAlter; pVtab = pOp->p4.pVtab->pVtab; pName = &aMem[pOp->p1]; assert( pVtab->pModule->xRename ); @@ -88108,6 +90053,7 @@ case OP_VRename: { rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); if( rc ) goto abort_due_to_error; rc = pVtab->pModule->xRename(pVtab, pName->z); + if( isLegacy==0 ) db->flags &= ~SQLITE_LegacyAlter; sqlite3VtabImportErrmsg(p, pVtab); p->expired = 0; if( rc ) goto abort_due_to_error; @@ -88156,6 +90102,8 @@ case OP_VUpdate: { || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); assert( p->readOnly==0 ); + if( db->mallocFailed ) goto no_mem; + sqlite3VdbeIncrWriteCounter(p, 0); pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; @@ -88276,8 +90224,8 @@ case OP_MaxPgcnt: { /* out2 */ ** ** See also: Function0, AggStep, AggFinal */ -case OP_PureFunc0: -case OP_Function0: { +case OP_PureFunc0: /* group */ +case OP_Function0: { /* group */ int n; sqlite3_context *pCtx; @@ -88301,8 +90249,8 @@ case OP_Function0: { pOp->opcode += 2; /* Fall through into OP_Function */ } -case OP_PureFunc: -case OP_Function: { +case OP_PureFunc: /* group */ +case OP_Function: { /* group */ int i; sqlite3_context *pCtx; @@ -88473,6 +90421,22 @@ case OP_CursorHint: { } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ +#ifdef SQLITE_DEBUG +/* Opcode: Abortable * * * * * +** +** Verify that an Abort can happen. Assert if an Abort at this point +** might cause database corruption. This opcode only appears in debugging +** builds. +** +** An Abort is safe if either there have been no writes, or if there is +** an active statement journal. +*/ +case OP_Abortable: { + sqlite3VdbeAssertAbortable(p); + break; +} +#endif + /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump @@ -88484,8 +90448,9 @@ case OP_CursorHint: { ** This opcode records information from the optimizer. It is the ** the same as a no-op. This opcodesnever appears in a real VM program. */ -default: { /* This is really OP_Noop and OP_Explain */ +default: { /* This is really OP_Noop, OP_Explain */ assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain ); + break; } @@ -91210,7 +93175,11 @@ static int vdbeMergeEngineInit( ){ int rc = SQLITE_OK; /* Return code */ int i; /* For looping over PmaReader objects */ - int nTree = pMerger->nTree; + int nTree; /* Number of subtrees to merge */ + + /* Failure to allocate the merge would have been detected prior to + ** invoking this routine */ + assert( pMerger!=0 ); /* eMode is always INCRINIT_NORMAL in single-threaded mode */ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); @@ -91219,6 +93188,7 @@ static int vdbeMergeEngineInit( assert( pMerger->pTask==0 ); pMerger->pTask = pTask; + nTree = pMerger->nTree; for(i=0; i0 && eMode==INCRINIT_ROOT ){ /* PmaReaders should be normally initialized in order, as if they are @@ -92347,6 +94317,14 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ }else if( pExpr->x.pList ){ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + Window *pWin = pExpr->y.pWin; + if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort; + if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort; + if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort; + } +#endif } break; } @@ -92530,29 +94508,31 @@ static void resolveAlias( assert( pOrig!=0 ); db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); - if( pDup==0 ) return; - if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); - if( pExpr->op==TK_COLLATE ){ - pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); - } - ExprSetProperty(pDup, EP_Alias); + if( pDup!=0 ){ + if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); + if( pExpr->op==TK_COLLATE ){ + pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); + } + ExprSetProperty(pDup, EP_Alias); - /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This - ** prevents ExprDelete() from deleting the Expr structure itself, - ** allowing it to be repopulated by the memcpy() on the following line. - ** The pExpr->u.zToken might point into memory that will be freed by the - ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to - ** make a copy of the token before doing the sqlite3DbFree(). - */ - ExprSetProperty(pExpr, EP_Static); - sqlite3ExprDelete(db, pExpr); - memcpy(pExpr, pDup, sizeof(*pExpr)); - if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ - assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); - pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); - pExpr->flags |= EP_MemToken; + /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This + ** prevents ExprDelete() from deleting the Expr structure itself, + ** allowing it to be repopulated by the memcpy() on the following line. + ** The pExpr->u.zToken might point into memory that will be freed by the + ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to + ** make a copy of the token before doing the sqlite3DbFree(). + */ + ExprSetProperty(pExpr, EP_Static); + sqlite3ExprDelete(db, pExpr); + memcpy(pExpr, pDup, sizeof(*pExpr)); + if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ + assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); + pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); + pExpr->flags |= EP_MemToken; + } + sqlite3DbFree(db, pDup); } - sqlite3DbFree(db, pDup); + ExprSetProperty(pExpr, EP_Alias); } @@ -92612,7 +94592,7 @@ SQLITE_PRIVATE int sqlite3MatchSpanName( ** (even if X is implied). ** pExpr->iTable Set to the cursor number for the table obtained ** from pSrcList. -** pExpr->pTab Points to the Table structure of X.Y (even if +** pExpr->y.pTab Points to the Table structure of X.Y (even if ** X and/or Y are implied.) ** pExpr->iColumn Set to the column number within the table. ** pExpr->op Set to TK_COLUMN. @@ -92646,7 +94626,7 @@ static int lookupName( struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ NameContext *pTopNC = pNC; /* First namecontext in the list */ Schema *pSchema = 0; /* Schema of the expression */ - int isTrigger = 0; /* True if resolved to a trigger column */ + int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */ Table *pTab = 0; /* Table hold the row */ Column *pCol; /* A column of pTab */ @@ -92656,7 +94636,6 @@ static int lookupName( /* Initialize the node to no-match */ pExpr->iTable = -1; - pExpr->pTab = 0; ExprSetVVAProperty(pExpr, EP_NoReduce); /* Translate the schema name in zDb into a pointer to the corresponding @@ -92717,6 +94696,9 @@ static int lookupName( if( sqlite3StrICmp(zTabName, zTab)!=0 ){ continue; } + if( IN_RENAME_OBJECT && pItem->zAlias ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); + } } if( 0==(cntTab++) ){ pMatch = pItem; @@ -92741,32 +94723,45 @@ static int lookupName( } if( pMatch ){ pExpr->iTable = pMatch->iCursor; - pExpr->pTab = pMatch->pTab; + pExpr->y.pTab = pMatch->pTab; /* RIGHT JOIN not (yet) supported */ assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } - pSchema = pExpr->pTab->pSchema; + pSchema = pExpr->y.pTab->pSchema; } } /* if( pSrcList ) */ -#ifndef SQLITE_OMIT_TRIGGER +#if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) /* If we have not already resolved the name, then maybe - ** it is a new.* or old.* trigger argument reference + ** it is a new.* or old.* trigger argument reference. Or + ** maybe it is an excluded.* from an upsert. */ - if( zDb==0 && zTab!=0 && cntTab==0 && pParse->pTriggerTab!=0 ){ - int op = pParse->eTriggerOp; - assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); - if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){ - pExpr->iTable = 1; - pTab = pParse->pTriggerTab; - }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ - pExpr->iTable = 0; - pTab = pParse->pTriggerTab; - }else{ - pTab = 0; + if( zDb==0 && zTab!=0 && cntTab==0 ){ + pTab = 0; +#ifndef SQLITE_OMIT_TRIGGER + if( pParse->pTriggerTab!=0 ){ + int op = pParse->eTriggerOp; + assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); + if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){ + pExpr->iTable = 1; + pTab = pParse->pTriggerTab; + }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ + pExpr->iTable = 0; + pTab = pParse->pTriggerTab; + } } +#endif /* SQLITE_OMIT_TRIGGER */ +#ifndef SQLITE_OMIT_UPSERT + if( (pNC->ncFlags & NC_UUpsert)!=0 ){ + Upsert *pUpsert = pNC->uNC.pUpsert; + if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ + pTab = pUpsert->pUpsertSrc->a[0].pTab; + pExpr->iTable = 2; + } + } +#endif /* SQLITE_OMIT_UPSERT */ if( pTab ){ int iCol; @@ -92786,24 +94781,42 @@ static int lookupName( } if( iColnCol ){ cnt++; - if( iCol<0 ){ - pExpr->affinity = SQLITE_AFF_INTEGER; - }else if( pExpr->iTable==0 ){ - testcase( iCol==31 ); - testcase( iCol==32 ); - pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<iTable==2 ){ + testcase( iCol==(-1) ); + if( IN_RENAME_OBJECT ){ + pExpr->iColumn = iCol; + pExpr->y.pTab = pTab; + eNewExprOp = TK_COLUMN; + }else{ + pExpr->iTable = pNC->uNC.pUpsert->regData + iCol; + eNewExprOp = TK_REGISTER; + ExprSetProperty(pExpr, EP_Alias); + } + }else +#endif /* SQLITE_OMIT_UPSERT */ + { +#ifndef SQLITE_OMIT_TRIGGER + if( iCol<0 ){ + pExpr->affinity = SQLITE_AFF_INTEGER; + }else if( pExpr->iTable==0 ){ + testcase( iCol==31 ); + testcase( iCol==32 ); + pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<y.pTab = pTab; + pExpr->iColumn = (i16)iCol; + eNewExprOp = TK_TRIGGER; +#endif /* SQLITE_OMIT_TRIGGER */ } - pExpr->iColumn = (i16)iCol; - pExpr->pTab = pTab; - isTrigger = 1; } } } -#endif /* !defined(SQLITE_OMIT_TRIGGER) */ +#endif /* !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) */ /* ** Perhaps the name is a reference to the ROWID @@ -92838,10 +94851,12 @@ static int lookupName( ** is supported for backwards compatibility only. Hence, we issue a warning ** on sqlite3_log() whenever the capability is used. */ - if( (pEList = pNC->pEList)!=0 - && zTab==0 + if( (pNC->ncFlags & NC_UEList)!=0 && cnt==0 + && zTab==0 ){ + pEList = pNC->uNC.pEList; + assert( pEList!=0 ); for(j=0; jnExpr; j++){ char *zAs = pEList->a[j].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ @@ -92862,6 +94877,9 @@ static int lookupName( cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); + } goto lookupname_end; } } @@ -92890,7 +94908,7 @@ static int lookupName( assert( pExpr->op==TK_ID ); if( ExprHasProperty(pExpr,EP_DblQuoted) ){ pExpr->op = TK_STRING; - pExpr->pTab = 0; + pExpr->y.pTab = 0; return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ @@ -92938,7 +94956,7 @@ static int lookupName( pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; - pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); + pExpr->op = eNewExprOp; ExprSetProperty(pExpr, EP_Leaf); lookupname_end: if( cnt==1 ){ @@ -92968,9 +94986,9 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ struct SrcList_item *pItem = &pSrc->a[iSrc]; - p->pTab = pItem->pTab; + p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; - if( p->pTab->iPKey==iCol ){ + if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; @@ -93060,7 +95078,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pItem = pSrcList->a; assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 ); pExpr->op = TK_COLUMN; - pExpr->pTab = pItem->pTab; + pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn = -1; pExpr->affinity = SQLITE_AFF_INTEGER; @@ -93089,17 +95107,22 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ zTable = 0; zColumn = pExpr->u.zToken; }else{ + Expr *pLeft = pExpr->pLeft; notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; - zTable = pExpr->pLeft->u.zToken; - zColumn = pRight->u.zToken; }else{ assert( pRight->op==TK_DOT ); - zDb = pExpr->pLeft->u.zToken; - zTable = pRight->pLeft->u.zToken; - zColumn = pRight->pRight->u.zToken; + zDb = pLeft->u.zToken; + pLeft = pRight->pLeft; + pRight = pRight->pRight; + } + zTable = pLeft->u.zToken; + zColumn = pRight->u.zToken; + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); + sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); @@ -93181,41 +95204,105 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx); } + if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 + && pParse->nested==0 + && sqlite3Config.bInternalFunctions==0 + ){ + /* Internal-use-only functions are disallowed unless the + ** SQL is being compiled using sqlite3NestedParse() */ + no_such_func = 1; + pDef = 0; + } } - if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ - sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); - pNC->nErr++; - is_agg = 0; - }else if( no_such_func && pParse->db->init.busy==0 -#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION - && pParse->explain==0 + + if( 0==IN_RENAME_OBJECT ){ +#ifndef SQLITE_OMIT_WINDOWFUNC + assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX) + || (pDef->xValue==0 && pDef->xInverse==0) + || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize) + ); + if( pDef && pDef->xValue==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ + sqlite3ErrorMsg(pParse, + "%.*s() may not be used as a window function", nId, zId + ); + pNC->nErr++; + }else if( + (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) + || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pExpr->y.pWin) + || (is_agg && pExpr->y.pWin && (pNC->ncFlags & NC_AllowWin)==0) + ){ + const char *zType; + if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->y.pWin ){ + zType = "window"; + }else{ + zType = "aggregate"; + } + sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); + pNC->nErr++; + is_agg = 0; + } +#else + if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ + sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId); + pNC->nErr++; + is_agg = 0; + } #endif - ){ - sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); - pNC->nErr++; - }else if( wrong_num_args ){ - sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", - nId, zId); - pNC->nErr++; + else if( no_such_func && pParse->db->init.busy==0 +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + && pParse->explain==0 +#endif + ){ + sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); + pNC->nErr++; + }else if( wrong_num_args ){ + sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", + nId, zId); + pNC->nErr++; + } + if( is_agg ){ +#ifndef SQLITE_OMIT_WINDOWFUNC + pNC->ncFlags &= ~(pExpr->y.pWin ? NC_AllowWin : NC_AllowAgg); +#else + pNC->ncFlags &= ~NC_AllowAgg; +#endif + } } - if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg; sqlite3WalkExprList(pWalker, pList); if( is_agg ){ - NameContext *pNC2 = pNC; - pExpr->op = TK_AGG_FUNCTION; - pExpr->op2 = 0; - while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ - pExpr->op2++; - pNC2 = pNC2->pNext; - } - assert( pDef!=0 ); - if( pNC2 ){ - assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); - testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); - pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pExpr->y.pWin ){ + Select *pSel = pNC->pWinSelect; + sqlite3WalkExprList(pWalker, pExpr->y.pWin->pPartition); + sqlite3WalkExprList(pWalker, pExpr->y.pWin->pOrderBy); + sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); + sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef); + if( 0==pSel->pWin + || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->y.pWin) + ){ + pExpr->y.pWin->pNextWin = pSel->pWin; + pSel->pWin = pExpr->y.pWin; + } + pNC->ncFlags |= NC_AllowWin; + }else +#endif /* SQLITE_OMIT_WINDOWFUNC */ + { + NameContext *pNC2 = pNC; + pExpr->op = TK_AGG_FUNCTION; + pExpr->op2 = 0; + while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ + pExpr->op2++; + pNC2 = pNC2->pNext; + } + assert( pDef!=0 ); + if( pNC2 ){ + assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); + testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); + pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); + } + pNC->ncFlags |= NC_AllowAgg; } - pNC->ncFlags |= NC_AllowAgg; } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function @@ -93370,8 +95457,8 @@ static int resolveOrderByTermToExprList( memset(&nc, 0, sizeof(nc)); nc.pParse = pParse; nc.pSrcList = pSelect->pSrc; - nc.pEList = pEList; - nc.ncFlags = NC_AllowAgg; + nc.uNC.pEList = pEList; + nc.ncFlags = NC_AllowAgg|NC_UEList; nc.nErr = 0; db = pParse->db; savedSuppErr = db->suppressErr; @@ -93616,6 +95703,19 @@ static int resolveOrderGroupBy( } for(j=0; jpEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pE, EP_WinFunc) ){ + /* Since this window function is being changed into a reference + ** to the same window function the result set, remove the instance + ** of this window function from the Select.pWin list. */ + Window **pp; + for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){ + if( *pp==pE->y.pWin ){ + *pp = (*pp)->pNextWin; + } + } + } +#endif pItem->u.x.iOrderByCol = j+1; } } @@ -93672,6 +95772,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; + sNC.pWinSelect = p; if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){ return WRC_Abort; } @@ -93720,12 +95821,13 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ - sNC.ncFlags = NC_AllowAgg; + sNC.ncFlags = NC_AllowAgg|NC_AllowWin; sNC.pSrcList = p->pSrc; sNC.pNext = pOuterNC; /* Resolve names in the result set. */ if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort; + sNC.ncFlags &= ~NC_AllowWin; /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. @@ -93754,7 +95856,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** Minor point: If this is the case, then the expression will be ** re-evaluated for each reference to it. */ - sNC.pEList = p->pEList; + assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert))==0 ); + sNC.uNC.pEList = p->pEList; + sNC.ncFlags |= NC_UEList; if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; @@ -93772,7 +95876,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** outer queries */ sNC.pNext = 0; - sNC.ncFlags |= NC_AllowAgg; + sNC.ncFlags |= NC_AllowAgg|NC_AllowWin; /* If this is a converted compound query, move the ORDER BY clause from ** the sub-query back to the parent query. At this point each term @@ -93803,6 +95907,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ if( db->mallocFailed ){ return WRC_Abort; } + sNC.ncFlags &= ~NC_AllowWin; /* Resolve the GROUP BY clause. At the same time, make sure ** the GROUP BY clause does not contain aggregate functions. @@ -93987,7 +96092,7 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference( Table *pTab, /* The table being referenced */ int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */ Expr *pExpr, /* Expression to resolve. May be NULL. */ - ExprList *pList /* Expression list to resolve. May be NUL. */ + ExprList *pList /* Expression list to resolve. May be NULL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ @@ -94068,8 +96173,8 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif - if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){ - return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn); + if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){ + return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); } if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft->flags&EP_xIsSelect ); @@ -94151,6 +96256,19 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ while( p ){ int op = p->op; if( p->flags & EP_Generic ) break; + if( (op==TK_AGG_COLUMN || op==TK_COLUMN + || op==TK_REGISTER || op==TK_TRIGGER) + && p->y.pTab!=0 + ){ + /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally + ** a TK_COLUMN but was previously evaluated and cached in a register */ + int j = p->iColumn; + if( j>=0 ){ + const char *zColl = p->y.pTab->aCol[j].zColl; + pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); + } + break; + } if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; @@ -94159,19 +96277,6 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } - if( (op==TK_AGG_COLUMN || op==TK_COLUMN - || op==TK_REGISTER || op==TK_TRIGGER) - && p->pTab!=0 - ){ - /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally - ** a TK_COLUMN but was previously evaluated and cached in a register */ - int j = p->iColumn; - if( j>=0 ){ - const char *zColl = p->pTab->aCol[j].zColl; - pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); - } - break; - } if( p->flags & EP_Collate ){ if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){ p = p->pLeft; @@ -94591,7 +96696,6 @@ static void codeVectorCompare( Expr *pL, *pR; int r1, r2; assert( i>=0 && i0 ) sqlite3ExprCachePush(pParse); r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5); @@ -94603,7 +96707,6 @@ static void codeVectorCompare( testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); - if( i>0 ) sqlite3ExprCachePop(pParse); if( i==nLeft-1 ){ break; } @@ -94951,7 +97054,12 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ ** Construct a new expression node for a function with multiple ** arguments. */ -SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ +SQLITE_PRIVATE Expr *sqlite3ExprFunction( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Argument list */ + Token *pToken, /* Name of the function */ + int eDistinct /* SF_Distinct or SF_ALL or 0 */ +){ Expr *pNew; sqlite3 *db = pParse->db; assert( pToken ); @@ -94960,10 +97068,14 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token * sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ return 0; } + if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ + sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); + } pNew->x.pList = pList; ExprSetProperty(pNew, EP_HasFunc); assert( !ExprHasProperty(pNew, EP_xIsSelect) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); + if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; } @@ -95055,6 +97167,10 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); + + assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed ); + assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced) + || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); @@ -95073,6 +97189,10 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ }else{ sqlite3ExprListDelete(db, p->x.pList); } + if( ExprHasProperty(p, EP_WinFunc) ){ + assert( p->op==TK_FUNCTION ); + sqlite3WindowDelete(db, p->y.pWin); + } } if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( !ExprHasProperty(p, EP_Static) ){ @@ -95121,7 +97241,7 @@ static int exprStructSize(Expr *p){ ** Note that with flags==EXPRDUP_REDUCE, this routines works on full-size ** (unreduced) Expr objects as they or originally constructed by the parser. ** During expression analysis, extra information is computed and moved into -** later parts of teh Expr object and that extra information might get chopped +** later parts of the Expr object and that extra information might get chopped ** off if the expression is reduced. Note also that it does not work to ** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal ** to reduce a pristine expression tree from the parser. The implementation @@ -95133,7 +97253,11 @@ static int dupedExprStructSize(Expr *p, int flags){ assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); - if( 0==flags || p->op==TK_SELECT_COLUMN ){ + if( 0==flags || p->op==TK_SELECT_COLUMN +#ifndef SQLITE_OMIT_WINDOWFUNC + || ExprHasProperty(p, EP_WinFunc) +#endif + ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); @@ -95158,7 +97282,7 @@ static int dupedExprStructSize(Expr *p, int flags){ static int dupedExprNodeSize(Expr *p, int flags){ int nByte = dupedExprStructSize(p, flags) & 0xfff; if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ - nByte += sqlite3Strlen30(p->u.zToken)+1; + nByte += sqlite3Strlen30NN(p->u.zToken)+1; } return ROUND8(nByte); } @@ -95261,7 +97385,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ } /* Fill in pNew->pLeft and pNew->pRight. */ - if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ + if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){ zAlloc += dupedExprNodeSize(p, dupFlags); if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){ pNew->pLeft = p->pLeft ? @@ -95269,6 +97393,12 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ pNew->pRight = p->pRight ? exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0; } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(p, EP_WinFunc) ){ + pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin); + assert( ExprHasProperty(pNew, EP_WinFunc) ); + } +#endif /* SQLITE_OMIT_WINDOWFUNC */ if( pzBuffer ){ *pzBuffer = zAlloc; } @@ -95373,6 +97503,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags) pItem->sortOrder = pOldItem->sortOrder; pItem->done = 0; pItem->bSpanIsTab = pOldItem->bSpanIsTab; + pItem->bSorterRef = pOldItem->bSorterRef; pItem->u = pOldItem->u; } return pNew; @@ -95478,7 +97609,11 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); - sqlite3SelectSetName(pNew, p->zSelName); +#ifndef SQLITE_OMIT_WINDOWFUNC + pNew->pWin = 0; + pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); +#endif + pNew->selId = p->selId; *pp = pNew; pp = &pNew->pPrior; pNext = pNew; @@ -95650,6 +97785,9 @@ SQLITE_PRIVATE void sqlite3ExprListSetName( assert( pItem->zName==0 ); pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); if( dequote ) sqlite3Dequote(pItem->zName); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName); + } } } @@ -95830,11 +97968,16 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); + if( ExprHasProperty(pExpr, EP_FixedCol) && pWalker->eCode!=2 ){ + return WRC_Continue; + } if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ return WRC_Continue; } /* Fall through */ case TK_IF_NULL_ROW: + case TK_REGISTER: + testcase( pExpr->op==TK_REGISTER ); testcase( pExpr->op==TK_IF_NULL_ROW ); pWalker->eCode = 0; return WRC_Abort; @@ -95852,8 +97995,8 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ } /* Fall through */ default: - testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail will disallow */ - testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail will disallow */ + testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */ + testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */ return WRC_Continue; } } @@ -95883,10 +98026,17 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ } /* -** Walk an expression tree. Return non-zero if the expression is constant -** that does no originate from the ON or USING clauses of a join. -** Return 0 if it involves variables or function calls or terms from -** an ON or USING clause. +** Walk an expression tree. Return non-zero if +** +** (1) the expression is constant, and +** (2) the expression does originate in the ON or USING clause +** of a LEFT JOIN, and +** (3) the expression does not contain any EP_FixedCol TK_COLUMN +** operands created by the constant propagation optimization. +** +** When this routine returns true, it indicates that the expression +** can be added to the pParse->pConstExpr list and evaluated once when +** the prepared statement starts up. See sqlite3ExprCodeAtInit(). */ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 2, 0); @@ -95916,7 +98066,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ Expr *p = pGroupBy->a[i].pExpr; if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p); - if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){ + if( sqlite3IsBinary(pColl) ){ return WRC_Prune; } } @@ -96058,8 +98208,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ return 0; case TK_COLUMN: return ExprHasProperty(p, EP_CanBeNull) || - p->pTab==0 || /* Reference to column of index on expression */ - (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0); + p->y.pTab==0 || /* Reference to column of index on expression */ + (p->iColumn>=0 && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; } @@ -96114,6 +98264,14 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ if( sqlite3StrICmp(z, "OID")==0 ) return 1; return 0; } +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE int sqlite3IsRowidN(const char *z, int n){ + if( sqlite3StrNICmp(z, "_ROWID_", n)==0 ) return 1; + if( sqlite3StrNICmp(z, "ROWID", n)==0 ) return 1; + if( sqlite3StrNICmp(z, "OID", n)==0 ) return 1; + return 0; +} +#endif /* ** pX is the RHS of an IN operator. If pX is a SELECT statement @@ -96338,7 +98496,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex( sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; - + ExplainQueryPlan((pParse, 0, + "USING ROWID SEARCH ON TABLE %s FOR IN-OPERATOR",pTab->zName)); sqlite3VdbeJumpHere(v, iAddr); }else{ Index *pIdx; /* Iterator variable */ @@ -96417,11 +98576,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex( if( colUsed==(MASKBIT(nExpr)-1) ){ /* If we reach this point, that means the index pIdx is usable */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); -#ifndef SQLITE_OMIT_EXPLAIN - sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0, - sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName), - P4_DYNAMIC); -#endif + ExplainQueryPlan((pParse, 0, + "USING INDEX %s FOR IN-OPERATOR",pIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); @@ -96600,7 +98756,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; - sqlite3ExprCachePush(pParse); /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it ** is encountered if any of the following is true: @@ -96616,17 +98771,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } -#ifndef SQLITE_OMIT_EXPLAIN - if( pParse->explain==2 ){ - char *zMsg = sqlite3MPrintf(pParse->db, "EXECUTE %s%s SUBQUERY %d", - jmpIfDynamic>=0?"":"CORRELATED ", - pExpr->op==TK_IN?"LIST":"SCALAR", - pParse->iNextSelectId - ); - sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); - } -#endif - switch( pExpr->op ){ case TK_IN: { int addr; /* Address of OP_OpenEphemeral instruction */ @@ -96664,6 +98808,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( Select *pSelect = pExpr->x.pSelect; ExprList *pEList = pSelect->pEList; + ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY", + jmpIfDynamic>=0?"":"CORRELATED " + )); assert( !isRowid ); /* If the LHS and RHS of the IN operator do not match, that ** error will have been caught long before we reach this point. */ @@ -96705,7 +98852,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( ExprList *pList = pExpr->x.pList; struct ExprList_item *pItem; int r1, r2, r3; - affinity = sqlite3ExprAffinity(pLeft); if( !affinity ){ affinity = SQLITE_AFF_BLOB; @@ -96745,7 +98891,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); - sqlite3ExprCacheAffinityChange(pParse, r3, 1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1); } } @@ -96786,6 +98931,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( assert( ExprHasProperty(pExpr, EP_xIsSelect) ); pSel = pExpr->x.pSelect; + ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY", + jmpIfDynamic>=0?"":"CORRELATED ")); nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); pParse->nMem += nReg; @@ -96824,7 +98971,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect( if( jmpIfDynamic>=0 ){ sqlite3VdbeJumpHere(v, jmpIfDynamic); } - sqlite3ExprCachePop(pParse); return rReg; } @@ -96943,7 +99089,6 @@ static void sqlite3ExprCodeIN( ** aiMap[] array contains a mapping from the original LHS field order to ** the field order that matches the RHS index. */ - sqlite3ExprCachePush(pParse); rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); for(i=0; idb, aiMap); @@ -97170,145 +99314,6 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ } } -/* -** Erase column-cache entry number i -*/ -static void cacheEntryClear(Parse *pParse, int i){ - if( pParse->aColCache[i].tempReg ){ - if( pParse->nTempRegaTempReg) ){ - pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; - } - } - pParse->nColCache--; - if( inColCache ){ - pParse->aColCache[i] = pParse->aColCache[pParse->nColCache]; - } -} - - -/* -** Record in the column cache that a particular column from a -** particular table is stored in a particular register. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){ - int i; - int minLru; - int idxLru; - struct yColCache *p; - - /* Unless an error has occurred, register numbers are always positive. */ - assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed ); - assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */ - - /* The SQLITE_ColumnCache flag disables the column cache. This is used - ** for testing only - to verify that SQLite always gets the same answer - ** with and without the column cache. - */ - if( OptimizationDisabled(pParse->db, SQLITE_ColumnCache) ) return; - - /* First replace any existing entry. - ** - ** Actually, the way the column cache is currently used, we are guaranteed - ** that the object will never already be in cache. Verify this guarantee. - */ -#ifndef NDEBUG - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - assert( p->iTable!=iTab || p->iColumn!=iCol ); - } -#endif - - /* If the cache is already full, delete the least recently used entry */ - if( pParse->nColCache>=SQLITE_N_COLCACHE ){ - minLru = 0x7fffffff; - idxLru = -1; - for(i=0, p=pParse->aColCache; ilrulru; - } - } - p = &pParse->aColCache[idxLru]; - }else{ - p = &pParse->aColCache[pParse->nColCache++]; - } - - /* Add the new entry to the end of the cache */ - p->iLevel = pParse->iCacheLevel; - p->iTable = iTab; - p->iColumn = iCol; - p->iReg = iReg; - p->tempReg = 0; - p->lru = pParse->iCacheCnt++; -} - -/* -** Indicate that registers between iReg..iReg+nReg-1 are being overwritten. -** Purge the range of registers from the column cache. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){ - int i = 0; - while( inColCache ){ - struct yColCache *p = &pParse->aColCache[i]; - if( p->iReg >= iReg && p->iReg < iReg+nReg ){ - cacheEntryClear(pParse, i); - }else{ - i++; - } - } -} - -/* -** Remember the current column cache context. Any new entries added -** added to the column cache after this call are removed when the -** corresponding pop occurs. -*/ -SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){ - pParse->iCacheLevel++; -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("PUSH to %d\n", pParse->iCacheLevel); - } -#endif -} - -/* -** Remove from the column cache any entries that were added since the -** the previous sqlite3ExprCachePush operation. In other words, restore -** the cache to the state it was in prior the most recent Push. -*/ -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ - int i = 0; - assert( pParse->iCacheLevel>=1 ); - pParse->iCacheLevel--; -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("POP to %d\n", pParse->iCacheLevel); - } -#endif - while( inColCache ){ - if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){ - cacheEntryClear(pParse, i); - }else{ - i++; - } - } -} - -/* -** When a cached column is reused, make sure that its register is -** no longer available as a temp register. ticket #3879: that same -** register might be in the cache in multiple places, so be sure to -** get them all. -*/ -static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){ - int i; - struct yColCache *p; - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - if( p->iReg==iReg ){ - p->tempReg = 0; - } - } -} /* Generate code that will load into register regOut a value that is ** appropriate for the iIdxCol-th column of index pIdx. @@ -97364,12 +99369,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( /* ** Generate code that will extract the iColumn-th column from -** table pTab and store the column value in a register. -** -** An effort is made to store the column value in register iReg. This -** is not garanteeed for GetColumn() - the result can be stored in -** any register. But the result is guaranteed to land in register iReg -** for GetColumnToReg(). +** table pTab and store the column value in register iReg. ** ** There must be an open cursor to pTab in iTable when this routine ** is called. If iColumn<0 then code is generated that extracts the rowid. @@ -97383,96 +99383,23 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn( u8 p5 /* P5 value for OP_Column + FLAGS */ ){ Vdbe *v = pParse->pVdbe; - int i; - struct yColCache *p; - - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - if( p->iTable==iTable && p->iColumn==iColumn ){ - p->lru = pParse->iCacheCnt++; - sqlite3ExprCachePinRegister(pParse, p->iReg); - return p->iReg; - } - } assert( v!=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg); if( p5 ){ sqlite3VdbeChangeP5(v, p5); - }else{ - sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg); } return iReg; } -SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg( - Parse *pParse, /* Parsing and code generating context */ - Table *pTab, /* Description of the table we are reading from */ - int iColumn, /* Index of the table column */ - int iTable, /* The cursor pointing to the table */ - int iReg /* Store results here */ -){ - int r1 = sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0); - if( r1!=iReg ) sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg); -} - - -/* -** Clear all column cache entries. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){ - int i; - -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("CLEAR\n"); - } -#endif - for(i=0; inColCache; i++){ - if( pParse->aColCache[i].tempReg - && pParse->nTempRegaTempReg) - ){ - pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; - } - } - pParse->nColCache = 0; -} - -/* -** Record the fact that an affinity change has occurred on iCount -** registers starting with iStart. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){ - sqlite3ExprCacheRemove(pParse, iStart, iCount); -} /* ** Generate code to move content from registers iFrom...iFrom+nReg-1 -** over to iTo..iTo+nReg-1. Keep the column cache up-to-date. +** over to iTo..iTo+nReg-1. */ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); - sqlite3ExprCacheRemove(pParse, iFrom, nReg); } -#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) -/* -** Return true if any register in the range iFrom..iTo (inclusive) -** is used as part of the column cache. -** -** This routine is used within assert() and testcase() macros only -** and does not appear in a normal build. -*/ -static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ - int i; - struct yColCache *p; - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - int r = p->iReg; - if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/ - } - return 0; -} -#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */ - - /* ** Convert a scalar expression node to a TK_REGISTER referencing ** register iReg. The caller must ensure that iReg already contains @@ -97548,6 +99475,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) return 0; } +expr_code_doover: if( pExpr==0 ){ op = TK_NULL; }else{ @@ -97569,6 +99497,28 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } case TK_COLUMN: { int iTab = pExpr->iTable; + if( ExprHasProperty(pExpr, EP_FixedCol) ){ + /* This COLUMN expression is really a constant due to WHERE clause + ** constraints, and that constant is coded by the pExpr->pLeft + ** expresssion. However, make sure the constant has the correct + ** datatype by applying the Affinity of the table column to the + ** constant. + */ + int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); + int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); + if( aff!=SQLITE_AFF_BLOB ){ + static const char zAff[] = "B\000C\000D\000E"; + assert( SQLITE_AFF_BLOB=='A' ); + assert( SQLITE_AFF_TEXT=='B' ); + if( iReg!=target ){ + sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target); + iReg = target; + } + sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, + &zAff[(aff-'B')*2], P4_STATIC); + } + return iReg; + } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ /* Generating CHECK constraints or inserting into partial index */ @@ -97579,7 +99529,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) iTab = pParse->iSelfTab - 1; } } - return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, + return sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); } @@ -97649,8 +99599,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); - testcase( usedAsColumnCache(pParse, inReg, inReg) ); - sqlite3ExprCacheAffinityChange(pParse, inReg, 1); return inReg; } #endif /* SQLITE_OMIT_CAST */ @@ -97794,6 +99742,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) u8 enc = ENC(db); /* The text encoding used by this database */ CollSeq *pColl = 0; /* A collating sequence */ +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + return pExpr->y.pWin->regResult; + } +#endif + if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ /* SQL functions can be expensive. So try to move constant functions ** out of the inner loop, even if that means an extra OP_Copy. */ @@ -97830,10 +99784,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) for(i=1; ia[i].pExpr, target); - sqlite3ExprCachePop(pParse); } sqlite3VdbeResolveLabel(v, endCoalesce); break; @@ -97899,10 +99850,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } } - sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); - sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */ }else{ r1 = 0; } @@ -97919,7 +99868,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** "glob(B,A). We want to use the A in "A glob B" to test ** for function overloading. But we use the B term in "glob(B,A)". */ - if( nFarg>=2 && (pExpr->flags & EP_InfixFunc) ){ + if( nFarg>=2 && ExprHasProperty(pExpr, EP_InfixFunc) ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr); }else if( nFarg>0 ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); @@ -98008,7 +99957,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) case TK_SPAN: case TK_COLLATE: case TK_UPLUS: { - return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + pExpr = pExpr->pLeft; + goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */ } case TK_TRIGGER: { @@ -98037,7 +99987,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ - Table *pTab = pExpr->pTab; + Table *pTab = pExpr->y.pTab; int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; assert( pExpr->iTable==0 || pExpr->iTable==1 ); @@ -98046,10 +99996,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( p1>=0 && p1<(pTab->nCol*2+2) ); sqlite3VdbeAddOp2(v, OP_Param, p1, target); - VdbeComment((v, "%s.%s -> $%d", + VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), - (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName), - target + (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[pExpr->iColumn].zName) )); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -98075,9 +100024,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) case TK_IF_NULL_ROW: { int addrINR; addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); - sqlite3ExprCachePush(pParse); inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); - sqlite3ExprCachePop(pParse); sqlite3VdbeJumpHere(v, addrINR); sqlite3VdbeChangeP3(v, addrINR, inReg); break; @@ -98114,7 +100061,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) Expr opCompare; /* The X==Ei expression */ Expr *pX; /* The X expression */ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ - VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; ) assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); assert(pExpr->x.pList->nExpr > 0); @@ -98138,7 +100084,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) regFree1 = 0; } for(i=0; iop==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeGoto(v, endLabel); - sqlite3ExprCachePop(pParse); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ - sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); - sqlite3ExprCachePop(pParse); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } - assert( pParse->db->mallocFailed || pParse->nErr>0 - || pParse->iCacheLevel==iCacheLevel ); sqlite3VdbeResolveLabel(v, endLabel); break; } @@ -98312,7 +100252,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){ ** might choose to code the expression at initialization time. */ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ - if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){ + if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeAtInit(pParse, pExpr, target); }else{ sqlite3ExprCode(pParse, pExpr, target); @@ -98381,6 +100321,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; ipExpr; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( pItem->bSorterRef ){ + i--; + n--; + }else +#endif if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; @@ -98388,7 +100334,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } - }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){ + }else if( (flags & SQLITE_ECEL_FACTOR)!=0 + && sqlite3ExprIsConstantNotJoin(pExpr) + ){ sqlite3ExprCodeAtInit(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); @@ -98514,18 +100462,14 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int int d2 = sqlite3VdbeMakeLabel(v); testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse); break; } case TK_OR: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse); break; } case TK_NOT: { @@ -98684,19 +100628,15 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int case TK_AND: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse); break; } case TK_OR: { int d2 = sqlite3VdbeMakeLabel(v); testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse); break; } case TK_NOT: { @@ -98909,17 +100849,35 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ if( pA->op==TK_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; +#ifndef SQLITE_OMIT_WINDOWFUNC + /* Justification for the assert(): + ** window functions have p->op==TK_FUNCTION but aggregate functions + ** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate + ** function and a window function should have failed before reaching + ** this point. And, it is not possible to have a window function and + ** a scalar function with the same name and number of arguments. So + ** if we reach this point, either A and B both window functions or + ** neither are a window functions. */ + assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) ); + if( ExprHasProperty(pA,EP_WinFunc) ){ + if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=0 ) return 2; + } +#endif + }else if( pA->op==TK_COLLATE ){ + if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ - return pA->op==TK_COLLATE ? 1 : 2; + return 2; } } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; - if( sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; + if( (combinedFlags & EP_FixedCol)==0 + && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; - if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ + assert( (combinedFlags & EP_Reduced)==0 ); + if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->iTable!=pB->iTable && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; @@ -99014,18 +100972,15 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, i /* ** This is the Expr node callback for sqlite3ExprImpliesNotNullRow(). ** If the expression node requires that the table at pWalker->iCur -** have a non-NULL column, then set pWalker->eCode to 1 and abort. +** have one or more non-NULL column, then set pWalker->eCode to 1 and abort. +** +** This routine controls an optimization. False positives (setting +** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives +** (never setting pWalker->eCode) is a harmless missed optimization. */ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ - /* This routine is only called for WHERE clause expressions and so it - ** cannot have any TK_AGG_COLUMN entries because those are only found - ** in HAVING clauses. We can get a TK_AGG_FUNCTION in a WHERE clause, - ** but that is an illegal construct and the query will be rejected at - ** a later stage of processing, so the TK_AGG_FUNCTION case does not - ** need to be considered here. */ - assert( pExpr->op!=TK_AGG_COLUMN ); + testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); - if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune; switch( pExpr->op ){ case TK_ISNOT: @@ -99067,8 +101022,8 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_LE ); testcase( pExpr->op==TK_GT ); testcase( pExpr->op==TK_GE ); - if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->pTab)) - || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->pTab)) + if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab)) + || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab)) ){ return WRC_Prune; } @@ -99265,8 +101220,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ NameContext *pNC = pWalker->u.pNC; Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; - AggInfo *pAggInfo = pNC->pAggInfo; + AggInfo *pAggInfo = pNC->uNC.pAggInfo; + assert( pNC->ncFlags & NC_UAggInfo ); switch( pExpr->op ){ case TK_AGG_COLUMN: case TK_COLUMN: { @@ -99298,7 +101254,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; - pCol->pTab = pExpr->pTab; + pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; pCol->iMem = ++pParse->nMem; @@ -99444,21 +101400,9 @@ SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){ /* ** Deallocate a register, making available for reuse for some other ** purpose. -** -** If a register is currently being used by the column cache, then -** the deallocation is deferred until the column cache line that uses -** the register becomes stale. */ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg && pParse->nTempRegaTempReg) ){ - int i; - struct yColCache *p; - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - if( p->iReg==iReg ){ - p->tempReg = 1; - return; - } - } pParse->aTempReg[pParse->nTempReg++] = iReg; } } @@ -99472,7 +101416,6 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){ i = pParse->iRangeReg; n = pParse->nRangeReg; if( nReg<=n ){ - assert( !usedAsColumnCache(pParse, i, i+n-1) ); pParse->iRangeReg += nReg; pParse->nRangeReg -= nReg; }else{ @@ -99486,7 +101429,6 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ sqlite3ReleaseTempReg(pParse, iReg); return; } - sqlite3ExprCacheRemove(pParse, iReg, nReg); if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; pParse->iRangeReg = iReg; @@ -99548,352 +101490,6 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ */ #ifndef SQLITE_OMIT_ALTERTABLE - -/* -** This function is used by SQL generated to implement the -** ALTER TABLE command. The first argument is the text of a CREATE TABLE or -** CREATE INDEX command. The second is a table name. The table name in -** the CREATE TABLE or CREATE INDEX statement is replaced with the third -** argument and the result returned. Examples: -** -** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') -** -> 'CREATE TABLE def(a, b, c)' -** -** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') -** -> 'CREATE INDEX i ON def(a, b, c)' -*/ -static void renameTableFunc( - sqlite3_context *context, - int NotUsed, - sqlite3_value **argv -){ - unsigned char const *zSql = sqlite3_value_text(argv[0]); - unsigned char const *zTableName = sqlite3_value_text(argv[1]); - - int token; - Token tname; - unsigned char const *zCsr = zSql; - int len = 0; - char *zRet; - - sqlite3 *db = sqlite3_context_db_handle(context); - - UNUSED_PARAMETER(NotUsed); - - /* The principle used to locate the table name in the CREATE TABLE - ** statement is that the table name is the first non-space token that - ** is immediately followed by a TK_LP or TK_USING token. - */ - if( zSql ){ - do { - if( !*zCsr ){ - /* Ran out of input before finding an opening bracket. Return NULL. */ - return; - } - - /* Store the token that zCsr points to in tname. */ - tname.z = (char*)zCsr; - tname.n = len; - - /* Advance zCsr to the next token. Store that token type in 'token', - ** and its length in 'len' (to be used next iteration of this loop). - */ - do { - zCsr += len; - len = sqlite3GetToken(zCsr, &token); - } while( token==TK_SPACE ); - assert( len>0 ); - } while( token!=TK_LP && token!=TK_USING ); - - zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), - zSql, zTableName, tname.z+tname.n); - sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); - } -} - -/* -** This C function implements an SQL user function that is used by SQL code -** generated by the ALTER TABLE ... RENAME command to modify the definition -** of any foreign key constraints that use the table being renamed as the -** parent table. It is passed three arguments: -** -** 1) The complete text of the CREATE TABLE statement being modified, -** 2) The old name of the table being renamed, and -** 3) The new name of the table being renamed. -** -** It returns the new CREATE TABLE statement. For example: -** -** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3') -** -> 'CREATE TABLE t1(a REFERENCES t3)' -*/ -#ifndef SQLITE_OMIT_FOREIGN_KEY -static void renameParentFunc( - sqlite3_context *context, - int NotUsed, - sqlite3_value **argv -){ - sqlite3 *db = sqlite3_context_db_handle(context); - char *zOutput = 0; - char *zResult; - unsigned char const *zInput = sqlite3_value_text(argv[0]); - unsigned char const *zOld = sqlite3_value_text(argv[1]); - unsigned char const *zNew = sqlite3_value_text(argv[2]); - - unsigned const char *z; /* Pointer to token */ - int n; /* Length of token z */ - int token; /* Type of token */ - - UNUSED_PARAMETER(NotUsed); - if( zInput==0 || zOld==0 ) return; - for(z=zInput; *z; z=z+n){ - n = sqlite3GetToken(z, &token); - if( token==TK_REFERENCES ){ - char *zParent; - do { - z += n; - n = sqlite3GetToken(z, &token); - }while( token==TK_SPACE ); - - if( token==TK_ILLEGAL ) break; - zParent = sqlite3DbStrNDup(db, (const char *)z, n); - if( zParent==0 ) break; - sqlite3Dequote(zParent); - if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){ - char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"", - (zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew - ); - sqlite3DbFree(db, zOutput); - zOutput = zOut; - zInput = &z[n]; - } - sqlite3DbFree(db, zParent); - } - } - - zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput), - sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC); - sqlite3DbFree(db, zOutput); -} -#endif - -#ifndef SQLITE_OMIT_TRIGGER -/* This function is used by SQL generated to implement the -** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER -** statement. The second is a table name. The table name in the CREATE -** TRIGGER statement is replaced with the third argument and the result -** returned. This is analagous to renameTableFunc() above, except for CREATE -** TRIGGER, not CREATE INDEX and CREATE TABLE. -*/ -static void renameTriggerFunc( - sqlite3_context *context, - int NotUsed, - sqlite3_value **argv -){ - unsigned char const *zSql = sqlite3_value_text(argv[0]); - unsigned char const *zTableName = sqlite3_value_text(argv[1]); - - int token; - Token tname; - int dist = 3; - unsigned char const *zCsr = zSql; - int len = 0; - char *zRet; - sqlite3 *db = sqlite3_context_db_handle(context); - - UNUSED_PARAMETER(NotUsed); - - /* The principle used to locate the table name in the CREATE TRIGGER - ** statement is that the table name is the first token that is immediately - ** preceded by either TK_ON or TK_DOT and immediately followed by one - ** of TK_WHEN, TK_BEGIN or TK_FOR. - */ - if( zSql ){ - do { - - if( !*zCsr ){ - /* Ran out of input before finding the table name. Return NULL. */ - return; - } - - /* Store the token that zCsr points to in tname. */ - tname.z = (char*)zCsr; - tname.n = len; - - /* Advance zCsr to the next token. Store that token type in 'token', - ** and its length in 'len' (to be used next iteration of this loop). - */ - do { - zCsr += len; - len = sqlite3GetToken(zCsr, &token); - }while( token==TK_SPACE ); - assert( len>0 ); - - /* Variable 'dist' stores the number of tokens read since the most - ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN - ** token is read and 'dist' equals 2, the condition stated above - ** to be met. - ** - ** Note that ON cannot be a database, table or column name, so - ** there is no need to worry about syntax like - ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc. - */ - dist++; - if( token==TK_DOT || token==TK_ON ){ - dist = 0; - } - } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) ); - - /* Variable tname now contains the token that is the old table-name - ** in the CREATE TRIGGER statement. - */ - zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), - zSql, zTableName, tname.z+tname.n); - sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); - } -} -#endif /* !SQLITE_OMIT_TRIGGER */ - -/* -** Register built-in functions used to help implement ALTER TABLE -*/ -SQLITE_PRIVATE void sqlite3AlterFunctions(void){ - static FuncDef aAlterTableFuncs[] = { - FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc), -#ifndef SQLITE_OMIT_TRIGGER - FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc), -#endif -#ifndef SQLITE_OMIT_FOREIGN_KEY - FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc), -#endif - }; - sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); -} - -/* -** This function is used to create the text of expressions of the form: -** -** name= OR name= OR ... -** -** If argument zWhere is NULL, then a pointer string containing the text -** "name=" is returned, where is the quoted version -** of the string passed as argument zConstant. The returned buffer is -** allocated using sqlite3DbMalloc(). It is the responsibility of the -** caller to ensure that it is eventually freed. -** -** If argument zWhere is not NULL, then the string returned is -** " OR name=", where is the contents of zWhere. -** In this case zWhere is passed to sqlite3DbFree() before returning. -** -*/ -static char *whereOrName(sqlite3 *db, char *zWhere, char *zConstant){ - char *zNew; - if( !zWhere ){ - zNew = sqlite3MPrintf(db, "name=%Q", zConstant); - }else{ - zNew = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, zConstant); - sqlite3DbFree(db, zWhere); - } - return zNew; -} - -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) -/* -** Generate the text of a WHERE expression which can be used to select all -** tables that have foreign key constraints that refer to table pTab (i.e. -** constraints for which pTab is the parent table) from the sqlite_master -** table. -*/ -static char *whereForeignKeys(Parse *pParse, Table *pTab){ - FKey *p; - char *zWhere = 0; - for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ - zWhere = whereOrName(pParse->db, zWhere, p->pFrom->zName); - } - return zWhere; -} -#endif - -/* -** Generate the text of a WHERE expression which can be used to select all -** temporary triggers on table pTab from the sqlite_temp_master table. If -** table pTab has no temporary triggers, or is itself stored in the -** temporary database, NULL is returned. -*/ -static char *whereTempTriggers(Parse *pParse, Table *pTab){ - Trigger *pTrig; - char *zWhere = 0; - const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */ - - /* If the table is not located in the temp-db (in which case NULL is - ** returned, loop through the tables list of triggers. For each trigger - ** that is not part of the temp-db schema, add a clause to the WHERE - ** expression being built up in zWhere. - */ - if( pTab->pSchema!=pTempSchema ){ - sqlite3 *db = pParse->db; - for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ - if( pTrig->pSchema==pTempSchema ){ - zWhere = whereOrName(db, zWhere, pTrig->zName); - } - } - } - if( zWhere ){ - char *zNew = sqlite3MPrintf(pParse->db, "type='trigger' AND (%s)", zWhere); - sqlite3DbFree(pParse->db, zWhere); - zWhere = zNew; - } - return zWhere; -} - -/* -** Generate code to drop and reload the internal representation of table -** pTab from the database, including triggers and temporary triggers. -** Argument zName is the name of the table in the database schema at -** the time the generated code is executed. This can be different from -** pTab->zName if this function is being called to code part of an -** "ALTER TABLE RENAME TO" statement. -*/ -static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ - Vdbe *v; - char *zWhere; - int iDb; /* Index of database containing pTab */ -#ifndef SQLITE_OMIT_TRIGGER - Trigger *pTrig; -#endif - - v = sqlite3GetVdbe(pParse); - if( NEVER(v==0) ) return; - assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 ); - -#ifndef SQLITE_OMIT_TRIGGER - /* Drop any table triggers from the internal schema. */ - for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ - int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); - assert( iTrigDb==iDb || iTrigDb==1 ); - sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->zName, 0); - } -#endif - - /* Drop the table and index from the internal schema. */ - sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); - - /* Reload the table, index and permanent trigger schemas. */ - zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName); - if( !zWhere ) return; - sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); - -#ifndef SQLITE_OMIT_TRIGGER - /* Now, if the table is not stored in the temp database, reload any temp - ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. - */ - if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ - sqlite3VdbeAddParseSchemaOp(v, 1, zWhere); - } -#endif -} - /* ** Parameter zName is the name of a table that is about to be altered ** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). @@ -99910,6 +101506,49 @@ static int isSystemTable(Parse *pParse, const char *zName){ return 0; } +/* +** Generate code to verify that the schemas of database zDb and, if +** bTemp is not true, database "temp", can still be parsed. This is +** called at the end of the generation of an ALTER TABLE ... RENAME ... +** statement to ensure that the operation has not rendered any schema +** objects unusable. +*/ +static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ + sqlite3NestedParse(pParse, + "SELECT 1 " + "FROM \"%w\".%s " + "WHERE name NOT LIKE 'sqlite_%%'" + " AND sql NOT LIKE 'create virtual%%'" + " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ", + zDb, MASTER_NAME, + zDb, bTemp + ); + + if( bTemp==0 ){ + sqlite3NestedParse(pParse, + "SELECT 1 " + "FROM temp.%s " + "WHERE name NOT LIKE 'sqlite_%%'" + " AND sql NOT LIKE 'create virtual%%'" + " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ", + MASTER_NAME, zDb + ); + } +} + +/* +** Generate code to reload the schema for database iDb. And, if iDb!=1, for +** the temp database as well. +*/ +static void renameReloadSchema(Parse *pParse, int iDb){ + Vdbe *v = pParse->pVdbe; + if( v ){ + sqlite3ChangeCookie(pParse, iDb); + sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0); + if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0); + } +} + /* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. @@ -99927,9 +101566,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; -#ifndef SQLITE_OMIT_TRIGGER - char *zWhere = 0; /* Where clause to locate temp triggers */ -#endif VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ u32 savedDbFlags; /* Saved value of db->mDbFlags */ @@ -100002,8 +101638,63 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( if( v==0 ){ goto exit_rename_table; } - sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb); - sqlite3ChangeCookie(pParse, iDb); + + /* figure out how many UTF-8 characters are in zName */ + zTabName = pTab->zName; + nTabName = sqlite3Utf8CharLen(zTabName, -1); + + /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in + ** the schema to use the new table name. */ + sqlite3NestedParse(pParse, + "UPDATE \"%w\".%s SET " + "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " + "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" + "AND name NOT LIKE 'sqlite_%%'" + , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName + ); + + /* Update the tbl_name and name columns of the sqlite_master table + ** as required. */ + sqlite3NestedParse(pParse, + "UPDATE %Q.%s SET " + "tbl_name = %Q, " + "name = CASE " + "WHEN type='table' THEN %Q " + "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " + "'sqlite_autoindex_' || %Q || substr(name,%d+18) " + "ELSE name END " + "WHERE tbl_name=%Q COLLATE nocase AND " + "(type='table' OR type='index' OR type='trigger');", + zDb, MASTER_NAME, + zName, zName, zName, + nTabName, zTabName + ); + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* If the sqlite_sequence table exists in this database, then update + ** it with the new table name. + */ + if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ + sqlite3NestedParse(pParse, + "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q", + zDb, zName, pTab->zName); + } +#endif + + /* If the table being renamed is not itself part of the temp database, + ** edit view and trigger definitions within the temp database + ** as required. */ + if( iDb!=1 ){ + sqlite3NestedParse(pParse, + "UPDATE sqlite_temp_master SET " + "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), " + "tbl_name = " + "CASE WHEN tbl_name=%Q COLLATE nocase AND " + " sqlite_rename_test(%Q, sql, type, name, 1) " + "THEN %Q ELSE tbl_name END " + "WHERE type IN ('view', 'trigger')" + , zDb, zTabName, zName, zTabName, zDb, zName); + } /* If this is a virtual table, invoke the xRename() function if ** one is defined. The xRename() callback will modify the names @@ -100019,90 +101710,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( } #endif - /* figure out how many UTF-8 characters are in zName */ - zTabName = pTab->zName; - nTabName = sqlite3Utf8CharLen(zTabName, -1); - -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - if( db->flags&SQLITE_ForeignKeys ){ - /* If foreign-key support is enabled, rewrite the CREATE TABLE - ** statements corresponding to all child tables of foreign key constraints - ** for which the renamed table is the parent table. */ - if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){ - sqlite3NestedParse(pParse, - "UPDATE \"%w\".%s SET " - "sql = sqlite_rename_parent(sql, %Q, %Q) " - "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere); - sqlite3DbFree(db, zWhere); - } - } -#endif - - /* Modify the sqlite_master table to use the new table name. */ - sqlite3NestedParse(pParse, - "UPDATE %Q.%s SET " -#ifdef SQLITE_OMIT_TRIGGER - "sql = sqlite_rename_table(sql, %Q), " -#else - "sql = CASE " - "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" - "ELSE sqlite_rename_table(sql, %Q) END, " -#endif - "tbl_name = %Q, " - "name = CASE " - "WHEN type='table' THEN %Q " - "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " - "'sqlite_autoindex_' || %Q || substr(name,%d+18) " - "ELSE name END " - "WHERE tbl_name=%Q COLLATE nocase AND " - "(type='table' OR type='index' OR type='trigger');", - zDb, MASTER_NAME, zName, zName, zName, -#ifndef SQLITE_OMIT_TRIGGER - zName, -#endif - zName, nTabName, zTabName - ); - -#ifndef SQLITE_OMIT_AUTOINCREMENT - /* If the sqlite_sequence table exists in this database, then update - ** it with the new table name. - */ - if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ - sqlite3NestedParse(pParse, - "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q", - zDb, zName, pTab->zName); - } -#endif - -#ifndef SQLITE_OMIT_TRIGGER - /* If there are TEMP triggers on this table, modify the sqlite_temp_master - ** table. Don't do this if the table being ALTERed is itself located in - ** the temp database. - */ - if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ - sqlite3NestedParse(pParse, - "UPDATE sqlite_temp_master SET " - "sql = sqlite_rename_trigger(sql, %Q), " - "tbl_name = %Q " - "WHERE %s;", zName, zName, zWhere); - sqlite3DbFree(db, zWhere); - } -#endif - -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - if( db->flags&SQLITE_ForeignKeys ){ - FKey *p; - for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ - Table *pFrom = p->pFrom; - if( pFrom!=pTab ){ - reloadTableSchema(pParse, p->pFrom, pFrom->zName); - } - } - } -#endif - - /* Drop and reload the internal table schema. */ - reloadTableSchema(pParse, pTab, zName); + renameReloadSchema(pParse, iDb); + renameTestSchema(pParse, zDb, iDb==1); exit_rename_table: sqlite3SrcListDelete(db, pSrc); @@ -100128,12 +101737,11 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ - Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ + Vdbe *v; /* The prepared statement under construction */ int r1; /* Temporary registers */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; - assert( v!=0 ); pNew = pParse->pNewTable; assert( pNew ); @@ -100228,17 +101836,20 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ ** from less than 3 to 4, as that will corrupt any preexisting DESC ** index. */ - r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); - sqlite3VdbeUsesBtree(v, iDb); - sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); - sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); - sqlite3ReleaseTempReg(pParse, r1); + v = sqlite3GetVdbe(pParse); + if( v ){ + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); + sqlite3VdbeUsesBtree(v, iDb); + sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); + sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); + sqlite3ReleaseTempReg(pParse, r1); + } - /* Reload the schema of the modified table. */ - reloadTableSchema(pParse, pTab, pTab->zName); + /* Reload the table definition */ + renameReloadSchema(pParse, iDb); } /* @@ -100259,7 +101870,6 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ Table *pNew; Table *pTab; - Vdbe *v; int iDb; int i; int nAlloc; @@ -100323,16 +101933,1146 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ pNew->addColOffset = pTab->addColOffset; pNew->nTabRef = 1; - /* Begin a transaction and increment the schema cookie. */ - sqlite3BeginWriteOperation(pParse, 0, iDb); - v = sqlite3GetVdbe(pParse); - if( !v ) goto exit_begin_add_column; - sqlite3ChangeCookie(pParse, iDb); - exit_begin_add_column: sqlite3SrcListDelete(db, pSrc); return; } + +/* +** Parameter pTab is the subject of an ALTER TABLE ... RENAME COLUMN +** command. This function checks if the table is a view or virtual +** table (columns of views or virtual tables may not be renamed). If so, +** it loads an error message into pParse and returns non-zero. +** +** Or, if pTab is not a view or virtual table, zero is returned. +*/ +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) +static int isRealTable(Parse *pParse, Table *pTab){ + const char *zType = 0; +#ifndef SQLITE_OMIT_VIEW + if( pTab->pSelect ){ + zType = "view"; + } +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + zType = "virtual table"; + } +#endif + if( zType ){ + sqlite3ErrorMsg( + pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName + ); + return 1; + } + return 0; +} +#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ +# define isRealTable(x,y) (0) +#endif + +/* +** Handles the following parser reduction: +** +** cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew +*/ +SQLITE_PRIVATE void sqlite3AlterRenameColumn( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* Table being altered. pSrc->nSrc==1 */ + Token *pOld, /* Name of column being changed */ + Token *pNew /* New column name */ +){ + sqlite3 *db = pParse->db; /* Database connection */ + Table *pTab; /* Table being updated */ + int iCol; /* Index of column being renamed */ + char *zOld = 0; /* Old column name */ + char *zNew = 0; /* New column name */ + const char *zDb; /* Name of schema containing the table */ + int iSchema; /* Index of the schema */ + int bQuote; /* True to quote the new name */ + + /* Locate the table to be altered */ + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); + if( !pTab ) goto exit_rename_column; + + /* Cannot alter a system table */ + if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column; + if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column; + + /* Which schema holds the table to be altered */ + iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iSchema>=0 ); + zDb = db->aDb[iSchema].zDbSName; + +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Invoke the authorization callback. */ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ + goto exit_rename_column; + } +#endif + + /* Make sure the old name really is a column name in the table to be + ** altered. Set iCol to be the index of the column being renamed */ + zOld = sqlite3NameFromToken(db, pOld); + if( !zOld ) goto exit_rename_column; + for(iCol=0; iColnCol; iCol++){ + if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break; + } + if( iCol==pTab->nCol ){ + sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld); + goto exit_rename_column; + } + + /* Do the rename operation using a recursive UPDATE statement that + ** uses the sqlite_rename_column() SQL function to compute the new + ** CREATE statement text for the sqlite_master table. + */ + zNew = sqlite3NameFromToken(db, pNew); + if( !zNew ) goto exit_rename_column; + assert( pNew->n>0 ); + bQuote = sqlite3Isquote(pNew->z[0]); + sqlite3NestedParse(pParse, + "UPDATE \"%w\".%s SET " + "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " + "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)" + " AND sql NOT LIKE 'create virtual%%'", + zDb, MASTER_NAME, + zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, + pTab->zName + ); + + sqlite3NestedParse(pParse, + "UPDATE temp.%s SET " + "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) " + "WHERE type IN ('trigger', 'view')", + MASTER_NAME, + zDb, pTab->zName, iCol, zNew, bQuote + ); + + /* Drop and reload the database schema. */ + renameReloadSchema(pParse, iSchema); + renameTestSchema(pParse, zDb, iSchema==1); + + exit_rename_column: + sqlite3SrcListDelete(db, pSrc); + sqlite3DbFree(db, zOld); + sqlite3DbFree(db, zNew); + return; +} + +/* +** Each RenameToken object maps an element of the parse tree into +** the token that generated that element. The parse tree element +** might be one of: +** +** * A pointer to an Expr that represents an ID +** * The name of a table column in Column.zName +** +** A list of RenameToken objects can be constructed during parsing. +** Each new object is created by sqlite3RenameTokenMap(). +** As the parse tree is transformed, the sqlite3RenameTokenRemap() +** routine is used to keep the mapping current. +** +** After the parse finishes, renameTokenFind() routine can be used +** to look up the actual token value that created some element in +** the parse tree. +*/ +struct RenameToken { + void *p; /* Parse tree element created by token t */ + Token t; /* The token that created parse tree element p */ + RenameToken *pNext; /* Next is a list of all RenameToken objects */ +}; + +/* +** The context of an ALTER TABLE RENAME COLUMN operation that gets passed +** down into the Walker. +*/ +typedef struct RenameCtx RenameCtx; +struct RenameCtx { + RenameToken *pList; /* List of tokens to overwrite */ + int nList; /* Number of tokens in pList */ + int iCol; /* Index of column being renamed */ + Table *pTab; /* Table being ALTERed */ + const char *zOld; /* Old column name */ +}; + +#ifdef SQLITE_DEBUG +/* +** This function is only for debugging. It performs two tasks: +** +** 1. Checks that pointer pPtr does not already appear in the +** rename-token list. +** +** 2. Dereferences each pointer in the rename-token list. +** +** The second is most effective when debugging under valgrind or +** address-sanitizer or similar. If any of these pointers no longer +** point to valid objects, an exception is raised by the memory-checking +** tool. +** +** The point of this is to prevent comparisons of invalid pointer values. +** Even though this always seems to work, it is undefined according to the +** C standard. Example of undefined comparison: +** +** sqlite3_free(x); +** if( x==y ) ... +** +** Technically, as x no longer points into a valid object or to the byte +** following a valid object, it may not be used in comparison operations. +*/ +static void renameTokenCheckAll(Parse *pParse, void *pPtr){ + if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ + RenameToken *p; + u8 i = 0; + for(p=pParse->pRename; p; p=p->pNext){ + if( p->p ){ + assert( p->p!=pPtr ); + i += *(u8*)(p->p); + } + } + } +} +#else +# define renameTokenCheckAll(x,y) +#endif + +/* +** Remember that the parser tree element pPtr was created using +** the token pToken. +** +** In other words, construct a new RenameToken object and add it +** to the list of RenameToken objects currently being built up +** in pParse->pRename. +** +** The pPtr argument is returned so that this routine can be used +** with tail recursion in tokenExpr() routine, for a small performance +** improvement. +*/ +SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){ + RenameToken *pNew; + assert( pPtr || pParse->db->mallocFailed ); + renameTokenCheckAll(pParse, pPtr); + pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken)); + if( pNew ){ + pNew->p = pPtr; + pNew->t = *pToken; + pNew->pNext = pParse->pRename; + pParse->pRename = pNew; + } + + return pPtr; +} + +/* +** It is assumed that there is already a RenameToken object associated +** with parse tree element pFrom. This function remaps the associated token +** to parse tree element pTo. +*/ +SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){ + RenameToken *p; + renameTokenCheckAll(pParse, pTo); + for(p=pParse->pRename; p; p=p->pNext){ + if( p->p==pFrom ){ + p->p = pTo; + break; + } + } +} + +/* +** Walker callback used by sqlite3RenameExprUnmap(). +*/ +static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ + Parse *pParse = pWalker->pParse; + sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); + return WRC_Continue; +} + +/* +** Remove all nodes that are part of expression pExpr from the rename list. +*/ +SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ + Walker sWalker; + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = pParse; + sWalker.xExprCallback = renameUnmapExprCb; + sqlite3WalkExpr(&sWalker, pExpr); +} + +/* +** Remove all nodes that are part of expression-list pEList from the +** rename list. +*/ +SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){ + if( pEList ){ + int i; + Walker sWalker; + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = pParse; + sWalker.xExprCallback = renameUnmapExprCb; + sqlite3WalkExprList(&sWalker, pEList); + for(i=0; inExpr; i++){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName); + } + } +} + +/* +** Free the list of RenameToken objects given in the second argument +*/ +static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ + RenameToken *pNext; + RenameToken *p; + for(p=pToken; p; p=pNext){ + pNext = p->pNext; + sqlite3DbFree(db, p); + } +} + +/* +** Search the Parse object passed as the first argument for a RenameToken +** object associated with parse tree element pPtr. If found, remove it +** from the Parse object and add it to the list maintained by the +** RenameCtx object passed as the second argument. +*/ +static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){ + RenameToken **pp; + assert( pPtr!=0 ); + for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ + if( (*pp)->p==pPtr ){ + RenameToken *pToken = *pp; + *pp = pToken->pNext; + pToken->pNext = pCtx->pList; + pCtx->pList = pToken; + pCtx->nList++; + break; + } + } +} + +/* +** This is a Walker select callback. It does nothing. It is only required +** because without a dummy callback, sqlite3WalkExpr() and similar do not +** descend into sub-select statements. +*/ +static int renameColumnSelectCb(Walker *pWalker, Select *p){ + UNUSED_PARAMETER(pWalker); + UNUSED_PARAMETER(p); + return WRC_Continue; +} + +/* +** This is a Walker expression callback. +** +** For every TK_COLUMN node in the expression tree, search to see +** if the column being references is the column being renamed by an +** ALTER TABLE statement. If it is, then attach its associated +** RenameToken object to the list of RenameToken objects being +** constructed in RenameCtx object at pWalker->u.pRename. +*/ +static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){ + RenameCtx *p = pWalker->u.pRename; + if( pExpr->op==TK_TRIGGER + && pExpr->iColumn==p->iCol + && pWalker->pParse->pTriggerTab==p->pTab + ){ + renameTokenFind(pWalker->pParse, p, (void*)pExpr); + }else if( pExpr->op==TK_COLUMN + && pExpr->iColumn==p->iCol + && p->pTab==pExpr->y.pTab + ){ + renameTokenFind(pWalker->pParse, p, (void*)pExpr); + } + return WRC_Continue; +} + +/* +** The RenameCtx contains a list of tokens that reference a column that +** is being renamed by an ALTER TABLE statement. Return the "last" +** RenameToken in the RenameCtx and remove that RenameToken from the +** RenameContext. "Last" means the last RenameToken encountered when +** the input SQL is parsed from left to right. Repeated calls to this routine +** return all column name tokens in the order that they are encountered +** in the SQL statement. +*/ +static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){ + RenameToken *pBest = pCtx->pList; + RenameToken *pToken; + RenameToken **pp; + + for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){ + if( pToken->t.z>pBest->t.z ) pBest = pToken; + } + for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext); + *pp = pBest->pNext; + + return pBest; +} + +/* +** An error occured while parsing or otherwise processing a database +** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an +** ALTER TABLE RENAME COLUMN program. The error message emitted by the +** sub-routine is currently stored in pParse->zErrMsg. This function +** adds context to the error message and then stores it in pCtx. +*/ +static void renameColumnParseError( + sqlite3_context *pCtx, + int bPost, + sqlite3_value *pType, + sqlite3_value *pObject, + Parse *pParse +){ + const char *zT = (const char*)sqlite3_value_text(pType); + const char *zN = (const char*)sqlite3_value_text(pObject); + char *zErr; + + zErr = sqlite3_mprintf("error in %s %s%s: %s", + zT, zN, (bPost ? " after rename" : ""), + pParse->zErrMsg + ); + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); +} + +/* +** For each name in the the expression-list pEList (i.e. each +** pEList->a[i].zName) that matches the string in zOld, extract the +** corresponding rename-token from Parse object pParse and add it +** to the RenameCtx pCtx. +*/ +static void renameColumnElistNames( + Parse *pParse, + RenameCtx *pCtx, + ExprList *pEList, + const char *zOld +){ + if( pEList ){ + int i; + for(i=0; inExpr; i++){ + char *zName = pEList->a[i].zName; + if( 0==sqlite3_stricmp(zName, zOld) ){ + renameTokenFind(pParse, pCtx, (void*)zName); + } + } + } +} + +/* +** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName) +** that matches the string in zOld, extract the corresponding rename-token +** from Parse object pParse and add it to the RenameCtx pCtx. +*/ +static void renameColumnIdlistNames( + Parse *pParse, + RenameCtx *pCtx, + IdList *pIdList, + const char *zOld +){ + if( pIdList ){ + int i; + for(i=0; inId; i++){ + char *zName = pIdList->a[i].zName; + if( 0==sqlite3_stricmp(zName, zOld) ){ + renameTokenFind(pParse, pCtx, (void*)zName); + } + } + } +} + +/* +** Parse the SQL statement zSql using Parse object (*p). The Parse object +** is initialized by this function before it is used. +*/ +static int renameParseSql( + Parse *p, /* Memory to use for Parse object */ + const char *zDb, /* Name of schema SQL belongs to */ + int bTable, /* 1 -> RENAME TABLE, 0 -> RENAME COLUMN */ + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL to parse */ + int bTemp /* True if SQL is from temp schema */ +){ + int rc; + char *zErr = 0; + + db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); + + /* Parse the SQL statement passed as the first argument. If no error + ** occurs and the parse does not result in a new table, index or + ** trigger object, the database must be corrupt. */ + memset(p, 0, sizeof(Parse)); + p->eParseMode = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN); + p->db = db; + p->nQueryLoop = 1; + rc = sqlite3RunParser(p, zSql, &zErr); + assert( p->zErrMsg==0 ); + assert( rc!=SQLITE_OK || zErr==0 ); + assert( (0!=p->pNewTable) + (0!=p->pNewIndex) + (0!=p->pNewTrigger)<2 ); + p->zErrMsg = zErr; + if( db->mallocFailed ) rc = SQLITE_NOMEM; + if( rc==SQLITE_OK + && p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0 + ){ + rc = SQLITE_CORRUPT_BKPT; + } + +#ifdef SQLITE_DEBUG + /* Ensure that all mappings in the Parse.pRename list really do map to + ** a part of the input string. */ + if( rc==SQLITE_OK ){ + int nSql = sqlite3Strlen30(zSql); + RenameToken *pToken; + for(pToken=p->pRename; pToken; pToken=pToken->pNext){ + assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] ); + } + } +#endif + + db->init.iDb = 0; + return rc; +} + +/* +** This function edits SQL statement zSql, replacing each token identified +** by the linked list pRename with the text of zNew. If argument bQuote is +** true, then zNew is always quoted first. If no error occurs, the result +** is loaded into context object pCtx as the result. +** +** Or, if an error occurs (i.e. an OOM condition), an error is left in +** pCtx and an SQLite error code returned. +*/ +static int renameEditSql( + sqlite3_context *pCtx, /* Return result here */ + RenameCtx *pRename, /* Rename context */ + const char *zSql, /* SQL statement to edit */ + const char *zNew, /* New token text */ + int bQuote /* True to always quote token */ +){ + int nNew = sqlite3Strlen30(zNew); + int nSql = sqlite3Strlen30(zSql); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + int rc = SQLITE_OK; + char *zQuot; + char *zOut; + int nQuot; + + /* Set zQuot to point to a buffer containing a quoted copy of the + ** identifier zNew. If the corresponding identifier in the original + ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to + ** point to zQuot so that all substitutions are made using the + ** quoted version of the new column name. */ + zQuot = sqlite3MPrintf(db, "\"%w\"", zNew); + if( zQuot==0 ){ + return SQLITE_NOMEM; + }else{ + nQuot = sqlite3Strlen30(zQuot); + } + if( bQuote ){ + zNew = zQuot; + nNew = nQuot; + } + + /* At this point pRename->pList contains a list of RenameToken objects + ** corresponding to all tokens in the input SQL that must be replaced + ** with the new column name. All that remains is to construct and + ** return the edited SQL string. */ + assert( nQuot>=nNew ); + zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); + if( zOut ){ + int nOut = nSql; + memcpy(zOut, zSql, nSql); + while( pRename->pList ){ + int iOff; /* Offset of token to replace in zOut */ + RenameToken *pBest = renameColumnTokenNext(pRename); + + u32 nReplace; + const char *zReplace; + if( sqlite3IsIdChar(*pBest->t.z) ){ + nReplace = nNew; + zReplace = zNew; + }else{ + nReplace = nQuot; + zReplace = zQuot; + } + + iOff = pBest->t.z - zSql; + if( pBest->t.n!=nReplace ){ + memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], + nOut - (iOff + pBest->t.n) + ); + nOut += nReplace - pBest->t.n; + zOut[nOut] = '\0'; + } + memcpy(&zOut[iOff], zReplace, nReplace); + sqlite3DbFree(db, pBest); + } + + sqlite3_result_text(pCtx, zOut, -1, SQLITE_TRANSIENT); + sqlite3DbFree(db, zOut); + }else{ + rc = SQLITE_NOMEM; + } + + sqlite3_free(zQuot); + return rc; +} + +/* +** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming +** it was read from the schema of database zDb. Return SQLITE_OK if +** successful. Otherwise, return an SQLite error code and leave an error +** message in the Parse object. +*/ +static int renameResolveTrigger(Parse *pParse, const char *zDb){ + sqlite3 *db = pParse->db; + Trigger *pNew = pParse->pNewTrigger; + TriggerStep *pStep; + NameContext sNC; + int rc = SQLITE_OK; + + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + assert( pNew->pTabSchema ); + pParse->pTriggerTab = sqlite3FindTable(db, pNew->table, + db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName + ); + pParse->eTriggerOp = pNew->op; + /* ALWAYS() because if the table of the trigger does not exist, the + ** error would have been hit before this point */ + if( ALWAYS(pParse->pTriggerTab) ){ + rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); + } + + /* Resolve symbols in WHEN clause */ + if( rc==SQLITE_OK && pNew->pWhen ){ + rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen); + } + + for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){ + if( pStep->pSelect ){ + sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); + if( pParse->nErr ) rc = pParse->rc; + } + if( rc==SQLITE_OK && pStep->zTarget ){ + Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb); + if( pTarget==0 ){ + rc = SQLITE_ERROR; + }else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){ + SrcList sSrc; + memset(&sSrc, 0, sizeof(sSrc)); + sSrc.nSrc = 1; + sSrc.a[0].zName = pStep->zTarget; + sSrc.a[0].pTab = pTarget; + sNC.pSrcList = &sSrc; + if( pStep->pWhere ){ + rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere); + } + if( rc==SQLITE_OK ){ + rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList); + } + assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) ); + if( pStep->pUpsert ){ + Upsert *pUpsert = pStep->pUpsert; + assert( rc==SQLITE_OK ); + pUpsert->pUpsertSrc = &sSrc; + sNC.uNC.pUpsert = pUpsert; + sNC.ncFlags = NC_UUpsert; + rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); + if( rc==SQLITE_OK ){ + ExprList *pUpsertSet = pUpsert->pUpsertSet; + rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet); + } + if( rc==SQLITE_OK ){ + rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere); + } + if( rc==SQLITE_OK ){ + rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); + } + sNC.ncFlags = 0; + } + } + } + } + return rc; +} + +/* +** Invoke sqlite3WalkExpr() or sqlite3WalkSelect() on all Select or Expr +** objects that are part of the trigger passed as the second argument. +*/ +static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ + TriggerStep *pStep; + + /* Find tokens to edit in WHEN clause */ + sqlite3WalkExpr(pWalker, pTrigger->pWhen); + + /* Find tokens to edit in trigger steps */ + for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ + sqlite3WalkSelect(pWalker, pStep->pSelect); + sqlite3WalkExpr(pWalker, pStep->pWhere); + sqlite3WalkExprList(pWalker, pStep->pExprList); + if( pStep->pUpsert ){ + Upsert *pUpsert = pStep->pUpsert; + sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget); + sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet); + sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); + sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); + } + } +} + +/* +** Free the contents of Parse object (*pParse). Do not free the memory +** occupied by the Parse object itself. +*/ +static void renameParseCleanup(Parse *pParse){ + sqlite3 *db = pParse->db; + if( pParse->pVdbe ){ + sqlite3VdbeFinalize(pParse->pVdbe); + } + sqlite3DeleteTable(db, pParse->pNewTable); + if( pParse->pNewIndex ) sqlite3FreeIndex(db, pParse->pNewIndex); + sqlite3DeleteTrigger(db, pParse->pNewTrigger); + sqlite3DbFree(db, pParse->zErrMsg); + renameTokenFree(db, pParse->pRename); + sqlite3ParserReset(pParse); +} + +/* +** SQL function: +** +** sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld) +** +** 0. zSql: SQL statement to rewrite +** 1. type: Type of object ("table", "view" etc.) +** 2. object: Name of object +** 3. Database: Database name (e.g. "main") +** 4. Table: Table name +** 5. iCol: Index of column to rename +** 6. zNew: New column name +** 7. bQuote: Non-zero if the new column name should be quoted. +** 8. bTemp: True if zSql comes from temp schema +** +** Do a column rename operation on the CREATE statement given in zSql. +** The iCol-th column (left-most is 0) of table zTable is renamed from zCol +** into zNew. The name should be quoted if bQuote is true. +** +** This function is used internally by the ALTER TABLE RENAME COLUMN command. +** It is only accessible to SQL created using sqlite3NestedParse(). It is +** not reachable from ordinary SQL passed into sqlite3_prepare(). +*/ +static void renameColumnFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + RenameCtx sCtx; + const char *zSql = (const char*)sqlite3_value_text(argv[0]); + const char *zDb = (const char*)sqlite3_value_text(argv[3]); + const char *zTable = (const char*)sqlite3_value_text(argv[4]); + int iCol = sqlite3_value_int(argv[5]); + const char *zNew = (const char*)sqlite3_value_text(argv[6]); + int bQuote = sqlite3_value_int(argv[7]); + int bTemp = sqlite3_value_int(argv[8]); + const char *zOld; + int rc; + Parse sParse; + Walker sWalker; + Index *pIdx; + int i; + Table *pTab; +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; +#endif + + UNUSED_PARAMETER(NotUsed); + if( zSql==0 ) return; + if( zTable==0 ) return; + if( zNew==0 ) return; + if( iCol<0 ) return; + sqlite3BtreeEnterAll(db); + pTab = sqlite3FindTable(db, zTable, zDb); + if( pTab==0 || iCol>=pTab->nCol ){ + sqlite3BtreeLeaveAll(db); + return; + } + zOld = pTab->aCol[iCol].zName; + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol); + +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = 0; +#endif + rc = renameParseSql(&sParse, zDb, 0, db, zSql, bTemp); + + /* Find tokens that need to be replaced. */ + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = &sParse; + sWalker.xExprCallback = renameColumnExprCb; + sWalker.xSelectCallback = renameColumnSelectCb; + sWalker.u.pRename = &sCtx; + + sCtx.pTab = pTab; + if( rc!=SQLITE_OK ) goto renameColumnFunc_done; + if( sParse.pNewTable ){ + Select *pSelect = sParse.pNewTable->pSelect; + if( pSelect ){ + sParse.rc = SQLITE_OK; + sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0); + rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); + if( rc==SQLITE_OK ){ + sqlite3WalkSelect(&sWalker, pSelect); + } + if( rc!=SQLITE_OK ) goto renameColumnFunc_done; + }else{ + /* A regular table */ + int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName); + FKey *pFKey; + assert( sParse.pNewTable->pSelect==0 ); + sCtx.pTab = sParse.pNewTable; + if( bFKOnly==0 ){ + renameTokenFind( + &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName + ); + if( sCtx.iCol<0 ){ + renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey); + } + sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); + for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){ + sqlite3WalkExprList(&sWalker, pIdx->aColExpr); + } + } + + for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + for(i=0; inCol; i++){ + if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){ + renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]); + } + if( 0==sqlite3_stricmp(pFKey->zTo, zTable) + && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld) + ){ + renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol); + } + } + } + } + }else if( sParse.pNewIndex ){ + sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); + sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); + }else{ + /* A trigger */ + TriggerStep *pStep; + rc = renameResolveTrigger(&sParse, (bTemp ? 0 : zDb)); + if( rc!=SQLITE_OK ) goto renameColumnFunc_done; + + for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){ + if( pStep->zTarget ){ + Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb); + if( pTarget==pTab ){ + if( pStep->pUpsert ){ + ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet; + renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld); + } + renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld); + renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld); + } + } + } + + + /* Find tokens to edit in UPDATE OF clause */ + if( sParse.pTriggerTab==pTab ){ + renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld); + } + + /* Find tokens to edit in various expressions and selects */ + renameWalkTrigger(&sWalker, sParse.pNewTrigger); + } + + assert( rc==SQLITE_OK ); + rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); + +renameColumnFunc_done: + if( rc!=SQLITE_OK ){ + if( sParse.zErrMsg ){ + renameColumnParseError(context, 0, argv[1], argv[2], &sParse); + }else{ + sqlite3_result_error_code(context, rc); + } + } + + renameParseCleanup(&sParse); + renameTokenFree(db, sCtx.pList); +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + sqlite3BtreeLeaveAll(db); +} + +/* +** Walker expression callback used by "RENAME TABLE". +*/ +static int renameTableExprCb(Walker *pWalker, Expr *pExpr){ + RenameCtx *p = pWalker->u.pRename; + if( pExpr->op==TK_COLUMN && p->pTab==pExpr->y.pTab ){ + renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab); + } + return WRC_Continue; +} + +/* +** Walker select callback used by "RENAME TABLE". +*/ +static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ + int i; + RenameCtx *p = pWalker->u.pRename; + SrcList *pSrc = pSelect->pSrc; + for(i=0; inSrc; i++){ + struct SrcList_item *pItem = &pSrc->a[i]; + if( pItem->pTab==p->pTab ){ + renameTokenFind(pWalker->pParse, p, pItem->zName); + } + } + + return WRC_Continue; +} + + +/* +** This C function implements an SQL user function that is used by SQL code +** generated by the ALTER TABLE ... RENAME command to modify the definition +** of any foreign key constraints that use the table being renamed as the +** parent table. It is passed three arguments: +** +** 0: The database containing the table being renamed. +** 1. type: Type of object ("table", "view" etc.) +** 2. object: Name of object +** 3: The complete text of the schema statement being modified, +** 4: The old name of the table being renamed, and +** 5: The new name of the table being renamed. +** 6: True if the schema statement comes from the temp db. +** +** It returns the new schema statement. For example: +** +** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0) +** -> 'CREATE TABLE t1(a REFERENCES t3)' +*/ +static void renameTableFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + const char *zDb = (const char*)sqlite3_value_text(argv[0]); + const char *zInput = (const char*)sqlite3_value_text(argv[3]); + const char *zOld = (const char*)sqlite3_value_text(argv[4]); + const char *zNew = (const char*)sqlite3_value_text(argv[5]); + int bTemp = sqlite3_value_int(argv[6]); + UNUSED_PARAMETER(NotUsed); + + if( zInput && zOld && zNew ){ + Parse sParse; + int rc; + int bQuote = 1; + RenameCtx sCtx; + Walker sWalker; + +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; + db->xAuth = 0; +#endif + + sqlite3BtreeEnterAll(db); + + memset(&sCtx, 0, sizeof(RenameCtx)); + sCtx.pTab = sqlite3FindTable(db, zOld, zDb); + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = &sParse; + sWalker.xExprCallback = renameTableExprCb; + sWalker.xSelectCallback = renameTableSelectCb; + sWalker.u.pRename = &sCtx; + + rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp); + + if( rc==SQLITE_OK ){ + int isLegacy = (db->flags & SQLITE_LegacyAlter); + if( sParse.pNewTable ){ + Table *pTab = sParse.pNewTable; + + if( pTab->pSelect ){ + if( isLegacy==0 ){ + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = &sParse; + + sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC); + if( sParse.nErr ) rc = sParse.rc; + sqlite3WalkSelect(&sWalker, pTab->pSelect); + } + }else{ + /* Modify any FK definitions to point to the new table. */ +#ifndef SQLITE_OMIT_FOREIGN_KEY + if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){ + FKey *pFKey; + for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ + renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo); + } + } + } +#endif + + /* If this is the table being altered, fix any table refs in CHECK + ** expressions. Also update the name that appears right after the + ** "CREATE [VIRTUAL] TABLE" bit. */ + if( sqlite3_stricmp(zOld, pTab->zName)==0 ){ + sCtx.pTab = pTab; + if( isLegacy==0 ){ + sqlite3WalkExprList(&sWalker, pTab->pCheck); + } + renameTokenFind(&sParse, &sCtx, pTab->zName); + } + } + } + + else if( sParse.pNewIndex ){ + renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName); + if( isLegacy==0 ){ + sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); + } + } + +#ifndef SQLITE_OMIT_TRIGGER + else{ + Trigger *pTrigger = sParse.pNewTrigger; + TriggerStep *pStep; + if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) + && sCtx.pTab->pSchema==pTrigger->pTabSchema + ){ + renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table); + } + + if( isLegacy==0 ){ + rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb); + if( rc==SQLITE_OK ){ + renameWalkTrigger(&sWalker, pTrigger); + for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ + if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ + renameTokenFind(&sParse, &sCtx, pStep->zTarget); + } + } + } + } + } +#endif + } + + if( rc==SQLITE_OK ){ + rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote); + } + if( rc!=SQLITE_OK ){ + if( sParse.zErrMsg ){ + renameColumnParseError(context, 0, argv[1], argv[2], &sParse); + }else{ + sqlite3_result_error_code(context, rc); + } + } + + renameParseCleanup(&sParse); + renameTokenFree(db, sCtx.pList); + sqlite3BtreeLeaveAll(db); +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + } + + return; +} + +/* +** An SQL user function that checks that there are no parse or symbol +** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement. +** After an ALTER TABLE .. RENAME operation is performed and the schema +** reloaded, this function is called on each SQL statement in the schema +** to ensure that it is still usable. +** +** 0: Database name ("main", "temp" etc.). +** 1: SQL statement. +** 2: Object type ("view", "table", "trigger" or "index"). +** 3: Object name. +** 4: True if object is from temp schema. +** +** Unless it finds an error, this function normally returns NULL. However, it +** returns integer value 1 if: +** +** * the SQL argument creates a trigger, and +** * the table that the trigger is attached to is in database zDb. +*/ +static void renameTableTest( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + char const *zDb = (const char*)sqlite3_value_text(argv[0]); + char const *zInput = (const char*)sqlite3_value_text(argv[1]); + int bTemp = sqlite3_value_int(argv[4]); + int isLegacy = (db->flags & SQLITE_LegacyAlter); + +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; + db->xAuth = 0; +#endif + + UNUSED_PARAMETER(NotUsed); + if( zDb && zInput ){ + int rc; + Parse sParse; + rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp); + if( rc==SQLITE_OK ){ + if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){ + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = &sParse; + sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC); + if( sParse.nErr ) rc = sParse.rc; + } + + else if( sParse.pNewTrigger ){ + if( isLegacy==0 ){ + rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb); + } + if( rc==SQLITE_OK ){ + int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema); + int i2 = sqlite3FindDbName(db, zDb); + if( i1==i2 ) sqlite3_result_int(context, 1); + } + } + } + + if( rc!=SQLITE_OK ){ + renameColumnParseError(context, 1, argv[2], argv[3], &sParse); + } + renameParseCleanup(&sParse); + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif +} + +/* +** Register built-in functions used to help implement ALTER TABLE +*/ +SQLITE_PRIVATE void sqlite3AlterFunctions(void){ + static FuncDef aAlterTableFuncs[] = { + INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc), + INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc), + INTERNAL_FUNCTION(sqlite_rename_test, 5, renameTableTest), + }; + sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); +} #endif /* SQLITE_ALTER_TABLE */ /************** End of alter.c ***********************************************/ @@ -100824,6 +103564,7 @@ static const FuncDef statInitFuncdef = { 0, /* pNext */ statInit, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "stat_init", /* zName */ {0} }; @@ -101140,6 +103881,7 @@ static const FuncDef statPushFuncdef = { 0, /* pNext */ statPush, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "stat_push", /* zName */ {0} }; @@ -101291,6 +104033,7 @@ static const FuncDef statGetFuncdef = { 0, /* pNext */ statGet, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "stat_get", /* zName */ {0} }; @@ -101610,10 +104353,7 @@ static void analyzeOneTable( callStatGet(v, regStat4, STAT_GET_NLT, regLt); callStatGet(v, regStat4, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); - /* We know that the regSampleRowid row exists because it was read by - ** the previous loop. Thus the not-found jump of seekOp will never - ** be taken */ - VdbeCoverageNeverTaken(v); + VdbeCoverage(v); #ifdef SQLITE_ENABLE_STAT3 sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample); #else @@ -102253,7 +104993,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){ + if( rc==SQLITE_OK ){ db->lookaside.bDisable++; rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bDisable--; @@ -102378,7 +105118,7 @@ static void attachFunc( if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt); pNew->pBt = 0; pNew->pSchema = 0; - rc = sqlite3BtreeOpen(pVfs, "x", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); + rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); }else{ /* This is a real ATTACH ** @@ -102436,7 +105176,7 @@ static void attachFunc( sqlite3_free( zPath ); db->nDb++; } - db->skipBtreeMutex = 0; + db->noSharedCache = 0; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); @@ -102508,6 +105248,7 @@ static void attachFunc( if( rc==SQLITE_OK ){ sqlite3BtreeEnterAll(db); db->init.iDb = 0; + db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); @@ -102691,6 +105432,7 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){ 0, /* pNext */ detachFunc, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "sqlite_detach", /* zName */ {0} }; @@ -102710,6 +105452,7 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p 0, /* pNext */ attachFunc, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "sqlite_attach", /* zName */ {0} }; @@ -102780,6 +105523,9 @@ SQLITE_PRIVATE int sqlite3FixSrcList( if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; #endif + if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){ + return 1; + } } return 0; } @@ -102879,6 +105625,18 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep( if( sqlite3FixExprList(pFix, pStep->pExprList) ){ return 1; } +#ifndef SQLITE_OMIT_UPSERT + if( pStep->pUpsert ){ + Upsert *pUp = pStep->pUpsert; + if( sqlite3FixExprList(pFix, pUp->pUpsertTarget) + || sqlite3FixExpr(pFix, pUp->pUpsertTargetWhere) + || sqlite3FixExprList(pFix, pUp->pUpsertSet) + || sqlite3FixExpr(pFix, pUp->pUpsertWhere) + ){ + return 1; + } + } +#endif pStep = pStep->pNext; } return 0; @@ -102967,7 +105725,7 @@ SQLITE_API int sqlite3_set_authorizer( sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -103039,6 +105797,8 @@ SQLITE_PRIVATE void sqlite3AuthRead( int iDb; /* The index of the database the expression refers to */ int iCol; /* Index of column in table */ + assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); + assert( !IN_RENAME_OBJECT || db->xAuth==0 ); if( db->xAuth==0 ) return; iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ @@ -103047,7 +105807,6 @@ SQLITE_PRIVATE void sqlite3AuthRead( return; } - assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); if( pExpr->op==TK_TRIGGER ){ pTab = pParse->pTriggerTab; }else{ @@ -103096,7 +105855,8 @@ SQLITE_PRIVATE int sqlite3AuthCheck( /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ - if( db->init.busy || IN_DECLARE_VTAB ){ + assert( !IN_RENAME_OBJECT || db->xAuth==0 ); + if( db->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } @@ -103388,7 +106148,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ /* Get the VDBE program ready for execution */ if( v && pParse->nErr==0 && !db->mallocFailed ){ - assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; @@ -103506,28 +106265,29 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( const char *zDbase /* Name of the database. Might be NULL */ ){ Table *p; + sqlite3 *db = pParse->db; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ - if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 + && SQLITE_OK!=sqlite3ReadSchema(pParse) + ){ return 0; } - p = sqlite3FindTable(pParse->db, zName, zDbase); + p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3FindDbName(pParse->db, zDbase)<1 ){ - /* If zName is the not the name of a table in the schema created using - ** CREATE, then check to see if it is the name of an virtual table that - ** can be an eponymous virtual table. */ - Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); - if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ - pMod = sqlite3PragmaVtabRegister(pParse->db, zName); - } - if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ - return pMod->pEpoTab; - } + /* If zName is the not the name of a table in the schema created using + ** CREATE, then check to see if it is the name of an virtual table that + ** can be an eponymous virtual table. */ + Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); + if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ + pMod = sqlite3PragmaVtabRegister(db, zName); + } + if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ + return pMod->pEpoTab; } #endif if( (flags & LOCATE_NOERR)==0 ){ @@ -103600,7 +106360,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha /* ** Reclaim the memory used by an index */ -static void freeIndex(sqlite3 *db, Index *p){ +SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif @@ -103640,7 +106400,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char p->pNext = pIndex->pNext; } } - freeIndex(db, pIndex); + sqlite3FreeIndex(db, pIndex); } db->mDbFlags |= DBFLAG_SchemaChange; } @@ -103688,6 +106448,7 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); DbSetProperty(db, iDb, DB_ResetWanted); DbSetProperty(db, 1, DB_ResetWanted); + db->mDbFlags &= ~DBFLAG_SchemaKnownOk; } if( db->nSchemaLock==0 ){ @@ -103706,17 +106467,22 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ int i; sqlite3BtreeEnterAll(db); - assert( db->nSchemaLock==0 ); for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ - sqlite3SchemaClear(pDb->pSchema); + if( db->nSchemaLock==0 ){ + sqlite3SchemaClear(pDb->pSchema); + }else{ + DbSetProperty(db, i, DB_ResetWanted); + } } } - db->mDbFlags &= ~DBFLAG_SchemaChange; + db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk); sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); - sqlite3CollapseDatabaseArray(db); + if( db->nSchemaLock==0 ){ + sqlite3CollapseDatabaseArray(db); + } } /* @@ -103785,7 +106551,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); } - freeIndex(db, pIndex); + sqlite3FreeIndex(db, pIndex); } /* Delete any foreign keys attached to this table. */ @@ -103793,6 +106559,12 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ /* Delete the Table structure itself. */ +#ifdef SQLITE_ENABLE_NORMALIZE + if( pTable->pColHash ){ + sqlite3HashClear(pTable->pColHash); + sqlite3_free(pTable->pColHash); + } +#endif sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); @@ -103943,7 +106715,7 @@ SQLITE_PRIVATE int sqlite3TwoPartName( return -1; } }else{ - assert( db->init.iDb==0 || db->init.busy + assert( db->init.iDb==0 || db->init.busy || IN_RENAME_OBJECT || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; @@ -103951,6 +106723,20 @@ SQLITE_PRIVATE int sqlite3TwoPartName( return iDb; } +/* +** True if PRAGMA writable_schema is ON +*/ +SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3 *db){ + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==0 ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + SQLITE_WriteSchema ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + SQLITE_Defensive ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + (SQLITE_WriteSchema|SQLITE_Defensive) ); + return (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==SQLITE_WriteSchema; +} + /* ** This routine is used to check if the UTF-8 string zName is a legal ** unqualified name for a new schema object (table, index, view or @@ -103960,7 +106746,7 @@ SQLITE_PRIVATE int sqlite3TwoPartName( */ SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){ if( !pParse->db->init.busy && pParse->nested==0 - && (pParse->db->flags & SQLITE_WriteSchema)==0 + && sqlite3WritableSchema(pParse->db)==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); return SQLITE_ERROR; @@ -104038,6 +106824,9 @@ SQLITE_PRIVATE void sqlite3StartTable( } if( !OMIT_TEMPDB && isTemp ) iDb = 1; zName = sqlite3NameFromToken(db, pName); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (void*)zName, pName); + } } pParse->sNameToken = *pName; if( zName==0 ) return; @@ -104073,7 +106862,7 @@ SQLITE_PRIVATE void sqlite3StartTable( ** and types will be used, so there is no need to test for namespace ** collisions. */ - if( !IN_DECLARE_VTAB ){ + if( !IN_SPECIAL_PARSE ){ char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; @@ -104232,6 +107021,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ } z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); if( z==0 ) return; + if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName); memcpy(z, pName->z, pName->n); z[pName->n] = 0; sqlite3Dequote(z); @@ -104258,15 +107048,20 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ if( pType->n==0 ){ /* If there is no type specified, columns have the default affinity - ** 'BLOB'. */ + ** 'BLOB' with a default size of 4 bytes. */ pCol->affinity = SQLITE_AFF_BLOB; pCol->szEst = 1; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( 4>=sqlite3GlobalConfig.szSorterRef ){ + pCol->colFlags |= COLFLAG_SORTERREF; + } +#endif }else{ zType = z + sqlite3Strlen30(z) + 1; memcpy(zType, pType->z, pType->n); zType[pType->n] = 0; sqlite3Dequote(zType); - pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst); + pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } p->nCol++; @@ -104326,7 +107121,7 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){ ** If none of the substrings in the above table are found, ** SQLITE_AFF_NUMERIC is returned. */ -SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ +SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, Column *pCol){ u32 h = 0; char aff = SQLITE_AFF_NUMERIC; const char *zChar = 0; @@ -104363,27 +107158,32 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ } } - /* If pszEst is not NULL, store an estimate of the field size. The + /* If pCol is not NULL, store an estimate of the field size. The ** estimate is scaled so that the size of an integer is 1. */ - if( pszEst ){ - *pszEst = 1; /* default size is approx 4 bytes */ + if( pCol ){ + int v = 0; /* default size is approx 4 bytes */ if( aff r=(k/4+1) */ sqlite3GetInt32(zChar, &v); - v = v/4 + 1; - if( v>255 ) v = 255; - *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */ break; } zChar++; } }else{ - *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/ + v = 16; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/ } } +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( v>=sqlite3GlobalConfig.szSorterRef ){ + pCol->colFlags |= COLFLAG_SORTERREF; + } +#endif + v = v/4 + 1; + if( v>255 ) v = 255; + pCol->szEst = v; } return aff; } @@ -104428,6 +107228,9 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue( sqlite3DbFree(db, x.u.zToken); } } + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprUnmap(pParse, pExpr); + } sqlite3ExprDelete(db, pExpr); } @@ -104519,6 +107322,9 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 && sortOrder!=SQLITE_SO_DESC ){ + if( IN_RENAME_OBJECT && pList ){ + sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr); + } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); @@ -104844,6 +107650,31 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){ return 0; } +/* Recompute the colNotIdxed field of the Index. +** +** colNotIdxed is a bitmask that has a 0 bit representing each indexed +** columns that are within the first 63 columns of the table. The +** high-order bit of colNotIdxed is always 1. All unindexed columns +** of the table have a 1. +** +** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask +** to determine if the index is covering index. +*/ +static void recomputeColumnsNotIndexed(Index *pIdx){ + Bitmask m = 0; + int j; + for(j=pIdx->nColumn-1; j>=0; j--){ + int x = pIdx->aiColumn[j]; + if( x>=0 ){ + testcase( x==BMS-1 ); + testcase( x==BMS-2 ); + if( xcolNotIdxed = ~m; + assert( (pIdx->colNotIdxed>>63)==1 ); +} + /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both @@ -104886,10 +107717,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ } } - /* The remaining transformations only apply to b-tree tables, not to - ** virtual tables */ - if( IN_DECLARE_VTAB ) return; - /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY ** into BTREE_BLOBKEY. */ @@ -104912,7 +107739,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ assert( pParse->pNewTable==pTab ); sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); - if( db->mallocFailed ) return; + if( db->mallocFailed || pParse->nErr ) return; pPk = sqlite3PrimaryKeyIndex(pTab); pTab->iPKey = -1; }else{ @@ -104992,8 +107819,39 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ }else{ pPk->nColumn = pTab->nCol; } + recomputeColumnsNotIndexed(pPk); } +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Return true if zName is a shadow table name in the current database +** connection. +** +** zName is temporarily modified while this routine is running, but is +** restored to its original value prior to this routine returning. +*/ +static int isShadowTableName(sqlite3 *db, char *zName){ + char *zTail; /* Pointer to the last "_" in zName */ + Table *pTab; /* Table that zName is a shadow of */ + Module *pMod; /* Module for the virtual table */ + + zTail = strrchr(zName, '_'); + if( zTail==0 ) return 0; + *zTail = 0; + pTab = sqlite3FindTable(db, zName, 0); + *zTail = '_'; + if( pTab==0 ) return 0; + if( !IsVirtual(pTab) ) return 0; + pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]); + if( pMod==0 ) return 0; + if( pMod->pModule->iVersion<3 ) return 0; + if( pMod->pModule->xShadowName==0 ) return 0; + return pMod->pModule->xShadowName(zTail+1); +} +#else +# define isShadowTableName(x,y) 0 +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ + /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. @@ -105033,6 +107891,10 @@ SQLITE_PRIVATE void sqlite3EndTable( p = pParse->pNewTable; if( p==0 ) return; + if( pSelect==0 && isShadowTableName(db, p->zName) ){ + p->tabFlags |= TF_Shadow; + } + /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_master" or "sqlite_temp_master" table on the disk. ** So do not write to the disk again. Extract the root page number @@ -105295,7 +108157,12 @@ SQLITE_PRIVATE void sqlite3CreateView( ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ - p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + if( IN_RENAME_OBJECT ){ + p->pSelect = pSelect; + pSelect = 0; + }else{ + p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + } p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); if( db->mallocFailed ) goto create_view_fail; @@ -105320,6 +108187,9 @@ SQLITE_PRIVATE void sqlite3CreateView( create_view_fail: sqlite3SelectDelete(db, pSelect); + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprlistUnmap(pParse, pCNames); + } sqlite3ExprListDelete(db, pCNames); return; } @@ -105393,6 +108263,10 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ assert( pTable->pSelect ); pSel = sqlite3SelectDup(db, pTable->pSelect, 0); if( pSel ){ +#ifndef SQLITE_OMIT_ALTERTABLE + u8 eParseMode = pParse->eParseMode; + pParse->eParseMode = PARSE_MODE_NORMAL; +#endif n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; @@ -105438,10 +108312,18 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); db->lookaside.bDisable--; +#ifndef SQLITE_OMIT_ALTERTABLE + pParse->eParseMode = eParseMode; +#endif } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; + if( db->mallocFailed ){ + sqlite3DeleteColumnNames(db, pTable); + pTable->aCol = 0; + pTable->nCol = 0; + } #endif /* SQLITE_OMIT_VIEW */ return nErr; } @@ -105520,7 +108402,7 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); int r1 = sqlite3GetTempReg(pParse); - assert( iTable>1 ); + if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema"); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM @@ -105780,8 +108662,10 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); - sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); - sqlite3FkDropTable(pParse, pName, pTab); + if( !isView ){ + sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); + sqlite3FkDropTable(pParse, pName, pTab); + } sqlite3CodeDropTable(pParse, pTab, iDb, isView); } @@ -105856,6 +108740,9 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( pFKey->pNextFrom = p->pFKey; z = (char*)&pFKey->aCol[nCol]; pFKey->zTo = z; + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (void*)z, pTo); + } memcpy(z, pTo->z, pTo->n); z[pTo->n] = 0; sqlite3Dequote(z); @@ -105878,12 +108765,18 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( pFromCol->a[i].zName); goto fk_end; } + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName); + } } } if( pToCol ){ for(i=0; ia[i].zName); pFKey->aCol[i].zCol = z; + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName); + } memcpy(z, pToCol->a[i].zName, n); z[n] = 0; z += n+1; @@ -105992,6 +108885,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); regRecord = sqlite3GetTempReg(pParse); + sqlite3MultiWrite(pParse); sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); @@ -106005,12 +108899,13 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); if( IsUniqueIndex(pIndex) ){ - int j2 = sqlite3VdbeCurrentAddr(v) + 3; - sqlite3VdbeGoto(v, j2); + int j2 = sqlite3VdbeGoto(v, 1); addr2 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); + sqlite3VdbeJumpHere(v, j2); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } @@ -106173,7 +109068,11 @@ SQLITE_PRIVATE void sqlite3CreateIndex( #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif - && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ +#ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX + && sqlite3StrICmp(&pTab->zName[7],"master")!=0 +#endif + && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 + ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } @@ -106210,21 +109109,23 @@ SQLITE_PRIVATE void sqlite3CreateIndex( if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } - if( !db->init.busy ){ - if( sqlite3FindTable(db, zName, 0)!=0 ){ - sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); + if( !IN_RENAME_OBJECT ){ + if( !db->init.busy ){ + if( sqlite3FindTable(db, zName, 0)!=0 ){ + sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); + goto exit_create_index; + } + } + if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ + if( !ifNotExist ){ + sqlite3ErrorMsg(pParse, "index %s already exists", zName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); + } goto exit_create_index; } } - if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ - if( !ifNotExist ){ - sqlite3ErrorMsg(pParse, "index %s already exists", zName); - }else{ - assert( !db->init.busy ); - sqlite3CodeVerifySchema(pParse, iDb); - } - goto exit_create_index; - } }else{ int n; Index *pLoop; @@ -106239,13 +109140,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex( ** The following statement converts "sqlite3_autoindex..." into ** "sqlite3_butoindex..." in order to make the names distinct. ** The "vtab_err.test" test demonstrates the need of this statement. */ - if( IN_DECLARE_VTAB ) zName[7]++; + if( IN_SPECIAL_PARSE ) zName[7]++; } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION - { + if( !IN_RENAME_OBJECT ){ const char *zDb = pDb->zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; @@ -106332,7 +109233,12 @@ SQLITE_PRIVATE void sqlite3CreateIndex( ** TODO: Issue a warning if the table primary key is used as part of the ** index key. */ - for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ + pListItem = pList->a; + if( IN_RENAME_OBJECT ){ + pIndex->aColExpr = pList; + pList = 0; + } + for(i=0; inKeyCol; i++, pListItem++){ Expr *pCExpr; /* The i-th index expression */ int requestedSortOrder; /* ASC or DESC on the i-th expression */ const char *zColl; /* Collation sequence name */ @@ -106348,12 +109254,8 @@ SQLITE_PRIVATE void sqlite3CreateIndex( goto exit_create_index; } if( pIndex->aColExpr==0 ){ - ExprList *pCopy = sqlite3ExprListDup(db, pList, 0); - pIndex->aColExpr = pCopy; - if( !db->mallocFailed ){ - assert( pCopy!=0 ); - pListItem = &pCopy->a[i]; - } + pIndex->aColExpr = pList; + pList = 0; } j = XN_EXPR; pIndex->aiColumn[i] = XN_EXPR; @@ -106419,6 +109321,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( ** it as a covering index */ assert( HasRowid(pTab) || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 ); + recomputeColumnsNotIndexed(pIndex); if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ pIndex->isCovering = 1; for(j=0; jnCol; j++){ @@ -106491,98 +109394,101 @@ SQLITE_PRIVATE void sqlite3CreateIndex( } } - /* Link the new Index structure to its table and to the other - ** in-memory database structures. - */ - assert( pParse->nErr==0 ); - if( db->init.busy ){ - Index *p; - assert( !IN_DECLARE_VTAB ); - assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); - p = sqlite3HashInsert(&pIndex->pSchema->idxHash, - pIndex->zName, pIndex); - if( p ){ - assert( p==pIndex ); /* Malloc must have failed */ - sqlite3OomFault(db); - goto exit_create_index; - } - db->mDbFlags |= DBFLAG_SchemaChange; - if( pTblName!=0 ){ - pIndex->tnum = db->init.newTnum; - } - } + if( !IN_RENAME_OBJECT ){ - /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the - ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then - ** emit code to allocate the index rootpage on disk and make an entry for - ** the index in the sqlite_master table and populate the index with - ** content. But, do not do this if we are simply reading the sqlite_master - ** table to parse the schema, or if this index is the PRIMARY KEY index - ** of a WITHOUT ROWID table. - ** - ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY - ** or UNIQUE index in a CREATE TABLE statement. Since the table - ** has just been created, it contains no data and the index initialization - ** step can be skipped. - */ - else if( HasRowid(pTab) || pTblName!=0 ){ - Vdbe *v; - char *zStmt; - int iMem = ++pParse->nMem; - - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto exit_create_index; - - sqlite3BeginWriteOperation(pParse, 1, iDb); - - /* Create the rootpage for the index using CreateIndex. But before - ** doing so, code a Noop instruction and store its address in - ** Index.tnum. This is required in case this index is actually a - ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In - ** that case the convertToWithoutRowidTable() routine will replace - ** the Noop with a Goto to jump over the VDBE code generated below. */ - pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); - sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); - - /* Gather the complete text of the CREATE INDEX statement into - ** the zStmt variable + /* Link the new Index structure to its table and to the other + ** in-memory database structures. */ - if( pStart ){ - int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; - if( pName->z[n-1]==';' ) n--; - /* A named index with an explicit CREATE INDEX statement */ - zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", - onError==OE_None ? "" : " UNIQUE", n, pName->z); - }else{ - /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ - /* zStmt = sqlite3MPrintf(""); */ - zStmt = 0; + assert( pParse->nErr==0 ); + if( db->init.busy ){ + Index *p; + assert( !IN_SPECIAL_PARSE ); + assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); + p = sqlite3HashInsert(&pIndex->pSchema->idxHash, + pIndex->zName, pIndex); + if( p ){ + assert( p==pIndex ); /* Malloc must have failed */ + sqlite3OomFault(db); + goto exit_create_index; + } + db->mDbFlags |= DBFLAG_SchemaChange; + if( pTblName!=0 ){ + pIndex->tnum = db->init.newTnum; + } } - /* Add an entry in sqlite_master for this index + /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the + ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then + ** emit code to allocate the index rootpage on disk and make an entry for + ** the index in the sqlite_master table and populate the index with + ** content. But, do not do this if we are simply reading the sqlite_master + ** table to parse the schema, or if this index is the PRIMARY KEY index + ** of a WITHOUT ROWID table. + ** + ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY + ** or UNIQUE index in a CREATE TABLE statement. Since the table + ** has just been created, it contains no data and the index initialization + ** step can be skipped. */ - sqlite3NestedParse(pParse, - "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", - db->aDb[iDb].zDbSName, MASTER_NAME, - pIndex->zName, - pTab->zName, - iMem, - zStmt - ); - sqlite3DbFree(db, zStmt); + else if( HasRowid(pTab) || pTblName!=0 ){ + Vdbe *v; + char *zStmt; + int iMem = ++pParse->nMem; - /* Fill the index with data and reparse the schema. Code an OP_Expire - ** to invalidate all pre-compiled statements. - */ - if( pTblName ){ - sqlite3RefillIndex(pParse, pIndex, iMem); - sqlite3ChangeCookie(pParse, iDb); - sqlite3VdbeAddParseSchemaOp(v, iDb, - sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); - sqlite3VdbeAddOp0(v, OP_Expire); + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto exit_create_index; + + sqlite3BeginWriteOperation(pParse, 1, iDb); + + /* Create the rootpage for the index using CreateIndex. But before + ** doing so, code a Noop instruction and store its address in + ** Index.tnum. This is required in case this index is actually a + ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In + ** that case the convertToWithoutRowidTable() routine will replace + ** the Noop with a Goto to jump over the VDBE code generated below. */ + pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); + sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); + + /* Gather the complete text of the CREATE INDEX statement into + ** the zStmt variable + */ + if( pStart ){ + int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; + if( pName->z[n-1]==';' ) n--; + /* A named index with an explicit CREATE INDEX statement */ + zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", + onError==OE_None ? "" : " UNIQUE", n, pName->z); + }else{ + /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ + /* zStmt = sqlite3MPrintf(""); */ + zStmt = 0; + } + + /* Add an entry in sqlite_master for this index + */ + sqlite3NestedParse(pParse, + "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", + db->aDb[iDb].zDbSName, MASTER_NAME, + pIndex->zName, + pTab->zName, + iMem, + zStmt + ); + sqlite3DbFree(db, zStmt); + + /* Fill the index with data and reparse the schema. Code an OP_Expire + ** to invalidate all pre-compiled statements. + */ + if( pTblName ){ + sqlite3RefillIndex(pParse, pIndex, iMem); + sqlite3ChangeCookie(pParse, iDb); + sqlite3VdbeAddParseSchemaOp(v, iDb, + sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); + sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); + } + + sqlite3VdbeJumpHere(v, pIndex->tnum); } - - sqlite3VdbeJumpHere(v, pIndex->tnum); } /* When adding an index to the list of indices for a table, make @@ -106606,10 +109512,15 @@ SQLITE_PRIVATE void sqlite3CreateIndex( } pIndex = 0; } + else if( IN_RENAME_OBJECT ){ + assert( pParse->pNewIndex==0 ); + pParse->pNewIndex = pIndex; + pIndex = 0; + } /* Clean up before exiting */ exit_create_index: - if( pIndex ) freeIndex(db, pIndex); + if( pIndex ) sqlite3FreeIndex(db, pIndex); sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); @@ -106778,7 +109689,8 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( ** ** A new IdList is returned, or NULL if malloc() fails. */ -SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){ +SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){ + sqlite3 *db = pParse->db; int i; if( pList==0 ){ pList = sqlite3DbMallocZero(db, sizeof(IdList) ); @@ -106796,6 +109708,9 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pT return 0; } pList->a[i].zName = sqlite3NameFromToken(db, pToken); + if( IN_RENAME_OBJECT && pList->a[i].zName ){ + sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken); + } return pList; } @@ -107042,6 +109957,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( } assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; + assert( (pTable==0)==(pDatabase==0) ); + assert( pItem->zName==0 || pDatabase!=0 ); + if( IN_RENAME_OBJECT && pItem->zName ){ + Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable; + sqlite3RenameTokenMap(pParse, pItem->zName, pToken); + } assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); @@ -107352,16 +110273,16 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); if( pIdx->aColExpr ){ - sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName); + sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName); }else{ for(j=0; jnKeyCol; j++){ char *zCol; assert( pIdx->aiColumn[j]>=0 ); zCol = pTab->aCol[pIdx->aiColumn[j]].zName; - if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); - sqlite3StrAccumAppendAll(&errMsg, pTab->zName); - sqlite3StrAccumAppend(&errMsg, ".", 1); - sqlite3StrAccumAppendAll(&errMsg, zCol); + if( j ) sqlite3_str_append(&errMsg, ", ", 2); + sqlite3_str_appendall(&errMsg, pTab->zName); + sqlite3_str_append(&errMsg, ".", 1); + sqlite3_str_appendall(&errMsg, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); @@ -107936,6 +110857,21 @@ static FuncDef *functionSearch( } return 0; } +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE FuncDef *sqlite3FunctionSearchN( + int h, /* Hash of the name */ + const char *zFunc, /* Name of function */ + int nFunc /* Length of the name */ +){ + FuncDef *p; + for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ + if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 ){ + return p; + } + } + return 0; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ /* ** Insert a new FuncDef into a FuncDefHash hash table. @@ -107949,7 +110885,7 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( FuncDef *pOther; const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); - int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ; + int h = SQLITE_FUNC_HASH(zName[0], nName); assert( zName[0]>='a' && zName[0]<='z' ); pOther = functionSearch(h, zName); if( pOther ){ @@ -108028,7 +110964,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( */ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){ bestScore = 0; - h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; + h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName); p = functionSearch(h, zName); while( p ){ int score = matchQuality(p, nArg, enc); @@ -108047,10 +110983,12 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( if( createFlag && bestScorezName = (const char*)&pBest[1]; pBest->nArg = (u16)nArg; pBest->funcFlags = enc; memcpy((char*)&pBest[1], zName, nName+1); + for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z]; pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest); if( pOther==pBest ){ sqlite3DbFree(db, pBest); @@ -108174,32 +111112,49 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ return pTab; } +/* Return true if table pTab is read-only. +** +** A table is read-only if any of the following are true: +** +** 1) It is a virtual table and no implementation of the xUpdate method +** has been provided +** +** 2) It is a system table (i.e. sqlite_master), this call is not +** part of a nested parse and writable_schema pragma has not +** been specified +** +** 3) The table is a shadow table, the database connection is in +** defensive mode, and the current sqlite3_prepare() +** is for a top-level SQL statement. +*/ +static int tabIsReadOnly(Parse *pParse, Table *pTab){ + sqlite3 *db; + if( IsVirtual(pTab) ){ + return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0; + } + if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0; + db = pParse->db; + if( (pTab->tabFlags & TF_Readonly)!=0 ){ + return sqlite3WritableSchema(db)==0 && pParse->nested==0; + } + assert( pTab->tabFlags & TF_Shadow ); + return (db->flags & SQLITE_Defensive)!=0 +#ifndef SQLITE_OMIT_VIRTUALTABLE + && db->pVtabCtx==0 +#endif + && db->nVdbeExec==0; +} + /* ** Check to make sure the given table is writable. If it is not ** writable, generate an error message and return 1. If it is ** writable return 0; */ SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ - /* A table is not writable under the following circumstances: - ** - ** 1) It is a virtual table and no implementation of the xUpdate method - ** has been provided, or - ** 2) It is a system table (i.e. sqlite_master), this call is not - ** part of a nested parse and writable_schema pragma has not - ** been specified. - ** - ** In either case leave an error message in pParse and return non-zero. - */ - if( ( IsVirtual(pTab) - && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ) - || ( (pTab->tabFlags & TF_Readonly)!=0 - && (pParse->db->flags & SQLITE_WriteSchema)==0 - && pParse->nested==0 ) - ){ + if( tabIsReadOnly(pParse, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } - #ifndef SQLITE_OMIT_VIEW if( !viewOk && pTab->pSelect ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); @@ -108368,7 +111323,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( AuthContext sContext; /* Authorization context */ NameContext sNC; /* Name context to resolve expressions in */ int iDb; /* Database number */ - int memCnt = -1; /* Memory cell used for change counting */ + int memCnt = 0; /* Memory cell used for change counting */ int rcauth; /* Value returned by authorization callback */ int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ @@ -108473,7 +111428,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( goto delete_from_cleanup; } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, 1, iDb); + sqlite3BeginWriteOperation(pParse, bComplex, iDb); /* If we are trying to delete from a view, realize that view into ** an ephemeral table. @@ -108501,7 +111456,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( /* Initialize the counter of the number of rows deleted, if ** we are counting rows. */ - if( db->flags & SQLITE_CountRows ){ + if( (db->flags & SQLITE_CountRows)!=0 + && !pParse->nested + && !pParse->pTriggerTab + ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); } @@ -108529,7 +111487,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( assert( !isView ); sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); if( HasRowid(pTab) ){ - sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt, + sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1, pTab->zName, P4_STATIC); } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ @@ -108574,9 +111532,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); + if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); /* Keep track of the number of rows to be deleted */ - if( db->flags & SQLITE_CountRows ){ + if( memCnt ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } @@ -108589,9 +111548,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( } iKey = iPk; }else{ - iKey = pParse->nMem + 1; - iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0); - if( iKey>pParse->nMem ) pParse->nMem = iKey; + iKey = ++pParse->nMem; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey); } if( eOnePass!=ONEPASS_OFF ){ @@ -108679,13 +111637,16 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); - sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); - sqlite3VdbeChangeP5(v, OE_Abort); assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); sqlite3MayAbort(pParse); - if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){ - pParse->isMultiWrite = 0; + if( eOnePass==ONEPASS_SINGLE ){ + sqlite3VdbeAddOp1(v, OP_Close, iTabCur); + if( sqlite3IsToplevel(pParse) ){ + pParse->isMultiWrite = 0; + } } + sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); + sqlite3VdbeChangeP5(v, OE_Abort); }else #endif { @@ -108719,7 +111680,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ - if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ + if( memCnt ){ sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC); @@ -109021,7 +111982,6 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iSelfTab = iDataCur + 1; - sqlite3ExprCachePush(pParse); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); pParse->iSelfTab = 0; @@ -109068,7 +112028,6 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ if( iLabel ){ sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); - sqlite3ExprCachePop(pParse); } } @@ -109327,7 +112286,7 @@ static void printfFunc( x.apArg = argv+1; sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); str.printfFlags = SQLITE_PRINTF_SQLFUNC; - sqlite3XPrintf(&str, zFormat, &x); + sqlite3_str_appendf(&str, zFormat, &x); n = str.nChar; sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, SQLITE_DYNAMIC); @@ -110581,7 +113540,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ i64 v = sqlite3_value_int64(argv[0]); p->rSum += v; if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){ - p->overflow = 1; + p->approx = p->overflow = 1; } }else{ p->rSum += sqlite3_value_double(argv[0]); @@ -110589,6 +113548,32 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ } } } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){ + SumCtx *p; + int type; + assert( argc==1 ); + UNUSED_PARAMETER(argc); + p = sqlite3_aggregate_context(context, sizeof(*p)); + type = sqlite3_value_numeric_type(argv[0]); + /* p is always non-NULL because sumStep() will have been called first + ** to initialize it */ + if( ALWAYS(p) && type!=SQLITE_NULL ){ + assert( p->cnt>0 ); + p->cnt--; + assert( type==SQLITE_INTEGER || p->approx ); + if( type==SQLITE_INTEGER && p->approx==0 ){ + i64 v = sqlite3_value_int64(argv[0]); + p->rSum -= v; + p->iSum -= v; + }else{ + p->rSum -= sqlite3_value_double(argv[0]); + } + } +} +#else +# define sumInverse 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ static void sumFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); @@ -110623,6 +113608,9 @@ static void totalFinalize(sqlite3_context *context){ typedef struct CountCtx CountCtx; struct CountCtx { i64 n; +#ifdef SQLITE_DEBUG + int bInverse; /* True if xInverse() ever called */ +#endif }; /* @@ -110640,7 +113628,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){ ** sure it still operates correctly, verify that its count agrees with our ** internal count when using count(*) and when the total count can be ** expressed as a 32-bit integer. */ - assert( argc==1 || p==0 || p->n>0x7fffffff + assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse || p->n==sqlite3_aggregate_count(context) ); #endif } @@ -110649,6 +113637,21 @@ static void countFinalize(sqlite3_context *context){ p = sqlite3_aggregate_context(context, 0); sqlite3_result_int64(context, p ? p->n : 0); } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){ + CountCtx *p; + p = sqlite3_aggregate_context(ctx, sizeof(*p)); + /* p is always non-NULL since countStep() will have been called first */ + if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){ + p->n--; +#ifdef SQLITE_DEBUG + p->bInverse = 1; +#endif + } +} +#else +# define countInverse 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** Routines to implement min() and max() aggregate functions. @@ -110665,7 +113668,7 @@ static void minmaxStep( pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest)); if( !pBest ) return; - if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + if( sqlite3_value_type(pArg)==SQLITE_NULL ){ if( pBest->flags ) sqlite3SkipAccumulatorLoad(context); }else if( pBest->flags ){ int max; @@ -110691,16 +113694,26 @@ static void minmaxStep( sqlite3VdbeMemCopy(pBest, pArg); } } -static void minMaxFinalize(sqlite3_context *context){ +static void minMaxValueFinalize(sqlite3_context *context, int bValue){ sqlite3_value *pRes; pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); if( pRes ){ if( pRes->flags ){ sqlite3_result_value(context, pRes); } - sqlite3VdbeMemRelease(pRes); + if( bValue==0 ) sqlite3VdbeMemRelease(pRes); } } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void minMaxValue(sqlite3_context *context){ + minMaxValueFinalize(context, 1); +} +#else +# define minMaxValue 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ +static void minMaxFinalize(sqlite3_context *context){ + minMaxValueFinalize(context, 0); +} /* ** group_concat(EXPR, ?SEPARATOR?) @@ -110730,20 +113743,52 @@ static void groupConcatStep( zSep = ","; nSep = 1; } - if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep); + if( zSep ) sqlite3_str_append(pAccum, zSep, nSep); } zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); - if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal); + if( zVal ) sqlite3_str_append(pAccum, zVal, nVal); } } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void groupConcatInverse( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int n; + StrAccum *pAccum; + assert( argc==1 || argc==2 ); + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); + /* pAccum is always non-NULL since groupConcatStep() will have always + ** run frist to initialize it */ + if( ALWAYS(pAccum) ){ + n = sqlite3_value_bytes(argv[0]); + if( argc==2 ){ + n += sqlite3_value_bytes(argv[1]); + }else{ + n++; + } + if( n>=(int)pAccum->nChar ){ + pAccum->nChar = 0; + }else{ + pAccum->nChar -= n; + memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar); + } + if( pAccum->nChar==0 ) pAccum->mxAlloc = 0; + } +} +#else +# define groupConcatInverse 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ static void groupConcatFinalize(sqlite3_context *context){ StrAccum *pAccum; pAccum = sqlite3_aggregate_context(context, 0); if( pAccum ){ - if( pAccum->accError==STRACCUM_TOOBIG ){ + if( pAccum->accError==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(context); - }else if( pAccum->accError==STRACCUM_NOMEM ){ + }else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1, @@ -110751,6 +113796,24 @@ static void groupConcatFinalize(sqlite3_context *context){ } } } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void groupConcatValue(sqlite3_context *context){ + sqlite3_str *pAccum; + pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0); + if( pAccum ){ + if( pAccum->accError==SQLITE_TOOBIG ){ + sqlite3_result_error_toobig(context); + }else if( pAccum->accError==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(context); + }else{ + const char *zText = sqlite3_str_value(pAccum); + sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); + } + } +} +#else +# define groupConcatValue 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** This routine does per-connection function registration. Most @@ -110788,10 +113851,10 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) }else{ pInfo = (struct compareInfo*)&likeInfoNorm; } - sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0); - sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0); + sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); + sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, - (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0); + (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0, 0, 0); setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); setLikeOptFlag(db, "like", caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); @@ -110900,11 +113963,11 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(trim, 2, 3, 0, trimFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), - AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize, + WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), - AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize, + WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), @@ -110935,14 +113998,17 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), - AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), - AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), - AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), - AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, - SQLITE_FUNC_COUNT ), - AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), - AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), - AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), + WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0), + WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), + WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), + WAGGREGATE(count, 0,0,0, countStep, + countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ), + WAGGREGATE(count, 1,0,0, countStep, + countFinalize, countFinalize, countInverse, 0 ), + WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, + groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), + WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, + groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE @@ -110962,6 +114028,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); #endif + sqlite3WindowFunctions(); #if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4) sqlite3AnalyzeFunctions(); #endif @@ -111320,6 +114387,12 @@ static void fkLookupParent( int iCur = pParse->nTab - 1; /* Cursor number to use */ int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */ + sqlite3VdbeVerifyAbortable(v, + (!pFKey->isDeferred + && !(pParse->db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel + && !pParse->isMultiWrite) ? OE_Abort : OE_Ignore); + /* If nIncr is less than zero, then check at runtime if there are any ** outstanding constraints to resolve. If there are not, there is no need ** to check if deleting this row resolves any outstanding violations. @@ -111485,7 +114558,7 @@ static Expr *exprTableColumn( ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ - pExpr->pTab = pTab; + pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; } @@ -111693,11 +114766,12 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ */ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; - if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){ + if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ + assert( pTab->pSelect==0 ); /* Not a view */ if( sqlite3FkReferences(pTab)==0 ){ /* Search for a deferred foreign key constraint for which this table ** is the child table. If one cannot be found, return without @@ -111727,6 +114801,7 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa ** constraints are violated. */ if( (db->flags & SQLITE_DeferFKs)==0 ){ + sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, @@ -112559,7 +115634,8 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB ); pTab->zColAff = zColAff; } - i = sqlite3Strlen30(zColAff); + assert( zColAff!=0 ); + i = sqlite3Strlen30NN(zColAff); if( i ){ if( iReg ){ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); @@ -112639,11 +115715,26 @@ static int autoIncBegin( Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ + assert( pParse->db->aDb[iDb].pSchema!=0 ); if( (pTab->tabFlags & TF_Autoincrement)!=0 && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; + Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab; + + /* Verify that the sqlite_sequence table exists and is an ordinary + ** rowid table with exactly two columns. + ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ + if( pSeqTab==0 + || !HasRowid(pSeqTab) + || IsVirtual(pSeqTab) + || pSeqTab->nCol!=2 + ){ + pParse->nErr++; + pParse->rc = SQLITE_CORRUPT_SEQUENCE; + return 0; + } pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } @@ -112901,7 +115992,8 @@ SQLITE_PRIVATE void sqlite3Insert( SrcList *pTabList, /* Name of table into which we are inserting */ Select *pSelect, /* A SELECT statement to use as the data source */ IdList *pColumn, /* Column names corresponding to IDLIST. */ - int onError /* How to handle constraint errors */ + int onError, /* How to handle constraint errors */ + Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */ ){ sqlite3 *db; /* The main database structure */ Table *pTab; /* The table to insert into. aka TABLE */ @@ -113196,7 +116288,10 @@ SQLITE_PRIVATE void sqlite3Insert( /* Initialize the count of rows to be inserted */ - if( db->flags & SQLITE_CountRows ){ + if( (db->flags & SQLITE_CountRows)!=0 + && !pParse->nested + && !pParse->pTriggerTab + ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } @@ -113216,6 +116311,19 @@ SQLITE_PRIVATE void sqlite3Insert( pParse->nMem += pIdx->nColumn; } } +#ifndef SQLITE_OMIT_UPSERT + if( pUpsert ){ + pTabList->a[0].iCursor = iDataCur; + pUpsert->pUpsertSrc = pTabList; + pUpsert->regData = regData; + pUpsert->iDataCur = iDataCur; + pUpsert->iIdxCur = iIdxCur; + if( pUpsert->pUpsertTarget ){ + sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert); + } + } +#endif + /* This is the top of the main insertion loop */ if( useTempTable ){ @@ -113418,7 +116526,7 @@ SQLITE_PRIVATE void sqlite3Insert( int isReplace; /* Set to true if constraints may cause a replace */ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, - regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0 + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert ); sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); @@ -113441,7 +116549,7 @@ SQLITE_PRIVATE void sqlite3Insert( /* Update the count of rows that are inserted */ - if( (db->flags & SQLITE_CountRows)!=0 ){ + if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } @@ -113478,7 +116586,7 @@ insert_end: ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ - if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ + if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC); @@ -113487,6 +116595,7 @@ insert_end: insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); + sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); sqlite3DbFree(db, aRegIdx); @@ -113506,14 +116615,15 @@ insert_cleanup: #endif /* -** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged() +** Meanings of bits in of pWalker->eCode for +** sqlite3ExprReferencesUpdatedColumn() */ #define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */ #define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */ -/* This is the Walker callback from checkConstraintUnchanged(). Set -** bit 0x01 of pWalker->eCode if -** pWalker->eCode to 0 if this expression node references any of the +/* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn(). +* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this +** expression node references any of the ** columns that are being modifed by an UPDATE statement. */ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ @@ -113535,12 +116645,21 @@ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ ** only columns that are modified by the UPDATE are those for which ** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true. ** -** Return true if CHECK constraint pExpr does not use any of the +** Return true if CHECK constraint pExpr uses any of the ** changing columns (or the rowid if it is changing). In other words, -** return true if this CHECK constraint can be skipped when validating +** return true if this CHECK constraint must be validated for ** the new row in the UPDATE statement. +** +** 2018-09-15: pExpr might also be an expression for an index-on-expressions. +** The operation of this routine is the same - return true if an only if +** the expression uses one or more of columns identified by the second and +** third arguments. */ -static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ +SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn( + Expr *pExpr, /* The expression to be checked */ + int *aiChng, /* aiChng[x]>=0 if column x changed by the UPDATE */ + int chngRowid /* True if UPDATE changes the rowid */ +){ Walker w; memset(&w, 0, sizeof(w)); w.eCode = 0; @@ -113555,7 +116674,7 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ testcase( w.eCode==CKCNSTRNT_COLUMN ); testcase( w.eCode==CKCNSTRNT_ROWID ); testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); - return !w.eCode; + return w.eCode!=0; } /* @@ -113653,7 +116772,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( u8 overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ - int *aiChng /* column i is unchanged if aiChng[i]<0 */ + int *aiChng, /* column i is unchanged if aiChng[i]<0 */ + Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */ ){ Vdbe *v; /* VDBE under constrution */ Index *pIdx; /* Pointer to one of the indices */ @@ -113666,10 +116786,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int addr1; /* Address of jump instruction */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ - int ipkTop = 0; /* Top of the rowid change constraint check */ - int ipkBottom = 0; /* Bottom of the rowid change constraint check */ + Index *pUpIdx = 0; /* Index to which to apply the upsert */ u8 isUpdate; /* True if this is an UPDATE operation */ u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ + int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */ + int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */ + int ipkTop = 0; /* Top of the IPK uniqueness check */ + int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */ isUpdate = regOldData!=0; db = pParse->db; @@ -113757,8 +116880,15 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( for(i=0; inExpr; i++){ int allOk; Expr *pExpr = pCheck->a[i].pExpr; - if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue; + if( aiChng + && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng) + ){ + /* The check constraints do not reference any of the columns being + ** updated so there is no point it verifying the check constraint */ + continue; + } allOk = sqlite3VdbeMakeLabel(v); + sqlite3VdbeVerifyAbortable(v, onError); sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); @@ -113776,6 +116906,50 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } #endif /* !defined(SQLITE_OMIT_CHECK) */ + /* UNIQUE and PRIMARY KEY constraints should be handled in the following + ** order: + ** + ** (1) OE_Update + ** (2) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore + ** (3) OE_Replace + ** + ** OE_Fail and OE_Ignore must happen before any changes are made. + ** OE_Update guarantees that only a single row will change, so it + ** must happen before OE_Replace. Technically, OE_Abort and OE_Rollback + ** could happen in any order, but they are grouped up front for + ** convenience. + ** + ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43 + ** The order of constraints used to have OE_Update as (2) and OE_Abort + ** and so forth as (1). But apparently PostgreSQL checks the OE_Update + ** constraint before any others, so it had to be moved. + ** + ** Constraint checking code is generated in this order: + ** (A) The rowid constraint + ** (B) Unique index constraints that do not have OE_Replace as their + ** default conflict resolution strategy + ** (C) Unique index that do use OE_Replace by default. + ** + ** The ordering of (2) and (3) is accomplished by making sure the linked + ** list of indexes attached to a table puts all OE_Replace indexes last + ** in the list. See sqlite3CreateIndex() for where that happens. + */ + + if( pUpsert ){ + if( pUpsert->pUpsertTarget==0 ){ + /* An ON CONFLICT DO NOTHING clause, without a constraint-target. + ** Make all unique constraint resolution be OE_Ignore */ + assert( pUpsert->pUpsertSet==0 ); + overrideError = OE_Ignore; + pUpsert = 0; + }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){ + /* If the constraint-target uniqueness check must be run first. + ** Jump to that uniqueness check now */ + upsertJump = sqlite3VdbeAddOp0(v, OP_Goto); + VdbeComment((v, "UPSERT constraint goes first")); + } + } + /* If rowid is changing, make sure the new rowid does not previously ** exist in the table. */ @@ -113790,6 +116964,28 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( onError = OE_Abort; } + /* figure out whether or not upsert applies in this case */ + if( pUpsert && pUpsert->pUpsertIdx==0 ){ + if( pUpsert->pUpsertSet==0 ){ + onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ + }else{ + onError = OE_Update; /* DO UPDATE */ + } + } + + /* If the response to a rowid conflict is REPLACE but the response + ** to some other UNIQUE constraint is FAIL or IGNORE, then we need + ** to defer the running of the rowid conflict checking until after + ** the UNIQUE constraints have run. + */ + if( onError==OE_Replace /* IPK rule is REPLACE */ + && onError!=overrideError /* Rules for other contraints are different */ + && pTab->pIndex /* There exist other constraints */ + ){ + ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; + VdbeComment((v, "defer IPK REPLACE until last")); + } + if( isUpdate ){ /* pkChng!=0 does not mean that the rowid has changed, only that ** it might have changed. Skip the conflict logic below if the rowid @@ -113799,26 +116995,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( VdbeCoverage(v); } - /* If the response to a rowid conflict is REPLACE but the response - ** to some other UNIQUE constraint is FAIL or IGNORE, then we need - ** to defer the running of the rowid conflict checking until after - ** the UNIQUE constraints have run. - */ - if( onError==OE_Replace && overrideError!=OE_Replace ){ - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->onError==OE_Ignore || pIdx->onError==OE_Fail ){ - ipkTop = sqlite3VdbeAddOp0(v, OP_Goto); - break; - } - } - } - /* Check to see if the new rowid already exists in the table. Skip ** the following conflict logic if it does not. */ + VdbeNoopComment((v, "uniqueness check for ROWID")); + sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); - /* Generate code that deals with a rowid collision */ switch( onError ){ default: { onError = OE_Abort; @@ -113827,6 +117010,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( case OE_Rollback: case OE_Abort: case OE_Fail: { + testcase( onError==OE_Rollback ); + testcase( onError==OE_Abort ); + testcase( onError==OE_Fail ); sqlite3RowidConstraint(pParse, onError, pTab); break; } @@ -113863,14 +117049,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( regNewData, 1, 0, OE_Replace, 1, -1); }else{ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK - if( HasRowid(pTab) ){ - /* This OP_Delete opcode fires the pre-update-hook only. It does - ** not modify the b-tree. It is more efficient to let the coming - ** OP_Insert replace the existing entry than it is to delete the - ** existing entry and then insert a new one. */ - sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP); - sqlite3VdbeAppendP4(v, pTab, P4_TABLE); - } + assert( HasRowid(pTab) ); + /* This OP_Delete opcode fires the pre-update-hook only. It does + ** not modify the b-tree. It is more efficient to let the coming + ** OP_Insert replace the existing entry than it is to delete the + ** existing entry and then insert a new one. */ + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ if( pTab->pIndex ){ sqlite3MultiWrite(pParse); @@ -113880,8 +117065,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( seenReplace = 1; break; } +#ifndef SQLITE_OMIT_UPSERT + case OE_Update: { + sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur); + /* Fall through */ + } +#endif case OE_Ignore: { - /*assert( seenReplace==0 );*/ + testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } @@ -113889,7 +117080,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( sqlite3VdbeResolveLabel(v, addrRowidOk); if( ipkTop ){ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); - sqlite3VdbeJumpHere(v, ipkTop); + sqlite3VdbeJumpHere(v, ipkTop-1); } } @@ -113907,12 +117098,21 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ - if( bAffinityDone==0 ){ + if( pUpIdx==pIdx ){ + addrUniqueOk = upsertJump+1; + upsertBypass = sqlite3VdbeGoto(v, 0); + VdbeComment((v, "Skip upsert subroutine")); + sqlite3VdbeJumpHere(v, upsertJump); + }else{ + addrUniqueOk = sqlite3VdbeMakeLabel(v); + } + if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } + VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName)); iThisCur = iIdxCur+ix; - addrUniqueOk = sqlite3VdbeMakeLabel(v); + /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ @@ -113972,6 +117172,15 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( onError = OE_Abort; } + /* Figure out if the upsert clause applies to this index */ + if( pUpIdx==pIdx ){ + if( pUpsert->pUpsertSet==0 ){ + onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ + }else{ + onError = OE_Update; /* DO UPDATE */ + } + } + /* Collision detection may be omitted if all of the following are true: ** (1) The conflict resolution algorithm is REPLACE ** (2) The table is a WITHOUT ROWID table @@ -113992,7 +117201,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( } /* Check to see if the new index entry will be unique */ - sqlite3ExprCachePush(pParse); + sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, regIdx, pIdx->nKeyCol); VdbeCoverage(v); @@ -114054,25 +117263,37 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail - || onError==OE_Ignore || onError==OE_Replace ); + || onError==OE_Ignore || onError==OE_Replace || onError==OE_Update ); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { + testcase( onError==OE_Rollback ); + testcase( onError==OE_Abort ); + testcase( onError==OE_Fail ); sqlite3UniqueConstraint(pParse, onError, pIdx); break; } +#ifndef SQLITE_OMIT_UPSERT + case OE_Update: { + sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix); + /* Fall through */ + } +#endif case OE_Ignore: { + testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } default: { Trigger *pTrigger = 0; assert( onError==OE_Replace ); - sqlite3MultiWrite(pParse); if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } + if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ + sqlite3MultiWrite(pParse); + } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); @@ -114080,15 +117301,22 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( break; } } - sqlite3VdbeResolveLabel(v, addrUniqueOk); - sqlite3ExprCachePop(pParse); + if( pUpIdx==pIdx ){ + sqlite3VdbeGoto(v, upsertJump+1); + sqlite3VdbeJumpHere(v, upsertBypass); + }else{ + sqlite3VdbeResolveLabel(v, addrUniqueOk); + } if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); } + + /* If the IPK constraint is a REPLACE, run it last */ if( ipkTop ){ sqlite3VdbeGoto(v, ipkTop+1); + VdbeComment((v, "Do IPK REPLACE")); sqlite3VdbeJumpHere(v, ipkBottom); } - + *pbMayReplace = seenReplace; VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } @@ -114184,7 +117412,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); - sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); } if( pParse->nested ){ pik_flags = 0; @@ -114587,6 +117814,7 @@ static int xferOptimization( emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); + sqlite3VdbeVerifyAbortable(v, onError); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); VdbeCoverage(v); sqlite3RowidConstraint(pParse, onError, pDest); @@ -115144,6 +118372,30 @@ struct sqlite3_api_routines { int (*vtab_nochange)(sqlite3_context*); int (*value_nochange)(sqlite3_value*); const char *(*vtab_collation)(sqlite3_index_info*,int); + /* Version 3.24.0 and later */ + int (*keyword_count)(void); + int (*keyword_name)(int,const char**,int*); + int (*keyword_check)(const char*,int); + sqlite3_str *(*str_new)(sqlite3*); + char *(*str_finish)(sqlite3_str*); + void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); + void (*str_append)(sqlite3_str*, const char *zIn, int N); + void (*str_appendall)(sqlite3_str*, const char *zIn); + void (*str_appendchar)(sqlite3_str*, int N, char C); + void (*str_reset)(sqlite3_str*); + int (*str_errcode)(sqlite3_str*); + int (*str_length)(sqlite3_str*); + char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ + int (*create_window_function)(sqlite3*,const char*,int,int,void*, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInv)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); }; /* @@ -115414,6 +118666,25 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_vtab_nochange sqlite3_api->vtab_nochange #define sqlite3_value_nochange sqlite3_api->value_nochange #define sqlite3_vtab_collation sqlite3_api->vtab_collation +/* Version 3.24.0 and later */ +#define sqlite3_keyword_count sqlite3_api->keyword_count +#define sqlite3_keyword_name sqlite3_api->keyword_name +#define sqlite3_keyword_check sqlite3_api->keyword_check +#define sqlite3_str_new sqlite3_api->str_new +#define sqlite3_str_finish sqlite3_api->str_finish +#define sqlite3_str_appendf sqlite3_api->str_appendf +#define sqlite3_str_vappendf sqlite3_api->str_vappendf +#define sqlite3_str_append sqlite3_api->str_append +#define sqlite3_str_appendall sqlite3_api->str_appendall +#define sqlite3_str_appendchar sqlite3_api->str_appendchar +#define sqlite3_str_reset sqlite3_api->str_reset +#define sqlite3_str_errcode sqlite3_api->str_errcode +#define sqlite3_str_length sqlite3_api->str_length +#define sqlite3_str_value sqlite3_api->str_value +/* Version 3.25.0 and later */ +#define sqlite3_create_window_function sqlite3_api->create_window_function +/* Version 3.26.0 and later */ +#define sqlite3_normalized_sql sqlite3_api->normalized_sql #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -115502,6 +118773,7 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_declare_vtab 0 # define sqlite3_vtab_config 0 # define sqlite3_vtab_on_conflict 0 +# define sqlite3_vtab_collation 0 #endif #ifdef SQLITE_OMIT_SHARED_CACHE @@ -115852,7 +119124,30 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.22.0 and later */ sqlite3_vtab_nochange, sqlite3_value_nochange, - sqlite3_vtab_collation + sqlite3_vtab_collation, + /* Version 3.24.0 and later */ + sqlite3_keyword_count, + sqlite3_keyword_name, + sqlite3_keyword_check, + sqlite3_str_new, + sqlite3_str_finish, + sqlite3_str_appendf, + sqlite3_str_vappendf, + sqlite3_str_append, + sqlite3_str_appendall, + sqlite3_str_appendchar, + sqlite3_str_reset, + sqlite3_str_errcode, + sqlite3_str_length, + sqlite3_str_value, + /* Version 3.25.0 and later */ + sqlite3_create_window_function, + /* Version 3.26.0 and later */ +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3_normalized_sql +#else + 0 +#endif }; /* @@ -115918,10 +119213,8 @@ static int sqlite3LoadExtension( #if SQLITE_OS_UNIX || SQLITE_OS_WIN for(ii=0; iiflags & pPragma->iArg)!=0 ); }else{ - int mask = pPragma->iArg; /* Mask of bits to set or clear. */ + u64 mask = pPragma->iArg; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ @@ -117963,15 +121276,17 @@ SQLITE_PRIVATE void sqlite3Pragma( Table *pTab; pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i, k; int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); - pParse->nMem = 6; - sqlite3CodeVerifySchema(pParse, iDb); + pParse->nMem = 7; + sqlite3CodeVerifySchema(pParse, iTabDb); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ - if( IsHiddenColumn(pCol) ){ + int isHidden = IsHiddenColumn(pCol); + if( isHidden && pPragma->iArg==0 ){ nHidden++; continue; } @@ -117983,13 +121298,14 @@ SQLITE_PRIVATE void sqlite3Pragma( for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN ); - sqlite3VdbeMultiLoad(v, 1, "issisi", + sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, pCol->zName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, pCol->pDflt ? pCol->pDflt->u.zToken : 0, - k); + k, + isHidden); } } } @@ -118027,6 +121343,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx ){ + int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema); int i; int mx; if( pPragma->iArg ){ @@ -118039,7 +121356,7 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem = 3; } pTab = pIdx->pTable; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iIdxDb); assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; iaiColumn[i]; @@ -118063,8 +121380,9 @@ SQLITE_PRIVATE void sqlite3Pragma( int i; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); pParse->nMem = 5; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iTabDb); for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ const char *azOrigin[] = { "c", "u", "pk" }; sqlite3VdbeMultiLoad(v, 1, "isisi", @@ -118111,6 +121429,7 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem = 2; for(i=0; iu.pHash ){ + if( p->funcFlags & SQLITE_FUNC_INTERNAL ) continue; sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1); } } @@ -118152,9 +121471,10 @@ SQLITE_PRIVATE void sqlite3Pragma( if( pTab ){ pFK = pTab->pFKey; if( pFK ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i = 0; pParse->nMem = 8; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iTabDb); while(pFK){ int j; for(j=0; jnCol; j++){ @@ -118199,9 +121519,9 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; - sqlite3CodeVerifySchema(pParse, iDb); k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ + int iTabDb; if( zRight ){ pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); k = 0; @@ -118210,21 +121530,23 @@ SQLITE_PRIVATE void sqlite3Pragma( k = sqliteHashNext(k); } if( pTab==0 || pTab->pFKey==0 ) continue; - sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); + sqlite3CodeVerifySchema(pParse, iTabDb); + sqlite3TableLock(pParse, iTabDb, pTab->tnum, 0, pTab->zName); if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; - sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); + sqlite3OpenTable(pParse, 0, iTabDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); if( pParent==0 ) continue; pIdx = 0; - sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); + sqlite3TableLock(pParse, iTabDb, pParent->tnum, 0, pParent->zName); x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); if( x==0 ){ if( pIdx==0 ){ - sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); + sqlite3OpenTable(pParse, i, iTabDb, pParent, OP_OpenRead); }else{ - sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); + sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iTabDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); } }else{ @@ -118427,7 +121749,6 @@ SQLITE_PRIVATE void sqlite3Pragma( if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); - sqlite3ExprCacheClear(pParse); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); /* reg[7] counts the number of entries in the table. @@ -118441,6 +121762,11 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( sqlite3NoTempsInRange(pParse,1,7+j) ); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); + if( !isQuick ){ + /* Sanity check on record header decoding */ + sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + } /* Verify that all NOT NULL columns really are NOT NULL */ for(j=0; jnCol; j++){ char *zErr; @@ -118465,7 +121791,6 @@ SQLITE_PRIVATE void sqlite3Pragma( char *zErr; int k; pParse->iSelfTab = iDataCur + 1; - sqlite3ExprCachePush(pParse); for(k=pCheck->nExpr-1; k>0; k--){ sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); } @@ -118478,14 +121803,10 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); integrityCheckResultRow(v); sqlite3VdbeResolveLabel(v, addrCkOk); - sqlite3ExprCachePop(pParse); } sqlite3ExprListDelete(db, pCheck); } if( !isQuick ){ /* Omit the remaining tests for quick_check */ - /* Sanity check on record header decoding */ - sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3); - sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4, jmp5; @@ -118994,12 +122315,24 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif #ifdef SQLITE_HAS_CODEC + /* Pragma iArg + ** ---------- ------ + ** key 0 + ** rekey 1 + ** hexkey 2 + ** hexrekey 3 + ** textkey 4 + ** textrekey 5 + */ case PragTyp_KEY: { - if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - break; - } - case PragTyp_REKEY: { - if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); + if( zRight ){ + int n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; + if( (pPragma->iArg & 1)==0 ){ + sqlite3_key_v2(db, zDb, zRight, n); + }else{ + sqlite3_rekey_v2(db, zDb, zRight, n); + } + } break; } case PragTyp_HEXKEY: { @@ -119011,7 +122344,7 @@ SQLITE_PRIVATE void sqlite3Pragma( iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); if( (i&1)!=0 ) zKey[i/2] = iByte; } - if( (zLeft[3] & 0xf)==0xb ){ + if( (pPragma->iArg & 1)==0 ){ sqlite3_key_v2(db, zDb, zKey, i/2); }else{ sqlite3_rekey_v2(db, zDb, zKey, i/2); @@ -119093,26 +122426,25 @@ static int pragmaVtabConnect( UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); - sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x"); + sqlite3_str_appendall(&acc, "CREATE TABLE x"); for(i=0, j=pPragma->iPragCName; inPragCName; i++, j++){ - sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]); + sqlite3_str_appendf(&acc, "%c\"%s\"", cSep, pragCName[j]); cSep = ','; } if( i==0 ){ - sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName); - cSep = ','; + sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName); i++; } j = 0; if( pPragma->mPragFlg & PragFlg_Result1 ){ - sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN"); + sqlite3_str_appendall(&acc, ",arg HIDDEN"); j++; } if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){ - sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN"); + sqlite3_str_appendall(&acc, ",schema HIDDEN"); j++; } - sqlite3StrAccumAppend(&acc, ")", 1); + sqlite3_str_append(&acc, ")", 1); sqlite3StrAccumFinish(&acc); assert( strlen(zBuf) < sizeof(zBuf)-1 ); rc = sqlite3_declare_vtab(db, zBuf); @@ -119264,13 +122596,13 @@ static int pragmaVtabFilter( } } sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]); - sqlite3StrAccumAppendAll(&acc, "PRAGMA "); + sqlite3_str_appendall(&acc, "PRAGMA "); if( pCsr->azArg[1] ){ - sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]); + sqlite3_str_appendf(&acc, "%Q.", pCsr->azArg[1]); } - sqlite3StrAccumAppendAll(&acc, pTab->pName->zName); + sqlite3_str_appendall(&acc, pTab->pName->zName); if( pCsr->azArg[0] ){ - sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]); + sqlite3_str_appendf(&acc, "=%Q", pCsr->azArg[0]); } zSql = sqlite3StrAccumFinish(&acc); if( zSql==0 ) return SQLITE_NOMEM; @@ -119342,7 +122674,8 @@ static const sqlite3_module pragmaVtabModule = { 0, /* xRename - rename the table */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; /* @@ -119393,15 +122726,23 @@ static void corruptSchema( const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; - if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){ + if( db->mallocFailed ){ + pData->rc = SQLITE_NOMEM_BKPT; + }else if( pData->pzErrMsg[0]!=0 ){ + /* A error message has already been generated. Do not overwrite it */ + }else if( pData->mInitFlags & INITFLAG_AlterTable ){ + *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra); + pData->rc = SQLITE_ERROR; + }else if( db->flags & SQLITE_WriteSchema ){ + pData->rc = SQLITE_CORRUPT_BKPT; + }else{ char *z; if( zObj==0 ) zObj = "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); - sqlite3DbFree(db, *pData->pzErrMsg); *pData->pzErrMsg = z; + pData->rc = SQLITE_CORRUPT_BKPT; } - pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT; } /* @@ -119453,7 +122794,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; - assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); + /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); @@ -119500,7 +122841,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ -static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ +SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ int rc; int i; #ifndef SQLITE_OMIT_DEPRECATED @@ -119513,6 +122854,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ const char *zMasterName; int openedTransaction = 0; + assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pSchema ); assert( sqlite3_mutex_held(db->mutex) ); @@ -119534,6 +122876,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; + initData.mInitFlags = mFlags; sqlite3InitCallback(&initData, 3, (char **)azArg, 0); if( initData.rc ){ rc = initData.rc; @@ -119555,7 +122898,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ ** will be closed before this function returns. */ sqlite3BtreeEnter(pDb->pBt); if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){ - rc = sqlite3BtreeBeginTrans(pDb->pBt, 0); + rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); goto initone_error_out; @@ -119583,6 +122926,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ for(i=0; ipBt, i+1, (u32 *)&meta[i]); } + if( (db->flags & SQLITE_ResetDatabase)!=0 ){ + memset(meta, 0, sizeof(meta)); + } pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1]; /* If opening a non-empty database, check the text encoding. For the @@ -119682,8 +123028,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); } - if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){ - /* Black magic: If the SQLITE_WriteSchema flag is set, then consider + if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){ + /* Black magic: If the SQLITE_NoSchemaError flag is set, then consider ** the schema loaded, even if errors occurred. In this situation the ** current sqlite3_prepare() operation will fail, but the following one ** will attempt to compile the supplied statement against whatever subset @@ -119737,13 +123083,14 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ assert( db->nDb>0 ); /* Do the main schema first */ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ - rc = sqlite3InitOne(db, 0, pzErrMsg); + rc = sqlite3InitOne(db, 0, pzErrMsg, 0); if( rc ) return rc; } /* All other schemas after the main schema. The "temp" schema must be last */ for(i=db->nDb-1; i>0; i--){ + assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) ); if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ - rc = sqlite3InitOne(db, i, pzErrMsg); + rc = sqlite3InitOne(db, i, pzErrMsg, 0); if( rc ) return rc; } } @@ -119763,10 +123110,12 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ assert( sqlite3_mutex_held(db->mutex) ); if( !db->init.busy ){ rc = sqlite3Init(db, &pParse->zErrMsg); - } - if( rc!=SQLITE_OK ){ - pParse->rc = rc; - pParse->nErr++; + if( rc!=SQLITE_OK ){ + pParse->rc = rc; + pParse->nErr++; + }else if( db->noSharedCache ){ + db->mDbFlags |= DBFLAG_SchemaKnownOk; + } } return rc; } @@ -119794,7 +123143,7 @@ static void schemaIsValid(Parse *pParse){ ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ if( !sqlite3BtreeIsInReadTrans(pBt) ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); } @@ -119977,7 +123326,7 @@ static int sqlite3Prepare( if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ static const char * const azColName[] = { "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", - "selectid", "order", "from", "detail" + "id", "parent", "notused", "detail" }; int iFirst, mx; if( sParse.explain==2 ){ @@ -120061,6 +123410,294 @@ static int sqlite3LockAndPrepare( return rc; } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Checks if the specified token is a table, column, or function name, +** based on the databases associated with the statement being prepared. +** If the function fails, zero is returned and pRc is filled with the +** error code. +*/ +static int shouldTreatAsIdentifier( + sqlite3 *db, /* Database handle. */ + const char *zToken, /* Pointer to start of token to be checked */ + int nToken, /* Length of token to be checked */ + int *pRc /* Pointer to error code upon failure */ +){ + int bFound = 0; /* Non-zero if token is an identifier name. */ + int i, j; /* Database and column loop indexes. */ + Schema *pSchema; /* Schema for current database. */ + Hash *pHash; /* Hash table of tables for current database. */ + HashElem *e; /* Hash element for hash table iteration. */ + Table *pTab; /* Database table for columns being checked. */ + + if( sqlite3IsRowidN(zToken, nToken) ){ + return 1; + } + if( nToken>0 ){ + int hash = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zToken[0]], nToken); + if( sqlite3FunctionSearchN(hash, zToken, nToken) ) return 1; + } + assert( db!=0 ); + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + pHash = &db->aFunc; + if( sqlite3HashFindN(pHash, zToken, nToken) ){ + bFound = 1; + break; + } + pSchema = db->aDb[i].pSchema; + if( pSchema==0 ) continue; + pHash = &pSchema->tblHash; + if( sqlite3HashFindN(pHash, zToken, nToken) ){ + bFound = 1; + break; + } + for(e=sqliteHashFirst(pHash); e; e=sqliteHashNext(e)){ + pTab = sqliteHashData(e); + if( pTab==0 ) continue; + pHash = pTab->pColHash; + if( pHash==0 ){ + pTab->pColHash = pHash = sqlite3_malloc(sizeof(Hash)); + if( pHash ){ + sqlite3HashInit(pHash); + for(j=0; jnCol; j++){ + Column *pCol = &pTab->aCol[j]; + sqlite3HashInsert(pHash, pCol->zName, pCol); + } + }else{ + *pRc = SQLITE_NOMEM_BKPT; + bFound = 0; + goto done; + } + } + if( pHash && sqlite3HashFindN(pHash, zToken, nToken) ){ + bFound = 1; + goto done; + } + } + } +done: + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return bFound; +} + +/* +** Attempt to estimate the final output buffer size needed for the fully +** normalized version of the specified SQL string. This should take into +** account any potential expansion that could occur (e.g. via IN clauses +** being expanded, etc). This size returned is the total number of bytes +** including the NUL terminator. +*/ +static int estimateNormalizedSize( + const char *zSql, /* The original SQL string */ + int nSql, /* Length of original SQL string */ + u8 prepFlags /* The flags passed to sqlite3_prepare_v3() */ +){ + int nOut = nSql + 4; + const char *z = zSql; + while( nOut0 ){ + zOut[j++] = '"'; + continue; + }else if( k==nToken-1 ){ + zOut[j++] = '"'; + continue; + } + } + if( bKeyword ){ + zOut[j++] = sqlite3Toupper(zSql[iIn+k]); + }else{ + zOut[j++] = sqlite3Tolower(zSql[iIn+k]); + } + } + *piOut = j; +} + +/* +** Perform normalization of the SQL contained in the prepared statement and +** store the result in the zNormSql field. The schema for the associated +** databases are consulted while performing the normalization in order to +** determine if a token appears to be an identifier. All identifiers are +** left intact in the normalized SQL and all literals are replaced with a +** single '?'. +*/ +SQLITE_PRIVATE void sqlite3Normalize( + Vdbe *pVdbe, /* VM being reprepared */ + const char *zSql, /* The original SQL string */ + int nSql, /* Size of the input string in bytes */ + u8 prepFlags /* The flags passed to sqlite3_prepare_v3() */ +){ + sqlite3 *db; /* Database handle. */ + char *z; /* The output string */ + int nZ; /* Size of the output string in bytes */ + int i; /* Next character to read from zSql[] */ + int j; /* Next character to fill in on z[] */ + int tokenType = 0; /* Type of the next token */ + int prevTokenType = 0; /* Type of the previous token, except spaces */ + int n; /* Size of the next token */ + int nParen = 0; /* Nesting level of parenthesis */ + Hash inHash; /* Table of parenthesis levels to output index. */ + + db = sqlite3VdbeDb(pVdbe); + assert( db!=0 ); + assert( pVdbe->zNormSql==0 ); + if( zSql==0 ) return; + nZ = estimateNormalizedSize(zSql, nSql, prepFlags); + z = sqlite3DbMallocRawNN(db, nZ); + if( z==0 ) return; + sqlite3HashInit(&inHash); + for(i=j=0; i0 ){ + sqlite3HashInsert(&inHash, zSql+nParen, 0); + assert( jj+6=0 ); + assert( nZ-1-j=0 ); + /* Fall through */ + } + case TK_MINUS: + case TK_SEMI: + case TK_PLUS: + case TK_STAR: + case TK_SLASH: + case TK_REM: + case TK_EQ: + case TK_LE: + case TK_NE: + case TK_LSHIFT: + case TK_LT: + case TK_RSHIFT: + case TK_GT: + case TK_GE: + case TK_BITOR: + case TK_CONCAT: + case TK_COMMA: + case TK_BITAND: + case TK_BITNOT: + case TK_DOT: + case TK_IN: + case TK_IS: + case TK_NOT: + case TK_NULL: + case TK_ID: { + if( tokenType==TK_NULL ){ + if( prevTokenType==TK_IS || prevTokenType==TK_NOT ){ + /* NULL is a keyword in this case, not a literal value */ + }else{ + /* Here the NULL is a literal value */ + z[j++] = '?'; + break; + } + } + if( j>0 && sqlite3IsIdChar(z[j-1]) && sqlite3IsIdChar(zSql[i]) ){ + z[j++] = ' '; + } + if( tokenType==TK_ID ){ + int i2 = i, n2 = n, rc = SQLITE_OK; + if( nParen>0 ){ + assert( nParen0 && z[j-1]==' ' ){ j--; } + if( j>0 && z[j-1]!=';' ){ z[j++] = ';'; } + z[j] = 0; + assert( jzNormSql = z; + sqlite3HashClear(&inHash); +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + /* ** Rerun the compilation of a statement after a schema change. ** @@ -120291,7 +123928,7 @@ SQLITE_API int sqlite3_prepare16_v3( /***/ int sqlite3SelectTrace = 0; # define SELECTTRACE(K,P,S,X) \ if(sqlite3SelectTrace&(K)) \ - sqlite3DebugPrintf("%s/%p: ",(S)->zSelName,(S)),\ + sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\ sqlite3DebugPrintf X #else # define SELECTTRACE(K,P,S,X) @@ -120314,6 +123951,20 @@ struct DistinctCtx { /* ** An instance of the following object is used to record information about ** the ORDER BY (or GROUP BY) clause of query is being coded. +** +** The aDefer[] array is used by the sorter-references optimization. For +** example, assuming there is no index that can be used for the ORDER BY, +** for the query: +** +** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10; +** +** it may be more efficient to add just the "a" values to the sorter, and +** retrieve the associated "bigblob" values directly from table t1 as the +** 10 smallest "a" values are extracted from the sorter. +** +** When the sorter-reference optimization is used, there is one entry in the +** aDefer[] array for each database table that may be read as values are +** extracted from the sorter. */ typedef struct SortCtx SortCtx; struct SortCtx { @@ -120324,8 +123975,17 @@ struct SortCtx { int labelBkOut; /* Start label for the block-output subroutine */ int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ + int labelOBLopt; /* Jump here when sorter is full */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ - u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + u8 nDefer; /* Number of valid entries in aDefer[] */ + struct DeferredCsr { + Table *pTab; /* Table definition */ + int iCsr; /* Cursor number for table */ + int nKey; /* Number of PK columns for table pTab (>=1) */ + } aDefer[4]; +#endif + struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ @@ -120343,6 +124003,11 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ sqlite3ExprDelete(db, p->pHaving); sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pLimit); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){ + sqlite3WindowListDelete(db, p->pWinDefn); + } +#endif if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith); if( bFree ) sqlite3DbFreeNN(db, p); p = pPrior; @@ -120393,9 +124058,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->selFlags = selFlags; pNew->iLimit = 0; pNew->iOffset = 0; -#if SELECTTRACE_ENABLED - pNew->zSelName[0] = 0; -#endif + pNew->selId = ++pParse->nSelect; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; @@ -120409,6 +124072,10 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->pNext = 0; pNew->pLimit = pLimit; pNew->pWith = 0; +#ifndef SQLITE_OMIT_WINDOWFUNC + pNew->pWin = 0; + pNew->pWinDefn = 0; +#endif if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); pNew = 0; @@ -120419,17 +124086,6 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( return pNew; } -#if SELECTTRACE_ENABLED -/* -** Set the name of a Select object -*/ -SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){ - if( p && zName ){ - sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName); - } -} -#endif - /* ** Delete the given Select structure and all of its substructures. @@ -120776,13 +124432,61 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ return 0; } -/* Forward reference */ -static KeyInfo *keyInfoFromExprList( - Parse *pParse, /* Parsing context */ - ExprList *pList, /* Form the KeyInfo object from this ExprList */ - int iStart, /* Begin with this column of pList */ - int nExtra /* Add this many extra columns to the end */ -); +/* +** An instance of this object holds information (beyond pParse and pSelect) +** needed to load the next result row that is to be added to the sorter. +*/ +typedef struct RowLoadInfo RowLoadInfo; +struct RowLoadInfo { + int regResult; /* Store results in array of registers here */ + u8 ecelFlags; /* Flag argument to ExprCodeExprList() */ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + ExprList *pExtra; /* Extra columns needed by sorter refs */ + int regExtraResult; /* Where to load the extra columns */ +#endif +}; + +/* +** This routine does the work of loading query data into an array of +** registers so that it can be added to the sorter. +*/ +static void innerLoopLoadRow( + Parse *pParse, /* Statement under construction */ + Select *pSelect, /* The query being coded */ + RowLoadInfo *pInfo /* Info needed to complete the row load */ +){ + sqlite3ExprCodeExprList(pParse, pSelect->pEList, pInfo->regResult, + 0, pInfo->ecelFlags); +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( pInfo->pExtra ){ + sqlite3ExprCodeExprList(pParse, pInfo->pExtra, pInfo->regExtraResult, 0, 0); + sqlite3ExprListDelete(pParse->db, pInfo->pExtra); + } +#endif +} + +/* +** Code the OP_MakeRecord instruction that generates the entry to be +** added into the sorter. +** +** Return the register in which the result is stored. +*/ +static int makeSorterRecord( + Parse *pParse, + SortCtx *pSort, + Select *pSelect, + int regBase, + int nBase +){ + int nOBSat = pSort->nOBSat; + Vdbe *v = pParse->pVdbe; + int regOut = ++pParse->nMem; + if( pSort->pDeferredRowLoad ){ + innerLoopLoadRow(pParse, pSelect, pSort->pDeferredRowLoad); + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regOut); + return regOut; +} /* ** Generate code that will push the record in registers regData @@ -120794,7 +124498,7 @@ static void pushOntoSorter( Select *pSelect, /* The whole SELECT statement */ int regData, /* First register holding data to be sorted */ int regOrigData, /* First register holding data before packing */ - int nData, /* Number of elements in the data array */ + int nData, /* Number of elements in the regData data array */ int nPrefixReg /* No. of reg prior to regData available for use */ ){ Vdbe *v = pParse->pVdbe; /* Stmt under construction */ @@ -120802,16 +124506,32 @@ static void pushOntoSorter( int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ int regBase; /* Regs for sorter record */ - int regRecord = ++pParse->nMem; /* Assembled sorter record */ + int regRecord = 0; /* Assembled sorter record */ int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ int op; /* Opcode to add sorter record to sorter */ int iLimit; /* LIMIT counter */ + int iSkip = 0; /* End of the sorter insert loop */ assert( bSeq==0 || bSeq==1 ); + + /* Three cases: + ** (1) The data to be sorted has already been packed into a Record + ** by a prior OP_MakeRecord. In this case nData==1 and regData + ** will be completely unrelated to regOrigData. + ** (2) All output columns are included in the sort record. In that + ** case regData==regOrigData. + ** (3) Some output columns are omitted from the sort record due to + ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the + ** SQLITE_ECEL_OMITREF optimization, or due to the + ** SortCtx.pDeferredRowLoad optimiation. In any of these cases + ** regOrigData is 0 to prevent this routine from trying to copy + ** values that might not yet exist. + */ assert( nData==1 || regData==regOrigData || regOrigData==0 ); + if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); - regBase = regData - nExpr - bSeq; + regBase = regData - nPrefixReg; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; @@ -120827,7 +124547,6 @@ static void pushOntoSorter( if( nPrefixReg==0 && nData>0 ){ sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord); if( nOBSat>0 ){ int regPrevKey; /* The first nOBSat columns of the previous row */ int addrFirst; /* Address of the OP_IfNot opcode */ @@ -120836,6 +124555,7 @@ static void pushOntoSorter( int nKey; /* Number of sorting key columns, including OP_Sequence */ KeyInfo *pKI; /* Original KeyInfo on the sorter table */ + regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase); regPrevKey = pParse->nMem+1; pParse->nMem += pSort->nOBSat; nKey = nExpr - pSort->nOBSat + bSeq; @@ -120853,7 +124573,7 @@ static void pushOntoSorter( memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); testcase( pKI->nAllField > pKI->nKeyField+2 ); - pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, + pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat, pKI->nAllField-pKI->nKeyField-1); addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); @@ -120869,6 +124589,34 @@ static void pushOntoSorter( sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat); sqlite3VdbeJumpHere(v, addrJmp); } + if( iLimit ){ + /* At this point the values for the new sorter entry are stored + ** in an array of registers. They need to be composed into a record + ** and inserted into the sorter if either (a) there are currently + ** less than LIMIT+OFFSET items or (b) the new record is smaller than + ** the largest record currently in the sorter. If (b) is true and there + ** are already LIMIT+OFFSET items in the sorter, delete the largest + ** entry before inserting the new one. This way there are never more + ** than LIMIT+OFFSET items in the sorter. + ** + ** If the new record does not need to be inserted into the sorter, + ** jump to the next iteration of the loop. If the pSort->labelOBLopt + ** value is not zero, then it is a label of where to jump. Otherwise, + ** just bypass the row insert logic. See the header comment on the + ** sqlite3WhereOrderByLimitOptLabel() function for additional info. + */ + int iCsr = pSort->iECursor; + sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Last, iCsr, 0); + iSkip = sqlite3VdbeAddOp4Int(v, OP_IdxLE, + iCsr, 0, regBase+nOBSat, nExpr-nOBSat); + VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_Delete, iCsr); + } + if( regRecord==0 ){ + regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase); + } if( pSort->sortFlags & SORTFLAG_UseSorter ){ op = OP_SorterInsert; }else{ @@ -120876,33 +124624,9 @@ static void pushOntoSorter( } sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, regBase+nOBSat, nBase-nOBSat); - if( iLimit ){ - int addr; - int r1 = 0; - /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit - ** register is initialized with value of LIMIT+OFFSET.) After the sorter - ** fills up, delete the least entry in the sorter after each insert. - ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */ - addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v); - sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); - if( pSort->bOrderedInnerLoop ){ - r1 = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1); - VdbeComment((v, "seq")); - } - sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); - if( pSort->bOrderedInnerLoop ){ - /* If the inner loop is driven by an index such that values from - ** the same iteration of the inner loop are in sorted order, then - ** immediately jump to the next iteration of an inner loop if the - ** entry from the current iteration does not fit into the top - ** LIMIT+OFFSET entries of the sorter. */ - int iBrk = sqlite3VdbeCurrentAddr(v) + 2; - sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1); - sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - VdbeCoverage(v); - } - sqlite3VdbeJumpHere(v, addr); + if( iSkip ){ + sqlite3VdbeChangeP2(v, iSkip, + pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v)); } } @@ -120948,6 +124672,87 @@ static void codeDistinct( sqlite3ReleaseTempReg(pParse, r1); } +#ifdef SQLITE_ENABLE_SORTER_REFERENCES +/* +** This function is called as part of inner-loop generation for a SELECT +** statement with an ORDER BY that is not optimized by an index. It +** determines the expressions, if any, that the sorter-reference +** optimization should be used for. The sorter-reference optimization +** is used for SELECT queries like: +** +** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10 +** +** If the optimization is used for expression "bigblob", then instead of +** storing values read from that column in the sorter records, the PK of +** the row from table t1 is stored instead. Then, as records are extracted from +** the sorter to return to the user, the required value of bigblob is +** retrieved directly from table t1. If the values are very large, this +** can be more efficient than storing them directly in the sorter records. +** +** The ExprList_item.bSorterRef flag is set for each expression in pEList +** for which the sorter-reference optimization should be enabled. +** Additionally, the pSort->aDefer[] array is populated with entries +** for all cursors required to evaluate all selected expressions. Finally. +** output variable (*ppExtra) is set to an expression list containing +** expressions for all extra PK values that should be stored in the +** sorter records. +*/ +static void selectExprDefer( + Parse *pParse, /* Leave any error here */ + SortCtx *pSort, /* Sorter context */ + ExprList *pEList, /* Expressions destined for sorter */ + ExprList **ppExtra /* Expressions to append to sorter record */ +){ + int i; + int nDefer = 0; + ExprList *pExtra = 0; + for(i=0; inExpr; i++){ + struct ExprList_item *pItem = &pEList->a[i]; + if( pItem->u.x.iOrderByCol==0 ){ + Expr *pExpr = pItem->pExpr; + Table *pTab = pExpr->y.pTab; + if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab) + && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF) + ){ + int j; + for(j=0; jaDefer[j].iCsr==pExpr->iTable ) break; + } + if( j==nDefer ){ + if( nDefer==ArraySize(pSort->aDefer) ){ + continue; + }else{ + int nKey = 1; + int k; + Index *pPk = 0; + if( !HasRowid(pTab) ){ + pPk = sqlite3PrimaryKeyIndex(pTab); + nKey = pPk->nKeyCol; + } + for(k=0; kiTable = pExpr->iTable; + pNew->y.pTab = pExpr->y.pTab; + pNew->iColumn = pPk ? pPk->aiColumn[k] : -1; + pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew); + } + } + pSort->aDefer[nDefer].pTab = pExpr->y.pTab; + pSort->aDefer[nDefer].iCsr = pExpr->iTable; + pSort->aDefer[nDefer].nKey = nKey; + nDefer++; + } + } + pItem->bSorterRef = 1; + } + } + } + pSort->nDefer = (u8)nDefer; + *ppExtra = pExtra; +} +#endif + /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. @@ -120974,6 +124779,7 @@ static void selectInnerLoop( int iParm = pDest->iSDParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ int nPrefixReg = 0; /* Number of extra registers before regResult */ + RowLoadInfo sRowLoadInfo; /* Info for deferred row loading */ /* Usually, regResult is the first cell in an array of memory cells ** containing the current result row. In this case regOrig is set to the @@ -121020,10 +124826,14 @@ static void selectInnerLoop( VdbeComment((v, "%s", p->pEList->a[i].zName)); } }else if( eDest!=SRT_Exists ){ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + ExprList *pExtra = 0; +#endif /* If the destination is an EXISTS(...) expression, the actual ** values returned by the SELECT are not required. */ - u8 ecelFlags; + u8 ecelFlags; /* "ecel" is an abbreviation of "ExprCodeExprList" */ + ExprList *pEList; if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){ ecelFlags = SQLITE_ECEL_DUP; }else{ @@ -121037,18 +124847,68 @@ static void selectInnerLoop( ** This allows the p->pEList field to be omitted from the sorted record, ** saving space and CPU cycles. */ ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF); + for(i=pSort->nOBSat; ipOrderBy->nExpr; i++){ int j; if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){ p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; } } - regOrig = 0; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + selectExprDefer(pParse, pSort, p->pEList, &pExtra); + if( pExtra && pParse->db->mallocFailed==0 ){ + /* If there are any extra PK columns to add to the sorter records, + ** allocate extra memory cells and adjust the OpenEphemeral + ** instruction to account for the larger records. This is only + ** required if there are one or more WITHOUT ROWID tables with + ** composite primary keys in the SortCtx.aDefer[] array. */ + VdbeOp *pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); + pOp->p2 += (pExtra->nExpr - pSort->nDefer); + pOp->p4.pKeyInfo->nAllField += (pExtra->nExpr - pSort->nDefer); + pParse->nMem += pExtra->nExpr; + } +#endif + + /* Adjust nResultCol to account for columns that are omitted + ** from the sorter by the optimizations in this branch */ + pEList = p->pEList; + for(i=0; inExpr; i++){ + if( pEList->a[i].u.x.iOrderByCol>0 +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + || pEList->a[i].bSorterRef +#endif + ){ + nResultCol--; + regOrig = 0; + } + } + + testcase( regOrig ); + testcase( eDest==SRT_Set ); + testcase( eDest==SRT_Mem ); + testcase( eDest==SRT_Coroutine ); + testcase( eDest==SRT_Output ); assert( eDest==SRT_Set || eDest==SRT_Mem || eDest==SRT_Coroutine || eDest==SRT_Output ); } - nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult, - 0,ecelFlags); + sRowLoadInfo.regResult = regResult; + sRowLoadInfo.ecelFlags = ecelFlags; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + sRowLoadInfo.pExtra = pExtra; + sRowLoadInfo.regExtraResult = regResult + nResultCol; + if( pExtra ) nResultCol += pExtra->nExpr; +#endif + if( p->iLimit + && (ecelFlags & SQLITE_ECEL_OMITREF)!=0 + && nPrefixReg>0 + ){ + assert( pSort!=0 ); + assert( hasDistinct==0 ); + pSort->pDeferredRowLoad = &sRowLoadInfo; + regOrig = 0; + }else{ + innerLoopLoadRow(pParse, p, &sRowLoadInfo); + } } /* If the DISTINCT keyword was present on the SELECT statement @@ -121164,7 +125024,8 @@ static void selectInnerLoop( } #endif if( pSort ){ - pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg); + assert( regResult==regOrig ); + pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, regOrig, 1, nPrefixReg); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); @@ -121194,7 +125055,6 @@ static void selectInnerLoop( assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); - sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } @@ -121238,7 +125098,6 @@ static void selectInnerLoop( sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); - sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); } break; } @@ -121381,7 +125240,7 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } ** function is responsible for seeing that this structure is eventually ** freed. */ -static KeyInfo *keyInfoFromExprList( +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList( Parse *pParse, /* Parsing context */ ExprList *pList, /* Form the KeyInfo object from this ExprList */ int iStart, /* Begin with this column of pList */ @@ -121431,11 +125290,7 @@ static const char *selectOpName(int id){ ** is determined by the zUsage argument. */ static void explainTempTable(Parse *pParse, const char *zUsage){ - if( pParse->explain==2 ){ - Vdbe *v = pParse->pVdbe; - char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage); - sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); - } + ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s", zUsage)); } /* @@ -121453,42 +125308,6 @@ static void explainTempTable(Parse *pParse, const char *zUsage){ # define explainSetInteger(y,z) #endif -#if !defined(SQLITE_OMIT_EXPLAIN) && !defined(SQLITE_OMIT_COMPOUND_SELECT) -/* -** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function -** is a no-op. Otherwise, it adds a single row of output to the EQP result, -** where the caption is of one of the two forms: -** -** "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)" -** "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)" -** -** where iSub1 and iSub2 are the integers passed as the corresponding -** function parameters, and op is the text representation of the parameter -** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT, -** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is -** false, or the second form if it is true. -*/ -static void explainComposite( - Parse *pParse, /* Parse context */ - int op, /* One of TK_UNION, TK_EXCEPT etc. */ - int iSub1, /* Subquery id 1 */ - int iSub2, /* Subquery id 2 */ - int bUseTmp /* True if a temp table was used */ -){ - assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL ); - if( pParse->explain==2 ){ - Vdbe *v = pParse->pVdbe; - char *zMsg = sqlite3MPrintf( - pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2, - bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op) - ); - sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); - } -} -#else -/* No-op versions of the explainXXX() functions and macros. */ -# define explainComposite(v,w,x,y,z) -#endif /* ** If the inner loop was generated using a non-null pOrderBy argument, @@ -121506,7 +125325,7 @@ static void generateSortTail( Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = pSort->labelDone; /* Jump here to exit loop */ int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ - int addr; + int addr; /* Top of output loop. Jump for Next. */ int addrOnce = 0; int iTab; ExprList *pOrderBy = pSort->pOrderBy; @@ -121515,11 +125334,11 @@ static void generateSortTail( int regRow; int regRowid; int iCol; - int nKey; + int nKey; /* Number of key columns in sorter record */ int iSortTab; /* Sorter cursor to read from */ - int nSortData; /* Trailing values to read from sorter */ int i; int bSeq; /* True if sorter record includes seq. no. */ + int nRefKey = 0; struct ExprList_item *aOutEx = p->pEList->a; assert( addrBreak<0 ); @@ -121528,15 +125347,24 @@ static void generateSortTail( sqlite3VdbeGoto(v, addrBreak); sqlite3VdbeResolveLabel(v, pSort->labelBkOut); } + +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + /* Open any cursors needed for sorter-reference expressions */ + for(i=0; inDefer; i++){ + Table *pTab = pSort->aDefer[i].pTab; + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + sqlite3OpenTable(pParse, pSort->aDefer[i].iCsr, iDb, pTab, OP_OpenRead); + nRefKey = MAX(nRefKey, pSort->aDefer[i].nKey); + } +#endif + iTab = pSort->iECursor; if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){ regRowid = 0; regRow = pDest->iSdst; - nSortData = nColumn; }else{ regRowid = sqlite3GetTempReg(pParse); regRow = sqlite3GetTempRange(pParse, nColumn); - nSortData = nColumn; } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ @@ -121545,7 +125373,8 @@ static void generateSortTail( if( pSort->labelBkOut ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } - sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, + nKey+1+nColumn+nRefKey); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); @@ -121558,18 +125387,59 @@ static void generateSortTail( iSortTab = iTab; bSeq = 1; } - for(i=0, iCol=nKey+bSeq-1; i=0; i--){ - int iRead; - if( aOutEx[i].u.x.iOrderByCol ){ - iRead = aOutEx[i].u.x.iOrderByCol-1; - }else{ - iRead = iCol--; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( pSort->nDefer ){ + int iKey = iCol+1; + int regKey = sqlite3GetTempRange(pParse, nRefKey); + + for(i=0; inDefer; i++){ + int iCsr = pSort->aDefer[i].iCsr; + Table *pTab = pSort->aDefer[i].pTab; + int nKey = pSort->aDefer[i].nKey; + + sqlite3VdbeAddOp1(v, OP_NullRow, iCsr); + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iKey++, regKey); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iCsr, + sqlite3VdbeCurrentAddr(v)+1, regKey); + }else{ + int k; + int iJmp; + assert( sqlite3PrimaryKeyIndex(pTab)->nKeyCol==nKey ); + for(k=0; k=0; i--){ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( aOutEx[i].bSorterRef ){ + sqlite3ExprCode(pParse, aOutEx[i].pExpr, regRow+i); + }else +#endif + { + int iRead; + if( aOutEx[i].u.x.iOrderByCol ){ + iRead = aOutEx[i].u.x.iOrderByCol-1; + }else{ + iRead = iCol--; + } + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); + VdbeComment((v, "%s", aOutEx[i].zName?aOutEx[i].zName : aOutEx[i].zSpan)); } - sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); - VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); } switch( eDest ){ case SRT_Table: @@ -121584,7 +125454,6 @@ static void generateSortTail( assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, pDest->zAffSdst, nColumn); - sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn); break; } @@ -121599,7 +125468,6 @@ static void generateSortTail( testcase( eDest==SRT_Coroutine ); if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); - sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn); }else{ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); } @@ -121719,7 +125587,7 @@ static const char *columnTypeImpl( break; } - assert( pTab && pExpr->pTab==pTab ); + assert( pTab && pExpr->y.pTab==pTab ); if( pS ){ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin @@ -121887,7 +125755,7 @@ static void generateColumnNames( } #endif - if( pParse->colNamesSet || db->mallocFailed ) return; + if( pParse->colNamesSet ) return; /* Column names are determined by the left-most term of a compound select */ while( pSelect->pPrior ) pSelect = pSelect->pPrior; SELECTTRACE(1,pParse,pSelect,("generating column names\n")); @@ -121904,7 +125772,7 @@ static void generateColumnNames( assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ - assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */ + assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */ if( pEList->a[i].zName ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zName; @@ -121912,7 +125780,7 @@ static void generateColumnNames( }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; - pTab = p->pTab; + pTab = p->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iColnCol) ); @@ -122003,7 +125871,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( if( pColExpr->op==TK_COLUMN ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; - Table *pTab = pColExpr->pTab; + Table *pTab = pColExpr->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; @@ -122200,7 +126068,6 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ - sqlite3ExprCacheClear(pParse); if( pLimit ){ assert( pLimit->op==TK_LIMIT ); assert( pLimit->pLeft!=0 ); @@ -122358,6 +126225,13 @@ static void generateWithRecursiveQuery( Expr *pLimit; /* Saved LIMIT and OFFSET */ int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ){ + sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries"); + return; + } +#endif + /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; @@ -122414,6 +126288,7 @@ static void generateWithRecursiveQuery( /* Store the results of the setup-query in Queue. */ pSetup->pNext = 0; + ExplainQueryPlan((pParse, 1, "SETUP")); rc = sqlite3Select(pParse, pSetup, &destQueue); pSetup->pNext = p; if( rc ) goto end_of_recursive_query; @@ -122448,6 +126323,7 @@ static void generateWithRecursiveQuery( sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); }else{ p->pPrior = 0; + ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); sqlite3Select(pParse, p, &destQueue); assert( p->pPrior==0 ); p->pPrior = pSetup; @@ -122493,10 +126369,9 @@ static int multiSelectValues( Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ - Select *pPrior; - Select *pRightmost = p; int nRow = 1; int rc = 0; + int bShowAll = p->pLimit==0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); @@ -122505,14 +126380,13 @@ static int multiSelectValues( if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); p = p->pPrior; - nRow++; + nRow += bShowAll; }while(1); + ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow, + nRow==1 ? "" : "S")); while( p ){ - pPrior = p->pPrior; - p->pPrior = 0; - rc = sqlite3Select(pParse, p, pDest); - p->pPrior = pPrior; - if( rc || pRightmost->pLimit ) break; + selectInnerLoop(pParse, p, -1, 0, 0, pDest, 1, 1); + if( !bShowAll ) break; p->nSelectRow = nRow; p = p->pNext; } @@ -122561,10 +126435,6 @@ static int multiSelect( SelectDest dest; /* Alternative data destination */ Select *pDelete = 0; /* Chain of simple selects to delete */ sqlite3 *db; /* Database connection */ -#ifndef SQLITE_OMIT_EXPLAIN - int iSub1 = 0; /* EQP id of left-hand query */ - int iSub2 = 0; /* EQP id of right-hand query */ -#endif /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. @@ -122615,217 +126485,231 @@ static int multiSelect( */ if( p->pOrderBy ){ return multiSelectOrderBy(pParse, p, pDest); - }else + }else{ - /* Generate code for the left and right SELECT statements. - */ - switch( p->op ){ - case TK_ALL: { - int addr = 0; - int nLimit; - assert( !pPrior->pLimit ); - pPrior->iLimit = p->iLimit; - pPrior->iOffset = p->iOffset; - pPrior->pLimit = p->pLimit; - explainSetInteger(iSub1, pParse->iNextSelectId); - rc = sqlite3Select(pParse, pPrior, &dest); - p->pLimit = 0; - if( rc ){ - goto multi_select_end; - } - p->pPrior = 0; - p->iLimit = pPrior->iLimit; - p->iOffset = pPrior->iOffset; - if( p->iLimit ){ - addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); - VdbeComment((v, "Jump ahead if LIMIT reached")); - if( p->iOffset ){ - sqlite3VdbeAddOp3(v, OP_OffsetLimit, - p->iLimit, p->iOffset+1, p->iOffset); - } - } - explainSetInteger(iSub2, pParse->iNextSelectId); - rc = sqlite3Select(pParse, p, &dest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - if( pPrior->pLimit - && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit) - && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) - ){ - p->nSelectRow = sqlite3LogEst((u64)nLimit); - } - if( addr ){ - sqlite3VdbeJumpHere(v, addr); - } - break; +#ifndef SQLITE_OMIT_EXPLAIN + if( pPrior->pPrior==0 ){ + ExplainQueryPlan((pParse, 1, "COMPOUND QUERY")); + ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY")); } - case TK_EXCEPT: - case TK_UNION: { - int unionTab; /* Cursor number of the temporary table holding result */ - u8 op = 0; /* One of the SRT_ operations to apply to self */ - int priorOp; /* The SRT_ operation to apply to prior selects */ - Expr *pLimit; /* Saved values of p->nLimit */ - int addr; - SelectDest uniondest; +#endif - testcase( p->op==TK_EXCEPT ); - testcase( p->op==TK_UNION ); - priorOp = SRT_Union; - if( dest.eDest==priorOp ){ - /* We can reuse a temporary table generated by a SELECT to our - ** right. + /* Generate code for the left and right SELECT statements. + */ + switch( p->op ){ + case TK_ALL: { + int addr = 0; + int nLimit; + assert( !pPrior->pLimit ); + pPrior->iLimit = p->iLimit; + pPrior->iOffset = p->iOffset; + pPrior->pLimit = p->pLimit; + rc = sqlite3Select(pParse, pPrior, &dest); + p->pLimit = 0; + if( rc ){ + goto multi_select_end; + } + p->pPrior = 0; + p->iLimit = pPrior->iLimit; + p->iOffset = pPrior->iOffset; + if( p->iLimit ){ + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); + VdbeComment((v, "Jump ahead if LIMIT reached")); + if( p->iOffset ){ + sqlite3VdbeAddOp3(v, OP_OffsetLimit, + p->iLimit, p->iOffset+1, p->iOffset); + } + } + ExplainQueryPlan((pParse, 1, "UNION ALL")); + rc = sqlite3Select(pParse, p, &dest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + if( pPrior->pLimit + && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit) + && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) + ){ + p->nSelectRow = sqlite3LogEst((u64)nLimit); + } + if( addr ){ + sqlite3VdbeJumpHere(v, addr); + } + break; + } + case TK_EXCEPT: + case TK_UNION: { + int unionTab; /* Cursor number of the temp table holding result */ + u8 op = 0; /* One of the SRT_ operations to apply to self */ + int priorOp; /* The SRT_ operation to apply to prior selects */ + Expr *pLimit; /* Saved values of p->nLimit */ + int addr; + SelectDest uniondest; + + testcase( p->op==TK_EXCEPT ); + testcase( p->op==TK_UNION ); + priorOp = SRT_Union; + if( dest.eDest==priorOp ){ + /* We can reuse a temporary table generated by a SELECT to our + ** right. + */ + assert( p->pLimit==0 ); /* Not allowed on leftward elements */ + unionTab = dest.iSDParm; + }else{ + /* We will need to create our own temporary table to hold the + ** intermediate results. + */ + unionTab = pParse->nTab++; + assert( p->pOrderBy==0 ); + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + findRightmost(p)->selFlags |= SF_UsesEphemeral; + assert( p->pEList ); + } + + /* Code the SELECT statements to our left */ - assert( p->pLimit==0 ); /* Not allowed on leftward elements */ - unionTab = dest.iSDParm; - }else{ - /* We will need to create our own temporary table to hold the - ** intermediate results. + assert( !pPrior->pOrderBy ); + sqlite3SelectDestInit(&uniondest, priorOp, unionTab); + rc = sqlite3Select(pParse, pPrior, &uniondest); + if( rc ){ + goto multi_select_end; + } + + /* Code the current SELECT statement */ - unionTab = pParse->nTab++; + if( p->op==TK_EXCEPT ){ + op = SRT_Except; + }else{ + assert( p->op==TK_UNION ); + op = SRT_Union; + } + p->pPrior = 0; + pLimit = p->pLimit; + p->pLimit = 0; + uniondest.eDest = op; + ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", + selectOpName(p->op))); + rc = sqlite3Select(pParse, p, &uniondest); + testcase( rc!=SQLITE_OK ); + /* Query flattening in sqlite3Select() might refill p->pOrderBy. + ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ + sqlite3ExprListDelete(db, p->pOrderBy); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->pOrderBy = 0; + if( p->op==TK_UNION ){ + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + } + sqlite3ExprDelete(db, p->pLimit); + p->pLimit = pLimit; + p->iLimit = 0; + p->iOffset = 0; + + /* Convert the data in the temporary table into whatever form + ** it is that we currently need. + */ + assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); + if( dest.eDest!=priorOp ){ + int iCont, iBreak, iStart; + assert( p->pEList ); + iBreak = sqlite3VdbeMakeLabel(v); + iCont = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iBreak); + sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); + iStart = sqlite3VdbeCurrentAddr(v); + selectInnerLoop(pParse, p, unionTab, + 0, 0, &dest, iCont, iBreak); + sqlite3VdbeResolveLabel(v, iCont); + sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); + sqlite3VdbeResolveLabel(v, iBreak); + sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); + } + break; + } + default: assert( p->op==TK_INTERSECT ); { + int tab1, tab2; + int iCont, iBreak, iStart; + Expr *pLimit; + int addr; + SelectDest intersectdest; + int r1; + + /* INTERSECT is different from the others since it requires + ** two temporary tables. Hence it has its own case. Begin + ** by allocating the tables we will need. + */ + tab1 = pParse->nTab++; + tab2 = pParse->nTab++; assert( p->pOrderBy==0 ); - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); + + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); - } - - /* Code the SELECT statements to our left - */ - assert( !pPrior->pOrderBy ); - sqlite3SelectDestInit(&uniondest, priorOp, unionTab); - explainSetInteger(iSub1, pParse->iNextSelectId); - rc = sqlite3Select(pParse, pPrior, &uniondest); - if( rc ){ - goto multi_select_end; - } - - /* Code the current SELECT statement - */ - if( p->op==TK_EXCEPT ){ - op = SRT_Except; - }else{ - assert( p->op==TK_UNION ); - op = SRT_Union; - } - p->pPrior = 0; - pLimit = p->pLimit; - p->pLimit = 0; - uniondest.eDest = op; - explainSetInteger(iSub2, pParse->iNextSelectId); - rc = sqlite3Select(pParse, p, &uniondest); - testcase( rc!=SQLITE_OK ); - /* Query flattening in sqlite3Select() might refill p->pOrderBy. - ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ - sqlite3ExprListDelete(db, p->pOrderBy); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->pOrderBy = 0; - if( p->op==TK_UNION ){ - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - } - sqlite3ExprDelete(db, p->pLimit); - p->pLimit = pLimit; - p->iLimit = 0; - p->iOffset = 0; - - /* Convert the data in the temporary table into whatever form - ** it is that we currently need. - */ - assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); - if( dest.eDest!=priorOp ){ - int iCont, iBreak, iStart; + + /* Code the SELECTs to our left into temporary table "tab1". + */ + sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); + rc = sqlite3Select(pParse, pPrior, &intersectdest); + if( rc ){ + goto multi_select_end; + } + + /* Code the current SELECT into temporary table "tab2" + */ + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); + assert( p->addrOpenEphm[1] == -1 ); + p->addrOpenEphm[1] = addr; + p->pPrior = 0; + pLimit = p->pLimit; + p->pLimit = 0; + intersectdest.iSDParm = tab2; + ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", + selectOpName(p->op))); + rc = sqlite3Select(pParse, p, &intersectdest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + if( p->nSelectRow>pPrior->nSelectRow ){ + p->nSelectRow = pPrior->nSelectRow; + } + sqlite3ExprDelete(db, p->pLimit); + p->pLimit = pLimit; + + /* Generate code to take the intersection of the two temporary + ** tables. + */ assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); - iStart = sqlite3VdbeCurrentAddr(v); - selectInnerLoop(pParse, p, unionTab, + sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); + r1 = sqlite3GetTempReg(pParse); + iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); + sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, r1); + selectInnerLoop(pParse, p, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); + sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); + sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); + break; } - break; } - default: assert( p->op==TK_INTERSECT ); { - int tab1, tab2; - int iCont, iBreak, iStart; - Expr *pLimit; - int addr; - SelectDest intersectdest; - int r1; - - /* INTERSECT is different from the others since it requires - ** two temporary tables. Hence it has its own case. Begin - ** by allocating the tables we will need. - */ - tab1 = pParse->nTab++; - tab2 = pParse->nTab++; - assert( p->pOrderBy==0 ); - - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); - assert( p->addrOpenEphm[0] == -1 ); - p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; - assert( p->pEList ); - - /* Code the SELECTs to our left into temporary table "tab1". - */ - sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); - explainSetInteger(iSub1, pParse->iNextSelectId); - rc = sqlite3Select(pParse, pPrior, &intersectdest); - if( rc ){ - goto multi_select_end; - } - - /* Code the current SELECT into temporary table "tab2" - */ - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); - assert( p->addrOpenEphm[1] == -1 ); - p->addrOpenEphm[1] = addr; - p->pPrior = 0; - pLimit = p->pLimit; - p->pLimit = 0; - intersectdest.iSDParm = tab2; - explainSetInteger(iSub2, pParse->iNextSelectId); - rc = sqlite3Select(pParse, p, &intersectdest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; - sqlite3ExprDelete(db, p->pLimit); - p->pLimit = pLimit; - - /* Generate code to take the intersection of the two temporary - ** tables. - */ - assert( p->pEList ); - iBreak = sqlite3VdbeMakeLabel(v); - iCont = sqlite3VdbeMakeLabel(v); - computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); - r1 = sqlite3GetTempReg(pParse); - iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); - sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); - sqlite3ReleaseTempReg(pParse, r1); - selectInnerLoop(pParse, p, tab1, - 0, 0, &dest, iCont, iBreak); - sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); - sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); - sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); - break; + + #ifndef SQLITE_OMIT_EXPLAIN + if( p->pNext==0 ){ + ExplainQueryPlanPop(pParse); } + #endif } - - explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL); - + /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. @@ -122976,7 +126860,6 @@ static int generateOutputSubroutine( r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1, pDest->zAffSdst, pIn->nSdst); - sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, pIn->iSdst, pIn->nSdst); sqlite3ReleaseTempReg(pParse, r1); @@ -123019,7 +126902,6 @@ static int generateOutputSubroutine( default: { assert( pDest->eDest==SRT_Output ); sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst); - sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst); break; } } @@ -123163,10 +127045,6 @@ static int multiSelectOrderBy( ExprList *pOrderBy; /* The ORDER BY clause */ int nOrderBy; /* Number of terms in the ORDER BY clause */ int *aPermute; /* Mapping from ORDER BY terms to result set columns */ -#ifndef SQLITE_OMIT_EXPLAIN - int iSub1; /* EQP id of left-hand query */ - int iSub2; /* EQP id of right-hand query */ -#endif assert( p->pOrderBy!=0 ); assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */ @@ -123286,6 +127164,8 @@ static int multiSelectOrderBy( sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); + ExplainQueryPlan((pParse, 1, "MERGE (%s)", selectOpName(p->op))); + /* Generate a coroutine to evaluate the SELECT statement to the ** left of the compound operator - the "A" select. */ @@ -123293,7 +127173,7 @@ static int multiSelectOrderBy( addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); VdbeComment((v, "left SELECT")); pPrior->iLimit = regLimitA; - explainSetInteger(iSub1, pParse->iNextSelectId); + ExplainQueryPlan((pParse, 1, "LEFT")); sqlite3Select(pParse, pPrior, &destA); sqlite3VdbeEndCoroutine(v, regAddrA); sqlite3VdbeJumpHere(v, addr1); @@ -123308,7 +127188,7 @@ static int multiSelectOrderBy( savedOffset = p->iOffset; p->iLimit = regLimitB; p->iOffset = 0; - explainSetInteger(iSub2, pParse->iNextSelectId); + ExplainQueryPlan((pParse, 1, "RIGHT")); sqlite3Select(pParse, p, &destB); p->iLimit = savedLimit; p->iOffset = savedOffset; @@ -123420,7 +127300,7 @@ static int multiSelectOrderBy( /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ - explainComposite(pParse, p->op, iSub1, iSub2, 0); + ExplainQueryPlanPop(pParse); return pParse->nErr!=0; } #endif @@ -123476,7 +127356,7 @@ static Expr *substExpr( Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; Expr ifNullRow; assert( pSubst->pEList!=0 && pExpr->iColumnpEList->nExpr ); - assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + assert( pExpr->pRight==0 ); if( sqlite3ExprIsVector(pCopy) ){ sqlite3VectorErrorMsg(pSubst->pParse, pCopy); }else{ @@ -123690,6 +127570,10 @@ static void substSelect( ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily ** return the value X for which Y was maximal.) ** +** (25) If either the subquery or the parent query contains a window +** function in the select list or ORDER BY clause, flattening +** is not attempted. +** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query @@ -123733,6 +127617,10 @@ static int flattenSubquery( pSub = pSubitem->pSelect; assert( pSub!=0 ); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */ +#endif + pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, @@ -123843,8 +127731,8 @@ static int flattenSubquery( assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 ); /***** If we reach this point, flattening is permitted. *****/ - SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", - pSub->zSelName, pSub, iFrom)); + SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n", + pSub->selId, pSub, iFrom)); /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; @@ -123895,7 +127783,6 @@ static int flattenSubquery( p->pPrior = 0; p->pLimit = 0; pNew = sqlite3SelectDup(db, p, 0); - sqlite3SelectSetName(pNew, pSub->zSelName); p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->pSrc = pSrc; @@ -123907,9 +127794,8 @@ static int flattenSubquery( if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; - SELECTTRACE(2,pParse,p, - ("compound-subquery flattener creates %s.%p as peer\n", - pNew->zSelName, pNew)); + SELECTTRACE(2,pParse,p,("compound-subquery flattener" + " creates %u as peer\n",pNew->selId)); } if( db->mallocFailed ) return 1; } @@ -124094,7 +127980,183 @@ static int flattenSubquery( } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ +/* +** A structure to keep track of all of the column values that are fixed to +** a known value due to WHERE clause constraints of the form COLUMN=VALUE. +*/ +typedef struct WhereConst WhereConst; +struct WhereConst { + Parse *pParse; /* Parsing context */ + int nConst; /* Number for COLUMN=CONSTANT terms */ + int nChng; /* Number of times a constant is propagated */ + Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */ +}; +/* +** Add a new entry to the pConst object. Except, do not add duplicate +** pColumn entires. +*/ +static void constInsert( + WhereConst *pConst, /* The WhereConst into which we are inserting */ + Expr *pColumn, /* The COLUMN part of the constraint */ + Expr *pValue /* The VALUE part of the constraint */ +){ + int i; + assert( pColumn->op==TK_COLUMN ); + + /* 2018-10-25 ticket [cf5ed20f] + ** Make sure the same pColumn is not inserted more than once */ + for(i=0; inConst; i++){ + const Expr *pExpr = pConst->apExpr[i*2]; + assert( pExpr->op==TK_COLUMN ); + if( pExpr->iTable==pColumn->iTable + && pExpr->iColumn==pColumn->iColumn + ){ + return; /* Already present. Return without doing anything. */ + } + } + + pConst->nConst++; + pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, + pConst->nConst*2*sizeof(Expr*)); + if( pConst->apExpr==0 ){ + pConst->nConst = 0; + }else{ + if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft; + pConst->apExpr[pConst->nConst*2-2] = pColumn; + pConst->apExpr[pConst->nConst*2-1] = pValue; + } +} + +/* +** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE +** is a constant expression and where the term must be true because it +** is part of the AND-connected terms of the expression. For each term +** found, add it to the pConst structure. +*/ +static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ + Expr *pRight, *pLeft; + if( pExpr==0 ) return; + if( ExprHasProperty(pExpr, EP_FromJoin) ) return; + if( pExpr->op==TK_AND ){ + findConstInWhere(pConst, pExpr->pRight); + findConstInWhere(pConst, pExpr->pLeft); + return; + } + if( pExpr->op!=TK_EQ ) return; + pRight = pExpr->pRight; + pLeft = pExpr->pLeft; + assert( pRight!=0 ); + assert( pLeft!=0 ); + if( pRight->op==TK_COLUMN + && !ExprHasProperty(pRight, EP_FixedCol) + && sqlite3ExprIsConstant(pLeft) + && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight)) + ){ + constInsert(pConst, pRight, pLeft); + }else + if( pLeft->op==TK_COLUMN + && !ExprHasProperty(pLeft, EP_FixedCol) + && sqlite3ExprIsConstant(pRight) + && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight)) + ){ + constInsert(pConst, pLeft, pRight); + } +} + +/* +** This is a Walker expression callback. pExpr is a candidate expression +** to be replaced by a value. If pExpr is equivalent to one of the +** columns named in pWalker->u.pConst, then overwrite it with its +** corresponding value. +*/ +static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ + int i; + WhereConst *pConst; + if( pExpr->op!=TK_COLUMN ) return WRC_Continue; + if( ExprHasProperty(pExpr, EP_FixedCol) ) return WRC_Continue; + pConst = pWalker->u.pConst; + for(i=0; inConst; i++){ + Expr *pColumn = pConst->apExpr[i*2]; + if( pColumn==pExpr ) continue; + if( pColumn->iTable!=pExpr->iTable ) continue; + if( pColumn->iColumn!=pExpr->iColumn ) continue; + /* A match is found. Add the EP_FixedCol property */ + pConst->nChng++; + ExprClearProperty(pExpr, EP_Leaf); + ExprSetProperty(pExpr, EP_FixedCol); + assert( pExpr->pLeft==0 ); + pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0); + break; + } + return WRC_Prune; +} + +/* +** The WHERE-clause constant propagation optimization. +** +** If the WHERE clause contains terms of the form COLUMN=CONSTANT or +** CONSTANT=COLUMN that must be tree (in other words, if the terms top-level +** AND-connected terms that are not part of a ON clause from a LEFT JOIN) +** then throughout the query replace all other occurrences of COLUMN +** with CONSTANT within the WHERE clause. +** +** For example, the query: +** +** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b +** +** Is transformed into +** +** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=39 AND t3.c=39 +** +** Return true if any transformations where made and false if not. +** +** Implementation note: Constant propagation is tricky due to affinity +** and collating sequence interactions. Consider this example: +** +** CREATE TABLE t1(a INT,b TEXT); +** INSERT INTO t1 VALUES(123,'0123'); +** SELECT * FROM t1 WHERE a=123 AND b=a; +** SELECT * FROM t1 WHERE a=123 AND b=123; +** +** The two SELECT statements above should return different answers. b=a +** is alway true because the comparison uses numeric affinity, but b=123 +** is false because it uses text affinity and '0123' is not the same as '123'. +** To work around this, the expression tree is not actually changed from +** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol +** and the "123" value is hung off of the pLeft pointer. Code generator +** routines know to generate the constant "123" instead of looking up the +** column value. Also, to avoid collation problems, this optimization is +** only attempted if the "a=123" term uses the default BINARY collation. +*/ +static int propagateConstants( + Parse *pParse, /* The parsing context */ + Select *p /* The query in which to propagate constants */ +){ + WhereConst x; + Walker w; + int nChng = 0; + x.pParse = pParse; + do{ + x.nConst = 0; + x.nChng = 0; + x.apExpr = 0; + findConstInWhere(&x, p->pWhere); + if( x.nConst ){ + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.xExprCallback = propagateConstantExprRewrite; + w.xSelectCallback = sqlite3SelectWalkNoop; + w.xSelectCallback2 = 0; + w.walkerDepth = 0; + w.u.pConst = &x; + sqlite3WalkExpr(&w, p->pWhere); + sqlite3DbFree(x.pParse->db, x.apExpr); + nChng += x.nChng; + } + }while( x.nChng ); + return nChng; +} #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* @@ -124124,7 +128186,7 @@ static int flattenSubquery( ** (2) The inner query is the recursive part of a common table expression. ** ** (3) The inner query has a LIMIT clause (since the changes to the WHERE -** close would change the meaning of the LIMIT). +** clause would change the meaning of the LIMIT). ** ** (4) The inner query is the right operand of a LEFT JOIN and the ** expression to be pushed down does not come from the ON clause @@ -124143,6 +128205,10 @@ static int flattenSubquery( ** But if the (b2=2) term were to be pushed down into the bb subquery, ** then the (1,1,NULL) row would be suppressed. ** +** (6) The inner query features one or more window-functions (since +** changes to the WHERE clause of the inner query could change the +** window over which window functions are calculated). +** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. */ @@ -124158,6 +128224,10 @@ static int pushDownWhereTerms( if( pWhere==0 ) return 0; if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */ +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pSubq->pWin ) return 0; /* restriction (6) */ +#endif + #ifdef SQLITE_DEBUG /* Only the first term of a compound can have a WITH clause. But make ** sure no other terms are marked SF_Recursive in case something changes @@ -124603,6 +128673,35 @@ static void selectPopWith(Walker *pWalker, Select *p){ #define selectPopWith 0 #endif +/* +** The SrcList_item structure passed as the second argument represents a +** sub-query in the FROM clause of a SELECT statement. This function +** allocates and populates the SrcList_item.pTab object. If successful, +** SQLITE_OK is returned. Otherwise, if an OOM error is encountered, +** SQLITE_NOMEM. +*/ +SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){ + Select *pSel = pFrom->pSelect; + Table *pTab; + + assert( pSel ); + pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); + if( pTab==0 ) return SQLITE_NOMEM; + pTab->nTabRef = 1; + if( pFrom->zAlias ){ + pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias); + }else{ + pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId); + } + while( pSel->pPrior ){ pSel = pSel->pPrior; } + sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); + pTab->iPKey = -1; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); + pTab->tabFlags |= TF_Ephemeral; + + return SQLITE_OK; +} + /* ** This routine is a Walker callback for "expanding" a SELECT statement. ** "Expanding" means to do the following: @@ -124675,19 +128774,7 @@ static int selectExpander(Walker *pWalker, Select *p){ assert( pSel!=0 ); assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; - pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); - if( pTab==0 ) return WRC_Abort; - pTab->nTabRef = 1; - if( pFrom->zAlias ){ - pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias); - }else{ - pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab); - } - while( pSel->pPrior ){ pSel = pSel->pPrior; } - sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); - pTab->iPKey = -1; - pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); - pTab->tabFlags |= TF_Ephemeral; + if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; #endif }else{ /* An ordinary table or view name in the FROM clause */ @@ -124710,7 +128797,6 @@ static int selectExpander(Walker *pWalker, Select *p){ if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); - sqlite3SelectSetName(pFrom->pSelect, pTab->zName); nCol = pTab->nCol; pTab->nCol = -1; sqlite3WalkSelect(pWalker, pFrom->pSelect); @@ -124988,7 +129074,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ struct SrcList_item *pFrom; assert( p->selFlags & SF_Resolved ); - assert( (p->selFlags & SF_HasTypeInfo)==0 ); + if( p->selFlags & SF_HasTypeInfo ) return; p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; pTabList = p->pSrc; @@ -125091,7 +129177,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ "argument"); pFunc->iDistinct = -1; }else{ - KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0); + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); } @@ -125115,11 +129201,17 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ } } + /* ** Update the accumulator memory cells for an aggregate based on ** the current cursor position. +** +** If regAcc is non-zero and there are no min() or max() aggregates +** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator +** registers i register regAcc contains 0. The caller will take care +** of setting and clearing regAcc. */ -static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ +static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ Vdbe *v = pParse->pVdbe; int i; int regHit = 0; @@ -125162,36 +129254,24 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem); + sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); - sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); - sqlite3ExprCacheClear(pParse); } } - - /* Before populating the accumulator registers, clear the column cache. - ** Otherwise, if any of the required column values are already present - ** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value - ** to pC->iMem. But by the time the value is used, the original register - ** may have been used, invalidating the underlying buffer holding the - ** text or blob value. See ticket [883034dcb5]. - ** - ** Another solution would be to change the OP_SCopy used to copy cached - ** values to an OP_Copy. - */ + if( regHit==0 && pAggInfo->nAccumulator ){ + regHit = regAcc; + } if( regHit ){ addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); } - sqlite3ExprCacheClear(pParse); for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ sqlite3ExprCode(pParse, pC->pExpr, pC->iMem); } pAggInfo->directMode = 0; - sqlite3ExprCacheClear(pParse); if( addrHitTest ){ sqlite3VdbeJumpHere(v, addrHitTest); } @@ -125209,14 +129289,11 @@ static void explainSimpleCount( ){ if( pParse->explain==2 ){ int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); - char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", + sqlite3VdbeExplain(pParse, 0, "SCAN TABLE %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" ); - sqlite3VdbeAddOp4( - pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC - ); } } #else @@ -125324,6 +129401,7 @@ static struct SrcList_item *isSelfJoinView( ** The transformation only works if all of the following are true: ** ** * The subquery is a UNION ALL of two or more terms +** * The subquery does not have a LIMIT clause ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) ** @@ -125347,6 +129425,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ do{ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ + if( pSub->pLimit ) return 0; /* No LIMIT clause */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); @@ -125429,19 +129508,15 @@ SQLITE_PRIVATE int sqlite3Select( ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */ u8 minMaxFlag; /* Flag for min/max queries */ -#ifndef SQLITE_OMIT_EXPLAIN - int iRestoreSelectId = pParse->iSelectId; - pParse->iSelectId = pParse->iNextSelectId++; -#endif - db = pParse->db; + v = sqlite3GetVdbe(pParse); if( p==0 || db->mallocFailed || pParse->nErr ){ return 1; } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); #if SELECTTRACE_ENABLED - SELECTTRACE(1,pParse,p, ("begin processing:\n")); + SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain)); if( sqlite3SelectTrace & 0x100 ){ sqlite3TreeViewSelect(0, p, 0); } @@ -125463,29 +129538,37 @@ SQLITE_PRIVATE int sqlite3Select( p->selFlags &= ~SF_Distinct; } sqlite3SelectPrep(pParse, p, 0); - memset(&sSort, 0, sizeof(sSort)); - sSort.pOrderBy = p->pOrderBy; - pTabList = p->pSrc; if( pParse->nErr || db->mallocFailed ){ goto select_end; } assert( p->pEList!=0 ); - isAgg = (p->selFlags & SF_Aggregate)!=0; #if SELECTTRACE_ENABLED - if( sqlite3SelectTrace & 0x100 ){ - SELECTTRACE(0x100,pParse,p, ("after name resolution:\n")); + if( sqlite3SelectTrace & 0x104 ){ + SELECTTRACE(0x104,pParse,p, ("after name resolution:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif - /* Get a pointer the VDBE under construction, allocating a new VDBE if one - ** does not already exist */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto select_end; if( pDest->eDest==SRT_Output ){ generateColumnNames(pParse, p); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( sqlite3WindowRewrite(pParse, p) ){ + goto select_end; + } +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x108 ){ + SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif +#endif /* SQLITE_OMIT_WINDOWFUNC */ + pTabList = p->pSrc; + isAgg = (p->selFlags & SF_Aggregate)!=0; + memset(&sSort, 0, sizeof(sSort)); + sSort.pOrderBy = p->pOrderBy; + /* Try to various optimizations (flattening subqueries, and strength ** reduction of join operators) in the FROM clause up into the main query */ @@ -125574,14 +129657,46 @@ SQLITE_PRIVATE int sqlite3Select( */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); - explainSetInteger(pParse->iSelectId, iRestoreSelectId); #if SELECTTRACE_ENABLED - SELECTTRACE(1,pParse,p,("end compound-select processing\n")); + SELECTTRACE(0x1,pParse,p,("end compound-select processing\n")); + if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ + sqlite3TreeViewSelect(0, p, 0); + } #endif + if( p->pNext==0 ) ExplainQueryPlanPop(pParse); return rc; } #endif + /* Do the WHERE-clause constant propagation optimization if this is + ** a join. No need to speed time on this operation for non-join queries + ** as the equivalent optimization will be handled by query planner in + ** sqlite3WhereBegin(). + */ + if( pTabList->nSrc>1 + && OptimizationEnabled(db, SQLITE_PropagateConst) + && propagateConstants(pParse, p) + ){ +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After constant propagation:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + }else{ + SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n")); + } + +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION + if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) + && countOfViewOptimization(pParse, p) + ){ + if( db->mallocFailed ) goto select_end; + pEList = p->pEList; + pTabList = p->pSrc; + } +#endif + /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries @@ -125655,7 +129770,8 @@ SQLITE_PRIVATE int sqlite3Select( ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ - SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); + SELECTTRACE(0x100,pParse,p, + ("After WHERE-clause push-down into subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -125689,7 +129805,7 @@ SQLITE_PRIVATE int sqlite3Select( VdbeComment((v, "%s", pItem->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; @@ -125724,12 +129840,11 @@ SQLITE_PRIVATE int sqlite3Select( pPrior = isSelfJoinView(pTabList, pItem); if( pPrior ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); - explainSetInteger(pItem->iSelectId, pPrior->iSelectId); assert( pPrior->pSelect!=0 ); pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId)); sqlite3Select(pParse, pSub, &dest); } pItem->pTab->nRowLogEst = pSub->nSelectRow; @@ -125760,16 +129875,6 @@ SQLITE_PRIVATE int sqlite3Select( } #endif -#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION - if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) - && countOfViewOptimization(pParse, p) - ){ - if( db->mallocFailed ) goto select_end; - pEList = p->pEList; - pTabList = p->pSrc; - } -#endif - /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: @@ -125813,7 +129918,8 @@ SQLITE_PRIVATE int sqlite3Select( */ if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; - pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr); + pKeyInfo = sqlite3KeyInfoFromExprList( + pParse, sSort.pOrderBy, 0, pEList->nExpr); sSort.iECursor = pParse->nTab++; sSort.addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, @@ -125847,9 +129953,9 @@ SQLITE_PRIVATE int sqlite3Select( if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - sDistinct.tabTnct, 0, 0, - (char*)keyInfoFromExprList(pParse, p->pEList,0,0), - P4_KEYINFO); + sDistinct.tabTnct, 0, 0, + (char*)sqlite3KeyInfoFromExprList(pParse, p->pEList,0,0), + P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; }else{ @@ -125858,9 +129964,16 @@ SQLITE_PRIVATE int sqlite3Select( if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ - u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); + u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) + | (p->selFlags & SF_FixedLimit); +#ifndef SQLITE_OMIT_WINDOWFUNC + Window *pWin = p->pWin; /* Master window object (or NULL) */ + if( pWin ){ + sqlite3WindowCodeInit(pParse, pWin); + } +#endif assert( WHERE_USE_LIMIT==SF_FixedLimit ); - wctrlFlags |= p->selFlags & SF_FixedLimit; + /* Begin the database scan. */ SELECTTRACE(1,pParse,p,("WhereBegin\n")); @@ -125875,7 +129988,7 @@ SQLITE_PRIVATE int sqlite3Select( } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); - sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo); + sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } @@ -125889,15 +130002,37 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } - /* Use the standard inner loop. */ assert( p->pEList==pEList ); - selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, - sqlite3WhereContinueLabel(pWInfo), - sqlite3WhereBreakLabel(pWInfo)); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pWin ){ + int addrGosub = sqlite3VdbeMakeLabel(v); + int iCont = sqlite3VdbeMakeLabel(v); + int iBreak = sqlite3VdbeMakeLabel(v); + int regGosub = ++pParse->nMem; - /* End the database scan loop. - */ - sqlite3WhereEnd(pWInfo); + sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); + + sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); + sqlite3VdbeResolveLabel(v, addrGosub); + VdbeNoopComment((v, "inner-loop subroutine")); + sSort.labelOBLopt = 0; + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak); + sqlite3VdbeResolveLabel(v, iCont); + sqlite3VdbeAddOp1(v, OP_Return, regGosub); + VdbeComment((v, "end inner-loop subroutine")); + sqlite3VdbeResolveLabel(v, iBreak); + }else +#endif /* SQLITE_OMIT_WINDOWFUNC */ + { + /* Use the standard inner loop. */ + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, + sqlite3WhereContinueLabel(pWInfo), + sqlite3WhereBreakLabel(pWInfo)); + + /* End the database scan loop. + */ + sqlite3WhereEnd(pWInfo); + } }else{ /* This case when there exist aggregate functions or a GROUP BY clause ** or both */ @@ -125956,7 +130091,8 @@ SQLITE_PRIVATE int sqlite3Select( memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; - sNC.pAggInfo = &sAggInfo; + sNC.uNC.pAggInfo = &sAggInfo; + VVA_ONLY( sNC.ncFlags = NC_UAggInfo; ) sAggInfo.mnReg = pParse->nMem+1; sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; sAggInfo.pGroupBy = pGroupBy; @@ -126025,7 +130161,7 @@ SQLITE_PRIVATE int sqlite3Select( ** will be converted into a Noop. */ sAggInfo.sortingIdx = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn); + pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); @@ -126044,8 +130180,6 @@ SQLITE_PRIVATE int sqlite3Select( pParse->nMem += pGroupBy->nExpr; sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag); VdbeComment((v, "clear abort flag")); - sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); - VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1); /* Begin a loop that will extract all source rows in GROUP BY order. @@ -126091,15 +130225,14 @@ SQLITE_PRIVATE int sqlite3Select( } } regBase = sqlite3GetTempRange(pParse, nCol); - sqlite3ExprCacheClear(pParse); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); j = nGroupBy; for(i=0; iiSorterColumn>=j ){ int r1 = j + regBase; - sqlite3ExprCodeGetColumnToReg(pParse, - pCol->pTab, pCol->iColumn, pCol->iTable, r1); + sqlite3ExprCodeGetColumnOfTable(v, + pCol->pTab, pCol->iTable, pCol->iColumn, r1); j++; } } @@ -126115,8 +130248,6 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); sAggInfo.useSortingIdx = 1; - sqlite3ExprCacheClear(pParse); - } /* If the index or temporary table used by the GROUP BY sort @@ -126139,7 +130270,6 @@ SQLITE_PRIVATE int sqlite3Select( ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); - sqlite3ExprCacheClear(pParse); if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut, sortPTab); @@ -126178,7 +130308,7 @@ SQLITE_PRIVATE int sqlite3Select( ** the current row */ sqlite3VdbeJumpHere(v, addr1); - updateAccumulator(pParse, &sAggInfo); + updateAccumulator(pParse, iUseFlag, &sAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); @@ -126230,6 +130360,8 @@ SQLITE_PRIVATE int sqlite3Select( */ sqlite3VdbeResolveLabel(v, addrReset); resetAccumulator(pParse, &sAggInfo); + sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); + VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp1(v, OP_Return, regReset); } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ @@ -126295,6 +130427,23 @@ SQLITE_PRIVATE int sqlite3Select( }else #endif /* SQLITE_OMIT_BTREECOUNT */ { + int regAcc = 0; /* "populate accumulators" flag */ + + /* If there are accumulator registers but no min() or max() functions, + ** allocate register regAcc. Register regAcc will contain 0 the first + ** time the inner loop runs, and 1 thereafter. The code generated + ** by updateAccumulator() only updates the accumulator registers if + ** regAcc contains 0. */ + if( sAggInfo.nAccumulator ){ + for(i=0; ifuncFlags&SQLITE_FUNC_NEEDCOLL ) break; + } + if( i==sAggInfo.nFunc ){ + regAcc = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc); + } + } + /* This case runs if the aggregate has no GROUP BY clause. The ** processing is much simpler since there is only a single row ** of output. @@ -126316,7 +130465,8 @@ SQLITE_PRIVATE int sqlite3Select( if( pWInfo==0 ){ goto select_end; } - updateAccumulator(pParse, &sAggInfo); + updateAccumulator(pParse, regAcc, &sAggInfo); + if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc); if( sqlite3WhereIsOrdered(pWInfo)>0 ){ sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo)); VdbeComment((v, "%s() by index", @@ -126345,6 +130495,7 @@ SQLITE_PRIVATE int sqlite3Select( if( sSort.pOrderBy ){ explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); + assert( p->pEList==pEList ); generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } @@ -126360,13 +130511,16 @@ SQLITE_PRIVATE int sqlite3Select( ** successful coding of the SELECT. */ select_end: - explainSetInteger(pParse->iSelectId, iRestoreSelectId); sqlite3ExprListDelete(db, pMinMaxOrderBy); sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); #if SELECTTRACE_ENABLED - SELECTTRACE(1,pParse,p,("end processing\n")); + SELECTTRACE(0x1,pParse,p,("end processing\n")); + if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ + sqlite3TreeViewSelect(0, p, 0); + } #endif + ExplainQueryPlanPop(pParse); return rc; } @@ -126600,6 +130754,7 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS sqlite3ExprListDelete(db, pTmp->pExprList); sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); + sqlite3UpsertDelete(db, pTmp->pUpsert); sqlite3DbFree(db, pTmp->zSpan); sqlite3DbFree(db, pTmp); @@ -126755,14 +130910,16 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ - if( !noErr ){ - sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); - }else{ - assert( !db->init.busy ); - sqlite3CodeVerifySchema(pParse, iDb); + if( !IN_RENAME_OBJECT ){ + if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ + if( !noErr ){ + sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); + } + goto trigger_cleanup; } - goto trigger_cleanup; } /* Do not create a trigger on a system table */ @@ -126786,7 +130943,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( } #ifndef SQLITE_OMIT_AUTHORIZATION - { + if( !IN_RENAME_OBJECT ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int code = SQLITE_CREATE_TRIGGER; const char *zDb = db->aDb[iTabDb].zDbSName; @@ -126820,8 +130977,15 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; - pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); - pTrigger->pColumns = sqlite3IdListDup(db, pColumns); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName); + pTrigger->pWhen = pWhen; + pWhen = 0; + }else{ + pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); + } + pTrigger->pColumns = pColumns; + pColumns = 0; assert( pParse->pNewTrigger==0 ); pParse->pNewTrigger = pTrigger; @@ -126870,6 +131034,14 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( goto triggerfinish_cleanup; } +#ifndef SQLITE_OMIT_ALTERTABLE + if( IN_RENAME_OBJECT ){ + assert( !db->init.busy ); + pParse->pNewTrigger = pTrig; + pTrig = 0; + }else +#endif + /* if we are not initializing, ** build the sqlite_master entry */ @@ -126911,7 +131083,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( triggerfinish_cleanup: sqlite3DeleteTrigger(db, pTrig); - assert( !pParse->pNewTrigger ); + assert( IN_RENAME_OBJECT || !pParse->pNewTrigger ); sqlite3DeleteTriggerStep(db, pStepList); } @@ -126958,12 +131130,13 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep( ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep *triggerStepAllocate( - sqlite3 *db, /* Database connection */ + Parse *pParse, /* Parser context */ u8 op, /* Trigger opcode */ Token *pName, /* The target name */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); @@ -126974,6 +131147,9 @@ static TriggerStep *triggerStepAllocate( pTriggerStep->zTarget = z; pTriggerStep->op = op; pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName); + } } return pTriggerStep; } @@ -126986,25 +131162,36 @@ static TriggerStep *triggerStepAllocate( ** body of a trigger. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( - sqlite3 *db, /* The database connection */ + Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table into which we insert */ IdList *pColumn, /* List of columns in pTableName to insert into */ Select *pSelect, /* A SELECT statement that supplies values */ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ + Upsert *pUpsert, /* ON CONFLICT clauses for upsert */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; assert(pSelect != 0 || db->mallocFailed); - pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd); if( pTriggerStep ){ - pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + if( IN_RENAME_OBJECT ){ + pTriggerStep->pSelect = pSelect; + pSelect = 0; + }else{ + pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + } pTriggerStep->pIdList = pColumn; + pTriggerStep->pUpsert = pUpsert; pTriggerStep->orconf = orconf; }else{ + testcase( pColumn ); sqlite3IdListDelete(db, pColumn); + testcase( pUpsert ); + sqlite3UpsertDelete(db, pUpsert); } sqlite3SelectDelete(db, pSelect); @@ -127017,7 +131204,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( - sqlite3 *db, /* The database connection */ + Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table to be updated */ ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ @@ -127025,12 +131212,20 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); if( pTriggerStep ){ - pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); - pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + if( IN_RENAME_OBJECT ){ + pTriggerStep->pExprList = pEList; + pTriggerStep->pWhere = pWhere; + pEList = 0; + pWhere = 0; + }else{ + pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); + pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + } pTriggerStep->orconf = orconf; } sqlite3ExprListDelete(db, pEList); @@ -127044,17 +131239,23 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( ** sees a DELETE statement inside the body of a CREATE TRIGGER. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( - sqlite3 *db, /* Database connection */ + Parse *pParse, /* Parser */ Token *pTableName, /* The table from which rows are deleted */ Expr *pWhere, /* The WHERE clause */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd); if( pTriggerStep ){ - pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + if( IN_RENAME_OBJECT ){ + pTriggerStep->pWhere = pWhere; + pWhere = 0; + }else{ + pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + } pTriggerStep->orconf = OE_Default; } sqlite3ExprDelete(db, pWhere); @@ -127321,7 +131522,7 @@ static int codeTriggerProgram( targetSrcList(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), - pParse->eOrconf, 0, 0 + pParse->eOrconf, 0, 0, 0 ); break; } @@ -127330,7 +131531,8 @@ static int codeTriggerProgram( targetSrcList(pParse, pStep), sqlite3SelectDup(db, pStep->pSelect, 0), sqlite3IdListDup(db, pStep->pIdList), - pParse->eOrconf + pParse->eOrconf, + sqlite3UpsertDup(db, pStep->pUpsert) ); break; } @@ -127794,6 +131996,57 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ #endif } +/* +** Check to see if column iCol of index pIdx references any of the +** columns defined by aXRef and chngRowid. Return true if it does +** and false if not. This is an optimization. False-positives are a +** performance degradation, but false-negatives can result in a corrupt +** index and incorrect answers. +** +** aXRef[j] will be non-negative if column j of the original table is +** being updated. chngRowid will be true if the rowid of the table is +** being updated. +*/ +static int indexColumnIsBeingUpdated( + Index *pIdx, /* The index to check */ + int iCol, /* Which column of the index to check */ + int *aXRef, /* aXRef[j]>=0 if column j is being updated */ + int chngRowid /* true if the rowid is being updated */ +){ + i16 iIdxCol = pIdx->aiColumn[iCol]; + assert( iIdxCol!=XN_ROWID ); /* Cannot index rowid */ + if( iIdxCol>=0 ){ + return aXRef[iIdxCol]>=0; + } + assert( iIdxCol==XN_EXPR ); + assert( pIdx->aColExpr!=0 ); + assert( pIdx->aColExpr->a[iCol].pExpr!=0 ); + return sqlite3ExprReferencesUpdatedColumn(pIdx->aColExpr->a[iCol].pExpr, + aXRef,chngRowid); +} + +/* +** Check to see if index pIdx is a partial index whose conditional +** expression might change values due to an UPDATE. Return true if +** the index is subject to change and false if the index is guaranteed +** to be unchanged. This is an optimization. False-positives are a +** performance degradation, but false-negatives can result in a corrupt +** index and incorrect answers. +** +** aXRef[j] will be non-negative if column j of the original table is +** being updated. chngRowid will be true if the rowid of the table is +** being updated. +*/ +static int indexWhereClauseMightChange( + Index *pIdx, /* The index to check */ + int *aXRef, /* aXRef[j]>=0 if column j is being updated */ + int chngRowid /* true if the rowid is being updated */ +){ + if( pIdx->pPartIdxWhere==0 ) return 0; + return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, + aXRef, chngRowid); +} + /* ** Process an UPDATE statement. ** @@ -127808,7 +132061,8 @@ SQLITE_PRIVATE void sqlite3Update( Expr *pWhere, /* The WHERE clause. May be null */ int onError, /* How to handle constraint errors */ ExprList *pOrderBy, /* ORDER BY clause. May be null */ - Expr *pLimit /* LIMIT clause. May be null */ + Expr *pLimit, /* LIMIT clause. May be null */ + Upsert *pUpsert /* ON CONFLICT clause, or null */ ){ int i, j; /* Loop counters */ Table *pTab; /* The table to be updated */ @@ -127915,16 +132169,23 @@ SQLITE_PRIVATE void sqlite3Update( ** need to occur right after the database cursor. So go ahead and ** allocate enough space, just in case. */ - pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++; + iBaseCur = iDataCur = pParse->nTab++; iIdxCur = iDataCur+1; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); + testcase( pPk!=0 && pPk!=pTab->pIndex ); for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ - if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){ + if( pPk==pIdx ){ iDataCur = pParse->nTab; - pTabList->a[0].iCursor = iDataCur; } pParse->nTab++; } + if( pUpsert ){ + /* On an UPSERT, reuse the same cursors already opened by INSERT */ + iDataCur = pUpsert->iDataCur; + iIdxCur = pUpsert->iIdxCur; + pParse->nTab = iBaseCur; + } + pTabList->a[0].iCursor = iDataCur; /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. @@ -127941,6 +132202,8 @@ SQLITE_PRIVATE void sqlite3Update( memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; + sNC.uNC.pUpsert = pUpsert; + sNC.ncFlags = NC_UUpsert; /* Resolve the column names in all the expressions of the ** of the UPDATE statement. Also find the column index @@ -128007,19 +132270,18 @@ SQLITE_PRIVATE void sqlite3Update( /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold ** the key for accessing each index. - ** - ** FIXME: Be smarter about omitting indexes that use expressions. */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; - if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){ + if( chngKey || hasFK>1 || pIdx==pPk + || indexWhereClauseMightChange(pIdx,aXRef,chngRowid) + ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; }else{ reg = 0; for(i=0; inKeyCol; i++){ - i16 iIdxCol = pIdx->aiColumn[i]; - if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){ + if( indexColumnIsBeingUpdated(pIdx, i, aXRef, chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; if( (onError==OE_Replace) @@ -128044,7 +132306,7 @@ SQLITE_PRIVATE void sqlite3Update( v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, 1, iDb); + sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb); /* Allocate required registers. */ if( !IsVirtual(pTab) ){ @@ -128095,8 +132357,16 @@ SQLITE_PRIVATE void sqlite3Update( } #endif - /* Initialize the count of updated rows */ - if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){ + /* Jump to labelBreak to abandon further processing of this UPDATE */ + labelContinue = labelBreak = sqlite3VdbeMakeLabel(v); + + /* Not an UPSERT. Normal processing. Begin by + ** initialize the count of updated rows */ + if( (db->flags&SQLITE_CountRows)!=0 + && !pParse->pTriggerTab + && !pParse->nested + && pUpsert==0 + ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } @@ -128109,46 +132379,61 @@ SQLITE_PRIVATE void sqlite3Update( iPk = pParse->nMem+1; pParse->nMem += nPk; regKey = ++pParse->nMem; - iEph = pParse->nTab++; - - sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1); - addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); - sqlite3VdbeSetP4KeyInfo(pParse, pPk); - } - - /* Begin the database scan. - ** - ** Do not consider a single-pass strategy for a multi-row update if - ** there are any triggers or foreign keys to process, or rows may - ** be deleted as a result of REPLACE conflict handling. Any of these - ** things might disturb a cursor being used to scan through the table - ** or index, causing a single-pass approach to malfunction. */ - flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE; - if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ - flags |= WHERE_ONEPASS_MULTIROW; - } - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur); - if( pWInfo==0 ) goto update_cleanup; - - /* A one-pass strategy that might update more than one row may not - ** be used if any column of the index used for the scan is being - ** updated. Otherwise, if there is an index on "b", statements like - ** the following could create an infinite loop: - ** - ** UPDATE t1 SET b=b+1 WHERE b>? - ** - ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI - ** strategy that uses an index for which one or more columns are being - ** updated. */ - eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); - if( eOnePass==ONEPASS_MULTI ){ - int iCur = aiCurOnePass[1]; - if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ - eOnePass = ONEPASS_OFF; + if( pUpsert==0 ){ + iEph = pParse->nTab++; + sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1); + addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); + sqlite3VdbeSetP4KeyInfo(pParse, pPk); } - assert( iCur!=iDataCur || !HasRowid(pTab) ); } + if( pUpsert ){ + /* If this is an UPSERT, then all cursors have already been opened by + ** the outer INSERT and the data cursor should be pointing at the row + ** that is to be updated. So bypass the code that searches for the + ** row(s) to be updated. + */ + pWInfo = 0; + eOnePass = ONEPASS_SINGLE; + sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL); + }else{ + /* Begin the database scan. + ** + ** Do not consider a single-pass strategy for a multi-row update if + ** there are any triggers or foreign keys to process, or rows may + ** be deleted as a result of REPLACE conflict handling. Any of these + ** things might disturb a cursor being used to scan through the table + ** or index, causing a single-pass approach to malfunction. */ + flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE; + if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ + flags |= WHERE_ONEPASS_MULTIROW; + } + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur); + if( pWInfo==0 ) goto update_cleanup; + + /* A one-pass strategy that might update more than one row may not + ** be used if any column of the index used for the scan is being + ** updated. Otherwise, if there is an index on "b", statements like + ** the following could create an infinite loop: + ** + ** UPDATE t1 SET b=b+1 WHERE b>? + ** + ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI + ** strategy that uses an index for which one or more columns are being + ** updated. */ + eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); + if( eOnePass!=ONEPASS_SINGLE ){ + sqlite3MultiWrite(pParse); + if( eOnePass==ONEPASS_MULTI ){ + int iCur = aiCurOnePass[1]; + if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ + eOnePass = ONEPASS_OFF; + } + assert( iCur!=iDataCur || !HasRowid(pTab) ); + } + } + } + if( HasRowid(pTab) ){ /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF ** mode, write the rowid into the FIFO. In either of the one-pass modes, @@ -128168,7 +132453,7 @@ SQLITE_PRIVATE void sqlite3Update( sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i); } if( eOnePass ){ - sqlite3VdbeChangeToNoop(v, addrOpen); + if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; }else{ @@ -128178,59 +132463,58 @@ SQLITE_PRIVATE void sqlite3Update( } } - if( eOnePass!=ONEPASS_MULTI ){ - sqlite3WhereEnd(pWInfo); - } - - labelBreak = sqlite3VdbeMakeLabel(v); - if( !isView ){ - int addrOnce = 0; - - /* Open every index that needs updating. */ + if( pUpsert==0 ){ + if( eOnePass!=ONEPASS_MULTI ){ + sqlite3WhereEnd(pWInfo); + } + + if( !isView ){ + int addrOnce = 0; + + /* Open every index that needs updating. */ + if( eOnePass!=ONEPASS_OFF ){ + if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; + if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; + } + + if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, + aToOpen, 0, 0); + if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); + } + + /* Top of the update loop */ if( eOnePass!=ONEPASS_OFF ){ - if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; - if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; - } - - if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ - addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); - } - sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen, - 0, 0); - if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); - } - - /* Top of the update loop */ - if( eOnePass!=ONEPASS_OFF ){ - if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ - assert( pPk ); - sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); - VdbeCoverageNeverTaken(v); - } - if( eOnePass==ONEPASS_SINGLE ){ - labelContinue = labelBreak; - }else{ + if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ + assert( pPk ); + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey); + VdbeCoverage(v); + } + if( eOnePass!=ONEPASS_SINGLE ){ + labelContinue = sqlite3VdbeMakeLabel(v); + } + sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); + VdbeCoverageIf(v, pPk==0); + VdbeCoverageIf(v, pPk!=0); + }else if( pPk ){ labelContinue = sqlite3VdbeMakeLabel(v); + sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); + addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); + VdbeCoverage(v); + }else{ + labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak, + regOldRowid); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); + VdbeCoverage(v); } - sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); - VdbeCoverageIf(v, pPk==0); - VdbeCoverageIf(v, pPk!=0); - }else if( pPk ){ - labelContinue = sqlite3VdbeMakeLabel(v); - sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); - addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); - sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); - VdbeCoverage(v); - }else{ - labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, labelBreak, - regOldRowid); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); - VdbeCoverage(v); } - /* If the record number will change, set register regNewRowid to - ** contain the new value. If the record number is not being modified, + /* If the rowid value will change, set register regNewRowid to + ** contain the new value. If the rowid is not being modified, ** then regNewRowid is the same register as regOldRowid, which is ** already populated. */ assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid ); @@ -128293,7 +132577,7 @@ SQLITE_PRIVATE void sqlite3Update( */ testcase( i==31 ); testcase( i==32 ); - sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); } @@ -128322,10 +132606,14 @@ SQLITE_PRIVATE void sqlite3Update( VdbeCoverage(v); } - /* If it did not delete it, the row-trigger may still have modified + /* After-BEFORE-trigger-reload-loop: + ** If it did not delete it, the BEFORE trigger may still have modified ** some of the columns of the row being updated. Load the values for - ** all columns not modified by the update statement into their - ** registers in case this has happened. + ** all columns not modified by the update statement into their registers + ** in case this has happened. Only unmodified columns are reloaded. + ** The values computed for modified columns use the values before the + ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26) + ** for an example. */ for(i=0; inCol; i++){ if( aXRef[i]<0 && i!=pTab->iPKey ){ @@ -128341,7 +132629,7 @@ SQLITE_PRIVATE void sqlite3Update( assert( regOldRowid>0 ); sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace, - aXRef); + aXRef, 0); /* Do FK constraint checks. */ if( hasFK ){ @@ -128411,7 +132699,7 @@ SQLITE_PRIVATE void sqlite3Update( /* Increment the row counter */ - if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){ + if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } @@ -128438,16 +132726,15 @@ SQLITE_PRIVATE void sqlite3Update( ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ - if( pParse->nested==0 && pParse->pTriggerTab==0 ){ + if( pParse->nested==0 && pParse->pTriggerTab==0 && pUpsert==0 ){ sqlite3AutoincrementEnd(pParse); } /* - ** Return the number of rows that were changed. If this routine is - ** generating code because of a call to sqlite3NestedParse(), do not - ** invoke the callback function. + ** Return the number of rows that were changed, if we are tracking + ** that information. */ - if( (db->flags&SQLITE_CountRows) && !pParse->pTriggerTab && !pParse->nested ){ + if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC); @@ -128519,7 +132806,7 @@ static void updateVirtualTable( int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ - int bOnePass; /* True to use onepass strategy */ + int eOnePass; /* True to use onepass strategy */ int addr; /* Address of OP_OpenEphemeral */ /* Allocate nArg registers in which to gather the arguments for VUpdate. Then @@ -128543,7 +132830,7 @@ static void updateVirtualTable( sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); - sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */ + sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */ } } if( HasRowid(pTab) ){ @@ -128564,19 +132851,20 @@ static void updateVirtualTable( sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); } - bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); + eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); - if( bOnePass ){ + /* There is no ONEPASS_MULTI on virtual tables */ + assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); + + if( eOnePass ){ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded - ** above. Also, if this is a top-level parse (not a trigger), clear the - ** multi-write flag so that the VM does not open a statement journal */ + ** above. */ sqlite3VdbeChangeToNoop(v, addr); - if( sqlite3IsToplevel(pParse) ){ - pParse->isMultiWrite = 0; - } + sqlite3VdbeAddOp1(v, OP_Close, iCsr); }else{ /* Create a record from the argument register contents and insert it into ** the ephemeral table. */ + sqlite3MultiWrite(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); #ifdef SQLITE_DEBUG /* Signal an assert() within OP_MakeRecord that it is allowed to @@ -128588,7 +132876,7 @@ static void updateVirtualTable( } - if( bOnePass==0 ){ + if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ sqlite3WhereEnd(pWInfo); @@ -128608,7 +132896,7 @@ static void updateVirtualTable( /* End of the ephemeral table scan. Or, if using the onepass strategy, ** jump to here if the scan visited zero rows. */ - if( bOnePass==0 ){ + if( eOnePass==ONEPASS_OFF ){ sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); @@ -128619,6 +132907,261 @@ static void updateVirtualTable( #endif /* SQLITE_OMIT_VIRTUALTABLE */ /************** End of update.c **********************************************/ +/************** Begin file upsert.c ******************************************/ +/* +** 2018-04-12 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains code to implement various aspects of UPSERT +** processing and handling of the Upsert object. +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_UPSERT +/* +** Free a list of Upsert objects +*/ +SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){ + if( p ){ + sqlite3ExprListDelete(db, p->pUpsertTarget); + sqlite3ExprDelete(db, p->pUpsertTargetWhere); + sqlite3ExprListDelete(db, p->pUpsertSet); + sqlite3ExprDelete(db, p->pUpsertWhere); + sqlite3DbFree(db, p); + } +} + +/* +** Duplicate an Upsert object. +*/ +SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){ + if( p==0 ) return 0; + return sqlite3UpsertNew(db, + sqlite3ExprListDup(db, p->pUpsertTarget, 0), + sqlite3ExprDup(db, p->pUpsertTargetWhere, 0), + sqlite3ExprListDup(db, p->pUpsertSet, 0), + sqlite3ExprDup(db, p->pUpsertWhere, 0) + ); +} + +/* +** Create a new Upsert object. +*/ +SQLITE_PRIVATE Upsert *sqlite3UpsertNew( + sqlite3 *db, /* Determines which memory allocator to use */ + ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */ + Expr *pTargetWhere, /* Optional WHERE clause on the target */ + ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */ + Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */ +){ + Upsert *pNew; + pNew = sqlite3DbMallocRaw(db, sizeof(Upsert)); + if( pNew==0 ){ + sqlite3ExprListDelete(db, pTarget); + sqlite3ExprDelete(db, pTargetWhere); + sqlite3ExprListDelete(db, pSet); + sqlite3ExprDelete(db, pWhere); + return 0; + }else{ + pNew->pUpsertTarget = pTarget; + pNew->pUpsertTargetWhere = pTargetWhere; + pNew->pUpsertSet = pSet; + pNew->pUpsertWhere = pWhere; + pNew->pUpsertIdx = 0; + } + return pNew; +} + +/* +** Analyze the ON CONFLICT clause described by pUpsert. Resolve all +** symbols in the conflict-target. +** +** Return SQLITE_OK if everything works, or an error code is something +** is wrong. +*/ +SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( + Parse *pParse, /* The parsing context */ + SrcList *pTabList, /* Table into which we are inserting */ + Upsert *pUpsert /* The ON CONFLICT clauses */ +){ + Table *pTab; /* That table into which we are inserting */ + int rc; /* Result code */ + int iCursor; /* Cursor used by pTab */ + Index *pIdx; /* One of the indexes of pTab */ + ExprList *pTarget; /* The conflict-target clause */ + Expr *pTerm; /* One term of the conflict-target clause */ + NameContext sNC; /* Context for resolving symbolic names */ + Expr sCol[2]; /* Index column converted into an Expr */ + + assert( pTabList->nSrc==1 ); + assert( pTabList->a[0].pTab!=0 ); + assert( pUpsert!=0 ); + assert( pUpsert->pUpsertTarget!=0 ); + + /* Resolve all symbolic names in the conflict-target clause, which + ** includes both the list of columns and the optional partial-index + ** WHERE clause. + */ + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + sNC.pSrcList = pTabList; + rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); + if( rc ) return rc; + rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); + if( rc ) return rc; + + /* Check to see if the conflict target matches the rowid. */ + pTab = pTabList->a[0].pTab; + pTarget = pUpsert->pUpsertTarget; + iCursor = pTabList->a[0].iCursor; + if( HasRowid(pTab) + && pTarget->nExpr==1 + && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN + && pTerm->iColumn==XN_ROWID + ){ + /* The conflict-target is the rowid of the primary table */ + assert( pUpsert->pUpsertIdx==0 ); + return SQLITE_OK; + } + + /* Initialize sCol[0..1] to be an expression parse tree for a + ** single column of an index. The sCol[0] node will be the TK_COLLATE + ** operator and sCol[1] will be the TK_COLUMN operator. Code below + ** will populate the specific collation and column number values + ** prior to comparing against the conflict-target expression. + */ + memset(sCol, 0, sizeof(sCol)); + sCol[0].op = TK_COLLATE; + sCol[0].pLeft = &sCol[1]; + sCol[1].op = TK_COLUMN; + sCol[1].iTable = pTabList->a[0].iCursor; + + /* Check for matches against other indexes */ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int ii, jj, nn; + if( !IsUniqueIndex(pIdx) ) continue; + if( pTarget->nExpr!=pIdx->nKeyCol ) continue; + if( pIdx->pPartIdxWhere ){ + if( pUpsert->pUpsertTargetWhere==0 ) continue; + if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere, + pIdx->pPartIdxWhere, iCursor)!=0 ){ + continue; + } + } + nn = pIdx->nKeyCol; + for(ii=0; iiazColl[ii]; + if( pIdx->aiColumn[ii]==XN_EXPR ){ + assert( pIdx->aColExpr!=0 ); + assert( pIdx->aColExpr->nExpr>ii ); + pExpr = pIdx->aColExpr->a[ii].pExpr; + if( pExpr->op!=TK_COLLATE ){ + sCol[0].pLeft = pExpr; + pExpr = &sCol[0]; + } + }else{ + sCol[0].pLeft = &sCol[1]; + sCol[1].iColumn = pIdx->aiColumn[ii]; + pExpr = &sCol[0]; + } + for(jj=0; jja[jj].pExpr, pExpr,iCursor)<2 ){ + break; /* Column ii of the index matches column jj of target */ + } + } + if( jj>=nn ){ + /* The target contains no match for column jj of the index */ + break; + } + } + if( iipUpsertIdx = pIdx; + return SQLITE_OK; + } + sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any " + "PRIMARY KEY or UNIQUE constraint"); + return SQLITE_ERROR; +} + +/* +** Generate bytecode that does an UPDATE as part of an upsert. +** +** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK. +** In this case parameter iCur is a cursor open on the table b-tree that +** currently points to the conflicting table row. Otherwise, if pIdx +** is not NULL, then pIdx is the constraint that failed and iCur is a +** cursor points to the conflicting row. +*/ +SQLITE_PRIVATE void sqlite3UpsertDoUpdate( + Parse *pParse, /* The parsing and code-generating context */ + Upsert *pUpsert, /* The ON CONFLICT clause for the upsert */ + Table *pTab, /* The table being updated */ + Index *pIdx, /* The UNIQUE constraint that failed */ + int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */ +){ + Vdbe *v = pParse->pVdbe; + sqlite3 *db = pParse->db; + SrcList *pSrc; /* FROM clause for the UPDATE */ + int iDataCur; + + assert( v!=0 ); + assert( pUpsert!=0 ); + VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); + iDataCur = pUpsert->iDataCur; + if( pIdx && iCur!=iDataCur ){ + if( HasRowid(pTab) ){ + int regRowid = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, regRowid); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + int nPk = pPk->nKeyCol; + int iPk = pParse->nMem+1; + int i; + pParse->nMem += nPk; + for(i=0; iaiColumn[i]>=0 ); + k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); + sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i); + VdbeComment((v, "%s.%s", pIdx->zName, + pTab->aCol[pPk->aiColumn[i]].zName)); + } + sqlite3VdbeVerifyAbortable(v, OE_Abort); + i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk); + VdbeCoverage(v); + sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, + "corrupt database", P4_STATIC); + sqlite3VdbeJumpHere(v, i); + } + } + /* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So + ** we have to make a copy before passing it down into sqlite3Update() */ + pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0); + sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet, + pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert); + pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */ + pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */ + VdbeNoopComment((v, "End DO UPDATE of UPSERT")); +} + +#endif /* SQLITE_OMIT_UPSERT */ + +/************** End of upsert.c **********************************************/ /************** Begin file vacuum.c ******************************************/ /* ** 2003 April 6 @@ -128661,8 +133204,14 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); - assert( sqlite3_strnicmp(zSubSql,"SELECT",6)!=0 || CORRUPT_DB ); - if( zSubSql && zSubSql[0]!='S' ){ + /* The secondary SQL must be one of CREATE TABLE, CREATE INDEX, + ** or INSERT. Historically there have been attacks that first + ** corrupt the sqlite_master.sql field with other kinds of statements + ** then run VACUUM to get those statements to execute at inappropriate + ** times. */ + if( zSubSql + && (strncmp(zSubSql,"CRE",3)==0 || strncmp(zSubSql,"INS",3)==0) + ){ rc = execSql(db, pzErrMsg, zSubSql); if( rc!=SQLITE_OK ) break; } @@ -128782,7 +133331,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ saved_mTrace = db->mTrace; db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); + db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder + | SQLITE_Defensive | SQLITE_CountRows); db->mTrace = 0; zDbMain = db->aDb[iDb].zDbSName; @@ -128840,7 +133390,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ */ rc = execSql(db, pzErrMsg, "BEGIN"); if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = sqlite3BtreeBeginTrans(pMain, 2); + rc = sqlite3BtreeBeginTrans(pMain, 2, 0); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Do not attempt to change the page size for a WAL database */ @@ -128875,7 +133425,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execSqlF(db, pzErrMsg, "SELECT sql FROM \"%w\".sqlite_master" - " WHERE type='index' AND length(sql)>10", + " WHERE type='index'", zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; @@ -129258,7 +133808,7 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){ assert( sqlite3_mutex_held(db->mutex) ); if( p ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); @@ -129324,7 +133874,6 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( Token *pModuleName, /* Name of the module for the virtual table */ int ifNotExists /* No error if the table already exists */ ){ - int iDb; /* The database the table is being created in */ Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ @@ -129334,8 +133883,6 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( assert( 0==pTable->pIndex ); db = pParse->db; - iDb = sqlite3SchemaToIndex(db, pTable->pSchema); - assert( iDb>=0 ); assert( pTable->nModuleArg==0 ); addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); @@ -129355,6 +133902,8 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( ** The second call, to obtain permission to create the table, is made now. */ if( pTable->azModuleArg ){ + int iDb = sqlite3SchemaToIndex(db, pTable->pSchema); + assert( iDb>=0 ); /* The database the table is being created in */ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); } @@ -129754,7 +134303,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ assert( IsVirtual(pTab) ); memset(&sParse, 0, sizeof(sParse)); - sParse.declareVtab = 1; + sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; sParse.db = db; sParse.nQueryLoop = 1; if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) @@ -129795,7 +134344,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } - sParse.declareVtab = 0; + sParse.eParseMode = PARSE_MODE_NORMAL; if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); @@ -130045,14 +134594,11 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( void *pArg = 0; FuncDef *pNew; int rc = 0; - char *zLowerName; - unsigned char *z; - /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; - pTab = pExpr->pTab; + pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; @@ -130062,16 +134608,22 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( if( pMod->xFindFunction==0 ) return pDef; /* Call the xFindFunction method on the virtual table implementation - ** to see if the implementation wants to overload this function + ** to see if the implementation wants to overload this function. + ** + ** Though undocumented, we have historically always invoked xFindFunction + ** with an all lower-case function name. Continue in this tradition to + ** avoid any chance of an incompatibility. */ - zLowerName = sqlite3DbStrDup(db, pDef->zName); - if( zLowerName ){ - for(z=(unsigned char*)zLowerName; *z; z++){ - *z = sqlite3UpperToLower[*z]; +#ifdef SQLITE_DEBUG + { + int i; + for(i=0; pDef->zName[i]; i++){ + unsigned char x = (unsigned char)pDef->zName[i]; + assert( x==sqlite3UpperToLower[x] ); } - rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg); - sqlite3DbFree(db, zLowerName); } +#endif + rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg); if( rc==0 ){ return pDef; } @@ -130346,6 +134898,8 @@ struct WhereLevel { struct InLoop { int iCur; /* The VDBE cursor used by this IN operator */ int addrInTop; /* Top of the IN loop */ + int iBase; /* Base register of multi-key index record */ + int nPrefix; /* Number of prior entires in the key */ u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ @@ -130584,6 +135138,7 @@ struct WhereClause { WhereInfo *pWInfo; /* WHERE clause processing context */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ + u8 hasOr; /* True if any a[].eOperator is WO_OR */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ @@ -130663,12 +135218,33 @@ struct WhereLoopBuilder { int nRecValid; /* Number of valid fields currently in pRec */ #endif unsigned int bldFlags; /* SQLITE_BLDF_* flags */ + unsigned int iPlanLimit; /* Search limiter */ }; /* Allowed values for WhereLoopBuider.bldFlags */ #define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */ #define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ +/* The WhereLoopBuilder.iPlanLimit is used to limit the number of +** index+constraint combinations the query planner will consider for a +** particular query. If this parameter is unlimited, then certain +** pathological queries can spend excess time in the sqlite3WhereBegin() +** routine. The limit is high enough that is should not impact real-world +** queries. +** +** SQLITE_QUERY_PLANNER_LIMIT is the baseline limit. The limit is +** increased by SQLITE_QUERY_PLANNER_LIMIT_INCR before each term of the FROM +** clause is processed, so that every table in a join is guaranteed to be +** able to propose a some index+constraint combinations even if the initial +** baseline limit was exhausted by prior tables of the join. +*/ +#ifndef SQLITE_QUERY_PLANNER_LIMIT +# define SQLITE_QUERY_PLANNER_LIMIT 20000 +#endif +#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR +# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 +#endif + /* ** The WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second @@ -130731,12 +135307,10 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ - int iLevel, /* Value for "level" column of output */ - int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ); #else -# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0 +# define sqlite3WhereExplainOneScan(u,v,w,x) 0 #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3WhereAddScanStatus( @@ -130759,6 +135333,7 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause*); SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8); SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*); @@ -130821,6 +135396,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */ #define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ +#define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ /************** End of whereInt.h ********************************************/ /************** Continuing where we left off in wherecode.c ******************/ @@ -130856,23 +135432,23 @@ static void explainAppendTerm( int i; assert( nTerm>=1 ); - if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5); + if( bAnd ) sqlite3_str_append(pStr, " AND ", 5); - if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1); for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1); - sqlite3StrAccumAppend(pStr, zOp, 1); + sqlite3_str_append(pStr, zOp, 1); - if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1); for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1); } /* @@ -130896,11 +135472,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ int i, j; if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; - sqlite3StrAccumAppend(pStr, " (", 2); + sqlite3_str_append(pStr, " (", 2); for(i=0; i=nSkip ? "%s=?" : "ANY(%s)", z); + if( i ) sqlite3_str_append(pStr, " AND ", 5); + sqlite3_str_appendf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z); } j = i; @@ -130911,7 +135487,7 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<"); } - sqlite3StrAccumAppend(pStr, ")", 1); + sqlite3_str_append(pStr, ")", 1); } /* @@ -130927,8 +135503,6 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ - int iLevel, /* Value for "level" column of output */ - int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; @@ -130939,7 +135513,6 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ - int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ @@ -130956,15 +135529,15 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); - sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); + sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ - sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId); + sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId); }else{ - sqlite3XPrintf(&str, " TABLE %s", pItem->zName); + sqlite3_str_appendf(&str, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ - sqlite3XPrintf(&str, " AS %s", pItem->zAlias); + sqlite3_str_appendf(&str, " AS %s", pItem->zAlias); } if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; @@ -130987,8 +135560,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( zFmt = "INDEX %s"; } if( zFmt ){ - sqlite3StrAccumAppend(&str, " USING ", 7); - sqlite3XPrintf(&str, zFmt, pIdx->zName); + sqlite3_str_append(&str, " USING ", 7); + sqlite3_str_appendf(&str, zFmt, pIdx->zName); explainIndexRange(&str, pLoop); } }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ @@ -131003,23 +135576,26 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( assert( flags&WHERE_TOP_LIMIT); zRangeOp = "<"; } - sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); + sqlite3_str_appendf(&str, + " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ - sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s", + sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ - sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); + sqlite3_str_appendf(&str, " (~%llu rows)", + sqlite3LogEstToInt(pLoop->nOut)); }else{ - sqlite3StrAccumAppend(&str, " (~1 row)", 9); + sqlite3_str_append(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); - ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); + ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), + pParse->addrExplain, 0, zMsg,P4_DYNAMIC); } return ret; } @@ -131152,7 +135728,6 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ /* Code the OP_Affinity opcode if there is anything left to do. */ if( n>0 ){ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); - sqlite3ExprCacheAffinityChange(pParse, base, n); } } @@ -131231,7 +135806,7 @@ static Expr *removeUnindexableInClauseTerms( for(i=iEq; inLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iField = pLoop->aLTerm[i]->iField - 1; - assert( pOrigRhs->a[iField].pExpr!=0 ); + if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); pOrigRhs->a[iField].pExpr = 0; assert( pOrigLhs->a[iField].pExpr!=0 ); @@ -131396,7 +135971,14 @@ static int codeEqualityTerm( sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v); if( i==iEq ){ pIn->iCur = iTab; - pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; + pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; + if( iEq>0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + pIn->iBase = iReg - i; + pIn->nPrefix = i; + pLoop->wsFlags |= WHERE_IN_EARLYOUT; + }else{ + pIn->nPrefix = 0; + } }else{ pIn->eEndLoopOp = OP_Noop; } @@ -131683,11 +136265,8 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ struct CCurHint *pHint = pWalker->u.pCCurHint; if( pExpr->op==TK_COLUMN ){ if( pExpr->iTable!=pHint->iTabCur ){ - Vdbe *v = pWalker->pParse->pVdbe; int reg = ++pWalker->pParse->nMem; /* Register for column value */ - sqlite3ExprCodeGetColumnOfTable( - v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg - ); + sqlite3ExprCode(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ @@ -131919,7 +136498,7 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; - pExpr->pTab = 0; + pExpr->y.pTab = 0; return WRC_Prune; }else{ return WRC_Continue; @@ -132020,6 +136599,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** initialize a memory cell that records if this table matches any ** row of the left table of the join. */ + assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) + || pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0 + ); if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); @@ -132037,7 +136619,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); pLevel->op = OP_Goto; }else @@ -132051,7 +136633,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int nConstraint = pLoop->nLTerm; int iIn; /* Counter for IN constraints */ - sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; jaddrNxt; sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); - sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); - VdbeComment((v, "pk")); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 @@ -132220,7 +136797,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeCoverageIf(v, pX->op==TK_LE); VdbeCoverageIf(v, pX->op==TK_LT); VdbeCoverageIf(v, pX->op==TK_GE); - sqlite3ExprCacheAffinityChange(pParse, r1, 1); sqlite3ReleaseTempReg(pParse, rTemp); }else{ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt); @@ -132255,7 +136831,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( testOp!=OP_Noop ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); VdbeCoverageIf(v, testOp==OP_Le); VdbeCoverageIf(v, testOp==OP_Lt); @@ -132460,6 +137035,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ + if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ + sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur); + } op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); @@ -132478,7 +137056,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( nConstraint = nEq; if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; - sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 @@ -132503,7 +137080,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } }else if( bStopAtNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); - sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); endEq = 0; nConstraint++; } @@ -132523,6 +137099,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); } + if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ + sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1); + } + /* Seek the table cursor, if required */ if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ @@ -132533,7 +137113,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( )){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); VdbeCoverage(v); }else{ @@ -132553,9 +137132,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( /* If pIdx is an index on one or more expressions, then look through ** all the expressions in pWInfo and try to transform matching expressions ** into reference to index columns. + ** + ** Do not do this for the RHS of a LEFT JOIN. This is because the + ** expression may be evaluated after OP_NullRow has been executed on + ** the cursor. In this case it is important to do the full evaluation, + ** as the result of the expression may not be NULL, even if all table + ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a */ - whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); - + if( pLevel->iLeftJoin==0 ){ + whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); + } /* Record the instruction used to terminate the loop. */ if( pLoop->wsFlags & WHERE_ONEROW ){ @@ -132711,7 +137297,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( for(iTerm=0; iTermnTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; if( &pWC->a[iTerm] == pTerm ) continue; - if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue; @@ -132730,13 +137315,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); + ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR")); for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ int jmp1 = 0; /* Address of jump operation */ - if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ + assert( (pTabItem[0].fg.jointype & JT_LEFT)==0 + || ExprHasProperty(pOrExpr, EP_FromJoin) + ); + if( pAndExpr ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } @@ -132748,7 +137337,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( pSubWInfo ){ WhereLoop *pSubLoop; int addrExplain = sqlite3WhereExplainOneScan( - pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 + pParse, pOrTab, &pSubWInfo->a[0], 0 ); sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); @@ -132758,23 +137347,23 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** row will be skipped in subsequent sub-WHERE clauses. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - int r; int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); if( HasRowid(pTab) ){ - r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid); jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, - r,iSet); + regRowid, iSet); VdbeCoverage(v); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); int nPk = pPk->nKeyCol; int iPk; + int r; /* Read the PK into an array of temp registers. */ r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPkaiColumn[iPk]; - sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, r+iPk); } /* Check if the temp table already contains this key. If so, @@ -132847,6 +137436,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } } } + ExplainQueryPlanPop(pParse); pLevel->u.pCovidx = pCov; if( pCov ) pLevel->iIdxCur = iCovCur; if( pAndExpr ){ @@ -132919,7 +137509,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } pE = pTerm->pExpr; assert( pE!=0 ); - if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ + if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){ continue; } @@ -133006,7 +137596,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); - sqlite3ExprCacheClear(pParse); for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); @@ -133222,18 +137811,18 @@ static int isLikeOrGlob( int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */ ){ - const u8 *z = 0; /* String on RHS of LIKE operator */ + const u8 *z = 0; /* String on RHS of LIKE operator */ Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ ExprList *pList; /* List of operands to the LIKE operator */ - int c; /* One character in z[] */ + u8 c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ - char wc[4]; /* Wildcard characters */ + u8 wc[4]; /* Wildcard characters */ sqlite3 *db = pParse->db; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ int rc; /* Result code to return */ - if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ + if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){ return 0; } #ifdef SQLITE_EBCDIC @@ -133258,23 +137847,6 @@ static int isLikeOrGlob( } if( z ){ - /* If the RHS begins with a digit or a minus sign, then the LHS must - ** be an ordinary column (not a virtual table column) with TEXT affinity. - ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false - ** even though "lhs LIKE rhs" is true. But if the RHS does not start - ** with a digit or '-', then "lhs LIKE rhs" will always be false if - ** the LHS is numeric and so the optimization still works. - */ - if( sqlite3Isdigit(z[0]) || z[0]=='-' ){ - if( pLeft->op!=TK_COLUMN - || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || IsVirtual(pLeft->pTab) /* Value might be numeric */ - ){ - sqlite3ValueFree(pVal); - return 0; - } - } - /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ @@ -133284,11 +137856,13 @@ static int isLikeOrGlob( /* The optimization is possible only if (1) the pattern does not begin ** with a wildcard and if (2) the non-wildcard prefix does not end with - ** an (illegal 0xff) character. The second condition is necessary so + ** an (illegal 0xff) character, or (3) the pattern does not consist of + ** a single escape character. The second condition is necessary so ** that we can increment the prefix key to find an upper bound for the - ** range search. - */ - if( cnt!=0 && 255!=(u8)z[cnt-1] ){ + ** range search. The third is because the caller assumes that the pattern + ** consists of at least one character after all escapes have been + ** removed. */ + if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){ Expr *pPrefix; /* A "complete" match if the pattern ends with "*" or "%" */ @@ -133305,6 +137879,32 @@ static int isLikeOrGlob( zNew[iTo++] = zNew[iFrom]; } zNew[iTo] = 0; + + /* If the RHS begins with a digit or a minus sign, then the LHS must be + ** an ordinary column (not a virtual table column) with TEXT affinity. + ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false + ** even though "lhs LIKE rhs" is true. But if the RHS does not start + ** with a digit or '-', then "lhs LIKE rhs" will always be false if + ** the LHS is numeric and so the optimization still works. + ** + ** 2018-09-10 ticket c94369cae9b561b1f996d0054bfab11389f9d033 + ** The RHS pattern must not be '/%' because the termination condition + ** will then become "x<'0'" and if the affinity is numeric, will then + ** be converted into "x<0", which is incorrect. + */ + if( sqlite3Isdigit(zNew[0]) + || zNew[0]=='-' + || (zNew[0]+1=='0' && iTo==1) + ){ + if( pLeft->op!=TK_COLUMN + || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT + || IsVirtual(pLeft->y.pTab) /* Value might be numeric */ + ){ + sqlite3ExprDelete(db, pPrefix); + sqlite3ValueFree(pVal); + return 0; + } + } } *ppPrefix = pPrefix; @@ -133366,6 +137966,7 @@ static int isLikeOrGlob( ** If the expression matches none of the patterns above, return 0. */ static int isAuxiliaryVtabOperator( + sqlite3 *db, /* Parsing context */ Expr *pExpr, /* Test this expression */ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ Expr **ppLeft, /* Column expression to left of MATCH/op2 */ @@ -133389,26 +137990,64 @@ static int isAuxiliaryVtabOperator( if( pList==0 || pList->nExpr!=2 ){ return 0; } + + /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a + ** virtual table on their second argument, which is the same as + ** the left-hand side operand in their in-fix form. + ** + ** vtab_column MATCH expression + ** MATCH(expression,vtab_column) + */ pCol = pList->a[1].pExpr; - if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){ - return 0; + if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ + for(i=0; iu.zToken, aOp[i].zOp)==0 ){ + *peOp2 = aOp[i].eOp2; + *ppRight = pList->a[0].pExpr; + *ppLeft = pCol; + return 1; + } + } } - for(i=0; iu.zToken, aOp[i].zOp)==0 ){ - *peOp2 = aOp[i].eOp2; - *ppRight = pList->a[0].pExpr; - *ppLeft = pCol; - return 1; + + /* We can also match against the first column of overloaded + ** functions where xFindFunction returns a value of at least + ** SQLITE_INDEX_CONSTRAINT_FUNCTION. + ** + ** OVERLOADED(vtab_column,expression) + ** + ** Historically, xFindFunction expected to see lower-case function + ** names. But for this use case, xFindFunction is expected to deal + ** with function names in an arbitrary case. + */ + pCol = pList->a[0].pExpr; + if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ + sqlite3_vtab *pVtab; + sqlite3_module *pMod; + void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**); + void *pNotUsed; + pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab; + assert( pVtab!=0 ); + assert( pVtab->pModule!=0 ); + pMod = (sqlite3_module *)pVtab->pModule; + if( pMod->xFindFunction!=0 ){ + i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed); + if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ + *peOp2 = i; + *ppRight = pList->a[1].pExpr; + *ppLeft = pCol; + return 1; + } } } }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ int res = 0; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; - if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){ + if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){ res++; } - if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){ + if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){ res++; SWAP(Expr*, pLeft, pRight); } @@ -133700,7 +138339,12 @@ static void exprAnalyzeOrTerm( ** empty. */ pOrInfo->indexable = indexable; - pTerm->eOperator = indexable==0 ? 0 : WO_OR; + if( indexable ){ + pTerm->eOperator = WO_OR; + pWC->hasOr = 1; + }else{ + pTerm->eOperator = WO_OR; + } /* For a two-way OR, attempt to implementation case 2. */ @@ -133841,12 +138485,11 @@ static void exprAnalyzeOrTerm( idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); - pTerm = &pWC->a[idxTerm]; + /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); } - pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */ } } } @@ -133881,7 +138524,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); - if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; + if( sqlite3IsBinary(pColl) ) return 1; return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); } @@ -134040,7 +138683,7 @@ static void exprAnalyze( pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); } pMaskSet->bVarSelect = 0; - prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr); + prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr); if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT; if( ExprHasProperty(pExpr, EP_FromJoin) ){ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); @@ -134222,7 +138865,7 @@ static void exprAnalyze( } *pC = c + 1; } - zCollSeqName = noCase ? "NOCASE" : "BINARY"; + zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), @@ -134259,7 +138902,7 @@ static void exprAnalyze( */ if( pWC->op==TK_AND ){ Expr *pRight = 0, *pLeft = 0; - int res = isAuxiliaryVtabOperator(pExpr, &eOp2, &pLeft, &pRight); + int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight); while( res-- > 0 ){ int idxNew; WhereTerm *pNewTerm; @@ -134356,6 +138999,7 @@ static void exprAnalyze( if( pExpr->op==TK_NOTNULL && pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 + && !ExprHasProperty(pExpr, EP_FromJoin) && OptimizationEnabled(db, SQLITE_Stat34) ){ Expr *pNewExpr; @@ -134433,6 +139077,7 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit( WhereInfo *pWInfo /* The WHERE processing context */ ){ pWC->pWInfo = pWInfo; + pWC->hasOr = 0; pWC->pOuter = 0; pWC->nTerm = 0; pWC->nSlot = ArraySize(pWC->aStatic); @@ -134469,17 +139114,18 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){ ** a bitmask indicating which tables are used in that expression ** tree. */ -SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ Bitmask mask; - if( p==0 ) return 0; - if( p->op==TK_COLUMN ){ + if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ return sqlite3WhereGetMask(pMaskSet, p->iTable); + }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ + assert( p->op!=TK_IF_NULL_ROW ); + return 0; } mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; - assert( !ExprHasProperty(p, EP_TokenOnly) ); - if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); + if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft); if( p->pRight ){ - mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight); + mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight); assert( p->x.pList==0 ); }else if( ExprHasProperty(p, EP_xIsSelect) ){ if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; @@ -134489,6 +139135,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ } return mask; } +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ + return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0; +} SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){ int i; Bitmask mask = 0; @@ -134542,6 +139191,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; for(j=k=0; jnExpr; j++){ + Expr *pRhs; while( knCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", @@ -134552,9 +139202,10 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; - pColRef->pTab = pTab; - pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, - sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0)); + pColRef->y.pTab = pTab; + pRhs = sqlite3PExpr(pParse, TK_UPLUS, + sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); + pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } @@ -134630,15 +139281,38 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ } /* -** Return TRUE if the innermost loop of the WHERE clause implementation -** returns rows in ORDER BY order for complete run of the inner loop. +** In the ORDER BY LIMIT optimization, if the inner-most loop is known +** to emit rows in increasing order, and if the last row emitted by the +** inner-most loop did not fit within the sorter, then we can skip all +** subsequent rows for the current iteration of the inner loop (because they +** will not fit in the sorter either) and continue with the second inner +** loop - the loop immediately outside the inner-most. ** -** Across multiple iterations of outer loops, the output rows need not be -** sorted. As long as rows are sorted for just the innermost loop, this -** routine can return TRUE. +** When a row does not fit in the sorter (because the sorter already +** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the +** label returned by this function. +** +** If the ORDER BY LIMIT optimization applies, the jump destination should +** be the continuation for the second-inner-most loop. If the ORDER BY +** LIMIT optimization does not apply, then the jump destination should +** be the continuation for the inner-most loop. +** +** It is always safe for this routine to return the continuation of the +** inner-most loop, in the sense that a correct answer will result. +** Returning the continuation the second inner loop is an optimization +** that might make the code run a little faster, but should not change +** the final answer. */ -SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){ - return pWInfo->bOrderedInnerLoop; +SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){ + WhereLevel *pInner; + if( !pWInfo->bOrderedInnerLoop ){ + /* The ORDER BY LIMIT optimization does not apply. Jump to the + ** continuation of the inner-most loop. */ + return pWInfo->iContinue; + } + pInner = &pWInfo->a[pWInfo->nLevel-1]; + assert( pInner->addrNxt!=0 ); + return pInner->addrNxt; } /* @@ -135365,7 +140039,6 @@ static void constructAutomaticIndex( VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ - sqlite3ExprCachePush(pParse); pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; @@ -135373,7 +140046,7 @@ static void constructAutomaticIndex( sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } @@ -135395,14 +140068,12 @@ static void constructAutomaticIndex( translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, pTabItem->regResult, 1); sqlite3VdbeGoto(v, addrTop); - pTabItem->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); } sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); - sqlite3ExprCachePop(pParse); /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); @@ -135508,6 +140179,20 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; + if( (pSrc->fg.jointype & JT_LEFT)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (pTerm->eOperator & (WO_IS|WO_ISNULL)) + ){ + /* An "IS" term in the WHERE clause where the virtual table is the rhs + ** of a LEFT JOIN. Do not pass this term to the virtual table + ** implementation, as this can lead to incorrect results from SQL such + ** as: + ** + ** "LEFT JOIN vtab WHERE vtab.col IS NULL" */ + testcase( pTerm->eOperator & WO_ISNULL ); + testcase( pTerm->eOperator & WO_IS ); + continue; + } assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; @@ -135560,9 +140245,11 @@ static sqlite3_index_info *allocateIndexInfo( ** method of the virtual table with the sqlite3_index_info object that ** comes in as the 3rd argument to this function. ** -** If an error occurs, pParse is populated with an error message and a -** non-zero value is returned. Otherwise, 0 is returned and the output -** part of the sqlite3_index_info structure is left populated. +** If an error occurs, pParse is populated with an error message and an +** appropriate error code is returned. A return of SQLITE_CONSTRAINT from +** xBestIndex is not considered an error. SQLITE_CONSTRAINT indicates that +** the current configuration of "unusable" flags in sqlite3_index_info can +** not result in a valid plan. ** ** Whether or not an error is returned, it is the responsibility of the ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates @@ -135576,7 +140263,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ rc = pVtab->pModule->xBestIndex(pVtab, p); TRACE_IDX_OUTPUTS(p); - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ @@ -135587,19 +140274,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; - -#if 0 - /* This error is now caught by the caller. - ** Search for "xBestIndex malfunction" below */ - for(i=0; inConstraint; i++){ - if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){ - sqlite3ErrorMsg(pParse, - "table %s: xBestIndex returned an invalid plan", pTab->zName); - } - } -#endif - - return pParse->nErr; + return rc; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ @@ -135999,7 +140674,9 @@ static int whereRangeScanEst( Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; - if( p->nSample>0 && nEqnSampleCol ){ + if( p->nSample>0 && nEqnSampleCol + && OptimizationEnabled(pParse->db, SQLITE_Stat34) + ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; @@ -136652,6 +141329,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ sqlite3 *db = pWInfo->pParse->db; int rc; + /* Stop the search once we hit the query planner search limit */ + if( pBuilder->iPlanLimit==0 ){ + WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); + if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; + return SQLITE_DONE; + } + pBuilder->iPlanLimit--; + /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ @@ -136983,15 +141668,12 @@ static int whereLoopAddBtreeIndex( ** to mix with a lower range bound from some other source */ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; - /* Do not allow IS constraints from the WHERE clause to be used by the + /* Do not allow constraints from the WHERE clause to be used by the ** right table of a LEFT JOIN. Only constraints in the ON clause are ** allowed */ if( (pSrc->fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) - && (eOp & (WO_IS|WO_ISNULL))!=0 ){ - testcase( eOp & WO_IS ); - testcase( eOp & WO_ISNULL ); continue; } @@ -137017,7 +141699,6 @@ static int whereLoopAddBtreeIndex( if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; - pNew->wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ int i; @@ -137037,6 +141718,42 @@ static int whereLoopAddBtreeIndex( assert( nIn>0 ); /* RHS always has 2 or more terms... The parser ** changes "x IN (?)" into "x=?". */ } + if( pProbe->hasStat1 ){ + LogEst M, logK, safetyMargin; + /* Let: + ** N = the total number of rows in the table + ** K = the number of entries on the RHS of the IN operator + ** M = the number of rows in the table that match terms to the + ** to the left in the same index. If the IN operator is on + ** the left-most index column, M==N. + ** + ** Given the definitions above, it is better to omit the IN operator + ** from the index lookup and instead do a scan of the M elements, + ** testing each scanned row against the IN operator separately, if: + ** + ** M*log(K) < K*log(N) + ** + ** Our estimates for M, K, and N might be inaccurate, so we build in + ** a safety margin of 2 (LogEst: 10) that favors using the IN operator + ** with the index, as using an index has better worst-case behavior. + ** If we do not have real sqlite_stat1 data, always prefer to use + ** the index. + */ + M = pProbe->aiRowLogEst[saved_nEq]; + logK = estLog(nIn); + safetyMargin = 10; /* TUNING: extra weight for indexed IN */ + if( M + logK + safetyMargin < nIn + rLogSize ){ + WHERETRACE(0x40, + ("Scan preferred over IN operator on column %d of \"%s\" (%d<%d)\n", + saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize)); + continue; + }else{ + WHERETRACE(0x40, + ("IN operator preferred on column %d of \"%s\" (%d>=%d)\n", + saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize)); + } + } + pNew->wsFlags |= WHERE_COLUMN_IN; }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; @@ -137115,6 +141832,7 @@ static int whereLoopAddBtreeIndex( && pProbe->nSample && pNew->u.btree.nEq<=pProbe->nSampleCol && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) + && OptimizationEnabled(db, SQLITE_Stat34) ){ Expr *pExpr = pTerm->pExpr; if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ @@ -137203,6 +141921,7 @@ static int whereLoopAddBtreeIndex( if( saved_nEq==saved_nSkip && saved_nEq+1nKeyCol && pProbe->noSkipScan==0 + && OptimizationEnabled(db, SQLITE_SkipScan) && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ @@ -137266,24 +141985,6 @@ static int indexMightHelpWithOrderBy( return 0; } -/* -** Return a bitmask where 1s indicate that the corresponding column of -** the table is used by an index. Only the first 63 columns are considered. -*/ -static Bitmask columnsInIndex(Index *pIdx){ - Bitmask m = 0; - int j; - for(j=pIdx->nColumn-1; j>=0; j--){ - int x = pIdx->aiColumn[j]; - if( x>=0 ){ - testcase( x==BMS-1 ); - testcase( x==BMS-2 ); - if( xrSetup = rLogSize + rSize + 4; + pNew->rSetup = rLogSize + rSize; if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ - pNew->rSetup += 24; + pNew->rSetup += 28; + }else{ + pNew->rSetup -= 10; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); if( pNew->rSetup<0 ) pNew->rSetup = 0; @@ -137497,7 +142200,7 @@ static int whereLoopAddBtree( pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; m = 0; }else{ - m = pSrc->colUsed & ~columnsInIndex(pProbe); + m = pSrc->colUsed & pProbe->colNotIdxed; pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } @@ -137644,7 +142347,17 @@ static int whereLoopAddVirtualOne( /* Invoke the virtual table xBestIndex() method */ rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); - if( rc ) return rc; + if( rc ){ + if( rc==SQLITE_CONSTRAINT ){ + /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means + ** that the particular combination of parameters provided is unusable. + ** Make no entries in the loop table. + */ + WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n")); + return SQLITE_OK; + } + return rc; + } mxTerm = -1; assert( pNew->nLSlot>=nConstraint ); @@ -137748,7 +142461,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int if( pX->pLeft ){ pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight); } - zRet = (pC ? pC->zName : "BINARY"); + zRet = (pC ? pC->zName : sqlite3StrBINARY); } return zRet; } @@ -138040,9 +142753,11 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); + pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT; for(iTab=0, pItem=pTabList->a; pItemiTab = iTab; + pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the @@ -138064,11 +142779,19 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ { rc = whereLoopAddBtree(pBuilder, mPrereq); } - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; - if( rc || db->mallocFailed ) break; + if( rc || db->mallocFailed ){ + if( rc==SQLITE_DONE ){ + /* We hit the query planner search limit set by iPlanLimit */ + sqlite3_log(SQLITE_WARNING, "abbreviated query algorithm search"); + rc = SQLITE_OK; + }else{ + break; + } + } } whereLoopClear(db, pNew); @@ -138571,12 +143294,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; - if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){ + if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<3 ){ /* Do not use an automatic index if the this loop is expected - ** to run less than 2 times. */ + ** to run less than 1.25 times. It is tempting to also exclude + ** automatic index usage on an outer loop, but sometimes an automatic + ** index is useful in the outer loop of a correlated subquery. */ assert( 10==sqlite3LogEst(2) ); continue; } + /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); @@ -138596,7 +143322,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo, nRowEst, nOrderBy, isOrdered ); } - rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]); + /* TUNING: Add a small extra penalty (5) to sorting as an + ** extra encouragment to the query planner to select a plan + ** where the rows emerge in the correct order without any sorting + ** required. */ + rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5; WHERETRACE(0x002, ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", @@ -138786,6 +143516,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } + pWInfo->bOrderedInnerLoop = 0; if( pWInfo->pOrderBy ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ @@ -138897,7 +143628,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ } if( j!=pIdx->nKeyCol ) continue; pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; - if( pIdx->isCovering || (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){ + if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){ pLoop->wsFlags |= WHERE_IDX_ONLY; } pLoop->nLTerm = j; @@ -139158,6 +143889,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } + ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); }else{ /* Assign a bit from the bitmask to every term in the FROM clause. ** @@ -139553,7 +144285,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } #endif addrExplain = sqlite3WhereExplainOneScan( - pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags + pParse, pTabList, pLevel, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); @@ -139576,6 +144308,26 @@ whereBeginError: return 0; } +/* +** Part of sqlite3WhereEnd() will rewrite opcodes to reference the +** index rather than the main table. In SQLITE_DEBUG mode, we want +** to trace those changes if PRAGMA vdbe_addoptrace=on. This routine +** does that. +*/ +#ifndef SQLITE_DEBUG +# define OpcodeRewriteTrace(D,K,P) /* no-op */ +#else +# define OpcodeRewriteTrace(D,K,P) sqlite3WhereOpcodeRewriteTrace(D,K,P) + static void sqlite3WhereOpcodeRewriteTrace( + sqlite3 *db, + int pc, + VdbeOp *pOp + ){ + if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return; + sqlite3VdbePrintOp(0, pc, pOp); + } +#endif + /* ** Generate the end of the WHERE loop. See comments on ** sqlite3WhereBegin() for additional information. @@ -139592,7 +144344,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Generate loop termination code. */ VdbeModuleComment((v, "End WHERE-core")); - sqlite3ExprCacheClear(pParse); for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; @@ -139643,10 +144394,17 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ + if( pIn->nPrefix ){ + assert( pLoop->wsFlags & WHERE_IN_EARLYOUT ); + sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, + sqlite3VdbeCurrentAddr(v)+2, + pIn->iBase, pIn->nPrefix); + VdbeCoverage(v); + } sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); VdbeCoverage(v); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next); } sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } @@ -139737,6 +144495,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ){ last = sqlite3VdbeCurrentAddr(v); k = pLevel->addrBody; +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_VdbeAddopTrace ){ + printf("TRANSLATE opcodes in range %d..%d\n", k, last-1); + } +#endif pOp = sqlite3VdbeGetOp(v, k); for(; kp1!=pLevel->iTabCur ) continue; @@ -139756,16 +144519,22 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ if( x>=0 ){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; + OpcodeRewriteTrace(db, k, pOp); } assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 || pWInfo->eOnePass ); }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; pOp->opcode = OP_IdxRowid; + OpcodeRewriteTrace(db, k, pOp); }else if( pOp->opcode==OP_IfNullRow ){ pOp->p1 = pLevel->iIdxCur; + OpcodeRewriteTrace(db, k, pOp); } } +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n"); +#endif } } @@ -139777,6 +144546,2263 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ } /************** End of where.c ***********************************************/ +/************** Begin file window.c ******************************************/ +/* +** 2018 May 08 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ +/* #include "sqliteInt.h" */ + +#ifndef SQLITE_OMIT_WINDOWFUNC + +/* +** SELECT REWRITING +** +** Any SELECT statement that contains one or more window functions in +** either the select list or ORDER BY clause (the only two places window +** functions may be used) is transformed by function sqlite3WindowRewrite() +** in order to support window function processing. For example, with the +** schema: +** +** CREATE TABLE t1(a, b, c, d, e, f, g); +** +** the statement: +** +** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM t1 ORDER BY e; +** +** is transformed to: +** +** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM ( +** SELECT a, e, c, d, b FROM t1 ORDER BY c, d +** ) ORDER BY e; +** +** The flattening optimization is disabled when processing this transformed +** SELECT statement. This allows the implementation of the window function +** (in this case max()) to process rows sorted in order of (c, d), which +** makes things easier for obvious reasons. More generally: +** +** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to +** the sub-query. +** +** * ORDER BY, LIMIT and OFFSET remain part of the parent query. +** +** * Terminals from each of the expression trees that make up the +** select-list and ORDER BY expressions in the parent query are +** selected by the sub-query. For the purposes of the transformation, +** terminals are column references and aggregate functions. +** +** If there is more than one window function in the SELECT that uses +** the same window declaration (the OVER bit), then a single scan may +** be used to process more than one window function. For example: +** +** SELECT max(b) OVER (PARTITION BY c ORDER BY d), +** min(e) OVER (PARTITION BY c ORDER BY d) +** FROM t1; +** +** is transformed in the same way as the example above. However: +** +** SELECT max(b) OVER (PARTITION BY c ORDER BY d), +** min(e) OVER (PARTITION BY a ORDER BY b) +** FROM t1; +** +** Must be transformed to: +** +** SELECT max(b) OVER (PARTITION BY c ORDER BY d) FROM ( +** SELECT e, min(e) OVER (PARTITION BY a ORDER BY b), c, d, b FROM +** SELECT a, e, c, d, b FROM t1 ORDER BY a, b +** ) ORDER BY c, d +** ) ORDER BY e; +** +** so that both min() and max() may process rows in the order defined by +** their respective window declarations. +** +** INTERFACE WITH SELECT.C +** +** When processing the rewritten SELECT statement, code in select.c calls +** sqlite3WhereBegin() to begin iterating through the results of the +** sub-query, which is always implemented as a co-routine. It then calls +** sqlite3WindowCodeStep() to process rows and finish the scan by calling +** sqlite3WhereEnd(). +** +** sqlite3WindowCodeStep() generates VM code so that, for each row returned +** by the sub-query a sub-routine (OP_Gosub) coded by select.c is invoked. +** When the sub-routine is invoked: +** +** * The results of all window-functions for the row are stored +** in the associated Window.regResult registers. +** +** * The required terminal values are stored in the current row of +** temp table Window.iEphCsr. +** +** In some cases, depending on the window frame and the specific window +** functions invoked, sqlite3WindowCodeStep() caches each entire partition +** in a temp table before returning any rows. In other cases it does not. +** This detail is encapsulated within this file, the code generated by +** select.c is the same in either case. +** +** BUILT-IN WINDOW FUNCTIONS +** +** This implementation features the following built-in window functions: +** +** row_number() +** rank() +** dense_rank() +** percent_rank() +** cume_dist() +** ntile(N) +** lead(expr [, offset [, default]]) +** lag(expr [, offset [, default]]) +** first_value(expr) +** last_value(expr) +** nth_value(expr, N) +** +** These are the same built-in window functions supported by Postgres. +** Although the behaviour of aggregate window functions (functions that +** can be used as either aggregates or window funtions) allows them to +** be implemented using an API, built-in window functions are much more +** esoteric. Additionally, some window functions (e.g. nth_value()) +** may only be implemented by caching the entire partition in memory. +** As such, some built-in window functions use the same API as aggregate +** window functions and some are implemented directly using VDBE +** instructions. Additionally, for those functions that use the API, the +** window frame is sometimes modified before the SELECT statement is +** rewritten. For example, regardless of the specified window frame, the +** row_number() function always uses: +** +** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** +** See sqlite3WindowUpdate() for details. +** +** As well as some of the built-in window functions, aggregate window +** functions min() and max() are implemented using VDBE instructions if +** the start of the window frame is declared as anything other than +** UNBOUNDED PRECEDING. +*/ + +/* +** Implementation of built-in window function row_number(). Assumes that the +** window frame has been coerced to: +** +** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +*/ +static void row_numberStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ) (*p)++; + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void row_numberValueFunc(sqlite3_context *pCtx){ + i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + sqlite3_result_int64(pCtx, (p ? *p : 0)); +} + +/* +** Context object type used by rank(), dense_rank(), percent_rank() and +** cume_dist(). +*/ +struct CallCount { + i64 nValue; + i64 nStep; + i64 nTotal; +}; + +/* +** Implementation of built-in window function dense_rank(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +*/ +static void dense_rankStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ) p->nStep = 1; + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void dense_rankValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + if( p->nStep ){ + p->nValue++; + p->nStep = 0; + } + sqlite3_result_int64(pCtx, p->nValue); + } +} + +/* +** Implementation of built-in window function rank(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +*/ +static void rankStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + p->nStep++; + if( p->nValue==0 ){ + p->nValue = p->nStep; + } + } + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void rankValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + sqlite3_result_int64(pCtx, p->nValue); + p->nValue = 0; + } +} + +/* +** Implementation of built-in window function percent_rank(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +*/ +static void percent_rankStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==1 ); + + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + if( p->nTotal==0 ){ + p->nTotal = sqlite3_value_int64(apArg[0]); + } + p->nStep++; + if( p->nValue==0 ){ + p->nValue = p->nStep; + } + } +} +static void percent_rankValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + if( p->nTotal>1 ){ + double r = (double)(p->nValue-1) / (double)(p->nTotal-1); + sqlite3_result_double(pCtx, r); + }else{ + sqlite3_result_double(pCtx, 0.0); + } + p->nValue = 0; + } +} + +/* +** Implementation of built-in window function cume_dist(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +*/ +static void cume_distStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + assert( nArg==1 ); UNUSED_PARAMETER(nArg); + + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + if( p->nTotal==0 ){ + p->nTotal = sqlite3_value_int64(apArg[0]); + } + p->nStep++; + } +} +static void cume_distValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->nTotal ){ + double r = (double)(p->nStep) / (double)(p->nTotal); + sqlite3_result_double(pCtx, r); + } +} + +/* +** Context object for ntile() window function. +*/ +struct NtileCtx { + i64 nTotal; /* Total rows in partition */ + i64 nParam; /* Parameter passed to ntile(N) */ + i64 iRow; /* Current row */ +}; + +/* +** Implementation of ntile(). This assumes that the window frame has +** been coerced to: +** +** ROWS UNBOUNDED PRECEDING AND CURRENT ROW +*/ +static void ntileStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NtileCtx *p; + assert( nArg==2 ); UNUSED_PARAMETER(nArg); + p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + if( p->nTotal==0 ){ + p->nParam = sqlite3_value_int64(apArg[0]); + p->nTotal = sqlite3_value_int64(apArg[1]); + if( p->nParam<=0 ){ + sqlite3_result_error( + pCtx, "argument of ntile must be a positive integer", -1 + ); + } + } + p->iRow++; + } +} +static void ntileValueFunc(sqlite3_context *pCtx){ + struct NtileCtx *p; + p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->nParam>0 ){ + int nSize = (p->nTotal / p->nParam); + if( nSize==0 ){ + sqlite3_result_int64(pCtx, p->iRow); + }else{ + i64 nLarge = p->nTotal - p->nParam*nSize; + i64 iSmall = nLarge*(nSize+1); + i64 iRow = p->iRow-1; + + assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal ); + + if( iRowpVal); + p->pVal = sqlite3_value_dup(apArg[0]); + if( p->pVal==0 ){ + sqlite3_result_error_nomem(pCtx); + }else{ + p->nVal++; + } + } +} +static void last_valueInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct LastValueCtx *p; + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( ALWAYS(p) ){ + p->nVal--; + if( p->nVal==0 ){ + sqlite3_value_free(p->pVal); + p->pVal = 0; + } + } +} +static void last_valueValueFunc(sqlite3_context *pCtx){ + struct LastValueCtx *p; + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pVal ){ + sqlite3_result_value(pCtx, p->pVal); + } +} +static void last_valueFinalizeFunc(sqlite3_context *pCtx){ + struct LastValueCtx *p; + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pVal ){ + sqlite3_result_value(pCtx, p->pVal); + sqlite3_value_free(p->pVal); + p->pVal = 0; + } +} + +/* +** Static names for the built-in window function names. These static +** names are used, rather than string literals, so that FuncDef objects +** can be associated with a particular window function by direct +** comparison of the zName pointer. Example: +** +** if( pFuncDef->zName==row_valueName ){ ... } +*/ +static const char row_numberName[] = "row_number"; +static const char dense_rankName[] = "dense_rank"; +static const char rankName[] = "rank"; +static const char percent_rankName[] = "percent_rank"; +static const char cume_distName[] = "cume_dist"; +static const char ntileName[] = "ntile"; +static const char last_valueName[] = "last_value"; +static const char nth_valueName[] = "nth_value"; +static const char first_valueName[] = "first_value"; +static const char leadName[] = "lead"; +static const char lagName[] = "lag"; + +/* +** No-op implementations of xStep() and xFinalize(). Used as place-holders +** for built-in window functions that never call those interfaces. +** +** The noopValueFunc() is called but is expected to do nothing. The +** noopStepFunc() is never called, and so it is marked with NO_TEST to +** let the test coverage routine know not to expect this function to be +** invoked. +*/ +static void noopStepFunc( /*NO_TEST*/ + sqlite3_context *p, /*NO_TEST*/ + int n, /*NO_TEST*/ + sqlite3_value **a /*NO_TEST*/ +){ /*NO_TEST*/ + UNUSED_PARAMETER(p); /*NO_TEST*/ + UNUSED_PARAMETER(n); /*NO_TEST*/ + UNUSED_PARAMETER(a); /*NO_TEST*/ + assert(0); /*NO_TEST*/ +} /*NO_TEST*/ +static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } + +/* Window functions that use all window interfaces: xStep, xFinal, +** xValue, and xInverse */ +#define WINDOWFUNCALL(name,nArg,extra) { \ + nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ + name ## InvFunc, name ## Name, {0} \ +} + +/* Window functions that are implemented using bytecode and thus have +** no-op routines for their methods */ +#define WINDOWFUNCNOOP(name,nArg,extra) { \ + nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + noopStepFunc, noopValueFunc, noopValueFunc, \ + noopStepFunc, name ## Name, {0} \ +} + +/* Window functions that use all window interfaces: xStep, the +** same routine for xFinalize and xValue and which never call +** xInverse. */ +#define WINDOWFUNCX(name,nArg,extra) { \ + nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \ + noopStepFunc, name ## Name, {0} \ +} + + +/* +** Register those built-in window functions that are not also aggregates. +*/ +SQLITE_PRIVATE void sqlite3WindowFunctions(void){ + static FuncDef aWindowFuncs[] = { + WINDOWFUNCX(row_number, 0, 0), + WINDOWFUNCX(dense_rank, 0, 0), + WINDOWFUNCX(rank, 0, 0), + WINDOWFUNCX(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCX(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCX(ntile, 1, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCALL(last_value, 1, 0), + WINDOWFUNCNOOP(nth_value, 2, 0), + WINDOWFUNCNOOP(first_value, 1, 0), + WINDOWFUNCNOOP(lead, 1, 0), + WINDOWFUNCNOOP(lead, 2, 0), + WINDOWFUNCNOOP(lead, 3, 0), + WINDOWFUNCNOOP(lag, 1, 0), + WINDOWFUNCNOOP(lag, 2, 0), + WINDOWFUNCNOOP(lag, 3, 0), + }; + sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); +} + +/* +** This function is called immediately after resolving the function name +** for a window function within a SELECT statement. Argument pList is a +** linked list of WINDOW definitions for the current SELECT statement. +** Argument pFunc is the function definition just resolved and pWin +** is the Window object representing the associated OVER clause. This +** function updates the contents of pWin as follows: +** +** * If the OVER clause refered to a named window (as in "max(x) OVER win"), +** search list pList for a matching WINDOW definition, and update pWin +** accordingly. If no such WINDOW clause can be found, leave an error +** in pParse. +** +** * If the function is a built-in window function that requires the +** window to be coerced (see "BUILT-IN WINDOW FUNCTIONS" at the top +** of this file), pWin is updated here. +*/ +SQLITE_PRIVATE void sqlite3WindowUpdate( + Parse *pParse, + Window *pList, /* List of named windows for this SELECT */ + Window *pWin, /* Window frame to update */ + FuncDef *pFunc /* Window function definition */ +){ + if( pWin->zName && pWin->eType==0 ){ + Window *p; + for(p=pList; p; p=p->pNextWin){ + if( sqlite3StrICmp(p->zName, pWin->zName)==0 ) break; + } + if( p==0 ){ + sqlite3ErrorMsg(pParse, "no such window: %s", pWin->zName); + return; + } + pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0); + pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0); + pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0); + pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0); + pWin->eStart = p->eStart; + pWin->eEnd = p->eEnd; + pWin->eType = p->eType; + } + if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){ + sqlite3 *db = pParse->db; + if( pWin->pFilter ){ + sqlite3ErrorMsg(pParse, + "FILTER clause may only be used with aggregate window functions" + ); + }else + if( pFunc->zName==row_numberName || pFunc->zName==ntileName ){ + sqlite3ExprDelete(db, pWin->pStart); + sqlite3ExprDelete(db, pWin->pEnd); + pWin->pStart = pWin->pEnd = 0; + pWin->eType = TK_ROWS; + pWin->eStart = TK_UNBOUNDED; + pWin->eEnd = TK_CURRENT; + }else + + if( pFunc->zName==dense_rankName || pFunc->zName==rankName + || pFunc->zName==percent_rankName || pFunc->zName==cume_distName + ){ + sqlite3ExprDelete(db, pWin->pStart); + sqlite3ExprDelete(db, pWin->pEnd); + pWin->pStart = pWin->pEnd = 0; + pWin->eType = TK_RANGE; + pWin->eStart = TK_UNBOUNDED; + pWin->eEnd = TK_CURRENT; + } + } + pWin->pFunc = pFunc; +} + +/* +** Context object passed through sqlite3WalkExprList() to +** selectWindowRewriteExprCb() by selectWindowRewriteEList(). +*/ +typedef struct WindowRewrite WindowRewrite; +struct WindowRewrite { + Window *pWin; + SrcList *pSrc; + ExprList *pSub; + Select *pSubSelect; /* Current sub-select, if any */ +}; + +/* +** Callback function used by selectWindowRewriteEList(). If necessary, +** this function appends to the output expression-list and updates +** expression (*ppExpr) in place. +*/ +static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ + struct WindowRewrite *p = pWalker->u.pRewrite; + Parse *pParse = pWalker->pParse; + + /* If this function is being called from within a scalar sub-select + ** that used by the SELECT statement being processed, only process + ** TK_COLUMN expressions that refer to it (the outer SELECT). Do + ** not process aggregates or window functions at all, as they belong + ** to the scalar sub-select. */ + if( p->pSubSelect ){ + if( pExpr->op!=TK_COLUMN ){ + return WRC_Continue; + }else{ + int nSrc = p->pSrc->nSrc; + int i; + for(i=0; iiTable==p->pSrc->a[i].iCursor ) break; + } + if( i==nSrc ) return WRC_Continue; + } + } + + switch( pExpr->op ){ + + case TK_FUNCTION: + if( !ExprHasProperty(pExpr, EP_WinFunc) ){ + break; + }else{ + Window *pWin; + for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ + if( pExpr->y.pWin==pWin ){ + assert( pWin->pOwner==pExpr ); + return WRC_Prune; + } + } + } + /* Fall through. */ + + case TK_AGG_FUNCTION: + case TK_COLUMN: { + Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0); + p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup); + if( p->pSub ){ + assert( ExprHasProperty(pExpr, EP_Static)==0 ); + ExprSetProperty(pExpr, EP_Static); + sqlite3ExprDelete(pParse->db, pExpr); + ExprClearProperty(pExpr, EP_Static); + memset(pExpr, 0, sizeof(Expr)); + + pExpr->op = TK_COLUMN; + pExpr->iColumn = p->pSub->nExpr-1; + pExpr->iTable = p->pWin->iEphCsr; + } + + break; + } + + default: /* no-op */ + break; + } + + return WRC_Continue; +} +static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){ + struct WindowRewrite *p = pWalker->u.pRewrite; + Select *pSave = p->pSubSelect; + if( pSave==pSelect ){ + return WRC_Continue; + }else{ + p->pSubSelect = pSelect; + sqlite3WalkSelect(pWalker, pSelect); + p->pSubSelect = pSave; + } + return WRC_Prune; +} + + +/* +** Iterate through each expression in expression-list pEList. For each: +** +** * TK_COLUMN, +** * aggregate function, or +** * window function with a Window object that is not a member of the +** Window list passed as the second argument (pWin). +** +** Append the node to output expression-list (*ppSub). And replace it +** with a TK_COLUMN that reads the (N-1)th element of table +** pWin->iEphCsr, where N is the number of elements in (*ppSub) after +** appending the new one. +*/ +static void selectWindowRewriteEList( + Parse *pParse, + Window *pWin, + SrcList *pSrc, + ExprList *pEList, /* Rewrite expressions in this list */ + ExprList **ppSub /* IN/OUT: Sub-select expression-list */ +){ + Walker sWalker; + WindowRewrite sRewrite; + + memset(&sWalker, 0, sizeof(Walker)); + memset(&sRewrite, 0, sizeof(WindowRewrite)); + + sRewrite.pSub = *ppSub; + sRewrite.pWin = pWin; + sRewrite.pSrc = pSrc; + + sWalker.pParse = pParse; + sWalker.xExprCallback = selectWindowRewriteExprCb; + sWalker.xSelectCallback = selectWindowRewriteSelectCb; + sWalker.u.pRewrite = &sRewrite; + + (void)sqlite3WalkExprList(&sWalker, pEList); + + *ppSub = sRewrite.pSub; +} + +/* +** Append a copy of each expression in expression-list pAppend to +** expression list pList. Return a pointer to the result list. +*/ +static ExprList *exprListAppendList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to append. Might be NULL */ + ExprList *pAppend /* List of values to append. Might be NULL */ +){ + if( pAppend ){ + int i; + int nInit = pList ? pList->nExpr : 0; + for(i=0; inExpr; i++){ + Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0); + pList = sqlite3ExprListAppend(pParse, pList, pDup); + if( pList ) pList->a[nInit+i].sortOrder = pAppend->a[i].sortOrder; + } + } + return pList; +} + +/* +** If the SELECT statement passed as the second argument does not invoke +** any SQL window functions, this function is a no-op. Otherwise, it +** rewrites the SELECT statement so that window function xStep functions +** are invoked in the correct order as described under "SELECT REWRITING" +** at the top of this file. +*/ +SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ + int rc = SQLITE_OK; + if( p->pWin && p->pPrior==0 ){ + Vdbe *v = sqlite3GetVdbe(pParse); + sqlite3 *db = pParse->db; + Select *pSub = 0; /* The subquery */ + SrcList *pSrc = p->pSrc; + Expr *pWhere = p->pWhere; + ExprList *pGroupBy = p->pGroupBy; + Expr *pHaving = p->pHaving; + ExprList *pSort = 0; + + ExprList *pSublist = 0; /* Expression list for sub-query */ + Window *pMWin = p->pWin; /* Master window object */ + Window *pWin; /* Window object iterator */ + + p->pSrc = 0; + p->pWhere = 0; + p->pGroupBy = 0; + p->pHaving = 0; + + /* Create the ORDER BY clause for the sub-select. This is the concatenation + ** of the window PARTITION and ORDER BY clauses. Then, if this makes it + ** redundant, remove the ORDER BY from the parent SELECT. */ + pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0); + pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy); + if( pSort && p->pOrderBy ){ + if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){ + sqlite3ExprListDelete(db, p->pOrderBy); + p->pOrderBy = 0; + } + } + + /* Assign a cursor number for the ephemeral table used to buffer rows. + ** The OpenEphemeral instruction is coded later, after it is known how + ** many columns the table will have. */ + pMWin->iEphCsr = pParse->nTab++; + + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist); + pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); + + /* Append the PARTITION BY and ORDER BY expressions to the to the + ** sub-select expression list. They are required to figure out where + ** boundaries for partitions and sets of peer rows lie. */ + pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition); + pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy); + + /* Append the arguments passed to each window function to the + ** sub-select expression list. Also allocate two registers for each + ** window function - one for the accumulator, another for interim + ** results. */ + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); + pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList); + if( pWin->pFilter ){ + Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0); + pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter); + } + pWin->regAccum = ++pParse->nMem; + pWin->regResult = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + } + + /* If there is no ORDER BY or PARTITION BY clause, and the window + ** function accepts zero arguments, and there are no other columns + ** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible + ** that pSublist is still NULL here. Add a constant expression here to + ** keep everything legal in this case. + */ + if( pSublist==0 ){ + pSublist = sqlite3ExprListAppend(pParse, 0, + sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0) + ); + } + + pSub = sqlite3SelectNew( + pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 + ); + p->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + assert( p->pSrc || db->mallocFailed ); + if( p->pSrc ){ + p->pSrc->a[0].pSelect = pSub; + sqlite3SrcListAssignCursors(pParse, p->pSrc); + if( sqlite3ExpandSubquery(pParse, &p->pSrc->a[0]) ){ + rc = SQLITE_NOMEM; + }else{ + pSub->selFlags |= SF_Expanded; + p->selFlags &= ~SF_Aggregate; + sqlite3SelectPrep(pParse, pSub, 0); + } + + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); + }else{ + sqlite3SelectDelete(db, pSub); + } + if( db->mallocFailed ) rc = SQLITE_NOMEM; + } + + return rc; +} + +/* +** Free the Window object passed as the second argument. +*/ +SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3 *db, Window *p){ + if( p ){ + sqlite3ExprDelete(db, p->pFilter); + sqlite3ExprListDelete(db, p->pPartition); + sqlite3ExprListDelete(db, p->pOrderBy); + sqlite3ExprDelete(db, p->pEnd); + sqlite3ExprDelete(db, p->pStart); + sqlite3DbFree(db, p->zName); + sqlite3DbFree(db, p); + } +} + +/* +** Free the linked list of Window objects starting at the second argument. +*/ +SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p){ + while( p ){ + Window *pNext = p->pNextWin; + sqlite3WindowDelete(db, p); + p = pNext; + } +} + +/* +** The argument expression is an PRECEDING or FOLLOWING offset. The +** value should be a non-negative integer. If the value is not a +** constant, change it to NULL. The fact that it is then a non-negative +** integer will be caught later. But it is important not to leave +** variable values in the expression tree. +*/ +static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ + if( 0==sqlite3ExprIsConstant(pExpr) ){ + sqlite3ExprDelete(pParse->db, pExpr); + pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); + } + return pExpr; +} + +/* +** Allocate and return a new Window object describing a Window Definition. +*/ +SQLITE_PRIVATE Window *sqlite3WindowAlloc( + Parse *pParse, /* Parsing context */ + int eType, /* Frame type. TK_RANGE or TK_ROWS */ + int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */ + Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */ + int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */ + Expr *pEnd /* End window size if TK_FOLLOWING or PRECEDING */ +){ + Window *pWin = 0; + + /* Parser assures the following: */ + assert( eType==TK_RANGE || eType==TK_ROWS ); + assert( eStart==TK_CURRENT || eStart==TK_PRECEDING + || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING ); + assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING + || eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING ); + assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) ); + assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) ); + + + /* If a frame is declared "RANGE" (not "ROWS"), then it may not use + ** either " PRECEDING" or " FOLLOWING". + */ + if( eType==TK_RANGE && (pStart!=0 || pEnd!=0) ){ + sqlite3ErrorMsg(pParse, "RANGE must use only UNBOUNDED or CURRENT ROW"); + goto windowAllocErr; + } + + /* Additionally, the + ** starting boundary type may not occur earlier in the following list than + ** the ending boundary type: + ** + ** UNBOUNDED PRECEDING + ** PRECEDING + ** CURRENT ROW + ** FOLLOWING + ** UNBOUNDED FOLLOWING + ** + ** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending + ** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting + ** frame boundary. + */ + if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING) + || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT)) + ){ + sqlite3ErrorMsg(pParse, "unsupported frame delimiter for ROWS"); + goto windowAllocErr; + } + + pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( pWin==0 ) goto windowAllocErr; + pWin->eType = eType; + pWin->eStart = eStart; + pWin->eEnd = eEnd; + pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd); + pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart); + return pWin; + +windowAllocErr: + sqlite3ExprDelete(pParse->db, pEnd); + sqlite3ExprDelete(pParse->db, pStart); + return 0; +} + +/* +** Attach window object pWin to expression p. +*/ +SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ + if( p ){ + assert( p->op==TK_FUNCTION ); + /* This routine is only called for the parser. If pWin was not + ** allocated due to an OOM, then the parser would fail before ever + ** invoking this routine */ + if( ALWAYS(pWin) ){ + p->y.pWin = pWin; + ExprSetProperty(p, EP_WinFunc); + pWin->pOwner = p; + if( p->flags & EP_Distinct ){ + sqlite3ErrorMsg(pParse, + "DISTINCT is not supported for window functions"); + } + } + }else{ + sqlite3WindowDelete(pParse->db, pWin); + } +} + +/* +** Return 0 if the two window objects are identical, or non-zero otherwise. +** Identical window objects can be processed in a single scan. +*/ +SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ + if( p1->eType!=p2->eType ) return 1; + if( p1->eStart!=p2->eStart ) return 1; + if( p1->eEnd!=p2->eEnd ) return 1; + if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1; + if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; + if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1; + if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1; + return 0; +} + + +/* +** This is called by code in select.c before it calls sqlite3WhereBegin() +** to begin iterating through the sub-query results. It is used to allocate +** and initialize registers and cursors used by sqlite3WindowCodeStep(). +*/ +SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ + Window *pWin; + Vdbe *v = sqlite3GetVdbe(pParse); + int nPart = (pMWin->pPartition ? pMWin->pPartition->nExpr : 0); + nPart += (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); + if( nPart ){ + pMWin->regPart = pParse->nMem+1; + pParse->nMem += nPart; + sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nPart-1); + } + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *p = pWin->pFunc; + if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){ + /* The inline versions of min() and max() require a single ephemeral + ** table and 3 registers. The registers are used as follows: + ** + ** regApp+0: slot to copy min()/max() argument to for MakeRecord + ** regApp+1: integer value used to ensure keys are unique + ** regApp+2: output of MakeRecord + */ + ExprList *pList = pWin->pOwner->x.pList; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0); + pWin->csrApp = pParse->nTab++; + pWin->regApp = pParse->nMem+1; + pParse->nMem += 3; + if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){ + assert( pKeyInfo->aSortOrder[0]==0 ); + pKeyInfo->aSortOrder[0] = 1; + } + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2); + sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } + else if( p->zName==nth_valueName || p->zName==first_valueName ){ + /* Allocate two registers at pWin->regApp. These will be used to + ** store the start and end index of the current frame. */ + assert( pMWin->iEphCsr ); + pWin->regApp = pParse->nMem+1; + pWin->csrApp = pParse->nTab++; + pParse->nMem += 2; + sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); + } + else if( p->zName==leadName || p->zName==lagName ){ + assert( pMWin->iEphCsr ); + pWin->csrApp = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); + } + } +} + +/* +** A "PRECEDING " (eCond==0) or "FOLLOWING " (eCond==1) or the +** value of the second argument to nth_value() (eCond==2) has just been +** evaluated and the result left in register reg. This function generates VM +** code to check that the value is a non-negative integer and throws an +** exception if it is not. +*/ +static void windowCheckIntValue(Parse *pParse, int reg, int eCond){ + static const char *azErr[] = { + "frame starting offset must be a non-negative integer", + "frame ending offset must be a non-negative integer", + "second argument to nth_value must be a positive integer" + }; + static int aOp[] = { OP_Ge, OP_Ge, OP_Gt }; + Vdbe *v = sqlite3GetVdbe(pParse); + int regZero = sqlite3GetTempReg(pParse); + assert( eCond==0 || eCond==1 || eCond==2 ); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero); + sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverageIf(v, eCond==0); + VdbeCoverageIf(v, eCond==1); + VdbeCoverageIf(v, eCond==2); + sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); + VdbeCoverageNeverNullIf(v, eCond==0); + VdbeCoverageNeverNullIf(v, eCond==1); + VdbeCoverageNeverNullIf(v, eCond==2); + sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); + sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC); + sqlite3ReleaseTempReg(pParse, regZero); +} + +/* +** Return the number of arguments passed to the window-function associated +** with the object passed as the only argument to this function. +*/ +static int windowArgCount(Window *pWin){ + ExprList *pList = pWin->pOwner->x.pList; + return (pList ? pList->nExpr : 0); +} + +/* +** Generate VM code to invoke either xStep() (if bInverse is 0) or +** xInverse (if bInverse is non-zero) for each window function in the +** linked list starting at pMWin. Or, for built-in window functions +** that do not use the standard function API, generate the required +** inline VM code. +** +** If argument csr is greater than or equal to 0, then argument reg is +** the first register in an array of registers guaranteed to be large +** enough to hold the array of arguments for each function. In this case +** the arguments are extracted from the current row of csr into the +** array of registers before invoking OP_AggStep or OP_AggInverse +** +** Or, if csr is less than zero, then the array of registers at reg is +** already populated with all columns from the current row of the sub-query. +** +** If argument regPartSize is non-zero, then it is a register containing the +** number of rows in the current partition. +*/ +static void windowAggStep( + Parse *pParse, + Window *pMWin, /* Linked list of window functions */ + int csr, /* Read arguments from this cursor */ + int bInverse, /* True to invoke xInverse instead of xStep */ + int reg, /* Array of registers */ + int regPartSize /* Register containing size of partition */ +){ + Vdbe *v = sqlite3GetVdbe(pParse); + Window *pWin; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + int flags = pWin->pFunc->funcFlags; + int regArg; + int nArg = windowArgCount(pWin); + + if( csr>=0 ){ + int i; + for(i=0; iiArgCol+i, reg+i); + } + regArg = reg; + if( flags & SQLITE_FUNC_WINDOW_SIZE ){ + if( nArg==0 ){ + regArg = regPartSize; + }else{ + sqlite3VdbeAddOp2(v, OP_SCopy, regPartSize, reg+nArg); + } + nArg++; + } + }else{ + assert( !(flags & SQLITE_FUNC_WINDOW_SIZE) ); + regArg = reg + pWin->iArgCol; + } + + if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && pWin->eStart!=TK_UNBOUNDED + ){ + int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg); + VdbeCoverage(v); + if( bInverse==0 ){ + sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1); + sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp); + sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2); + sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2); + }else{ + sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp); + sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); + } + sqlite3VdbeJumpHere(v, addrIsNull); + }else if( pWin->regApp ){ + assert( pWin->pFunc->zName==nth_valueName + || pWin->pFunc->zName==first_valueName + ); + assert( bInverse==0 || bInverse==1 ); + sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); + }else if( pWin->pFunc->zName==leadName + || pWin->pFunc->zName==lagName + ){ + /* no-op */ + }else{ + int addrIf = 0; + if( pWin->pFilter ){ + int regTmp; + assert( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr ); + assert( nArg || pWin->pOwner->x.pList==0 ); + if( csr>0 ){ + regTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); + }else{ + regTmp = regArg + nArg; + } + addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); + VdbeCoverage(v); + if( csr>0 ){ + sqlite3ReleaseTempReg(pParse, regTmp); + } + } + if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ + CollSeq *pColl; + assert( nArg>0 ); + pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); + sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ); + } + sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, + bInverse, regArg, pWin->regAccum); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)nArg); + if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); + } + } +} + +/* +** Generate VM code to invoke either xValue() (bFinal==0) or xFinalize() +** (bFinal==1) for each window function in the linked list starting at +** pMWin. Or, for built-in window-functions that do not use the standard +** API, generate the equivalent VM code. +*/ +static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){ + Vdbe *v = sqlite3GetVdbe(pParse); + Window *pWin; + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && pWin->eStart!=TK_UNBOUNDED + ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult); + sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); + if( bFinal ){ + sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); + } + }else if( pWin->regApp ){ + }else{ + if( bFinal ){ + sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin)); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + }else{ + sqlite3VdbeAddOp3(v, OP_AggValue, pWin->regAccum, windowArgCount(pWin), + pWin->regResult); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + } + } + } +} + +/* +** This function generates VM code to invoke the sub-routine at address +** lblFlushPart once for each partition with the entire partition cached in +** the Window.iEphCsr temp table. +*/ +static void windowPartitionCache( + Parse *pParse, + Select *p, /* The rewritten SELECT statement */ + WhereInfo *pWInfo, /* WhereInfo to call WhereEnd() on */ + int regFlushPart, /* Register to use with Gosub lblFlushPart */ + int lblFlushPart, /* Subroutine to Gosub to */ + int *pRegSize /* OUT: Register containing partition size */ +){ + Window *pMWin = p->pWin; + Vdbe *v = sqlite3GetVdbe(pParse); + int iSubCsr = p->pSrc->a[0].iCursor; + int nSub = p->pSrc->a[0].pTab->nCol; + int k; + + int reg = pParse->nMem+1; + int regRecord = reg+nSub; + int regRowid = regRecord+1; + + *pRegSize = regRowid; + pParse->nMem += nSub + 2; + + /* Load the column values for the row returned by the sub-select + ** into an array of registers starting at reg. */ + for(k=0; kpPartition ){ + int addr; + ExprList *pPart = pMWin->pPartition; + int nPart = pPart->nExpr; + int regNewPart = reg + pMWin->nBufferCol; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); + + addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); + VdbeCoverageEqNe(v); + sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); + sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart); + VdbeComment((v, "call flush_partition")); + } + + /* Buffer the current row in the ephemeral table. */ + sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid); + + /* End of the input loop */ + sqlite3WhereEnd(pWInfo); + + /* Invoke "flush_partition" to deal with the final (or only) partition */ + sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart); + VdbeComment((v, "call flush_partition")); +} + +/* +** Invoke the sub-routine at regGosub (generated by code in select.c) to +** return the current row of Window.iEphCsr. If all window functions are +** aggregate window functions that use the standard API, a single +** OP_Gosub instruction is all that this routine generates. Extra VM code +** for per-row processing is only generated for the following built-in window +** functions: +** +** nth_value() +** first_value() +** lag() +** lead() +*/ +static void windowReturnOneRow( + Parse *pParse, + Window *pMWin, + int regGosub, + int addrGosub +){ + Vdbe *v = sqlite3GetVdbe(pParse); + Window *pWin; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + if( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName + ){ + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(v); + int tmpReg = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + + if( pFunc->zName==nth_valueName ){ + sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg); + windowCheckIntValue(pParse, tmpReg, 2); + }else{ + sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); + } + sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); + sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); + VdbeCoverageNeverNull(v); + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); + } + else if( pFunc->zName==leadName || pFunc->zName==lagName ){ + int nArg = pWin->pOwner->x.pList->nExpr; + int iEph = pMWin->iEphCsr; + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(v); + int tmpReg = sqlite3GetTempReg(pParse); + + if( nArg<3 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+2, pWin->regResult); + } + sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); + if( nArg<2 ){ + int val = (pFunc->zName==leadName ? 1 : -1); + sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); + }else{ + int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); + int tmpReg2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); + sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); + sqlite3ReleaseTempReg(pParse, tmpReg2); + } + + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); + } + } + sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); +} + +/* +** Invoke the code generated by windowReturnOneRow() and, optionally, the +** xInverse() function for each window function, for one or more rows +** from the Window.iEphCsr temp table. This routine generates VM code +** similar to: +** +** while( regCtr>0 ){ +** regCtr--; +** windowReturnOneRow() +** if( bInverse ){ +** AggInverse +** } +** Next (Window.iEphCsr) +** } +*/ +static void windowReturnRows( + Parse *pParse, + Window *pMWin, /* List of window functions */ + int regCtr, /* Register containing number of rows */ + int regGosub, /* Register for Gosub addrGosub */ + int addrGosub, /* Address of sub-routine for ReturnOneRow */ + int regInvArg, /* Array of registers for xInverse args */ + int regInvSize /* Register containing size of partition */ +){ + int addr; + Vdbe *v = sqlite3GetVdbe(pParse); + windowAggFinal(pParse, pMWin, 0); + addr = sqlite3VdbeAddOp3(v, OP_IfPos, regCtr, sqlite3VdbeCurrentAddr(v)+2 ,1); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); + windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); + if( regInvArg ){ + windowAggStep(pParse, pMWin, pMWin->iEphCsr, 1, regInvArg, regInvSize); + } + sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, addr); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addr+1); /* The OP_Goto */ +} + +/* +** Generate code to set the accumulator register for each window function +** in the linked list passed as the second argument to NULL. And perform +** any equivalent initialization required by any built-in window functions +** in the list. +*/ +static int windowInitAccum(Parse *pParse, Window *pMWin){ + Vdbe *v = sqlite3GetVdbe(pParse); + int regArg; + int nArg = 0; + Window *pWin; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + nArg = MAX(nArg, windowArgCount(pWin)); + if( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName + ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } + + if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ + assert( pWin->eStart!=TK_UNBOUNDED ); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } + } + regArg = pParse->nMem+1; + pParse->nMem += nArg; + return regArg; +} + + +/* +** This function does the work of sqlite3WindowCodeStep() for all "ROWS" +** window frame types except for "BETWEEN UNBOUNDED PRECEDING AND CURRENT +** ROW". Pseudo-code for each follows. +** +** ROWS BETWEEN PRECEDING AND FOLLOWING +** +** ... +** if( new partition ){ +** Gosub flush_partition +** } +** Insert (record in eph-table) +** sqlite3WhereEnd() +** Gosub flush_partition +** +** flush_partition: +** Once { +** OpenDup (iEphCsr -> csrStart) +** OpenDup (iEphCsr -> csrEnd) +** } +** regStart = // PRECEDING expression +** regEnd = // FOLLOWING expression +** if( regStart<0 || regEnd<0 ){ error! } +** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done +** Next(csrEnd) // if EOF skip Aggstep +** Aggstep (csrEnd) +** if( (regEnd--)<=0 ){ +** AggFinal (xValue) +** Gosub addrGosub +** Next(csr) // if EOF goto flush_partition_done +** if( (regStart--)<=0 ){ +** AggInverse (csrStart) +** Next(csrStart) +** } +** } +** flush_partition_done: +** ResetSorter (csr) +** Return +** +** ROWS BETWEEN PRECEDING AND CURRENT ROW +** ROWS BETWEEN CURRENT ROW AND FOLLOWING +** ROWS BETWEEN UNBOUNDED PRECEDING AND FOLLOWING +** +** These are similar to the above. For "CURRENT ROW", intialize the +** register to 0. For "UNBOUNDED PRECEDING" to infinity. +** +** ROWS BETWEEN PRECEDING AND UNBOUNDED FOLLOWING +** ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING +** +** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done +** while( 1 ){ +** Next(csrEnd) // Exit while(1) at EOF +** Aggstep (csrEnd) +** } +** while( 1 ){ +** AggFinal (xValue) +** Gosub addrGosub +** Next(csr) // if EOF goto flush_partition_done +** if( (regStart--)<=0 ){ +** AggInverse (csrStart) +** Next(csrStart) +** } +** } +** +** For the "CURRENT ROW AND UNBOUNDED FOLLOWING" case, the final if() +** condition is always true (as if regStart were initialized to 0). +** +** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING +** +** This is the only RANGE case handled by this routine. It modifies the +** second while( 1 ) loop in "ROWS BETWEEN CURRENT ... UNBOUNDED..." to +** be: +** +** while( 1 ){ +** AggFinal (xValue) +** while( 1 ){ +** regPeer++ +** Gosub addrGosub +** Next(csr) // if EOF goto flush_partition_done +** if( new peer ) break; +** } +** while( (regPeer--)>0 ){ +** AggInverse (csrStart) +** Next(csrStart) +** } +** } +** +** ROWS BETWEEN FOLLOWING AND FOLLOWING +** +** regEnd = regEnd - regStart +** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done +** Aggstep (csrEnd) +** Next(csrEnd) // if EOF fall-through +** if( (regEnd--)<=0 ){ +** if( (regStart--)<=0 ){ +** AggFinal (xValue) +** Gosub addrGosub +** Next(csr) // if EOF goto flush_partition_done +** } +** AggInverse (csrStart) +** Next (csrStart) +** } +** +** ROWS BETWEEN PRECEDING AND PRECEDING +** +** Replace the bit after "Rewind" in the above with: +** +** if( (regEnd--)<=0 ){ +** AggStep (csrEnd) +** Next (csrEnd) +** } +** AggFinal (xValue) +** Gosub addrGosub +** Next(csr) // if EOF goto flush_partition_done +** if( (regStart--)<=0 ){ +** AggInverse (csr2) +** Next (csr2) +** } +** +*/ +static void windowCodeRowExprStep( + Parse *pParse, + Select *p, + WhereInfo *pWInfo, + int regGosub, + int addrGosub +){ + Window *pMWin = p->pWin; + Vdbe *v = sqlite3GetVdbe(pParse); + int regFlushPart; /* Register for "Gosub flush_partition" */ + int lblFlushPart; /* Label for "Gosub flush_partition" */ + int lblFlushDone; /* Label for "Gosub flush_partition_done" */ + + int regArg; + int addr; + int csrStart = pParse->nTab++; + int csrEnd = pParse->nTab++; + int regStart; /* Value of PRECEDING */ + int regEnd; /* Value of FOLLOWING */ + int addrGoto; + int addrTop; + int addrIfPos1 = 0; + int addrIfPos2 = 0; + int regSize = 0; + + assert( pMWin->eStart==TK_PRECEDING + || pMWin->eStart==TK_CURRENT + || pMWin->eStart==TK_FOLLOWING + || pMWin->eStart==TK_UNBOUNDED + ); + assert( pMWin->eEnd==TK_FOLLOWING + || pMWin->eEnd==TK_CURRENT + || pMWin->eEnd==TK_UNBOUNDED + || pMWin->eEnd==TK_PRECEDING + ); + + /* Allocate register and label for the "flush_partition" sub-routine. */ + regFlushPart = ++pParse->nMem; + lblFlushPart = sqlite3VdbeMakeLabel(v); + lblFlushDone = sqlite3VdbeMakeLabel(v); + + regStart = ++pParse->nMem; + regEnd = ++pParse->nMem; + + windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, ®Size); + + addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); + + /* Start of "flush_partition" */ + sqlite3VdbeResolveLabel(v, lblFlushPart); + sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3); + VdbeCoverage(v); + VdbeComment((v, "Flush_partition subroutine")); + sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr); + sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr); + + /* If either regStart or regEnd are not non-negative integers, throw + ** an exception. */ + if( pMWin->pStart ){ + sqlite3ExprCode(pParse, pMWin->pStart, regStart); + windowCheckIntValue(pParse, regStart, 0); + } + if( pMWin->pEnd ){ + sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); + windowCheckIntValue(pParse, regEnd, 1); + } + + /* If this is "ROWS FOLLOWING AND ROWS FOLLOWING", do: + ** + ** if( regEndpEnd && pMWin->eStart==TK_FOLLOWING ){ + assert( pMWin->pStart!=0 ); + assert( pMWin->eEnd==TK_FOLLOWING ); + sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd); + VdbeCoverageNeverNull(v); + sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); + sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd); + } + + if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){ + assert( pMWin->pEnd!=0 ); + assert( pMWin->eStart==TK_PRECEDING ); + sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd); + VdbeCoverageNeverNull(v); + sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); + sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd); + } + + /* Initialize the accumulator register for each window function to NULL */ + regArg = windowInitAccum(pParse, pMWin); + + sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblFlushDone); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, lblFlushDone); + VdbeCoverageNeverTaken(v); + sqlite3VdbeChangeP5(v, 1); + sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, lblFlushDone); + VdbeCoverageNeverTaken(v); + sqlite3VdbeChangeP5(v, 1); + + /* Invoke AggStep function for each window function using the row that + ** csrEnd currently points to. Or, if csrEnd is already at EOF, + ** do nothing. */ + addrTop = sqlite3VdbeCurrentAddr(v); + if( pMWin->eEnd==TK_PRECEDING ){ + addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1); + VdbeCoverage(v); + } + sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + addr = sqlite3VdbeAddOp0(v, OP_Goto); + windowAggStep(pParse, pMWin, csrEnd, 0, regArg, regSize); + if( pMWin->eEnd==TK_UNBOUNDED ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); + sqlite3VdbeJumpHere(v, addr); + addrTop = sqlite3VdbeCurrentAddr(v); + }else{ + sqlite3VdbeJumpHere(v, addr); + if( pMWin->eEnd==TK_PRECEDING ){ + sqlite3VdbeJumpHere(v, addrIfPos1); + } + } + + if( pMWin->eEnd==TK_FOLLOWING ){ + addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1); + VdbeCoverage(v); + } + if( pMWin->eStart==TK_FOLLOWING ){ + addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0 , 1); + VdbeCoverage(v); + } + windowAggFinal(pParse, pMWin, 0); + windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); + sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblFlushDone); + if( pMWin->eStart==TK_FOLLOWING ){ + sqlite3VdbeJumpHere(v, addrIfPos2); + } + + if( pMWin->eStart==TK_CURRENT + || pMWin->eStart==TK_PRECEDING + || pMWin->eStart==TK_FOLLOWING + ){ + int lblSkipInverse = sqlite3VdbeMakeLabel(v);; + if( pMWin->eStart==TK_PRECEDING ){ + sqlite3VdbeAddOp3(v, OP_IfPos, regStart, lblSkipInverse, 1); + VdbeCoverage(v); + } + if( pMWin->eStart==TK_FOLLOWING ){ + sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse); + }else{ + sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1); + VdbeCoverageAlwaysTaken(v); + } + windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize); + sqlite3VdbeResolveLabel(v, lblSkipInverse); + } + if( pMWin->eEnd==TK_FOLLOWING ){ + sqlite3VdbeJumpHere(v, addrIfPos1); + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); + + /* flush_partition_done: */ + sqlite3VdbeResolveLabel(v, lblFlushDone); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); + sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); + VdbeComment((v, "end flush_partition subroutine")); + + /* Jump to here to skip over flush_partition */ + sqlite3VdbeJumpHere(v, addrGoto); +} + +/* +** This function does the work of sqlite3WindowCodeStep() for cases that +** would normally be handled by windowCodeDefaultStep() when there are +** one or more built-in window-functions that require the entire partition +** to be cached in a temp table before any rows can be returned. Additionally. +** "RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" is always handled by +** this function. +** +** Pseudo-code corresponding to the VM code generated by this function +** for each type of window follows. +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** +** flush_partition: +** Once { +** OpenDup (iEphCsr -> csrLead) +** } +** Integer ctr 0 +** foreach row (csrLead){ +** if( new peer ){ +** AggFinal (xValue) +** for(i=0; i csrLead) +** } +** foreach row (csrLead) { +** AggStep (csrLead) +** } +** foreach row (iEphCsr) { +** Gosub addrGosub +** } +** +** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING +** +** flush_partition: +** Once { +** OpenDup (iEphCsr -> csrLead) +** } +** foreach row (csrLead){ +** AggStep (csrLead) +** } +** Rewind (csrLead) +** Integer ctr 0 +** foreach row (csrLead){ +** if( new peer ){ +** AggFinal (xValue) +** for(i=0; ipWin; + Vdbe *v = sqlite3GetVdbe(pParse); + int k; + int addr; + ExprList *pPart = pMWin->pPartition; + ExprList *pOrderBy = pMWin->pOrderBy; + int nPeer = pOrderBy ? pOrderBy->nExpr : 0; + int regNewPeer; + + int addrGoto; /* Address of Goto used to jump flush_par.. */ + int addrNext; /* Jump here for next iteration of loop */ + int regFlushPart; + int lblFlushPart; + int csrLead; + int regCtr; + int regArg; /* Register array to martial function args */ + int regSize; + int lblEmpty; + int bReverse = pMWin->pOrderBy && pMWin->eStart==TK_CURRENT + && pMWin->eEnd==TK_UNBOUNDED; + + assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) + || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED) + || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT) + || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED) + ); + + lblEmpty = sqlite3VdbeMakeLabel(v); + regNewPeer = pParse->nMem+1; + pParse->nMem += nPeer; + + /* Allocate register and label for the "flush_partition" sub-routine. */ + regFlushPart = ++pParse->nMem; + lblFlushPart = sqlite3VdbeMakeLabel(v); + + csrLead = pParse->nTab++; + regCtr = ++pParse->nMem; + + windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, ®Size); + addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); + + /* Start of "flush_partition" */ + sqlite3VdbeResolveLabel(v, lblFlushPart); + sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_OpenDup, csrLead, pMWin->iEphCsr); + + /* Initialize the accumulator register for each window function to NULL */ + regArg = windowInitAccum(pParse, pMWin); + + sqlite3VdbeAddOp2(v, OP_Integer, 0, regCtr); + sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblEmpty); + VdbeCoverageNeverTaken(v); + + if( bReverse ){ + int addr2 = sqlite3VdbeCurrentAddr(v); + windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize); + sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr2); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty); + VdbeCoverageNeverTaken(v); + } + addrNext = sqlite3VdbeCurrentAddr(v); + + if( pOrderBy && (pMWin->eEnd==TK_CURRENT || pMWin->eStart==TK_CURRENT) ){ + int bCurrent = (pMWin->eStart==TK_CURRENT); + int addrJump = 0; /* Address of OP_Jump below */ + if( pMWin->eType==TK_RANGE ){ + int iOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); + int regPeer = pMWin->regPart + (pPart ? pPart->nExpr : 0); + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); + for(k=0; kiEphCsr); + sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); + + /* Jump to here to skip over flush_partition */ + sqlite3VdbeJumpHere(v, addrGoto); +} + + +/* +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** +** ... +** if( new partition ){ +** AggFinal (xFinalize) +** Gosub addrGosub +** ResetSorter eph-table +** } +** else if( new peer ){ +** AggFinal (xValue) +** Gosub addrGosub +** ResetSorter eph-table +** } +** AggStep +** Insert (record into eph-table) +** sqlite3WhereEnd() +** AggFinal (xFinalize) +** Gosub addrGosub +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING +** +** As above, except take no action for a "new peer". Invoke +** the sub-routine once only for each partition. +** +** RANGE BETWEEN CURRENT ROW AND CURRENT ROW +** +** As above, except that the "new peer" condition is handled in the +** same way as "new partition" (so there is no "else if" block). +** +** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** +** As above, except assume every row is a "new peer". +*/ +static void windowCodeDefaultStep( + Parse *pParse, + Select *p, + WhereInfo *pWInfo, + int regGosub, + int addrGosub +){ + Window *pMWin = p->pWin; + Vdbe *v = sqlite3GetVdbe(pParse); + int k; + int iSubCsr = p->pSrc->a[0].iCursor; + int nSub = p->pSrc->a[0].pTab->nCol; + int reg = pParse->nMem+1; + int regRecord = reg+nSub; + int regRowid = regRecord+1; + int addr; + ExprList *pPart = pMWin->pPartition; + ExprList *pOrderBy = pMWin->pOrderBy; + + assert( pMWin->eType==TK_RANGE + || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) + ); + + assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) + || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED) + || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT) + || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED && !pOrderBy) + ); + + if( pMWin->eEnd==TK_UNBOUNDED ){ + pOrderBy = 0; + } + + pParse->nMem += nSub + 2; + + /* Load the individual column values of the row returned by + ** the sub-select into an array of registers. */ + for(k=0; knExpr : 0); + int addrGoto = 0; + int addrJump = 0; + int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); + + if( pPart ){ + int regNewPart = reg + pMWin->nBufferCol; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); + addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); + VdbeCoverageEqNe(v); + windowAggFinal(pParse, pMWin, 1); + if( pOrderBy ){ + addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); + } + } + + if( pOrderBy ){ + int regNewPeer = reg + pMWin->nBufferCol + nPart; + int regPeer = pMWin->regPart + nPart; + + if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); + if( pMWin->eType==TK_RANGE ){ + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); + addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); + VdbeCoverage(v); + }else{ + addrJump = 0; + } + windowAggFinal(pParse, pMWin, pMWin->eStart==TK_CURRENT); + if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); + } + + sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); + sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); + VdbeCoverage(v); + + sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); + sqlite3VdbeAddOp3( + v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1 + ); + + if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); + } + + /* Invoke step function for window functions */ + windowAggStep(pParse, pMWin, -1, 0, reg, 0); + + /* Buffer the current row in the ephemeral table. */ + if( pMWin->nBufferCol>0 ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord); + }else{ + sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord); + sqlite3VdbeAppendP4(v, (void*)"", 0); + } + sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid); + + /* End the database scan loop. */ + sqlite3WhereEnd(pWInfo); + + windowAggFinal(pParse, pMWin, 1); + sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); + sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); + VdbeCoverage(v); +} + +/* +** Allocate and return a duplicate of the Window object indicated by the +** third argument. Set the Window.pOwner field of the new object to +** pOwner. +*/ +SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ + Window *pNew = 0; + if( ALWAYS(p) ){ + pNew = sqlite3DbMallocZero(db, sizeof(Window)); + if( pNew ){ + pNew->zName = sqlite3DbStrDup(db, p->zName); + pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); + pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); + pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); + pNew->eType = p->eType; + pNew->eEnd = p->eEnd; + pNew->eStart = p->eStart; + pNew->pStart = sqlite3ExprDup(db, p->pStart, 0); + pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0); + pNew->pOwner = pOwner; + } + } + return pNew; +} + +/* +** Return a copy of the linked list of Window objects passed as the +** second argument. +*/ +SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){ + Window *pWin; + Window *pRet = 0; + Window **pp = &pRet; + + for(pWin=p; pWin; pWin=pWin->pNextWin){ + *pp = sqlite3WindowDup(db, 0, pWin); + if( *pp==0 ) break; + pp = &((*pp)->pNextWin); + } + + return pRet; +} + +/* +** sqlite3WhereBegin() has already been called for the SELECT statement +** passed as the second argument when this function is invoked. It generates +** code to populate the Window.regResult register for each window function and +** invoke the sub-routine at instruction addrGosub once for each row. +** This function calls sqlite3WhereEnd() before returning. +*/ +SQLITE_PRIVATE void sqlite3WindowCodeStep( + Parse *pParse, /* Parse context */ + Select *p, /* Rewritten SELECT statement */ + WhereInfo *pWInfo, /* Context returned by sqlite3WhereBegin() */ + int regGosub, /* Register for OP_Gosub */ + int addrGosub /* OP_Gosub here to return each row */ +){ + Window *pMWin = p->pWin; + + /* There are three different functions that may be used to do the work + ** of this one, depending on the window frame and the specific built-in + ** window functions used (if any). + ** + ** windowCodeRowExprStep() handles all "ROWS" window frames, except for: + ** + ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW + ** + ** The exception is because windowCodeRowExprStep() implements all window + ** frame types by caching the entire partition in a temp table, and + ** "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" is easy enough to + ** implement without such a cache. + ** + ** windowCodeCacheStep() is used for: + ** + ** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + ** + ** It is also used for anything not handled by windowCodeRowExprStep() + ** that invokes a built-in window function that requires the entire + ** partition to be cached in a temp table before any rows are returned + ** (e.g. nth_value() or percent_rank()). + ** + ** Finally, assuming there is no built-in window function that requires + ** the partition to be cached, windowCodeDefaultStep() is used for: + ** + ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW + ** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING + ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW + ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW + ** + ** windowCodeDefaultStep() is the only one of the three functions that + ** does not cache each partition in a temp table before beginning to + ** return rows. + */ + if( pMWin->eType==TK_ROWS + && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy) + ){ + VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()")); + windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub); + }else{ + Window *pWin; + int bCache = 0; /* True to use CacheStep() */ + + if( pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED ){ + bCache = 1; + }else{ + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE) + || (pFunc->zName==nth_valueName) + || (pFunc->zName==first_valueName) + || (pFunc->zName==leadName) + || (pFunc->zName==lagName) + ){ + bCache = 1; + break; + } + } + } + + /* Otherwise, call windowCodeDefaultStep(). */ + if( bCache ){ + VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()")); + windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub); + }else{ + VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()")); + windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub); + } + } +} + +#endif /* SQLITE_OMIT_WINDOWFUNC */ + +/************** End of window.c **********************************************/ /************** Begin file parse.c *******************************************/ /* ** 2000-05-29 @@ -139803,6 +146829,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** input grammar file: */ /* #include */ +/* #include */ /************ Begin %include sections from the grammar ************************/ /* #include "sqliteInt.h" */ @@ -139854,6 +146881,8 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ */ struct TrigEvent { int a; IdList * b; }; +struct FrameBound { int eType; Expr *pExpr; }; + /* ** Disable lookaside memory allocation for objects that might be ** shared across database connections. @@ -139894,10 +146923,18 @@ static void disableLookaside(Parse *pParse){ static Expr *tokenExpr(Parse *pParse, int op, Token t){ Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); if( p ){ - memset(p, 0, sizeof(Expr)); + /* memset(p, 0, sizeof(Expr)); */ p->op = (u8)op; + p->affinity = 0; p->flags = EP_Leaf; p->iAgg = -1; + p->pLeft = p->pRight = 0; + p->x.pList = 0; + p->pAggInfo = 0; + p->y.pTab = 0; + p->op2 = 0; + p->iTable = 0; + p->iColumn = 0; p->u.zToken = (char*)&p[1]; memcpy(p->u.zToken, t.z, t.n); p->u.zToken[t.n] = 0; @@ -139908,15 +146945,19 @@ static void disableLookaside(Parse *pParse){ #if SQLITE_MAX_EXPR_DEPTH>0 p->nHeight = 1; #endif + if( IN_RENAME_OBJECT ){ + return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t); + } } return p; } + /* A routine to convert a binary TK_IS or TK_ISNOT expression into a ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; - if( pA && pY && pY->op==TK_NULL ){ + if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){ pA->op = (u8)op; sqlite3ExprDelete(db, pA->pRight); pA->pRight = 0; @@ -139985,8 +147026,10 @@ static void disableLookaside(Parse *pParse){ ** zero the stack is dynamically sized using realloc() ** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument ** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument +** sqlite3ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter ** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser ** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser +** sqlite3ParserCTX_* As sqlite3ParserARG_ except for %extra_context ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** YYNSTATE the combined number of states. @@ -140005,46 +147048,56 @@ static void disableLookaside(Parse *pParse){ # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ -#define YYCODETYPE unsigned char -#define YYNOCODE 253 +#define YYCODETYPE unsigned short int +#define YYNOCODE 277 #define YYACTIONTYPE unsigned short int -#define YYWILDCARD 83 +#define YYWILDCARD 91 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - int yy4; - struct TrigEvent yy90; - TriggerStep* yy203; - struct {int value; int mask;} yy215; - SrcList* yy259; - Expr* yy314; - ExprList* yy322; - const char* yy336; - IdList* yy384; - Select* yy387; - With* yy451; + Expr* yy18; + struct TrigEvent yy34; + IdList* yy48; + int yy70; + struct {int value; int mask;} yy111; + struct FrameBound yy119; + SrcList* yy135; + TriggerStep* yy207; + Window* yy327; + Upsert* yy340; + const char* yy392; + ExprList* yy420; + With* yy449; + Select* yy489; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 #endif -#define sqlite3ParserARG_SDECL Parse *pParse; -#define sqlite3ParserARG_PDECL ,Parse *pParse -#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse -#define sqlite3ParserARG_STORE yypParser->pParse = pParse +#define sqlite3ParserARG_SDECL +#define sqlite3ParserARG_PDECL +#define sqlite3ParserARG_PARAM +#define sqlite3ParserARG_FETCH +#define sqlite3ParserARG_STORE +#define sqlite3ParserCTX_SDECL Parse *pParse; +#define sqlite3ParserCTX_PDECL ,Parse *pParse +#define sqlite3ParserCTX_PARAM ,pParse +#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; +#define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 -#define YYNSTATE 472 -#define YYNRULE 333 -#define YYNTOKEN 143 -#define YY_MAX_SHIFT 471 -#define YY_MIN_SHIFTREDUCE 681 -#define YY_MAX_SHIFTREDUCE 1013 -#define YY_ERROR_ACTION 1014 -#define YY_ACCEPT_ACTION 1015 -#define YY_NO_ACTION 1016 -#define YY_MIN_REDUCE 1017 -#define YY_MAX_REDUCE 1349 +#define YYNSTATE 521 +#define YYNRULE 367 +#define YYNTOKEN 155 +#define YY_MAX_SHIFT 520 +#define YY_MIN_SHIFTREDUCE 756 +#define YY_MAX_SHIFTREDUCE 1122 +#define YY_ERROR_ACTION 1123 +#define YY_ACCEPT_ACTION 1124 +#define YY_NO_ACTION 1125 +#define YY_MIN_REDUCE 1126 +#define YY_MAX_REDUCE 1492 /************* End control #defines *******************************************/ +#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. @@ -140109,481 +147162,568 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (1566) +#define YY_ACTTAB_COUNT (2009) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 1169, 1015, 167, 167, 1, 168, 466, 1313, 466, 1083, - /* 10 */ 1062, 466, 97, 94, 183, 1057, 466, 329, 1083, 342, - /* 20 */ 97, 94, 183, 459, 459, 459, 436, 57, 57, 57, - /* 30 */ 57, 807, 57, 57, 367, 367, 367, 57, 57, 808, - /* 40 */ 1270, 1088, 1088, 104, 105, 95, 991, 991, 868, 871, - /* 50 */ 860, 860, 102, 102, 103, 103, 103, 103, 233, 233, - /* 60 */ 326, 1011, 449, 437, 449, 446, 351, 449, 461, 1142, - /* 70 */ 463, 342, 449, 426, 1316, 209, 180, 742, 80, 299, - /* 80 */ 857, 857, 869, 872, 101, 101, 101, 101, 100, 100, - /* 90 */ 99, 99, 99, 98, 368, 104, 105, 95, 991, 991, - /* 100 */ 868, 871, 860, 860, 102, 102, 103, 103, 103, 103, - /* 110 */ 99, 99, 99, 98, 368, 355, 97, 94, 183, 228, - /* 120 */ 106, 1012, 407, 342, 101, 101, 101, 101, 100, 100, - /* 130 */ 99, 99, 99, 98, 368, 861, 101, 101, 101, 101, - /* 140 */ 100, 100, 99, 99, 99, 98, 368, 104, 105, 95, - /* 150 */ 991, 991, 868, 871, 860, 860, 102, 102, 103, 103, - /* 160 */ 103, 103, 201, 368, 375, 420, 417, 416, 387, 273, - /* 170 */ 65, 97, 94, 183, 168, 342, 415, 951, 1343, 396, - /* 180 */ 66, 1343, 320, 959, 371, 970, 334, 340, 101, 101, - /* 190 */ 101, 101, 100, 100, 99, 99, 99, 98, 368, 104, - /* 200 */ 105, 95, 991, 991, 868, 871, 860, 860, 102, 102, - /* 210 */ 103, 103, 103, 103, 373, 100, 100, 99, 99, 99, - /* 220 */ 98, 368, 970, 971, 972, 201, 1100, 342, 420, 417, - /* 230 */ 416, 287, 366, 365, 337, 970, 1162, 463, 949, 415, - /* 240 */ 101, 101, 101, 101, 100, 100, 99, 99, 99, 98, - /* 250 */ 368, 104, 105, 95, 991, 991, 868, 871, 860, 860, - /* 260 */ 102, 102, 103, 103, 103, 103, 777, 241, 233, 233, - /* 270 */ 9, 847, 970, 971, 972, 390, 998, 1141, 998, 342, - /* 280 */ 463, 252, 829, 719, 98, 368, 840, 298, 338, 142, - /* 290 */ 839, 339, 101, 101, 101, 101, 100, 100, 99, 99, - /* 300 */ 99, 98, 368, 104, 105, 95, 991, 991, 868, 871, - /* 310 */ 860, 860, 102, 102, 103, 103, 103, 103, 272, 466, - /* 320 */ 392, 839, 839, 841, 97, 94, 183, 390, 1317, 253, - /* 330 */ 456, 342, 125, 166, 807, 712, 208, 407, 386, 970, - /* 340 */ 57, 57, 808, 238, 101, 101, 101, 101, 100, 100, - /* 350 */ 99, 99, 99, 98, 368, 104, 105, 95, 991, 991, - /* 360 */ 868, 871, 860, 860, 102, 102, 103, 103, 103, 103, - /* 370 */ 466, 108, 466, 267, 465, 442, 970, 971, 972, 261, - /* 380 */ 951, 1344, 909, 342, 1344, 142, 829, 848, 1292, 959, - /* 390 */ 371, 55, 55, 57, 57, 242, 101, 101, 101, 101, - /* 400 */ 100, 100, 99, 99, 99, 98, 368, 104, 105, 95, - /* 410 */ 991, 991, 868, 871, 860, 860, 102, 102, 103, 103, - /* 420 */ 103, 103, 272, 382, 262, 253, 456, 310, 364, 253, - /* 430 */ 456, 86, 264, 84, 266, 342, 441, 176, 175, 834, - /* 440 */ 464, 949, 767, 767, 332, 313, 1094, 396, 101, 101, - /* 450 */ 101, 101, 100, 100, 99, 99, 99, 98, 368, 104, - /* 460 */ 105, 95, 991, 991, 868, 871, 860, 860, 102, 102, - /* 470 */ 103, 103, 103, 103, 227, 227, 233, 233, 233, 233, - /* 480 */ 387, 273, 234, 234, 326, 950, 463, 342, 463, 298, - /* 490 */ 463, 914, 914, 404, 463, 1037, 123, 265, 27, 970, - /* 500 */ 101, 101, 101, 101, 100, 100, 99, 99, 99, 98, - /* 510 */ 368, 104, 105, 95, 991, 991, 868, 871, 860, 860, - /* 520 */ 102, 102, 103, 103, 103, 103, 435, 233, 233, 466, - /* 530 */ 285, 686, 687, 688, 127, 271, 970, 971, 972, 463, - /* 540 */ 1345, 327, 342, 407, 157, 1012, 988, 13, 13, 181, - /* 550 */ 41, 41, 101, 101, 101, 101, 100, 100, 99, 99, - /* 560 */ 99, 98, 368, 715, 794, 378, 104, 105, 95, 991, - /* 570 */ 991, 868, 871, 860, 860, 102, 102, 103, 103, 103, - /* 580 */ 103, 970, 378, 377, 346, 239, 847, 1086, 1086, 280, - /* 590 */ 1169, 283, 204, 203, 202, 177, 298, 342, 407, 298, - /* 600 */ 715, 840, 169, 299, 407, 839, 82, 101, 101, 101, - /* 610 */ 101, 100, 100, 99, 99, 99, 98, 368, 970, 971, - /* 620 */ 972, 104, 105, 95, 991, 991, 868, 871, 860, 860, - /* 630 */ 102, 102, 103, 103, 103, 103, 839, 839, 841, 362, - /* 640 */ 240, 124, 1169, 172, 126, 378, 1269, 1169, 1066, 342, - /* 650 */ 253, 456, 407, 407, 407, 396, 352, 401, 407, 429, - /* 660 */ 398, 85, 101, 101, 101, 101, 100, 100, 99, 99, - /* 670 */ 99, 98, 368, 104, 105, 95, 991, 991, 868, 871, - /* 680 */ 860, 860, 102, 102, 103, 103, 103, 103, 1169, 466, - /* 690 */ 230, 233, 233, 792, 1235, 1095, 1091, 1293, 1, 77, - /* 700 */ 278, 342, 205, 463, 974, 911, 1040, 348, 353, 911, - /* 710 */ 42, 42, 79, 403, 101, 101, 101, 101, 100, 100, - /* 720 */ 99, 99, 99, 98, 368, 104, 93, 95, 991, 991, - /* 730 */ 868, 871, 860, 860, 102, 102, 103, 103, 103, 103, - /* 740 */ 402, 9, 974, 243, 772, 458, 348, 232, 180, 771, - /* 750 */ 946, 312, 342, 328, 363, 349, 143, 831, 389, 1278, - /* 760 */ 211, 211, 21, 347, 432, 182, 101, 101, 101, 101, - /* 770 */ 100, 100, 99, 99, 99, 98, 368, 105, 95, 991, - /* 780 */ 991, 868, 871, 860, 860, 102, 102, 103, 103, 103, - /* 790 */ 103, 792, 724, 22, 732, 731, 233, 233, 1239, 256, - /* 800 */ 391, 274, 342, 211, 79, 360, 257, 413, 463, 397, - /* 810 */ 207, 288, 260, 450, 79, 1239, 1241, 101, 101, 101, - /* 820 */ 101, 100, 100, 99, 99, 99, 98, 368, 95, 991, - /* 830 */ 991, 868, 871, 860, 860, 102, 102, 103, 103, 103, - /* 840 */ 103, 91, 457, 296, 3, 233, 233, 5, 438, 212, - /* 850 */ 331, 394, 739, 740, 295, 898, 894, 463, 460, 207, - /* 860 */ 801, 1237, 722, 211, 698, 843, 1283, 101, 101, 101, - /* 870 */ 101, 100, 100, 99, 99, 99, 98, 368, 1239, 380, - /* 880 */ 357, 369, 233, 233, 989, 219, 236, 297, 423, 292, - /* 890 */ 422, 206, 454, 898, 463, 970, 91, 457, 290, 3, - /* 900 */ 722, 142, 268, 843, 847, 466, 1258, 149, 388, 425, - /* 910 */ 88, 89, 769, 460, 930, 87, 447, 90, 369, 468, - /* 920 */ 467, 385, 989, 839, 1257, 439, 57, 57, 395, 931, - /* 930 */ 1065, 158, 970, 971, 972, 772, 369, 471, 1019, 399, - /* 940 */ 771, 253, 456, 254, 932, 119, 891, 454, 233, 233, - /* 950 */ 4, 970, 1096, 275, 839, 839, 841, 842, 19, 847, - /* 960 */ 463, 449, 448, 163, 453, 88, 89, 776, 970, 1127, - /* 970 */ 279, 930, 90, 369, 468, 467, 91, 457, 839, 3, - /* 980 */ 235, 1064, 466, 1228, 233, 233, 931, 970, 970, 971, - /* 990 */ 972, 970, 908, 460, 908, 2, 463, 81, 457, 212, - /* 1000 */ 3, 932, 282, 10, 10, 970, 971, 972, 189, 839, - /* 1010 */ 839, 841, 842, 19, 460, 284, 369, 354, 907, 286, - /* 1020 */ 907, 753, 466, 1079, 970, 971, 972, 454, 970, 971, - /* 1030 */ 972, 754, 970, 1063, 989, 372, 792, 369, 1118, 847, - /* 1040 */ 291, 452, 466, 10, 10, 88, 89, 142, 454, 168, - /* 1050 */ 300, 412, 90, 369, 468, 467, 793, 356, 839, 706, - /* 1060 */ 847, 341, 121, 10, 10, 301, 88, 89, 379, 970, - /* 1070 */ 971, 972, 989, 90, 369, 468, 467, 244, 205, 839, - /* 1080 */ 1306, 245, 1135, 245, 250, 1168, 1114, 253, 456, 839, - /* 1090 */ 839, 841, 842, 19, 1125, 237, 122, 451, 1174, 733, - /* 1100 */ 324, 324, 323, 222, 321, 466, 1046, 695, 182, 225, - /* 1110 */ 839, 839, 841, 842, 19, 103, 103, 103, 103, 96, - /* 1120 */ 185, 466, 259, 1039, 1028, 170, 10, 10, 1027, 421, - /* 1130 */ 258, 1029, 1300, 708, 792, 466, 408, 734, 8, 347, - /* 1140 */ 444, 174, 12, 12, 290, 101, 101, 101, 101, 100, - /* 1150 */ 100, 99, 99, 99, 98, 368, 32, 32, 466, 187, - /* 1160 */ 466, 1111, 103, 103, 103, 103, 188, 466, 325, 138, - /* 1170 */ 186, 708, 303, 305, 307, 358, 970, 270, 393, 43, - /* 1180 */ 43, 44, 44, 1157, 333, 178, 418, 294, 45, 45, - /* 1190 */ 1232, 318, 101, 101, 101, 101, 100, 100, 99, 99, - /* 1200 */ 99, 98, 368, 381, 343, 366, 365, 466, 263, 253, - /* 1210 */ 456, 466, 1062, 970, 971, 972, 1231, 997, 309, 466, - /* 1220 */ 455, 466, 427, 466, 995, 173, 996, 1303, 46, 46, - /* 1230 */ 145, 376, 37, 37, 1006, 1277, 466, 214, 1275, 64, - /* 1240 */ 47, 47, 33, 33, 34, 34, 1003, 67, 466, 998, - /* 1250 */ 350, 998, 466, 155, 233, 233, 466, 36, 36, 24, - /* 1260 */ 140, 77, 1154, 466, 383, 466, 463, 428, 466, 48, - /* 1270 */ 48, 466, 147, 49, 49, 466, 150, 50, 50, 466, - /* 1280 */ 151, 152, 466, 384, 11, 11, 51, 51, 466, 110, - /* 1290 */ 110, 153, 52, 52, 411, 466, 38, 38, 466, 191, - /* 1300 */ 53, 53, 466, 54, 54, 466, 400, 466, 330, 39, - /* 1310 */ 39, 466, 1164, 466, 25, 466, 56, 56, 466, 131, - /* 1320 */ 131, 72, 466, 132, 132, 159, 133, 133, 61, 61, - /* 1330 */ 1226, 195, 40, 40, 111, 111, 58, 58, 406, 112, - /* 1340 */ 112, 466, 277, 113, 113, 466, 226, 466, 1246, 466, - /* 1350 */ 197, 466, 164, 466, 409, 466, 198, 466, 199, 466, - /* 1360 */ 335, 281, 109, 109, 466, 1030, 130, 130, 129, 129, - /* 1370 */ 117, 117, 116, 116, 114, 114, 115, 115, 60, 60, - /* 1380 */ 62, 62, 466, 359, 466, 59, 59, 424, 1082, 1081, - /* 1390 */ 1080, 724, 1073, 1054, 336, 293, 1053, 1052, 1315, 431, - /* 1400 */ 361, 76, 248, 31, 31, 35, 35, 1072, 249, 440, - /* 1410 */ 302, 434, 213, 1122, 6, 311, 1212, 107, 83, 251, - /* 1420 */ 78, 1123, 445, 220, 443, 1036, 304, 23, 1121, 469, - /* 1430 */ 965, 221, 223, 1104, 314, 224, 344, 317, 315, 316, - /* 1440 */ 470, 306, 1025, 1120, 308, 1262, 1020, 134, 120, 246, - /* 1450 */ 682, 370, 171, 255, 1263, 135, 184, 1261, 1260, 374, - /* 1460 */ 118, 906, 904, 827, 1050, 146, 136, 137, 148, 1049, - /* 1470 */ 63, 1047, 756, 190, 269, 920, 154, 156, 68, 69, - /* 1480 */ 70, 71, 139, 923, 192, 193, 144, 919, 345, 128, - /* 1490 */ 14, 194, 276, 211, 1000, 405, 196, 161, 912, 160, - /* 1500 */ 26, 697, 410, 295, 200, 289, 414, 162, 419, 73, - /* 1510 */ 15, 16, 141, 74, 28, 247, 846, 845, 735, 874, - /* 1520 */ 954, 75, 430, 955, 29, 433, 179, 229, 231, 800, - /* 1530 */ 165, 795, 87, 210, 889, 79, 875, 17, 873, 877, - /* 1540 */ 929, 18, 928, 216, 215, 878, 20, 30, 462, 844, - /* 1550 */ 707, 92, 766, 770, 7, 322, 217, 218, 319, 1308, - /* 1560 */ 960, 1016, 1016, 1016, 1016, 1307, + /* 0 */ 368, 105, 102, 197, 105, 102, 197, 515, 1124, 1, + /* 10 */ 1, 520, 2, 1128, 515, 1192, 1171, 1456, 275, 370, + /* 20 */ 127, 1389, 1197, 1197, 1192, 1166, 178, 1205, 64, 64, + /* 30 */ 477, 887, 322, 428, 348, 37, 37, 808, 362, 888, + /* 40 */ 509, 509, 509, 112, 113, 103, 1100, 1100, 953, 956, + /* 50 */ 946, 946, 110, 110, 111, 111, 111, 111, 365, 252, + /* 60 */ 252, 515, 252, 252, 497, 515, 309, 515, 459, 515, + /* 70 */ 1079, 491, 512, 478, 6, 512, 809, 134, 498, 228, + /* 80 */ 194, 428, 37, 37, 515, 208, 64, 64, 64, 64, + /* 90 */ 13, 13, 109, 109, 109, 109, 108, 108, 107, 107, + /* 100 */ 107, 106, 401, 258, 381, 13, 13, 398, 397, 428, + /* 110 */ 252, 252, 370, 476, 405, 1104, 1079, 1080, 1081, 386, + /* 120 */ 1106, 390, 497, 512, 497, 1423, 1419, 304, 1105, 307, + /* 130 */ 1256, 496, 370, 499, 16, 16, 112, 113, 103, 1100, + /* 140 */ 1100, 953, 956, 946, 946, 110, 110, 111, 111, 111, + /* 150 */ 111, 262, 1107, 495, 1107, 401, 112, 113, 103, 1100, + /* 160 */ 1100, 953, 956, 946, 946, 110, 110, 111, 111, 111, + /* 170 */ 111, 129, 1425, 343, 1420, 339, 1059, 492, 1057, 263, + /* 180 */ 73, 105, 102, 197, 994, 109, 109, 109, 109, 108, + /* 190 */ 108, 107, 107, 107, 106, 401, 370, 111, 111, 111, + /* 200 */ 111, 104, 492, 89, 1432, 109, 109, 109, 109, 108, + /* 210 */ 108, 107, 107, 107, 106, 401, 111, 111, 111, 111, + /* 220 */ 112, 113, 103, 1100, 1100, 953, 956, 946, 946, 110, + /* 230 */ 110, 111, 111, 111, 111, 109, 109, 109, 109, 108, + /* 240 */ 108, 107, 107, 107, 106, 401, 114, 108, 108, 107, + /* 250 */ 107, 107, 106, 401, 109, 109, 109, 109, 108, 108, + /* 260 */ 107, 107, 107, 106, 401, 152, 399, 399, 399, 109, + /* 270 */ 109, 109, 109, 108, 108, 107, 107, 107, 106, 401, + /* 280 */ 178, 493, 1412, 434, 1037, 1486, 1079, 515, 1486, 370, + /* 290 */ 421, 297, 357, 412, 74, 1079, 109, 109, 109, 109, + /* 300 */ 108, 108, 107, 107, 107, 106, 401, 1413, 37, 37, + /* 310 */ 1431, 274, 506, 112, 113, 103, 1100, 1100, 953, 956, + /* 320 */ 946, 946, 110, 110, 111, 111, 111, 111, 1436, 520, + /* 330 */ 2, 1128, 1079, 1080, 1081, 430, 275, 1079, 127, 366, + /* 340 */ 933, 1079, 1080, 1081, 220, 1205, 913, 458, 455, 454, + /* 350 */ 392, 167, 515, 1035, 152, 445, 924, 453, 152, 874, + /* 360 */ 923, 289, 109, 109, 109, 109, 108, 108, 107, 107, + /* 370 */ 107, 106, 401, 13, 13, 261, 853, 252, 252, 227, + /* 380 */ 106, 401, 370, 1079, 1080, 1081, 311, 388, 1079, 296, + /* 390 */ 512, 923, 923, 925, 231, 323, 1255, 1388, 1423, 490, + /* 400 */ 274, 506, 12, 208, 274, 506, 112, 113, 103, 1100, + /* 410 */ 1100, 953, 956, 946, 946, 110, 110, 111, 111, 111, + /* 420 */ 111, 1440, 286, 1128, 288, 1079, 1097, 247, 275, 1098, + /* 430 */ 127, 387, 405, 389, 1079, 1080, 1081, 1205, 159, 238, + /* 440 */ 255, 321, 461, 316, 460, 225, 790, 105, 102, 197, + /* 450 */ 513, 314, 842, 842, 445, 109, 109, 109, 109, 108, + /* 460 */ 108, 107, 107, 107, 106, 401, 515, 514, 515, 252, + /* 470 */ 252, 1079, 1080, 1081, 435, 370, 1098, 933, 1460, 794, + /* 480 */ 274, 506, 512, 105, 102, 197, 336, 63, 63, 64, + /* 490 */ 64, 27, 790, 924, 287, 208, 1354, 923, 515, 112, + /* 500 */ 113, 103, 1100, 1100, 953, 956, 946, 946, 110, 110, + /* 510 */ 111, 111, 111, 111, 107, 107, 107, 106, 401, 49, + /* 520 */ 49, 515, 28, 1079, 405, 497, 421, 297, 923, 923, + /* 530 */ 925, 186, 468, 1079, 467, 999, 999, 442, 515, 1079, + /* 540 */ 334, 515, 45, 45, 1083, 342, 173, 168, 109, 109, + /* 550 */ 109, 109, 108, 108, 107, 107, 107, 106, 401, 13, + /* 560 */ 13, 205, 13, 13, 252, 252, 1195, 1195, 370, 1079, + /* 570 */ 1080, 1081, 787, 265, 5, 359, 494, 512, 469, 1079, + /* 580 */ 1080, 1081, 398, 397, 1079, 1079, 1080, 1081, 3, 282, + /* 590 */ 1079, 1083, 112, 113, 103, 1100, 1100, 953, 956, 946, + /* 600 */ 946, 110, 110, 111, 111, 111, 111, 252, 252, 1015, + /* 610 */ 220, 1079, 873, 458, 455, 454, 943, 943, 954, 957, + /* 620 */ 512, 252, 252, 453, 1016, 1079, 445, 1107, 1209, 1107, + /* 630 */ 1079, 1080, 1081, 515, 512, 426, 1079, 1080, 1081, 1017, + /* 640 */ 512, 109, 109, 109, 109, 108, 108, 107, 107, 107, + /* 650 */ 106, 401, 1052, 515, 50, 50, 515, 1079, 1080, 1081, + /* 660 */ 828, 370, 1051, 379, 411, 1064, 1358, 207, 408, 773, + /* 670 */ 829, 1079, 1080, 1081, 64, 64, 322, 64, 64, 1302, + /* 680 */ 947, 411, 410, 1358, 1360, 112, 113, 103, 1100, 1100, + /* 690 */ 953, 956, 946, 946, 110, 110, 111, 111, 111, 111, + /* 700 */ 294, 482, 515, 1037, 1487, 515, 434, 1487, 354, 1120, + /* 710 */ 483, 996, 913, 485, 466, 996, 132, 178, 33, 450, + /* 720 */ 1203, 136, 406, 64, 64, 479, 64, 64, 419, 369, + /* 730 */ 283, 1146, 252, 252, 109, 109, 109, 109, 108, 108, + /* 740 */ 107, 107, 107, 106, 401, 512, 224, 440, 411, 266, + /* 750 */ 1358, 266, 252, 252, 370, 296, 416, 284, 934, 396, + /* 760 */ 976, 470, 400, 252, 252, 512, 9, 473, 231, 500, + /* 770 */ 354, 1036, 1035, 1488, 355, 374, 512, 1121, 112, 113, + /* 780 */ 103, 1100, 1100, 953, 956, 946, 946, 110, 110, 111, + /* 790 */ 111, 111, 111, 252, 252, 1015, 515, 1347, 295, 252, + /* 800 */ 252, 252, 252, 1098, 375, 249, 512, 445, 872, 322, + /* 810 */ 1016, 480, 512, 195, 512, 434, 273, 15, 15, 515, + /* 820 */ 314, 515, 95, 515, 93, 1017, 367, 109, 109, 109, + /* 830 */ 109, 108, 108, 107, 107, 107, 106, 401, 515, 1121, + /* 840 */ 39, 39, 51, 51, 52, 52, 503, 370, 515, 1204, + /* 850 */ 1098, 918, 439, 341, 133, 436, 223, 222, 221, 53, + /* 860 */ 53, 322, 1400, 761, 762, 763, 515, 370, 88, 54, + /* 870 */ 54, 112, 113, 103, 1100, 1100, 953, 956, 946, 946, + /* 880 */ 110, 110, 111, 111, 111, 111, 407, 55, 55, 196, + /* 890 */ 515, 112, 113, 103, 1100, 1100, 953, 956, 946, 946, + /* 900 */ 110, 110, 111, 111, 111, 111, 135, 264, 1149, 376, + /* 910 */ 515, 40, 40, 515, 872, 515, 993, 515, 993, 116, + /* 920 */ 109, 109, 109, 109, 108, 108, 107, 107, 107, 106, + /* 930 */ 401, 41, 41, 515, 43, 43, 44, 44, 56, 56, + /* 940 */ 109, 109, 109, 109, 108, 108, 107, 107, 107, 106, + /* 950 */ 401, 515, 379, 515, 57, 57, 515, 799, 515, 379, + /* 960 */ 515, 445, 200, 515, 323, 515, 1397, 515, 1459, 515, + /* 970 */ 1287, 817, 58, 58, 14, 14, 515, 59, 59, 118, + /* 980 */ 118, 60, 60, 515, 46, 46, 61, 61, 62, 62, + /* 990 */ 47, 47, 515, 190, 189, 91, 515, 140, 140, 515, + /* 1000 */ 394, 515, 277, 1200, 141, 141, 515, 1115, 515, 992, + /* 1010 */ 515, 992, 515, 69, 69, 370, 278, 48, 48, 259, + /* 1020 */ 65, 65, 119, 119, 246, 246, 260, 66, 66, 120, + /* 1030 */ 120, 121, 121, 117, 117, 370, 515, 512, 383, 112, + /* 1040 */ 113, 103, 1100, 1100, 953, 956, 946, 946, 110, 110, + /* 1050 */ 111, 111, 111, 111, 515, 872, 515, 139, 139, 112, + /* 1060 */ 113, 103, 1100, 1100, 953, 956, 946, 946, 110, 110, + /* 1070 */ 111, 111, 111, 111, 1287, 138, 138, 125, 125, 515, + /* 1080 */ 12, 515, 281, 1287, 515, 445, 131, 1287, 109, 109, + /* 1090 */ 109, 109, 108, 108, 107, 107, 107, 106, 401, 515, + /* 1100 */ 124, 124, 122, 122, 515, 123, 123, 515, 109, 109, + /* 1110 */ 109, 109, 108, 108, 107, 107, 107, 106, 401, 515, + /* 1120 */ 68, 68, 463, 783, 515, 70, 70, 302, 67, 67, + /* 1130 */ 1032, 253, 253, 356, 1287, 191, 196, 1433, 465, 1301, + /* 1140 */ 38, 38, 384, 94, 512, 42, 42, 177, 848, 274, + /* 1150 */ 506, 385, 420, 847, 1356, 441, 508, 376, 377, 153, + /* 1160 */ 423, 872, 432, 370, 224, 251, 194, 887, 182, 293, + /* 1170 */ 783, 848, 88, 254, 466, 888, 847, 915, 807, 806, + /* 1180 */ 230, 1241, 910, 370, 17, 413, 797, 112, 113, 103, + /* 1190 */ 1100, 1100, 953, 956, 946, 946, 110, 110, 111, 111, + /* 1200 */ 111, 111, 395, 814, 815, 1175, 983, 112, 101, 103, + /* 1210 */ 1100, 1100, 953, 956, 946, 946, 110, 110, 111, 111, + /* 1220 */ 111, 111, 375, 422, 427, 429, 298, 230, 230, 88, + /* 1230 */ 1240, 451, 312, 797, 226, 88, 109, 109, 109, 109, + /* 1240 */ 108, 108, 107, 107, 107, 106, 401, 86, 433, 979, + /* 1250 */ 927, 881, 226, 983, 230, 415, 109, 109, 109, 109, + /* 1260 */ 108, 108, 107, 107, 107, 106, 401, 320, 845, 781, + /* 1270 */ 846, 100, 130, 100, 1403, 290, 370, 319, 1377, 1376, + /* 1280 */ 437, 1449, 299, 1237, 303, 306, 308, 310, 1188, 1174, + /* 1290 */ 1173, 1172, 315, 324, 325, 1228, 370, 927, 1249, 271, + /* 1300 */ 1286, 113, 103, 1100, 1100, 953, 956, 946, 946, 110, + /* 1310 */ 110, 111, 111, 111, 111, 1224, 1235, 502, 501, 1292, + /* 1320 */ 1221, 1155, 103, 1100, 1100, 953, 956, 946, 946, 110, + /* 1330 */ 110, 111, 111, 111, 111, 1148, 1137, 1136, 1138, 1443, + /* 1340 */ 446, 244, 184, 98, 507, 188, 4, 353, 327, 109, + /* 1350 */ 109, 109, 109, 108, 108, 107, 107, 107, 106, 401, + /* 1360 */ 510, 329, 331, 199, 414, 456, 292, 285, 318, 109, + /* 1370 */ 109, 109, 109, 108, 108, 107, 107, 107, 106, 401, + /* 1380 */ 11, 1271, 1279, 402, 361, 192, 1171, 1351, 431, 505, + /* 1390 */ 346, 1350, 333, 98, 507, 504, 4, 187, 1446, 1115, + /* 1400 */ 233, 1396, 155, 1394, 1112, 152, 72, 75, 378, 425, + /* 1410 */ 510, 165, 149, 157, 933, 1276, 86, 30, 1268, 417, + /* 1420 */ 96, 96, 8, 160, 161, 162, 163, 97, 418, 402, + /* 1430 */ 517, 516, 449, 402, 923, 210, 358, 424, 1282, 438, + /* 1440 */ 169, 214, 360, 1345, 80, 504, 31, 444, 1365, 301, + /* 1450 */ 245, 274, 506, 216, 174, 305, 488, 447, 217, 462, + /* 1460 */ 1139, 487, 218, 363, 933, 923, 923, 925, 926, 24, + /* 1470 */ 96, 96, 1191, 1190, 1189, 391, 1182, 97, 1163, 402, + /* 1480 */ 517, 516, 799, 364, 923, 1162, 317, 1161, 98, 507, + /* 1490 */ 1181, 4, 1458, 472, 393, 269, 270, 475, 481, 1232, + /* 1500 */ 85, 1233, 326, 328, 232, 510, 495, 1231, 330, 98, + /* 1510 */ 507, 1230, 4, 486, 335, 923, 923, 925, 926, 24, + /* 1520 */ 1435, 1068, 404, 181, 336, 256, 510, 115, 402, 332, + /* 1530 */ 352, 352, 351, 241, 349, 1214, 1414, 770, 338, 10, + /* 1540 */ 504, 340, 272, 92, 1331, 1213, 87, 183, 484, 402, + /* 1550 */ 201, 488, 280, 239, 344, 345, 489, 1145, 29, 933, + /* 1560 */ 279, 504, 1074, 518, 240, 96, 96, 242, 243, 519, + /* 1570 */ 1134, 1129, 97, 154, 402, 517, 516, 372, 373, 923, + /* 1580 */ 933, 142, 143, 128, 1381, 267, 96, 96, 852, 757, + /* 1590 */ 203, 144, 403, 97, 1382, 402, 517, 516, 204, 1380, + /* 1600 */ 923, 146, 1379, 1159, 1158, 71, 1156, 276, 202, 185, + /* 1610 */ 923, 923, 925, 926, 24, 198, 257, 126, 991, 989, + /* 1620 */ 907, 98, 507, 156, 4, 145, 158, 206, 831, 209, + /* 1630 */ 291, 923, 923, 925, 926, 24, 1005, 911, 510, 164, + /* 1640 */ 147, 380, 371, 382, 166, 76, 77, 274, 506, 148, + /* 1650 */ 78, 79, 1008, 211, 212, 1004, 137, 213, 18, 300, + /* 1660 */ 230, 402, 997, 1109, 443, 215, 32, 170, 171, 772, + /* 1670 */ 409, 448, 319, 504, 219, 172, 452, 81, 19, 457, + /* 1680 */ 313, 20, 82, 268, 488, 150, 810, 179, 83, 487, + /* 1690 */ 464, 151, 933, 180, 959, 84, 1040, 34, 96, 96, + /* 1700 */ 471, 1041, 35, 474, 193, 97, 248, 402, 517, 516, + /* 1710 */ 1068, 404, 923, 250, 256, 880, 229, 175, 875, 352, + /* 1720 */ 352, 351, 241, 349, 100, 21, 770, 22, 1054, 1056, + /* 1730 */ 7, 98, 507, 1045, 4, 337, 1058, 23, 974, 201, + /* 1740 */ 176, 280, 88, 923, 923, 925, 926, 24, 510, 279, + /* 1750 */ 960, 958, 962, 1014, 963, 1013, 235, 234, 25, 36, + /* 1760 */ 99, 90, 507, 928, 4, 511, 350, 782, 26, 841, + /* 1770 */ 236, 402, 347, 1069, 237, 1125, 1125, 1451, 510, 203, + /* 1780 */ 1450, 1125, 1125, 504, 1125, 1125, 1125, 204, 1125, 1125, + /* 1790 */ 146, 1125, 1125, 1125, 1125, 1125, 1125, 202, 1125, 1125, + /* 1800 */ 1125, 402, 933, 1125, 1125, 1125, 1125, 1125, 96, 96, + /* 1810 */ 1125, 1125, 1125, 504, 1125, 97, 1125, 402, 517, 516, + /* 1820 */ 1125, 1125, 923, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + /* 1830 */ 1125, 371, 933, 1125, 1125, 1125, 274, 506, 96, 96, + /* 1840 */ 1125, 1125, 1125, 1125, 1125, 97, 1125, 402, 517, 516, + /* 1850 */ 1125, 1125, 923, 923, 923, 925, 926, 24, 1125, 409, + /* 1860 */ 1125, 1125, 1125, 256, 1125, 1125, 1125, 1125, 352, 352, + /* 1870 */ 351, 241, 349, 1125, 1125, 770, 1125, 1125, 1125, 1125, + /* 1880 */ 1125, 1125, 1125, 923, 923, 925, 926, 24, 201, 1125, + /* 1890 */ 280, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 279, 1125, + /* 1900 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + /* 1910 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + /* 1920 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 203, 1125, + /* 1930 */ 1125, 1125, 1125, 1125, 1125, 1125, 204, 1125, 1125, 146, + /* 1940 */ 1125, 1125, 1125, 1125, 1125, 1125, 202, 1125, 1125, 1125, + /* 1950 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + /* 1960 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + /* 1970 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + /* 1980 */ 371, 1125, 1125, 1125, 1125, 274, 506, 1125, 1125, 1125, + /* 1990 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + /* 2000 */ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 409, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 152, 144, 145, 146, 147, 152, 152, 172, 152, 180, - /* 10 */ 181, 152, 223, 224, 225, 180, 152, 164, 189, 19, - /* 20 */ 223, 224, 225, 168, 169, 170, 163, 173, 174, 173, - /* 30 */ 174, 31, 173, 174, 168, 169, 170, 173, 174, 39, - /* 40 */ 243, 191, 192, 43, 44, 45, 46, 47, 48, 49, - /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 195, 196, - /* 60 */ 22, 23, 208, 209, 208, 209, 218, 208, 209, 176, - /* 70 */ 207, 19, 208, 209, 23, 212, 213, 26, 26, 152, - /* 80 */ 46, 47, 48, 49, 84, 85, 86, 87, 88, 89, - /* 90 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47, - /* 100 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 110 */ 90, 91, 92, 93, 94, 188, 223, 224, 225, 171, - /* 120 */ 68, 83, 152, 19, 84, 85, 86, 87, 88, 89, - /* 130 */ 90, 91, 92, 93, 94, 101, 84, 85, 86, 87, - /* 140 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45, - /* 150 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - /* 160 */ 56, 57, 99, 94, 194, 102, 103, 104, 109, 110, - /* 170 */ 66, 223, 224, 225, 152, 19, 113, 22, 23, 152, - /* 180 */ 24, 26, 160, 1, 2, 59, 164, 173, 84, 85, - /* 190 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43, - /* 200 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 210 */ 54, 55, 56, 57, 244, 88, 89, 90, 91, 92, - /* 220 */ 93, 94, 96, 97, 98, 99, 196, 19, 102, 103, - /* 230 */ 104, 23, 88, 89, 173, 59, 163, 207, 83, 113, - /* 240 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - /* 250 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, - /* 260 */ 52, 53, 54, 55, 56, 57, 90, 240, 195, 196, - /* 270 */ 171, 82, 96, 97, 98, 152, 132, 176, 134, 19, - /* 280 */ 207, 200, 72, 23, 93, 94, 97, 152, 173, 79, - /* 290 */ 101, 210, 84, 85, 86, 87, 88, 89, 90, 91, - /* 300 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49, - /* 310 */ 50, 51, 52, 53, 54, 55, 56, 57, 108, 152, - /* 320 */ 152, 132, 133, 134, 223, 224, 225, 152, 186, 119, - /* 330 */ 120, 19, 197, 234, 31, 23, 26, 152, 239, 59, - /* 340 */ 173, 174, 39, 220, 84, 85, 86, 87, 88, 89, - /* 350 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47, - /* 360 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 370 */ 152, 22, 152, 16, 152, 208, 96, 97, 98, 194, - /* 380 */ 22, 23, 11, 19, 26, 79, 72, 23, 0, 1, - /* 390 */ 2, 173, 174, 173, 174, 220, 84, 85, 86, 87, - /* 400 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45, - /* 410 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - /* 420 */ 56, 57, 108, 109, 110, 119, 120, 152, 208, 119, - /* 430 */ 120, 137, 75, 139, 77, 19, 152, 88, 89, 23, - /* 440 */ 115, 83, 117, 118, 163, 227, 163, 152, 84, 85, - /* 450 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43, - /* 460 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 470 */ 54, 55, 56, 57, 195, 196, 195, 196, 195, 196, - /* 480 */ 109, 110, 195, 196, 22, 23, 207, 19, 207, 152, - /* 490 */ 207, 108, 109, 110, 207, 163, 22, 140, 24, 59, - /* 500 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - /* 510 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51, - /* 520 */ 52, 53, 54, 55, 56, 57, 152, 195, 196, 152, - /* 530 */ 16, 7, 8, 9, 197, 240, 96, 97, 98, 207, - /* 540 */ 249, 250, 19, 152, 22, 83, 26, 173, 174, 152, - /* 550 */ 173, 174, 84, 85, 86, 87, 88, 89, 90, 91, - /* 560 */ 92, 93, 94, 59, 124, 152, 43, 44, 45, 46, - /* 570 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 580 */ 57, 59, 169, 170, 157, 194, 82, 191, 192, 75, - /* 590 */ 152, 77, 108, 109, 110, 26, 152, 19, 152, 152, - /* 600 */ 96, 97, 24, 152, 152, 101, 138, 84, 85, 86, - /* 610 */ 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, - /* 620 */ 98, 43, 44, 45, 46, 47, 48, 49, 50, 51, - /* 630 */ 52, 53, 54, 55, 56, 57, 132, 133, 134, 188, - /* 640 */ 194, 197, 152, 123, 197, 232, 194, 152, 182, 19, - /* 650 */ 119, 120, 152, 152, 152, 152, 218, 230, 152, 163, - /* 660 */ 233, 138, 84, 85, 86, 87, 88, 89, 90, 91, - /* 670 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49, - /* 680 */ 50, 51, 52, 53, 54, 55, 56, 57, 152, 152, - /* 690 */ 23, 195, 196, 26, 194, 194, 194, 146, 147, 130, - /* 700 */ 194, 19, 46, 207, 59, 29, 166, 167, 218, 33, - /* 710 */ 173, 174, 26, 218, 84, 85, 86, 87, 88, 89, - /* 720 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47, - /* 730 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 740 */ 64, 171, 97, 240, 116, 166, 167, 212, 213, 121, - /* 750 */ 23, 152, 19, 26, 218, 247, 248, 23, 23, 152, - /* 760 */ 26, 26, 22, 107, 163, 98, 84, 85, 86, 87, - /* 770 */ 88, 89, 90, 91, 92, 93, 94, 44, 45, 46, - /* 780 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 790 */ 57, 124, 106, 53, 100, 101, 195, 196, 152, 152, - /* 800 */ 23, 23, 19, 26, 26, 19, 152, 23, 207, 239, - /* 810 */ 26, 23, 152, 163, 26, 169, 170, 84, 85, 86, - /* 820 */ 87, 88, 89, 90, 91, 92, 93, 94, 45, 46, - /* 830 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 840 */ 57, 19, 20, 101, 22, 195, 196, 22, 19, 24, - /* 850 */ 163, 19, 7, 8, 112, 59, 23, 207, 36, 26, - /* 860 */ 23, 152, 59, 26, 21, 59, 152, 84, 85, 86, - /* 870 */ 87, 88, 89, 90, 91, 92, 93, 94, 232, 221, - /* 880 */ 94, 59, 195, 196, 59, 99, 100, 101, 102, 103, - /* 890 */ 104, 105, 70, 97, 207, 59, 19, 20, 112, 22, - /* 900 */ 97, 79, 152, 97, 82, 152, 152, 71, 221, 90, - /* 910 */ 88, 89, 23, 36, 12, 26, 163, 95, 96, 97, - /* 920 */ 98, 78, 97, 101, 152, 96, 173, 174, 96, 27, - /* 930 */ 182, 22, 96, 97, 98, 116, 59, 148, 149, 152, - /* 940 */ 121, 119, 120, 154, 42, 156, 103, 70, 195, 196, - /* 950 */ 22, 59, 163, 152, 132, 133, 134, 135, 136, 82, - /* 960 */ 207, 208, 209, 71, 62, 88, 89, 90, 59, 152, - /* 970 */ 152, 12, 95, 96, 97, 98, 19, 20, 101, 22, - /* 980 */ 22, 182, 152, 140, 195, 196, 27, 59, 96, 97, - /* 990 */ 98, 59, 132, 36, 134, 22, 207, 19, 20, 24, - /* 1000 */ 22, 42, 152, 173, 174, 96, 97, 98, 219, 132, - /* 1010 */ 133, 134, 135, 136, 36, 152, 59, 187, 132, 152, - /* 1020 */ 134, 62, 152, 152, 96, 97, 98, 70, 96, 97, - /* 1030 */ 98, 72, 59, 152, 59, 246, 26, 59, 214, 82, - /* 1040 */ 152, 192, 152, 173, 174, 88, 89, 79, 70, 152, - /* 1050 */ 152, 19, 95, 96, 97, 98, 124, 187, 101, 23, - /* 1060 */ 82, 164, 26, 173, 174, 152, 88, 89, 100, 96, - /* 1070 */ 97, 98, 97, 95, 96, 97, 98, 187, 46, 101, - /* 1080 */ 122, 184, 152, 186, 211, 152, 152, 119, 120, 132, - /* 1090 */ 133, 134, 135, 136, 152, 5, 22, 152, 152, 35, - /* 1100 */ 10, 11, 12, 13, 14, 152, 152, 17, 98, 235, - /* 1110 */ 132, 133, 134, 135, 136, 54, 55, 56, 57, 58, - /* 1120 */ 30, 152, 32, 152, 152, 198, 173, 174, 152, 65, - /* 1130 */ 40, 152, 152, 59, 124, 152, 236, 73, 199, 107, - /* 1140 */ 187, 171, 173, 174, 112, 84, 85, 86, 87, 88, - /* 1150 */ 89, 90, 91, 92, 93, 94, 173, 174, 152, 69, - /* 1160 */ 152, 211, 54, 55, 56, 57, 76, 152, 150, 79, - /* 1170 */ 80, 97, 211, 211, 211, 111, 59, 241, 241, 173, - /* 1180 */ 174, 173, 174, 202, 202, 185, 177, 176, 173, 174, - /* 1190 */ 176, 201, 84, 85, 86, 87, 88, 89, 90, 91, - /* 1200 */ 92, 93, 94, 215, 114, 88, 89, 152, 215, 119, - /* 1210 */ 120, 152, 181, 96, 97, 98, 176, 100, 215, 152, - /* 1220 */ 229, 152, 163, 152, 107, 199, 109, 155, 173, 174, - /* 1230 */ 245, 141, 173, 174, 60, 159, 152, 122, 159, 242, - /* 1240 */ 173, 174, 173, 174, 173, 174, 38, 242, 152, 132, - /* 1250 */ 159, 134, 152, 22, 195, 196, 152, 173, 174, 222, - /* 1260 */ 43, 130, 202, 152, 18, 152, 207, 208, 152, 173, - /* 1270 */ 174, 152, 190, 173, 174, 152, 193, 173, 174, 152, - /* 1280 */ 193, 193, 152, 159, 173, 174, 173, 174, 152, 173, - /* 1290 */ 174, 193, 173, 174, 18, 152, 173, 174, 152, 158, - /* 1300 */ 173, 174, 152, 173, 174, 152, 159, 152, 202, 173, - /* 1310 */ 174, 152, 190, 152, 222, 152, 173, 174, 152, 173, - /* 1320 */ 174, 137, 152, 173, 174, 190, 173, 174, 173, 174, - /* 1330 */ 202, 158, 173, 174, 173, 174, 173, 174, 61, 173, - /* 1340 */ 174, 152, 237, 173, 174, 152, 159, 152, 238, 152, - /* 1350 */ 158, 152, 22, 152, 178, 152, 158, 152, 158, 152, - /* 1360 */ 178, 159, 173, 174, 152, 159, 173, 174, 173, 174, - /* 1370 */ 173, 174, 173, 174, 173, 174, 173, 174, 173, 174, - /* 1380 */ 173, 174, 152, 63, 152, 173, 174, 107, 175, 175, - /* 1390 */ 175, 106, 183, 175, 178, 175, 177, 175, 175, 178, - /* 1400 */ 94, 107, 231, 173, 174, 173, 174, 183, 231, 125, - /* 1410 */ 216, 178, 159, 217, 22, 159, 226, 129, 137, 228, - /* 1420 */ 128, 217, 126, 25, 127, 162, 216, 26, 217, 161, - /* 1430 */ 13, 153, 153, 206, 205, 6, 251, 202, 204, 203, - /* 1440 */ 151, 216, 151, 217, 216, 171, 151, 165, 179, 179, - /* 1450 */ 4, 3, 22, 142, 171, 165, 15, 171, 171, 81, - /* 1460 */ 16, 23, 23, 120, 171, 131, 165, 111, 123, 171, - /* 1470 */ 171, 171, 20, 125, 16, 1, 123, 131, 53, 53, - /* 1480 */ 53, 53, 111, 96, 34, 122, 248, 1, 251, 5, - /* 1490 */ 22, 107, 140, 26, 74, 41, 122, 107, 67, 67, - /* 1500 */ 24, 20, 19, 112, 105, 23, 66, 22, 66, 22, - /* 1510 */ 22, 22, 37, 22, 22, 66, 23, 23, 28, 23, - /* 1520 */ 23, 26, 24, 23, 22, 24, 122, 23, 23, 96, - /* 1530 */ 22, 124, 26, 34, 23, 26, 23, 34, 23, 23, - /* 1540 */ 23, 34, 23, 22, 26, 11, 22, 22, 26, 23, - /* 1550 */ 23, 22, 116, 23, 22, 15, 122, 122, 23, 122, - /* 1560 */ 1, 252, 252, 252, 252, 122, 252, 252, 252, 252, - /* 1570 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1580 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1590 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1600 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1610 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1620 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1630 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1640 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1650 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1660 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1670 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1680 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1690 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - /* 1700 */ 252, 252, 252, 252, 252, 252, 252, 252, 252, + /* 0 */ 184, 238, 239, 240, 238, 239, 240, 163, 155, 156, + /* 10 */ 157, 158, 159, 160, 163, 191, 192, 183, 165, 19, + /* 20 */ 167, 258, 202, 203, 200, 191, 163, 174, 184, 185, + /* 30 */ 174, 31, 163, 163, 171, 184, 185, 35, 175, 39, + /* 40 */ 179, 180, 181, 43, 44, 45, 46, 47, 48, 49, + /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 184, 206, + /* 60 */ 207, 163, 206, 207, 220, 163, 16, 163, 66, 163, + /* 70 */ 59, 270, 219, 229, 273, 219, 74, 208, 174, 223, + /* 80 */ 224, 163, 184, 185, 163, 232, 184, 185, 184, 185, + /* 90 */ 184, 185, 92, 93, 94, 95, 96, 97, 98, 99, + /* 100 */ 100, 101, 102, 233, 198, 184, 185, 96, 97, 163, + /* 110 */ 206, 207, 19, 163, 261, 104, 105, 106, 107, 198, + /* 120 */ 109, 119, 220, 219, 220, 274, 275, 77, 117, 79, + /* 130 */ 187, 229, 19, 229, 184, 185, 43, 44, 45, 46, + /* 140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 150 */ 57, 233, 141, 134, 143, 102, 43, 44, 45, 46, + /* 160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 170 */ 57, 152, 274, 216, 276, 218, 83, 163, 85, 233, + /* 180 */ 67, 238, 239, 240, 11, 92, 93, 94, 95, 96, + /* 190 */ 97, 98, 99, 100, 101, 102, 19, 54, 55, 56, + /* 200 */ 57, 58, 163, 26, 163, 92, 93, 94, 95, 96, + /* 210 */ 97, 98, 99, 100, 101, 102, 54, 55, 56, 57, + /* 220 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 230 */ 53, 54, 55, 56, 57, 92, 93, 94, 95, 96, + /* 240 */ 97, 98, 99, 100, 101, 102, 69, 96, 97, 98, + /* 250 */ 99, 100, 101, 102, 92, 93, 94, 95, 96, 97, + /* 260 */ 98, 99, 100, 101, 102, 81, 179, 180, 181, 92, + /* 270 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + /* 280 */ 163, 267, 268, 163, 22, 23, 59, 163, 26, 19, + /* 290 */ 117, 118, 175, 109, 24, 59, 92, 93, 94, 95, + /* 300 */ 96, 97, 98, 99, 100, 101, 102, 268, 184, 185, + /* 310 */ 269, 127, 128, 43, 44, 45, 46, 47, 48, 49, + /* 320 */ 50, 51, 52, 53, 54, 55, 56, 57, 157, 158, + /* 330 */ 159, 160, 105, 106, 107, 163, 165, 59, 167, 184, + /* 340 */ 90, 105, 106, 107, 108, 174, 73, 111, 112, 113, + /* 350 */ 19, 22, 163, 91, 81, 163, 106, 121, 81, 132, + /* 360 */ 110, 16, 92, 93, 94, 95, 96, 97, 98, 99, + /* 370 */ 100, 101, 102, 184, 185, 255, 98, 206, 207, 26, + /* 380 */ 101, 102, 19, 105, 106, 107, 23, 198, 59, 116, + /* 390 */ 219, 141, 142, 143, 24, 163, 187, 205, 274, 275, + /* 400 */ 127, 128, 182, 232, 127, 128, 43, 44, 45, 46, + /* 410 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 420 */ 57, 158, 77, 160, 79, 59, 26, 182, 165, 59, + /* 430 */ 167, 199, 261, 102, 105, 106, 107, 174, 72, 108, + /* 440 */ 109, 110, 111, 112, 113, 114, 59, 238, 239, 240, + /* 450 */ 123, 120, 125, 126, 163, 92, 93, 94, 95, 96, + /* 460 */ 97, 98, 99, 100, 101, 102, 163, 163, 163, 206, + /* 470 */ 207, 105, 106, 107, 254, 19, 106, 90, 197, 23, + /* 480 */ 127, 128, 219, 238, 239, 240, 22, 184, 185, 184, + /* 490 */ 185, 22, 105, 106, 149, 232, 205, 110, 163, 43, + /* 500 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 510 */ 54, 55, 56, 57, 98, 99, 100, 101, 102, 184, + /* 520 */ 185, 163, 53, 59, 261, 220, 117, 118, 141, 142, + /* 530 */ 143, 131, 174, 59, 229, 116, 117, 118, 163, 59, + /* 540 */ 163, 163, 184, 185, 59, 242, 72, 22, 92, 93, + /* 550 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 184, + /* 560 */ 185, 24, 184, 185, 206, 207, 202, 203, 19, 105, + /* 570 */ 106, 107, 23, 198, 22, 174, 198, 219, 220, 105, + /* 580 */ 106, 107, 96, 97, 59, 105, 106, 107, 22, 174, + /* 590 */ 59, 106, 43, 44, 45, 46, 47, 48, 49, 50, + /* 600 */ 51, 52, 53, 54, 55, 56, 57, 206, 207, 12, + /* 610 */ 108, 59, 132, 111, 112, 113, 46, 47, 48, 49, + /* 620 */ 219, 206, 207, 121, 27, 59, 163, 141, 207, 143, + /* 630 */ 105, 106, 107, 163, 219, 234, 105, 106, 107, 42, + /* 640 */ 219, 92, 93, 94, 95, 96, 97, 98, 99, 100, + /* 650 */ 101, 102, 76, 163, 184, 185, 163, 105, 106, 107, + /* 660 */ 63, 19, 86, 163, 163, 23, 163, 130, 205, 21, + /* 670 */ 73, 105, 106, 107, 184, 185, 163, 184, 185, 237, + /* 680 */ 110, 180, 181, 180, 181, 43, 44, 45, 46, 47, + /* 690 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 700 */ 174, 163, 163, 22, 23, 163, 163, 26, 22, 23, + /* 710 */ 220, 29, 73, 220, 272, 33, 22, 163, 24, 19, + /* 720 */ 174, 208, 259, 184, 185, 19, 184, 185, 80, 175, + /* 730 */ 230, 174, 206, 207, 92, 93, 94, 95, 96, 97, + /* 740 */ 98, 99, 100, 101, 102, 219, 46, 65, 247, 195, + /* 750 */ 247, 197, 206, 207, 19, 116, 117, 118, 23, 220, + /* 760 */ 112, 174, 220, 206, 207, 219, 22, 174, 24, 174, + /* 770 */ 22, 23, 91, 264, 265, 168, 219, 91, 43, 44, + /* 780 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + /* 790 */ 55, 56, 57, 206, 207, 12, 163, 149, 255, 206, + /* 800 */ 207, 206, 207, 59, 104, 23, 219, 163, 26, 163, + /* 810 */ 27, 105, 219, 163, 219, 163, 211, 184, 185, 163, + /* 820 */ 120, 163, 146, 163, 148, 42, 221, 92, 93, 94, + /* 830 */ 95, 96, 97, 98, 99, 100, 101, 102, 163, 91, + /* 840 */ 184, 185, 184, 185, 184, 185, 63, 19, 163, 205, + /* 850 */ 106, 23, 245, 163, 208, 248, 116, 117, 118, 184, + /* 860 */ 185, 163, 163, 7, 8, 9, 163, 19, 26, 184, + /* 870 */ 185, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 880 */ 52, 53, 54, 55, 56, 57, 163, 184, 185, 107, + /* 890 */ 163, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 900 */ 52, 53, 54, 55, 56, 57, 208, 255, 177, 178, + /* 910 */ 163, 184, 185, 163, 132, 163, 141, 163, 143, 22, + /* 920 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + /* 930 */ 102, 184, 185, 163, 184, 185, 184, 185, 184, 185, + /* 940 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + /* 950 */ 102, 163, 163, 163, 184, 185, 163, 115, 163, 163, + /* 960 */ 163, 163, 15, 163, 163, 163, 163, 163, 23, 163, + /* 970 */ 163, 26, 184, 185, 184, 185, 163, 184, 185, 184, + /* 980 */ 185, 184, 185, 163, 184, 185, 184, 185, 184, 185, + /* 990 */ 184, 185, 163, 96, 97, 147, 163, 184, 185, 163, + /* 1000 */ 199, 163, 163, 205, 184, 185, 163, 60, 163, 141, + /* 1010 */ 163, 143, 163, 184, 185, 19, 163, 184, 185, 230, + /* 1020 */ 184, 185, 184, 185, 206, 207, 230, 184, 185, 184, + /* 1030 */ 185, 184, 185, 184, 185, 19, 163, 219, 231, 43, + /* 1040 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 1050 */ 54, 55, 56, 57, 163, 26, 163, 184, 185, 43, + /* 1060 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 1070 */ 54, 55, 56, 57, 163, 184, 185, 184, 185, 163, + /* 1080 */ 182, 163, 163, 163, 163, 163, 22, 163, 92, 93, + /* 1090 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 163, + /* 1100 */ 184, 185, 184, 185, 163, 184, 185, 163, 92, 93, + /* 1110 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 163, + /* 1120 */ 184, 185, 98, 59, 163, 184, 185, 205, 184, 185, + /* 1130 */ 23, 206, 207, 26, 163, 26, 107, 153, 154, 237, + /* 1140 */ 184, 185, 231, 147, 219, 184, 185, 249, 124, 127, + /* 1150 */ 128, 231, 254, 129, 163, 231, 177, 178, 262, 263, + /* 1160 */ 118, 132, 19, 19, 46, 223, 224, 31, 24, 23, + /* 1170 */ 106, 124, 26, 22, 272, 39, 129, 23, 109, 110, + /* 1180 */ 26, 163, 140, 19, 22, 234, 59, 43, 44, 45, + /* 1190 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 1200 */ 56, 57, 231, 7, 8, 193, 59, 43, 44, 45, + /* 1210 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 1220 */ 56, 57, 104, 61, 23, 23, 23, 26, 26, 26, + /* 1230 */ 163, 23, 23, 106, 26, 26, 92, 93, 94, 95, + /* 1240 */ 96, 97, 98, 99, 100, 101, 102, 138, 105, 23, + /* 1250 */ 59, 23, 26, 106, 26, 163, 92, 93, 94, 95, + /* 1260 */ 96, 97, 98, 99, 100, 101, 102, 110, 23, 23, + /* 1270 */ 23, 26, 26, 26, 163, 163, 19, 120, 163, 163, + /* 1280 */ 163, 130, 163, 163, 163, 163, 163, 163, 163, 193, + /* 1290 */ 193, 163, 163, 163, 163, 225, 19, 106, 163, 222, + /* 1300 */ 163, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 1310 */ 53, 54, 55, 56, 57, 163, 163, 203, 163, 163, + /* 1320 */ 222, 163, 45, 46, 47, 48, 49, 50, 51, 52, + /* 1330 */ 53, 54, 55, 56, 57, 163, 163, 163, 163, 163, + /* 1340 */ 251, 250, 209, 19, 20, 182, 22, 161, 222, 92, + /* 1350 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + /* 1360 */ 36, 222, 222, 260, 226, 188, 256, 226, 187, 92, + /* 1370 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + /* 1380 */ 210, 213, 213, 59, 213, 196, 192, 187, 256, 244, + /* 1390 */ 212, 187, 226, 19, 20, 71, 22, 210, 166, 60, + /* 1400 */ 130, 170, 260, 170, 38, 81, 257, 257, 170, 104, + /* 1410 */ 36, 22, 43, 201, 90, 236, 138, 235, 213, 18, + /* 1420 */ 96, 97, 48, 204, 204, 204, 204, 103, 170, 105, + /* 1430 */ 106, 107, 18, 59, 110, 169, 213, 213, 201, 170, + /* 1440 */ 201, 169, 236, 213, 146, 71, 235, 62, 253, 252, + /* 1450 */ 170, 127, 128, 169, 22, 170, 82, 189, 169, 104, + /* 1460 */ 170, 87, 169, 189, 90, 141, 142, 143, 144, 145, + /* 1470 */ 96, 97, 186, 186, 186, 64, 194, 103, 186, 105, + /* 1480 */ 106, 107, 115, 189, 110, 188, 186, 186, 19, 20, + /* 1490 */ 194, 22, 186, 189, 102, 246, 246, 189, 133, 228, + /* 1500 */ 104, 228, 227, 227, 170, 36, 134, 228, 227, 19, + /* 1510 */ 20, 228, 22, 84, 271, 141, 142, 143, 144, 145, + /* 1520 */ 0, 1, 2, 216, 22, 5, 36, 137, 59, 227, + /* 1530 */ 10, 11, 12, 13, 14, 217, 269, 17, 216, 22, + /* 1540 */ 71, 170, 243, 146, 241, 217, 136, 215, 135, 59, + /* 1550 */ 30, 82, 32, 25, 214, 213, 87, 173, 26, 90, + /* 1560 */ 40, 71, 13, 172, 164, 96, 97, 164, 6, 162, + /* 1570 */ 162, 162, 103, 263, 105, 106, 107, 266, 266, 110, + /* 1580 */ 90, 176, 176, 190, 182, 190, 96, 97, 98, 4, + /* 1590 */ 70, 176, 3, 103, 182, 105, 106, 107, 78, 182, + /* 1600 */ 110, 81, 182, 182, 182, 182, 182, 151, 88, 22, + /* 1610 */ 141, 142, 143, 144, 145, 15, 89, 16, 23, 23, + /* 1620 */ 128, 19, 20, 139, 22, 119, 131, 24, 20, 133, + /* 1630 */ 16, 141, 142, 143, 144, 145, 1, 140, 36, 131, + /* 1640 */ 119, 61, 122, 37, 139, 53, 53, 127, 128, 119, + /* 1650 */ 53, 53, 105, 34, 130, 1, 5, 104, 22, 149, + /* 1660 */ 26, 59, 68, 75, 41, 130, 24, 68, 104, 20, + /* 1670 */ 150, 19, 120, 71, 114, 22, 67, 22, 22, 67, + /* 1680 */ 23, 22, 22, 67, 82, 37, 28, 23, 138, 87, + /* 1690 */ 22, 153, 90, 23, 23, 26, 23, 22, 96, 97, + /* 1700 */ 24, 23, 22, 24, 130, 103, 23, 105, 106, 107, + /* 1710 */ 1, 2, 110, 23, 5, 105, 34, 22, 132, 10, + /* 1720 */ 11, 12, 13, 14, 26, 34, 17, 34, 85, 83, + /* 1730 */ 44, 19, 20, 23, 22, 24, 75, 34, 23, 30, + /* 1740 */ 26, 32, 26, 141, 142, 143, 144, 145, 36, 40, + /* 1750 */ 23, 23, 23, 23, 11, 23, 22, 26, 22, 22, + /* 1760 */ 22, 19, 20, 23, 22, 26, 15, 23, 22, 124, + /* 1770 */ 130, 59, 23, 1, 130, 277, 277, 130, 36, 70, + /* 1780 */ 130, 277, 277, 71, 277, 277, 277, 78, 277, 277, + /* 1790 */ 81, 277, 277, 277, 277, 277, 277, 88, 277, 277, + /* 1800 */ 277, 59, 90, 277, 277, 277, 277, 277, 96, 97, + /* 1810 */ 277, 277, 277, 71, 277, 103, 277, 105, 106, 107, + /* 1820 */ 277, 277, 110, 277, 277, 277, 277, 277, 277, 277, + /* 1830 */ 277, 122, 90, 277, 277, 277, 127, 128, 96, 97, + /* 1840 */ 277, 277, 277, 277, 277, 103, 277, 105, 106, 107, + /* 1850 */ 277, 277, 110, 141, 142, 143, 144, 145, 277, 150, + /* 1860 */ 277, 277, 277, 5, 277, 277, 277, 277, 10, 11, + /* 1870 */ 12, 13, 14, 277, 277, 17, 277, 277, 277, 277, + /* 1880 */ 277, 277, 277, 141, 142, 143, 144, 145, 30, 277, + /* 1890 */ 32, 277, 277, 277, 277, 277, 277, 277, 40, 277, + /* 1900 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + /* 1910 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + /* 1920 */ 277, 277, 277, 277, 277, 277, 277, 277, 70, 277, + /* 1930 */ 277, 277, 277, 277, 277, 277, 78, 277, 277, 81, + /* 1940 */ 277, 277, 277, 277, 277, 277, 88, 277, 277, 277, + /* 1950 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + /* 1960 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + /* 1970 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + /* 1980 */ 122, 277, 277, 277, 277, 127, 128, 277, 277, 277, + /* 1990 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + /* 2000 */ 277, 277, 277, 277, 277, 277, 277, 277, 150, 277, + /* 2010 */ 277, 277, 277, 277, 277, 277, 277, 277, 277, }; -#define YY_SHIFT_COUNT (471) +#define YY_SHIFT_COUNT (520) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (1559) +#define YY_SHIFT_MAX (1858) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 182, 1090, 822, 822, 306, 957, 957, 957, 957, 210, - /* 10 */ 0, 0, 104, 630, 957, 957, 957, 957, 957, 957, - /* 20 */ 957, 1117, 1117, 126, 968, 306, 306, 306, 306, 306, - /* 30 */ 306, 52, 156, 208, 260, 312, 364, 416, 468, 523, - /* 40 */ 578, 630, 630, 630, 630, 630, 630, 630, 630, 630, - /* 50 */ 630, 630, 630, 630, 630, 630, 630, 630, 682, 630, - /* 60 */ 733, 783, 783, 877, 957, 957, 957, 957, 957, 957, - /* 70 */ 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, - /* 80 */ 957, 957, 957, 957, 957, 957, 957, 957, 957, 957, - /* 90 */ 957, 957, 957, 957, 957, 978, 957, 957, 957, 957, - /* 100 */ 957, 957, 957, 957, 957, 957, 957, 957, 957, 1061, - /* 110 */ 1108, 1108, 1108, 1108, 1108, 40, 127, 20, 280, 843, - /* 120 */ 1032, 144, 144, 280, 310, 310, 310, 310, 59, 191, - /* 130 */ 69, 1566, 1566, 1566, 786, 786, 786, 522, 836, 522, - /* 140 */ 959, 959, 892, 155, 358, 280, 280, 280, 280, 280, - /* 150 */ 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - /* 160 */ 280, 280, 280, 280, 280, 280, 371, 388, 645, 645, - /* 170 */ 531, 1566, 1566, 1566, 504, 189, 189, 909, 63, 176, - /* 180 */ 928, 440, 932, 973, 280, 280, 280, 280, 280, 314, - /* 190 */ 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - /* 200 */ 280, 280, 1064, 1064, 1064, 280, 280, 280, 280, 667, - /* 210 */ 280, 280, 280, 825, 280, 280, 902, 280, 280, 280, - /* 220 */ 280, 280, 280, 280, 280, 383, 676, 325, 975, 975, - /* 230 */ 975, 975, 1010, 325, 325, 819, 349, 524, 569, 829, - /* 240 */ 829, 832, 569, 832, 686, 51, 656, 303, 303, 303, - /* 250 */ 829, 294, 520, 628, 474, 1174, 1115, 1115, 1208, 1208, - /* 260 */ 1115, 1231, 1217, 1131, 1246, 1246, 1246, 1246, 1115, 1276, - /* 270 */ 1131, 1231, 1217, 1217, 1131, 1115, 1276, 1184, 1277, 1115, - /* 280 */ 1276, 1330, 1115, 1276, 1115, 1276, 1330, 1280, 1280, 1280, - /* 290 */ 1320, 1330, 1280, 1285, 1280, 1320, 1280, 1280, 1330, 1306, - /* 300 */ 1306, 1330, 1284, 1294, 1284, 1294, 1284, 1294, 1284, 1294, - /* 310 */ 1115, 1392, 1115, 1281, 1288, 1296, 1292, 1297, 1131, 1398, - /* 320 */ 1401, 1417, 1417, 1429, 1429, 1429, 1566, 1566, 1566, 1566, - /* 330 */ 1566, 1566, 1566, 1566, 1566, 1566, 1566, 1566, 1566, 1566, - /* 340 */ 1566, 1566, 34, 357, 38, 462, 514, 484, 1074, 727, - /* 350 */ 740, 734, 735, 777, 778, 784, 788, 803, 694, 845, - /* 360 */ 742, 796, 833, 837, 889, 860, 886, 1036, 806, 958, - /* 370 */ 1446, 1448, 1430, 1311, 1441, 1378, 1444, 1438, 1439, 1343, - /* 380 */ 1334, 1356, 1345, 1452, 1348, 1458, 1474, 1353, 1346, 1425, - /* 390 */ 1426, 1427, 1428, 1371, 1387, 1450, 1363, 1486, 1484, 1468, - /* 400 */ 1384, 1352, 1431, 1467, 1432, 1420, 1454, 1374, 1390, 1476, - /* 410 */ 1481, 1483, 1391, 1399, 1485, 1440, 1487, 1488, 1482, 1489, - /* 420 */ 1442, 1490, 1491, 1449, 1475, 1493, 1494, 1496, 1495, 1497, - /* 430 */ 1492, 1498, 1500, 1502, 1501, 1404, 1504, 1505, 1433, 1499, - /* 440 */ 1508, 1407, 1506, 1503, 1509, 1507, 1511, 1513, 1515, 1506, - /* 450 */ 1516, 1517, 1518, 1519, 1521, 1534, 1524, 1525, 1526, 1527, - /* 460 */ 1529, 1530, 1532, 1522, 1436, 1434, 1435, 1437, 1443, 1535, - /* 470 */ 1540, 1559, + /* 0 */ 1709, 1520, 1858, 1324, 1324, 277, 1374, 1469, 1602, 1712, + /* 10 */ 1712, 1712, 273, 0, 0, 113, 1016, 1712, 1712, 1712, + /* 20 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 11, 11, 236, + /* 30 */ 184, 277, 277, 277, 277, 277, 277, 93, 177, 270, + /* 40 */ 363, 456, 549, 642, 735, 828, 848, 996, 1144, 1016, + /* 50 */ 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, + /* 60 */ 1016, 1016, 1016, 1016, 1016, 1016, 1164, 1016, 1257, 1277, + /* 70 */ 1277, 1490, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, + /* 80 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, + /* 90 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, + /* 100 */ 1712, 1712, 1712, 1742, 1712, 1712, 1712, 1712, 1712, 1712, + /* 110 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 143, 162, 162, + /* 120 */ 162, 162, 162, 204, 151, 416, 531, 648, 700, 531, + /* 130 */ 486, 486, 531, 353, 353, 353, 353, 409, 279, 53, + /* 140 */ 2009, 2009, 331, 331, 331, 329, 366, 329, 329, 597, + /* 150 */ 597, 464, 474, 262, 681, 531, 531, 531, 531, 531, + /* 160 */ 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, + /* 170 */ 531, 531, 531, 531, 531, 531, 531, 173, 485, 984, + /* 180 */ 984, 576, 485, 19, 1022, 2009, 2009, 2009, 387, 250, + /* 190 */ 250, 525, 502, 278, 552, 227, 480, 566, 531, 531, + /* 200 */ 531, 531, 531, 531, 531, 531, 531, 531, 639, 531, + /* 210 */ 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, + /* 220 */ 531, 2, 2, 2, 531, 531, 531, 531, 782, 531, + /* 230 */ 531, 531, 744, 531, 531, 783, 531, 531, 531, 531, + /* 240 */ 531, 531, 531, 531, 419, 682, 327, 370, 370, 370, + /* 250 */ 370, 1029, 327, 327, 1024, 897, 856, 947, 1109, 706, + /* 260 */ 706, 1143, 1109, 1109, 1143, 842, 945, 1118, 1136, 1136, + /* 270 */ 1136, 706, 676, 400, 1047, 694, 1339, 1270, 1270, 1366, + /* 280 */ 1366, 1270, 1305, 1389, 1369, 1278, 1401, 1401, 1401, 1401, + /* 290 */ 1270, 1414, 1278, 1278, 1305, 1389, 1369, 1369, 1278, 1270, + /* 300 */ 1414, 1298, 1385, 1270, 1414, 1432, 1270, 1414, 1270, 1414, + /* 310 */ 1432, 1355, 1355, 1355, 1411, 1432, 1355, 1367, 1355, 1411, + /* 320 */ 1355, 1355, 1432, 1392, 1392, 1432, 1365, 1396, 1365, 1396, + /* 330 */ 1365, 1396, 1365, 1396, 1270, 1372, 1429, 1502, 1390, 1372, + /* 340 */ 1517, 1270, 1397, 1390, 1410, 1413, 1278, 1528, 1532, 1549, + /* 350 */ 1549, 1562, 1562, 1562, 2009, 2009, 2009, 2009, 2009, 2009, + /* 360 */ 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, + /* 370 */ 570, 345, 686, 748, 50, 740, 1064, 1107, 469, 537, + /* 380 */ 1042, 1146, 1162, 1154, 1201, 1202, 1203, 1208, 1209, 1127, + /* 390 */ 1069, 1196, 1157, 1147, 1226, 1228, 1245, 775, 868, 1246, + /* 400 */ 1247, 1191, 1151, 1585, 1589, 1587, 1456, 1600, 1527, 1601, + /* 410 */ 1595, 1596, 1492, 1484, 1506, 1603, 1495, 1608, 1496, 1614, + /* 420 */ 1635, 1508, 1497, 1521, 1580, 1606, 1505, 1592, 1593, 1597, + /* 430 */ 1598, 1530, 1547, 1619, 1524, 1654, 1651, 1636, 1553, 1510, + /* 440 */ 1594, 1634, 1599, 1588, 1623, 1535, 1564, 1642, 1649, 1652, + /* 450 */ 1552, 1560, 1653, 1609, 1655, 1656, 1657, 1659, 1612, 1658, + /* 460 */ 1660, 1616, 1648, 1664, 1550, 1668, 1538, 1670, 1671, 1669, + /* 470 */ 1673, 1675, 1676, 1678, 1680, 1679, 1574, 1683, 1690, 1610, + /* 480 */ 1682, 1695, 1586, 1698, 1691, 1698, 1693, 1643, 1661, 1646, + /* 490 */ 1686, 1710, 1711, 1714, 1716, 1703, 1715, 1698, 1727, 1728, + /* 500 */ 1729, 1730, 1731, 1732, 1734, 1743, 1736, 1737, 1740, 1744, + /* 510 */ 1738, 1746, 1739, 1645, 1640, 1644, 1647, 1650, 1749, 1751, + /* 520 */ 1772, }; -#define YY_REDUCE_COUNT (341) -#define YY_REDUCE_MIN (-211) -#define YY_REDUCE_MAX (1301) +#define YY_REDUCE_COUNT (369) +#define YY_REDUCE_MIN (-237) +#define YY_REDUCE_MAX (1424) static const short yy_reduce_ofst[] = { - /* 0 */ -143, 789, 753, 1059, -137, -146, -144, -141, -136, 687, - /* 10 */ -107, 101, -203, -52, 830, 870, 890, 167, 953, 218, - /* 20 */ 220, 413, 646, 897, 73, 281, 283, 332, 496, 601, - /* 30 */ 650, -211, -211, -211, -211, -211, -211, -211, -211, -211, - /* 40 */ -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, - /* 50 */ -211, -211, -211, -211, -211, -211, -211, -211, -211, -211, - /* 60 */ -211, -211, -211, 374, 377, 537, 969, 983, 1006, 1008, - /* 70 */ 1015, 1055, 1067, 1069, 1071, 1084, 1096, 1100, 1104, 1111, - /* 80 */ 1113, 1116, 1119, 1123, 1127, 1130, 1136, 1143, 1146, 1150, - /* 90 */ 1153, 1155, 1159, 1161, 1163, 1166, 1170, 1189, 1193, 1195, - /* 100 */ 1197, 1199, 1201, 1203, 1205, 1207, 1212, 1230, 1232, -211, - /* 110 */ -211, -211, -211, -211, -211, -211, -211, -211, -30, 427, - /* 120 */ -171, -145, -134, 22, 279, 287, 279, 287, 99, -211, - /* 130 */ -211, -211, -211, -211, -165, -165, -165, 123, 135, 175, - /* 140 */ -150, 396, 337, 291, 291, -147, 185, 391, 446, 444, - /* 150 */ 452, 500, 501, 502, 27, -152, 295, 438, 490, 503, - /* 160 */ 495, 506, -73, 447, 451, 536, 570, 551, 540, 579, - /* 170 */ 30, 508, 535, 81, 14, 61, 115, 168, 142, 222, - /* 180 */ 275, 284, 397, 599, 607, 647, 654, 660, 709, 658, - /* 190 */ 714, 750, 754, 772, 787, 801, 817, 818, 850, 863, - /* 200 */ 867, 871, 466, 748, 799, 881, 888, 898, 913, 824, - /* 210 */ 930, 933, 934, 873, 942, 945, 849, 946, 222, 954, - /* 220 */ 971, 972, 976, 979, 980, 900, 874, 927, 950, 961, - /* 230 */ 962, 963, 824, 927, 927, 939, 970, 1018, 981, 988, - /* 240 */ 993, 936, 982, 937, 1009, 1000, 1031, 1011, 1014, 1040, - /* 250 */ 1003, 991, 990, 1026, 1072, 985, 1076, 1079, 997, 1005, - /* 260 */ 1091, 1037, 1082, 1060, 1083, 1087, 1088, 1098, 1124, 1141, - /* 270 */ 1106, 1092, 1122, 1135, 1128, 1147, 1173, 1110, 1105, 1187, - /* 280 */ 1192, 1176, 1202, 1198, 1206, 1200, 1182, 1213, 1214, 1215, - /* 290 */ 1209, 1216, 1218, 1219, 1220, 1224, 1222, 1223, 1221, 1171, - /* 300 */ 1177, 1233, 1196, 1194, 1204, 1210, 1211, 1225, 1226, 1228, - /* 310 */ 1253, 1190, 1256, 1191, 1227, 1229, 1234, 1236, 1235, 1263, - /* 320 */ 1268, 1278, 1279, 1289, 1291, 1295, 1185, 1237, 1238, 1282, - /* 330 */ 1274, 1283, 1286, 1287, 1290, 1269, 1270, 1293, 1298, 1299, - /* 340 */ 1300, 1301, + /* 0 */ -147, 171, 263, -96, 358, -144, -149, -102, 124, -156, + /* 10 */ -98, 305, 401, -57, 209, -237, 245, -94, -79, 189, + /* 20 */ 375, 490, 493, 378, 303, 539, 542, 501, 503, 554, + /* 30 */ 415, 526, 546, 557, 587, 593, 595, -234, -234, -234, + /* 40 */ -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, + /* 50 */ -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, + /* 60 */ -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, + /* 70 */ -234, -50, 335, 470, 633, 656, 658, 660, 675, 685, + /* 80 */ 703, 727, 747, 750, 752, 754, 770, 788, 790, 793, + /* 90 */ 795, 797, 800, 802, 804, 806, 813, 820, 829, 833, + /* 100 */ 836, 838, 843, 845, 847, 849, 873, 891, 893, 916, + /* 110 */ 918, 921, 936, 941, 944, 956, 961, -234, -234, -234, + /* 120 */ -234, -234, -234, -234, -234, -234, 463, 607, -176, 14, + /* 130 */ -139, 87, -137, 818, 925, 818, 925, 898, -234, -234, + /* 140 */ -234, -234, -166, -166, -166, -130, -131, -82, -54, -180, + /* 150 */ 364, 41, 513, 509, 509, 117, 500, 789, 796, 646, + /* 160 */ 192, 291, 644, 798, 120, 807, 543, 911, 920, 652, + /* 170 */ 924, 922, 232, 698, 801, 971, 39, 220, 731, 442, + /* 180 */ 902, -199, 979, -43, 421, 896, 942, 605, -184, -126, + /* 190 */ 155, 172, 281, 304, 377, 538, 650, 690, 699, 723, + /* 200 */ 803, 839, 853, 919, 991, 1018, 1067, 1092, 951, 1111, + /* 210 */ 1112, 1115, 1116, 1117, 1119, 1120, 1121, 1122, 1123, 1124, + /* 220 */ 1125, 1012, 1096, 1097, 1128, 1129, 1130, 1131, 1070, 1135, + /* 230 */ 1137, 1152, 1077, 1153, 1155, 1114, 1156, 304, 1158, 1172, + /* 240 */ 1173, 1174, 1175, 1176, 1089, 1091, 1133, 1098, 1126, 1139, + /* 250 */ 1140, 1070, 1133, 1133, 1170, 1163, 1186, 1103, 1168, 1138, + /* 260 */ 1141, 1110, 1169, 1171, 1132, 1177, 1189, 1194, 1181, 1200, + /* 270 */ 1204, 1166, 1145, 1178, 1187, 1232, 1142, 1231, 1233, 1149, + /* 280 */ 1150, 1238, 1179, 1182, 1212, 1205, 1219, 1220, 1221, 1222, + /* 290 */ 1258, 1266, 1223, 1224, 1206, 1211, 1237, 1239, 1230, 1269, + /* 300 */ 1272, 1195, 1197, 1280, 1284, 1268, 1285, 1289, 1290, 1293, + /* 310 */ 1274, 1286, 1287, 1288, 1282, 1294, 1292, 1297, 1300, 1296, + /* 320 */ 1301, 1306, 1304, 1249, 1250, 1308, 1271, 1275, 1273, 1276, + /* 330 */ 1279, 1281, 1283, 1302, 1334, 1307, 1243, 1267, 1318, 1322, + /* 340 */ 1303, 1371, 1299, 1328, 1332, 1340, 1342, 1384, 1391, 1400, + /* 350 */ 1403, 1407, 1408, 1409, 1311, 1312, 1310, 1405, 1402, 1412, + /* 360 */ 1417, 1420, 1406, 1393, 1395, 1421, 1422, 1423, 1424, 1415, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1297, 1349, 1221, 1014, 1119, 1221, 1221, 1221, 1221, 1014, - /* 10 */ 1145, 1145, 1272, 1045, 1014, 1014, 1014, 1014, 1014, 1220, - /* 20 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 30 */ 1014, 1151, 1014, 1014, 1014, 1014, 1222, 1223, 1014, 1014, - /* 40 */ 1014, 1271, 1273, 1161, 1160, 1159, 1158, 1254, 1132, 1156, - /* 50 */ 1149, 1153, 1216, 1217, 1215, 1219, 1222, 1223, 1014, 1152, - /* 60 */ 1186, 1200, 1185, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 70 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 80 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 90 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 100 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1194, - /* 110 */ 1199, 1206, 1198, 1195, 1188, 1187, 1189, 1190, 1014, 1035, - /* 120 */ 1084, 1014, 1014, 1014, 1289, 1288, 1014, 1014, 1045, 1191, - /* 130 */ 1192, 1203, 1202, 1201, 1279, 1305, 1304, 1014, 1014, 1014, - /* 140 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 150 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 160 */ 1014, 1014, 1014, 1014, 1014, 1014, 1045, 1297, 1041, 1041, - /* 170 */ 1014, 1284, 1119, 1110, 1014, 1014, 1014, 1014, 1014, 1014, - /* 180 */ 1014, 1014, 1014, 1014, 1014, 1276, 1274, 1014, 1236, 1014, - /* 190 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 200 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 210 */ 1014, 1014, 1014, 1115, 1014, 1014, 1014, 1014, 1014, 1014, - /* 220 */ 1014, 1014, 1014, 1014, 1299, 1014, 1249, 1098, 1115, 1115, - /* 230 */ 1115, 1115, 1117, 1099, 1097, 1109, 1045, 1021, 1155, 1134, - /* 240 */ 1134, 1338, 1155, 1338, 1059, 1319, 1056, 1145, 1145, 1145, - /* 250 */ 1134, 1218, 1116, 1109, 1014, 1341, 1124, 1124, 1340, 1340, - /* 260 */ 1124, 1166, 1087, 1155, 1093, 1093, 1093, 1093, 1124, 1032, - /* 270 */ 1155, 1166, 1087, 1087, 1155, 1124, 1032, 1253, 1335, 1124, - /* 280 */ 1032, 1229, 1124, 1032, 1124, 1032, 1229, 1085, 1085, 1085, - /* 290 */ 1074, 1229, 1085, 1059, 1085, 1074, 1085, 1085, 1229, 1233, - /* 300 */ 1233, 1229, 1138, 1133, 1138, 1133, 1138, 1133, 1138, 1133, - /* 310 */ 1124, 1224, 1124, 1014, 1150, 1139, 1148, 1146, 1155, 1038, - /* 320 */ 1077, 1302, 1302, 1298, 1298, 1298, 1346, 1346, 1284, 1314, - /* 330 */ 1045, 1045, 1045, 1045, 1314, 1061, 1061, 1045, 1045, 1045, - /* 340 */ 1045, 1314, 1014, 1014, 1014, 1014, 1014, 1014, 1309, 1014, - /* 350 */ 1238, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 360 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1171, - /* 370 */ 1014, 1017, 1281, 1014, 1014, 1280, 1014, 1014, 1014, 1014, - /* 380 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 390 */ 1014, 1014, 1014, 1014, 1014, 1014, 1337, 1014, 1014, 1014, - /* 400 */ 1014, 1014, 1014, 1252, 1251, 1014, 1014, 1126, 1014, 1014, - /* 410 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 420 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 430 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 440 */ 1014, 1014, 1147, 1014, 1140, 1014, 1014, 1014, 1014, 1328, - /* 450 */ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - /* 460 */ 1014, 1014, 1014, 1323, 1101, 1173, 1014, 1172, 1176, 1014, - /* 470 */ 1026, 1014, + /* 0 */ 1492, 1492, 1492, 1340, 1123, 1229, 1123, 1123, 1123, 1340, + /* 10 */ 1340, 1340, 1123, 1259, 1259, 1391, 1154, 1123, 1123, 1123, + /* 20 */ 1123, 1123, 1123, 1123, 1339, 1123, 1123, 1123, 1123, 1123, + /* 30 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1265, 1123, + /* 40 */ 1123, 1123, 1123, 1123, 1341, 1342, 1123, 1123, 1123, 1390, + /* 50 */ 1392, 1275, 1274, 1273, 1272, 1373, 1246, 1270, 1263, 1267, + /* 60 */ 1335, 1336, 1334, 1338, 1342, 1341, 1123, 1266, 1306, 1320, + /* 70 */ 1305, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 80 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 90 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 100 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 110 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1314, 1319, 1325, + /* 120 */ 1318, 1315, 1308, 1307, 1309, 1310, 1123, 1144, 1193, 1123, + /* 130 */ 1123, 1123, 1123, 1409, 1408, 1123, 1123, 1154, 1311, 1312, + /* 140 */ 1322, 1321, 1398, 1448, 1447, 1123, 1123, 1123, 1123, 1123, + /* 150 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 160 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 170 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1154, 1150, 1300, + /* 180 */ 1299, 1418, 1150, 1253, 1123, 1404, 1229, 1220, 1123, 1123, + /* 190 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 200 */ 1123, 1395, 1393, 1123, 1355, 1123, 1123, 1123, 1123, 1123, + /* 210 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 220 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 230 */ 1123, 1123, 1225, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 240 */ 1123, 1123, 1123, 1442, 1123, 1368, 1207, 1225, 1225, 1225, + /* 250 */ 1225, 1227, 1208, 1206, 1219, 1154, 1130, 1484, 1269, 1248, + /* 260 */ 1248, 1481, 1269, 1269, 1481, 1168, 1462, 1165, 1259, 1259, + /* 270 */ 1259, 1248, 1337, 1226, 1219, 1123, 1484, 1234, 1234, 1483, + /* 280 */ 1483, 1234, 1278, 1284, 1196, 1269, 1202, 1202, 1202, 1202, + /* 290 */ 1234, 1141, 1269, 1269, 1278, 1284, 1196, 1196, 1269, 1234, + /* 300 */ 1141, 1372, 1478, 1234, 1141, 1348, 1234, 1141, 1234, 1141, + /* 310 */ 1348, 1194, 1194, 1194, 1183, 1348, 1194, 1168, 1194, 1183, + /* 320 */ 1194, 1194, 1348, 1352, 1352, 1348, 1252, 1247, 1252, 1247, + /* 330 */ 1252, 1247, 1252, 1247, 1234, 1253, 1417, 1123, 1264, 1253, + /* 340 */ 1343, 1234, 1123, 1264, 1262, 1260, 1269, 1147, 1186, 1445, + /* 350 */ 1445, 1441, 1441, 1441, 1489, 1489, 1404, 1457, 1154, 1154, + /* 360 */ 1154, 1154, 1457, 1170, 1170, 1154, 1154, 1154, 1154, 1457, + /* 370 */ 1123, 1123, 1123, 1123, 1123, 1123, 1452, 1123, 1357, 1238, + /* 380 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 390 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 400 */ 1123, 1123, 1289, 1123, 1126, 1401, 1123, 1123, 1399, 1123, + /* 410 */ 1123, 1123, 1123, 1123, 1123, 1239, 1123, 1123, 1123, 1123, + /* 420 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 430 */ 1123, 1123, 1123, 1123, 1480, 1123, 1123, 1123, 1123, 1123, + /* 440 */ 1123, 1371, 1370, 1123, 1123, 1236, 1123, 1123, 1123, 1123, + /* 450 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 460 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 470 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 480 */ 1123, 1123, 1123, 1261, 1123, 1416, 1123, 1123, 1123, 1123, + /* 490 */ 1123, 1123, 1123, 1430, 1254, 1123, 1123, 1471, 1123, 1123, + /* 500 */ 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, + /* 510 */ 1123, 1123, 1466, 1210, 1291, 1123, 1290, 1294, 1123, 1135, + /* 520 */ 1123, }; /********** End of lemon-generated parsing tables *****************************/ @@ -140664,6 +147804,7 @@ static const YYCODETYPE yyFallback[] = { 0, /* ESCAPE => nothing */ 0, /* ID => nothing */ 59, /* COLUMNKW => ID */ + 59, /* DO => ID */ 59, /* FOR => ID */ 59, /* IGNORE => ID */ 59, /* INITIALLY => ID */ @@ -140678,11 +147819,18 @@ static const YYCODETYPE yyFallback[] = { 59, /* REPLACE => ID */ 59, /* RESTRICT => ID */ 59, /* ROW => ID */ + 59, /* ROWS => ID */ 59, /* TRIGGER => ID */ 59, /* VACUUM => ID */ 59, /* VIEW => ID */ 59, /* VIRTUAL => ID */ 59, /* WITH => ID */ + 59, /* CURRENT => ID */ + 59, /* FOLLOWING => ID */ + 59, /* PARTITION => ID */ + 59, /* PRECEDING => ID */ + 59, /* RANGE => ID */ + 59, /* UNBOUNDED => ID */ 59, /* REINDEX => ID */ 59, /* RENAME => ID */ 59, /* CTIME_KW => ID */ @@ -140725,6 +147873,7 @@ struct yyParser { int yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ + sqlite3ParserCTX_SDECL /* A place to hold %extra_context */ #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ @@ -140833,197 +147982,222 @@ static const char *const yyTokenName[] = { /* 58 */ "ESCAPE", /* 59 */ "ID", /* 60 */ "COLUMNKW", - /* 61 */ "FOR", - /* 62 */ "IGNORE", - /* 63 */ "INITIALLY", - /* 64 */ "INSTEAD", - /* 65 */ "NO", - /* 66 */ "KEY", - /* 67 */ "OF", - /* 68 */ "OFFSET", - /* 69 */ "PRAGMA", - /* 70 */ "RAISE", - /* 71 */ "RECURSIVE", - /* 72 */ "REPLACE", - /* 73 */ "RESTRICT", - /* 74 */ "ROW", - /* 75 */ "TRIGGER", - /* 76 */ "VACUUM", - /* 77 */ "VIEW", - /* 78 */ "VIRTUAL", - /* 79 */ "WITH", - /* 80 */ "REINDEX", - /* 81 */ "RENAME", - /* 82 */ "CTIME_KW", - /* 83 */ "ANY", - /* 84 */ "BITAND", - /* 85 */ "BITOR", - /* 86 */ "LSHIFT", - /* 87 */ "RSHIFT", - /* 88 */ "PLUS", - /* 89 */ "MINUS", - /* 90 */ "STAR", - /* 91 */ "SLASH", - /* 92 */ "REM", - /* 93 */ "CONCAT", - /* 94 */ "COLLATE", - /* 95 */ "BITNOT", - /* 96 */ "INDEXED", - /* 97 */ "STRING", - /* 98 */ "JOIN_KW", - /* 99 */ "CONSTRAINT", - /* 100 */ "DEFAULT", - /* 101 */ "NULL", - /* 102 */ "PRIMARY", - /* 103 */ "UNIQUE", - /* 104 */ "CHECK", - /* 105 */ "REFERENCES", - /* 106 */ "AUTOINCR", - /* 107 */ "ON", - /* 108 */ "INSERT", - /* 109 */ "DELETE", - /* 110 */ "UPDATE", - /* 111 */ "SET", - /* 112 */ "DEFERRABLE", - /* 113 */ "FOREIGN", - /* 114 */ "DROP", - /* 115 */ "UNION", - /* 116 */ "ALL", - /* 117 */ "EXCEPT", - /* 118 */ "INTERSECT", - /* 119 */ "SELECT", - /* 120 */ "VALUES", - /* 121 */ "DISTINCT", - /* 122 */ "DOT", - /* 123 */ "FROM", - /* 124 */ "JOIN", - /* 125 */ "USING", - /* 126 */ "ORDER", - /* 127 */ "GROUP", - /* 128 */ "HAVING", - /* 129 */ "LIMIT", - /* 130 */ "WHERE", - /* 131 */ "INTO", - /* 132 */ "FLOAT", - /* 133 */ "BLOB", - /* 134 */ "INTEGER", - /* 135 */ "VARIABLE", - /* 136 */ "CASE", - /* 137 */ "WHEN", - /* 138 */ "THEN", - /* 139 */ "ELSE", - /* 140 */ "INDEX", - /* 141 */ "ALTER", - /* 142 */ "ADD", - /* 143 */ "error", - /* 144 */ "input", - /* 145 */ "cmdlist", - /* 146 */ "ecmd", - /* 147 */ "explain", - /* 148 */ "cmdx", - /* 149 */ "cmd", - /* 150 */ "transtype", - /* 151 */ "trans_opt", - /* 152 */ "nm", - /* 153 */ "savepoint_opt", - /* 154 */ "create_table", - /* 155 */ "create_table_args", - /* 156 */ "createkw", - /* 157 */ "temp", - /* 158 */ "ifnotexists", - /* 159 */ "dbnm", - /* 160 */ "columnlist", - /* 161 */ "conslist_opt", - /* 162 */ "table_options", - /* 163 */ "select", - /* 164 */ "columnname", - /* 165 */ "carglist", - /* 166 */ "typetoken", - /* 167 */ "typename", - /* 168 */ "signed", - /* 169 */ "plus_num", - /* 170 */ "minus_num", - /* 171 */ "scanpt", - /* 172 */ "ccons", - /* 173 */ "term", - /* 174 */ "expr", - /* 175 */ "onconf", - /* 176 */ "sortorder", - /* 177 */ "autoinc", - /* 178 */ "eidlist_opt", - /* 179 */ "refargs", - /* 180 */ "defer_subclause", - /* 181 */ "refarg", - /* 182 */ "refact", - /* 183 */ "init_deferred_pred_opt", - /* 184 */ "conslist", - /* 185 */ "tconscomma", - /* 186 */ "tcons", - /* 187 */ "sortlist", - /* 188 */ "eidlist", - /* 189 */ "defer_subclause_opt", - /* 190 */ "orconf", - /* 191 */ "resolvetype", - /* 192 */ "raisetype", - /* 193 */ "ifexists", - /* 194 */ "fullname", - /* 195 */ "selectnowith", - /* 196 */ "oneselect", - /* 197 */ "wqlist", - /* 198 */ "multiselect_op", - /* 199 */ "distinct", - /* 200 */ "selcollist", - /* 201 */ "from", - /* 202 */ "where_opt", - /* 203 */ "groupby_opt", - /* 204 */ "having_opt", - /* 205 */ "orderby_opt", - /* 206 */ "limit_opt", - /* 207 */ "values", - /* 208 */ "nexprlist", - /* 209 */ "exprlist", - /* 210 */ "sclp", - /* 211 */ "as", - /* 212 */ "seltablist", - /* 213 */ "stl_prefix", - /* 214 */ "joinop", - /* 215 */ "indexed_opt", - /* 216 */ "on_opt", - /* 217 */ "using_opt", - /* 218 */ "idlist", - /* 219 */ "with", - /* 220 */ "setlist", - /* 221 */ "insert_cmd", - /* 222 */ "idlist_opt", - /* 223 */ "likeop", - /* 224 */ "between_op", - /* 225 */ "in_op", - /* 226 */ "paren_exprlist", - /* 227 */ "case_operand", - /* 228 */ "case_exprlist", - /* 229 */ "case_else", - /* 230 */ "uniqueflag", - /* 231 */ "collate", - /* 232 */ "nmnum", - /* 233 */ "trigger_decl", - /* 234 */ "trigger_cmd_list", - /* 235 */ "trigger_time", - /* 236 */ "trigger_event", - /* 237 */ "foreach_clause", - /* 238 */ "when_clause", - /* 239 */ "trigger_cmd", - /* 240 */ "trnm", - /* 241 */ "tridxby", - /* 242 */ "database_kw_opt", - /* 243 */ "key_opt", - /* 244 */ "add_column_fullname", - /* 245 */ "kwcolumn_opt", - /* 246 */ "create_vtab", - /* 247 */ "vtabarglist", - /* 248 */ "vtabarg", - /* 249 */ "vtabargtoken", - /* 250 */ "lp", - /* 251 */ "anylist", + /* 61 */ "DO", + /* 62 */ "FOR", + /* 63 */ "IGNORE", + /* 64 */ "INITIALLY", + /* 65 */ "INSTEAD", + /* 66 */ "NO", + /* 67 */ "KEY", + /* 68 */ "OF", + /* 69 */ "OFFSET", + /* 70 */ "PRAGMA", + /* 71 */ "RAISE", + /* 72 */ "RECURSIVE", + /* 73 */ "REPLACE", + /* 74 */ "RESTRICT", + /* 75 */ "ROW", + /* 76 */ "ROWS", + /* 77 */ "TRIGGER", + /* 78 */ "VACUUM", + /* 79 */ "VIEW", + /* 80 */ "VIRTUAL", + /* 81 */ "WITH", + /* 82 */ "CURRENT", + /* 83 */ "FOLLOWING", + /* 84 */ "PARTITION", + /* 85 */ "PRECEDING", + /* 86 */ "RANGE", + /* 87 */ "UNBOUNDED", + /* 88 */ "REINDEX", + /* 89 */ "RENAME", + /* 90 */ "CTIME_KW", + /* 91 */ "ANY", + /* 92 */ "BITAND", + /* 93 */ "BITOR", + /* 94 */ "LSHIFT", + /* 95 */ "RSHIFT", + /* 96 */ "PLUS", + /* 97 */ "MINUS", + /* 98 */ "STAR", + /* 99 */ "SLASH", + /* 100 */ "REM", + /* 101 */ "CONCAT", + /* 102 */ "COLLATE", + /* 103 */ "BITNOT", + /* 104 */ "ON", + /* 105 */ "INDEXED", + /* 106 */ "STRING", + /* 107 */ "JOIN_KW", + /* 108 */ "CONSTRAINT", + /* 109 */ "DEFAULT", + /* 110 */ "NULL", + /* 111 */ "PRIMARY", + /* 112 */ "UNIQUE", + /* 113 */ "CHECK", + /* 114 */ "REFERENCES", + /* 115 */ "AUTOINCR", + /* 116 */ "INSERT", + /* 117 */ "DELETE", + /* 118 */ "UPDATE", + /* 119 */ "SET", + /* 120 */ "DEFERRABLE", + /* 121 */ "FOREIGN", + /* 122 */ "DROP", + /* 123 */ "UNION", + /* 124 */ "ALL", + /* 125 */ "EXCEPT", + /* 126 */ "INTERSECT", + /* 127 */ "SELECT", + /* 128 */ "VALUES", + /* 129 */ "DISTINCT", + /* 130 */ "DOT", + /* 131 */ "FROM", + /* 132 */ "JOIN", + /* 133 */ "USING", + /* 134 */ "ORDER", + /* 135 */ "GROUP", + /* 136 */ "HAVING", + /* 137 */ "LIMIT", + /* 138 */ "WHERE", + /* 139 */ "INTO", + /* 140 */ "NOTHING", + /* 141 */ "FLOAT", + /* 142 */ "BLOB", + /* 143 */ "INTEGER", + /* 144 */ "VARIABLE", + /* 145 */ "CASE", + /* 146 */ "WHEN", + /* 147 */ "THEN", + /* 148 */ "ELSE", + /* 149 */ "INDEX", + /* 150 */ "ALTER", + /* 151 */ "ADD", + /* 152 */ "WINDOW", + /* 153 */ "OVER", + /* 154 */ "FILTER", + /* 155 */ "input", + /* 156 */ "cmdlist", + /* 157 */ "ecmd", + /* 158 */ "cmdx", + /* 159 */ "explain", + /* 160 */ "cmd", + /* 161 */ "transtype", + /* 162 */ "trans_opt", + /* 163 */ "nm", + /* 164 */ "savepoint_opt", + /* 165 */ "create_table", + /* 166 */ "create_table_args", + /* 167 */ "createkw", + /* 168 */ "temp", + /* 169 */ "ifnotexists", + /* 170 */ "dbnm", + /* 171 */ "columnlist", + /* 172 */ "conslist_opt", + /* 173 */ "table_options", + /* 174 */ "select", + /* 175 */ "columnname", + /* 176 */ "carglist", + /* 177 */ "typetoken", + /* 178 */ "typename", + /* 179 */ "signed", + /* 180 */ "plus_num", + /* 181 */ "minus_num", + /* 182 */ "scanpt", + /* 183 */ "ccons", + /* 184 */ "term", + /* 185 */ "expr", + /* 186 */ "onconf", + /* 187 */ "sortorder", + /* 188 */ "autoinc", + /* 189 */ "eidlist_opt", + /* 190 */ "refargs", + /* 191 */ "defer_subclause", + /* 192 */ "refarg", + /* 193 */ "refact", + /* 194 */ "init_deferred_pred_opt", + /* 195 */ "conslist", + /* 196 */ "tconscomma", + /* 197 */ "tcons", + /* 198 */ "sortlist", + /* 199 */ "eidlist", + /* 200 */ "defer_subclause_opt", + /* 201 */ "orconf", + /* 202 */ "resolvetype", + /* 203 */ "raisetype", + /* 204 */ "ifexists", + /* 205 */ "fullname", + /* 206 */ "selectnowith", + /* 207 */ "oneselect", + /* 208 */ "wqlist", + /* 209 */ "multiselect_op", + /* 210 */ "distinct", + /* 211 */ "selcollist", + /* 212 */ "from", + /* 213 */ "where_opt", + /* 214 */ "groupby_opt", + /* 215 */ "having_opt", + /* 216 */ "orderby_opt", + /* 217 */ "limit_opt", + /* 218 */ "window_clause", + /* 219 */ "values", + /* 220 */ "nexprlist", + /* 221 */ "sclp", + /* 222 */ "as", + /* 223 */ "seltablist", + /* 224 */ "stl_prefix", + /* 225 */ "joinop", + /* 226 */ "indexed_opt", + /* 227 */ "on_opt", + /* 228 */ "using_opt", + /* 229 */ "exprlist", + /* 230 */ "xfullname", + /* 231 */ "idlist", + /* 232 */ "with", + /* 233 */ "setlist", + /* 234 */ "insert_cmd", + /* 235 */ "idlist_opt", + /* 236 */ "upsert", + /* 237 */ "over_clause", + /* 238 */ "likeop", + /* 239 */ "between_op", + /* 240 */ "in_op", + /* 241 */ "paren_exprlist", + /* 242 */ "case_operand", + /* 243 */ "case_exprlist", + /* 244 */ "case_else", + /* 245 */ "uniqueflag", + /* 246 */ "collate", + /* 247 */ "nmnum", + /* 248 */ "trigger_decl", + /* 249 */ "trigger_cmd_list", + /* 250 */ "trigger_time", + /* 251 */ "trigger_event", + /* 252 */ "foreach_clause", + /* 253 */ "when_clause", + /* 254 */ "trigger_cmd", + /* 255 */ "trnm", + /* 256 */ "tridxby", + /* 257 */ "database_kw_opt", + /* 258 */ "key_opt", + /* 259 */ "add_column_fullname", + /* 260 */ "kwcolumn_opt", + /* 261 */ "create_vtab", + /* 262 */ "vtabarglist", + /* 263 */ "vtabarg", + /* 264 */ "vtabargtoken", + /* 265 */ "lp", + /* 266 */ "anylist", + /* 267 */ "windowdefn_list", + /* 268 */ "windowdefn", + /* 269 */ "window", + /* 270 */ "frame_opt", + /* 271 */ "part_opt", + /* 272 */ "filter_opt", + /* 273 */ "range_or_rows", + /* 274 */ "frame_bound", + /* 275 */ "frame_bound_s", + /* 276 */ "frame_bound_e", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ @@ -141119,251 +148293,285 @@ static const char *const yyRuleName[] = { /* 85 */ "multiselect_op ::= UNION ALL", /* 86 */ "multiselect_op ::= EXCEPT|INTERSECT", /* 87 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 88 */ "values ::= VALUES LP nexprlist RP", - /* 89 */ "values ::= values COMMA LP exprlist RP", - /* 90 */ "distinct ::= DISTINCT", - /* 91 */ "distinct ::= ALL", - /* 92 */ "distinct ::=", - /* 93 */ "sclp ::=", - /* 94 */ "selcollist ::= sclp scanpt expr scanpt as", - /* 95 */ "selcollist ::= sclp scanpt STAR", - /* 96 */ "selcollist ::= sclp scanpt nm DOT STAR", - /* 97 */ "as ::= AS nm", - /* 98 */ "as ::=", - /* 99 */ "from ::=", - /* 100 */ "from ::= FROM seltablist", - /* 101 */ "stl_prefix ::= seltablist joinop", - /* 102 */ "stl_prefix ::=", - /* 103 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", - /* 104 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", - /* 105 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", - /* 106 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", - /* 107 */ "dbnm ::=", - /* 108 */ "dbnm ::= DOT nm", - /* 109 */ "fullname ::= nm", - /* 110 */ "fullname ::= nm DOT nm", - /* 111 */ "joinop ::= COMMA|JOIN", - /* 112 */ "joinop ::= JOIN_KW JOIN", - /* 113 */ "joinop ::= JOIN_KW nm JOIN", - /* 114 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 115 */ "on_opt ::= ON expr", - /* 116 */ "on_opt ::=", - /* 117 */ "indexed_opt ::=", - /* 118 */ "indexed_opt ::= INDEXED BY nm", - /* 119 */ "indexed_opt ::= NOT INDEXED", - /* 120 */ "using_opt ::= USING LP idlist RP", - /* 121 */ "using_opt ::=", - /* 122 */ "orderby_opt ::=", - /* 123 */ "orderby_opt ::= ORDER BY sortlist", - /* 124 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 125 */ "sortlist ::= expr sortorder", - /* 126 */ "sortorder ::= ASC", - /* 127 */ "sortorder ::= DESC", - /* 128 */ "sortorder ::=", - /* 129 */ "groupby_opt ::=", - /* 130 */ "groupby_opt ::= GROUP BY nexprlist", - /* 131 */ "having_opt ::=", - /* 132 */ "having_opt ::= HAVING expr", - /* 133 */ "limit_opt ::=", - /* 134 */ "limit_opt ::= LIMIT expr", - /* 135 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 136 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 137 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt", - /* 138 */ "where_opt ::=", - /* 139 */ "where_opt ::= WHERE expr", - /* 140 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", - /* 141 */ "setlist ::= setlist COMMA nm EQ expr", - /* 142 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 143 */ "setlist ::= nm EQ expr", - /* 144 */ "setlist ::= LP idlist RP EQ expr", - /* 145 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", - /* 146 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", - /* 147 */ "insert_cmd ::= INSERT orconf", - /* 148 */ "insert_cmd ::= REPLACE", - /* 149 */ "idlist_opt ::=", - /* 150 */ "idlist_opt ::= LP idlist RP", - /* 151 */ "idlist ::= idlist COMMA nm", - /* 152 */ "idlist ::= nm", - /* 153 */ "expr ::= LP expr RP", - /* 154 */ "expr ::= ID|INDEXED", - /* 155 */ "expr ::= JOIN_KW", - /* 156 */ "expr ::= nm DOT nm", - /* 157 */ "expr ::= nm DOT nm DOT nm", - /* 158 */ "term ::= NULL|FLOAT|BLOB", - /* 159 */ "term ::= STRING", - /* 160 */ "term ::= INTEGER", - /* 161 */ "expr ::= VARIABLE", - /* 162 */ "expr ::= expr COLLATE ID|STRING", - /* 163 */ "expr ::= CAST LP expr AS typetoken RP", - /* 164 */ "expr ::= ID|INDEXED LP distinct exprlist RP", - /* 165 */ "expr ::= ID|INDEXED LP STAR RP", - /* 166 */ "term ::= CTIME_KW", - /* 167 */ "expr ::= LP nexprlist COMMA expr RP", - /* 168 */ "expr ::= expr AND expr", - /* 169 */ "expr ::= expr OR expr", - /* 170 */ "expr ::= expr LT|GT|GE|LE expr", - /* 171 */ "expr ::= expr EQ|NE expr", - /* 172 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 173 */ "expr ::= expr PLUS|MINUS expr", - /* 174 */ "expr ::= expr STAR|SLASH|REM expr", - /* 175 */ "expr ::= expr CONCAT expr", - /* 176 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 177 */ "expr ::= expr likeop expr", - /* 178 */ "expr ::= expr likeop expr ESCAPE expr", - /* 179 */ "expr ::= expr ISNULL|NOTNULL", - /* 180 */ "expr ::= expr NOT NULL", - /* 181 */ "expr ::= expr IS expr", - /* 182 */ "expr ::= expr IS NOT expr", - /* 183 */ "expr ::= NOT expr", - /* 184 */ "expr ::= BITNOT expr", - /* 185 */ "expr ::= MINUS expr", - /* 186 */ "expr ::= PLUS expr", - /* 187 */ "between_op ::= BETWEEN", - /* 188 */ "between_op ::= NOT BETWEEN", - /* 189 */ "expr ::= expr between_op expr AND expr", - /* 190 */ "in_op ::= IN", - /* 191 */ "in_op ::= NOT IN", - /* 192 */ "expr ::= expr in_op LP exprlist RP", - /* 193 */ "expr ::= LP select RP", - /* 194 */ "expr ::= expr in_op LP select RP", - /* 195 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 196 */ "expr ::= EXISTS LP select RP", - /* 197 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 198 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 199 */ "case_exprlist ::= WHEN expr THEN expr", - /* 200 */ "case_else ::= ELSE expr", - /* 201 */ "case_else ::=", - /* 202 */ "case_operand ::= expr", - /* 203 */ "case_operand ::=", - /* 204 */ "exprlist ::=", - /* 205 */ "nexprlist ::= nexprlist COMMA expr", - /* 206 */ "nexprlist ::= expr", - /* 207 */ "paren_exprlist ::=", - /* 208 */ "paren_exprlist ::= LP exprlist RP", - /* 209 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 210 */ "uniqueflag ::= UNIQUE", - /* 211 */ "uniqueflag ::=", - /* 212 */ "eidlist_opt ::=", - /* 213 */ "eidlist_opt ::= LP eidlist RP", - /* 214 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 215 */ "eidlist ::= nm collate sortorder", - /* 216 */ "collate ::=", - /* 217 */ "collate ::= COLLATE ID|STRING", - /* 218 */ "cmd ::= DROP INDEX ifexists fullname", - /* 219 */ "cmd ::= VACUUM", - /* 220 */ "cmd ::= VACUUM nm", - /* 221 */ "cmd ::= PRAGMA nm dbnm", - /* 222 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 223 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 224 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 225 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 226 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 227 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 228 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 229 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 230 */ "trigger_time ::= BEFORE|AFTER", - /* 231 */ "trigger_time ::= INSTEAD OF", - /* 232 */ "trigger_time ::=", - /* 233 */ "trigger_event ::= DELETE|INSERT", - /* 234 */ "trigger_event ::= UPDATE", - /* 235 */ "trigger_event ::= UPDATE OF idlist", - /* 236 */ "when_clause ::=", - /* 237 */ "when_clause ::= WHEN expr", - /* 238 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 239 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 240 */ "trnm ::= nm DOT nm", - /* 241 */ "tridxby ::= INDEXED BY nm", - /* 242 */ "tridxby ::= NOT INDEXED", - /* 243 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt", - /* 244 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt", - /* 245 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 246 */ "trigger_cmd ::= scanpt select scanpt", - /* 247 */ "expr ::= RAISE LP IGNORE RP", - /* 248 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 249 */ "raisetype ::= ROLLBACK", - /* 250 */ "raisetype ::= ABORT", - /* 251 */ "raisetype ::= FAIL", - /* 252 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 253 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 254 */ "cmd ::= DETACH database_kw_opt expr", - /* 255 */ "key_opt ::=", - /* 256 */ "key_opt ::= KEY expr", - /* 257 */ "cmd ::= REINDEX", - /* 258 */ "cmd ::= REINDEX nm dbnm", - /* 259 */ "cmd ::= ANALYZE", - /* 260 */ "cmd ::= ANALYZE nm dbnm", - /* 261 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 262 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 263 */ "add_column_fullname ::= fullname", - /* 264 */ "cmd ::= create_vtab", - /* 265 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 266 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 267 */ "vtabarg ::=", - /* 268 */ "vtabargtoken ::= ANY", - /* 269 */ "vtabargtoken ::= lp anylist RP", - /* 270 */ "lp ::= LP", - /* 271 */ "with ::= WITH wqlist", - /* 272 */ "with ::= WITH RECURSIVE wqlist", - /* 273 */ "wqlist ::= nm eidlist_opt AS LP select RP", - /* 274 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", - /* 275 */ "input ::= cmdlist", - /* 276 */ "cmdlist ::= cmdlist ecmd", - /* 277 */ "cmdlist ::= ecmd", - /* 278 */ "ecmd ::= SEMI", - /* 279 */ "ecmd ::= explain cmdx SEMI", - /* 280 */ "explain ::=", - /* 281 */ "trans_opt ::=", - /* 282 */ "trans_opt ::= TRANSACTION", - /* 283 */ "trans_opt ::= TRANSACTION nm", - /* 284 */ "savepoint_opt ::= SAVEPOINT", - /* 285 */ "savepoint_opt ::=", - /* 286 */ "cmd ::= create_table create_table_args", - /* 287 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 288 */ "columnlist ::= columnname carglist", - /* 289 */ "nm ::= ID|INDEXED", - /* 290 */ "nm ::= STRING", - /* 291 */ "nm ::= JOIN_KW", - /* 292 */ "typetoken ::= typename", - /* 293 */ "typename ::= ID|STRING", - /* 294 */ "signed ::= plus_num", - /* 295 */ "signed ::= minus_num", - /* 296 */ "carglist ::= carglist ccons", - /* 297 */ "carglist ::=", - /* 298 */ "ccons ::= NULL onconf", - /* 299 */ "conslist_opt ::= COMMA conslist", - /* 300 */ "conslist ::= conslist tconscomma tcons", - /* 301 */ "conslist ::= tcons", - /* 302 */ "tconscomma ::=", - /* 303 */ "defer_subclause_opt ::= defer_subclause", - /* 304 */ "resolvetype ::= raisetype", - /* 305 */ "selectnowith ::= oneselect", - /* 306 */ "oneselect ::= values", - /* 307 */ "sclp ::= selcollist COMMA", - /* 308 */ "as ::= ID|STRING", - /* 309 */ "expr ::= term", - /* 310 */ "likeop ::= LIKE_KW|MATCH", - /* 311 */ "exprlist ::= nexprlist", - /* 312 */ "nmnum ::= plus_num", - /* 313 */ "nmnum ::= nm", - /* 314 */ "nmnum ::= ON", - /* 315 */ "nmnum ::= DELETE", - /* 316 */ "nmnum ::= DEFAULT", - /* 317 */ "plus_num ::= INTEGER|FLOAT", - /* 318 */ "foreach_clause ::=", - /* 319 */ "foreach_clause ::= FOR EACH ROW", - /* 320 */ "trnm ::= nm", - /* 321 */ "tridxby ::=", - /* 322 */ "database_kw_opt ::= DATABASE", - /* 323 */ "database_kw_opt ::=", - /* 324 */ "kwcolumn_opt ::=", - /* 325 */ "kwcolumn_opt ::= COLUMNKW", - /* 326 */ "vtabarglist ::= vtabarg", - /* 327 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 328 */ "vtabarg ::= vtabarg vtabargtoken", - /* 329 */ "anylist ::=", - /* 330 */ "anylist ::= anylist LP anylist RP", - /* 331 */ "anylist ::= anylist ANY", - /* 332 */ "with ::=", + /* 88 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", + /* 89 */ "values ::= VALUES LP nexprlist RP", + /* 90 */ "values ::= values COMMA LP nexprlist RP", + /* 91 */ "distinct ::= DISTINCT", + /* 92 */ "distinct ::= ALL", + /* 93 */ "distinct ::=", + /* 94 */ "sclp ::=", + /* 95 */ "selcollist ::= sclp scanpt expr scanpt as", + /* 96 */ "selcollist ::= sclp scanpt STAR", + /* 97 */ "selcollist ::= sclp scanpt nm DOT STAR", + /* 98 */ "as ::= AS nm", + /* 99 */ "as ::=", + /* 100 */ "from ::=", + /* 101 */ "from ::= FROM seltablist", + /* 102 */ "stl_prefix ::= seltablist joinop", + /* 103 */ "stl_prefix ::=", + /* 104 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 105 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 106 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 107 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 108 */ "dbnm ::=", + /* 109 */ "dbnm ::= DOT nm", + /* 110 */ "fullname ::= nm", + /* 111 */ "fullname ::= nm DOT nm", + /* 112 */ "xfullname ::= nm", + /* 113 */ "xfullname ::= nm DOT nm", + /* 114 */ "xfullname ::= nm DOT nm AS nm", + /* 115 */ "xfullname ::= nm AS nm", + /* 116 */ "joinop ::= COMMA|JOIN", + /* 117 */ "joinop ::= JOIN_KW JOIN", + /* 118 */ "joinop ::= JOIN_KW nm JOIN", + /* 119 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 120 */ "on_opt ::= ON expr", + /* 121 */ "on_opt ::=", + /* 122 */ "indexed_opt ::=", + /* 123 */ "indexed_opt ::= INDEXED BY nm", + /* 124 */ "indexed_opt ::= NOT INDEXED", + /* 125 */ "using_opt ::= USING LP idlist RP", + /* 126 */ "using_opt ::=", + /* 127 */ "orderby_opt ::=", + /* 128 */ "orderby_opt ::= ORDER BY sortlist", + /* 129 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 130 */ "sortlist ::= expr sortorder", + /* 131 */ "sortorder ::= ASC", + /* 132 */ "sortorder ::= DESC", + /* 133 */ "sortorder ::=", + /* 134 */ "groupby_opt ::=", + /* 135 */ "groupby_opt ::= GROUP BY nexprlist", + /* 136 */ "having_opt ::=", + /* 137 */ "having_opt ::= HAVING expr", + /* 138 */ "limit_opt ::=", + /* 139 */ "limit_opt ::= LIMIT expr", + /* 140 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 141 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 142 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt", + /* 143 */ "where_opt ::=", + /* 144 */ "where_opt ::= WHERE expr", + /* 145 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt", + /* 146 */ "setlist ::= setlist COMMA nm EQ expr", + /* 147 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 148 */ "setlist ::= nm EQ expr", + /* 149 */ "setlist ::= LP idlist RP EQ expr", + /* 150 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", + /* 151 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES", + /* 152 */ "upsert ::=", + /* 153 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt", + /* 154 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING", + /* 155 */ "upsert ::= ON CONFLICT DO NOTHING", + /* 156 */ "insert_cmd ::= INSERT orconf", + /* 157 */ "insert_cmd ::= REPLACE", + /* 158 */ "idlist_opt ::=", + /* 159 */ "idlist_opt ::= LP idlist RP", + /* 160 */ "idlist ::= idlist COMMA nm", + /* 161 */ "idlist ::= nm", + /* 162 */ "expr ::= LP expr RP", + /* 163 */ "expr ::= ID|INDEXED", + /* 164 */ "expr ::= JOIN_KW", + /* 165 */ "expr ::= nm DOT nm", + /* 166 */ "expr ::= nm DOT nm DOT nm", + /* 167 */ "term ::= NULL|FLOAT|BLOB", + /* 168 */ "term ::= STRING", + /* 169 */ "term ::= INTEGER", + /* 170 */ "expr ::= VARIABLE", + /* 171 */ "expr ::= expr COLLATE ID|STRING", + /* 172 */ "expr ::= CAST LP expr AS typetoken RP", + /* 173 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 174 */ "expr ::= ID|INDEXED LP STAR RP", + /* 175 */ "expr ::= ID|INDEXED LP distinct exprlist RP over_clause", + /* 176 */ "expr ::= ID|INDEXED LP STAR RP over_clause", + /* 177 */ "term ::= CTIME_KW", + /* 178 */ "expr ::= LP nexprlist COMMA expr RP", + /* 179 */ "expr ::= expr AND expr", + /* 180 */ "expr ::= expr OR expr", + /* 181 */ "expr ::= expr LT|GT|GE|LE expr", + /* 182 */ "expr ::= expr EQ|NE expr", + /* 183 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 184 */ "expr ::= expr PLUS|MINUS expr", + /* 185 */ "expr ::= expr STAR|SLASH|REM expr", + /* 186 */ "expr ::= expr CONCAT expr", + /* 187 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 188 */ "expr ::= expr likeop expr", + /* 189 */ "expr ::= expr likeop expr ESCAPE expr", + /* 190 */ "expr ::= expr ISNULL|NOTNULL", + /* 191 */ "expr ::= expr NOT NULL", + /* 192 */ "expr ::= expr IS expr", + /* 193 */ "expr ::= expr IS NOT expr", + /* 194 */ "expr ::= NOT expr", + /* 195 */ "expr ::= BITNOT expr", + /* 196 */ "expr ::= PLUS|MINUS expr", + /* 197 */ "between_op ::= BETWEEN", + /* 198 */ "between_op ::= NOT BETWEEN", + /* 199 */ "expr ::= expr between_op expr AND expr", + /* 200 */ "in_op ::= IN", + /* 201 */ "in_op ::= NOT IN", + /* 202 */ "expr ::= expr in_op LP exprlist RP", + /* 203 */ "expr ::= LP select RP", + /* 204 */ "expr ::= expr in_op LP select RP", + /* 205 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 206 */ "expr ::= EXISTS LP select RP", + /* 207 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 208 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 209 */ "case_exprlist ::= WHEN expr THEN expr", + /* 210 */ "case_else ::= ELSE expr", + /* 211 */ "case_else ::=", + /* 212 */ "case_operand ::= expr", + /* 213 */ "case_operand ::=", + /* 214 */ "exprlist ::=", + /* 215 */ "nexprlist ::= nexprlist COMMA expr", + /* 216 */ "nexprlist ::= expr", + /* 217 */ "paren_exprlist ::=", + /* 218 */ "paren_exprlist ::= LP exprlist RP", + /* 219 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 220 */ "uniqueflag ::= UNIQUE", + /* 221 */ "uniqueflag ::=", + /* 222 */ "eidlist_opt ::=", + /* 223 */ "eidlist_opt ::= LP eidlist RP", + /* 224 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 225 */ "eidlist ::= nm collate sortorder", + /* 226 */ "collate ::=", + /* 227 */ "collate ::= COLLATE ID|STRING", + /* 228 */ "cmd ::= DROP INDEX ifexists fullname", + /* 229 */ "cmd ::= VACUUM", + /* 230 */ "cmd ::= VACUUM nm", + /* 231 */ "cmd ::= PRAGMA nm dbnm", + /* 232 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 233 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 234 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 235 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 236 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 237 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 238 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 239 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 240 */ "trigger_time ::= BEFORE|AFTER", + /* 241 */ "trigger_time ::= INSTEAD OF", + /* 242 */ "trigger_time ::=", + /* 243 */ "trigger_event ::= DELETE|INSERT", + /* 244 */ "trigger_event ::= UPDATE", + /* 245 */ "trigger_event ::= UPDATE OF idlist", + /* 246 */ "when_clause ::=", + /* 247 */ "when_clause ::= WHEN expr", + /* 248 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 249 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 250 */ "trnm ::= nm DOT nm", + /* 251 */ "tridxby ::= INDEXED BY nm", + /* 252 */ "tridxby ::= NOT INDEXED", + /* 253 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt", + /* 254 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 255 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 256 */ "trigger_cmd ::= scanpt select scanpt", + /* 257 */ "expr ::= RAISE LP IGNORE RP", + /* 258 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 259 */ "raisetype ::= ROLLBACK", + /* 260 */ "raisetype ::= ABORT", + /* 261 */ "raisetype ::= FAIL", + /* 262 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 263 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 264 */ "cmd ::= DETACH database_kw_opt expr", + /* 265 */ "key_opt ::=", + /* 266 */ "key_opt ::= KEY expr", + /* 267 */ "cmd ::= REINDEX", + /* 268 */ "cmd ::= REINDEX nm dbnm", + /* 269 */ "cmd ::= ANALYZE", + /* 270 */ "cmd ::= ANALYZE nm dbnm", + /* 271 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 272 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 273 */ "add_column_fullname ::= fullname", + /* 274 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 275 */ "cmd ::= create_vtab", + /* 276 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 277 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 278 */ "vtabarg ::=", + /* 279 */ "vtabargtoken ::= ANY", + /* 280 */ "vtabargtoken ::= lp anylist RP", + /* 281 */ "lp ::= LP", + /* 282 */ "with ::= WITH wqlist", + /* 283 */ "with ::= WITH RECURSIVE wqlist", + /* 284 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 285 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 286 */ "windowdefn_list ::= windowdefn", + /* 287 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 288 */ "windowdefn ::= nm AS window", + /* 289 */ "window ::= LP part_opt orderby_opt frame_opt RP", + /* 290 */ "part_opt ::= PARTITION BY nexprlist", + /* 291 */ "part_opt ::=", + /* 292 */ "frame_opt ::=", + /* 293 */ "frame_opt ::= range_or_rows frame_bound_s", + /* 294 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e", + /* 295 */ "range_or_rows ::= RANGE", + /* 296 */ "range_or_rows ::= ROWS", + /* 297 */ "frame_bound_s ::= frame_bound", + /* 298 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 299 */ "frame_bound_e ::= frame_bound", + /* 300 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 301 */ "frame_bound ::= expr PRECEDING", + /* 302 */ "frame_bound ::= CURRENT ROW", + /* 303 */ "frame_bound ::= expr FOLLOWING", + /* 304 */ "window_clause ::= WINDOW windowdefn_list", + /* 305 */ "over_clause ::= filter_opt OVER window", + /* 306 */ "over_clause ::= filter_opt OVER nm", + /* 307 */ "filter_opt ::=", + /* 308 */ "filter_opt ::= FILTER LP WHERE expr RP", + /* 309 */ "input ::= cmdlist", + /* 310 */ "cmdlist ::= cmdlist ecmd", + /* 311 */ "cmdlist ::= ecmd", + /* 312 */ "ecmd ::= SEMI", + /* 313 */ "ecmd ::= cmdx SEMI", + /* 314 */ "ecmd ::= explain cmdx", + /* 315 */ "trans_opt ::=", + /* 316 */ "trans_opt ::= TRANSACTION", + /* 317 */ "trans_opt ::= TRANSACTION nm", + /* 318 */ "savepoint_opt ::= SAVEPOINT", + /* 319 */ "savepoint_opt ::=", + /* 320 */ "cmd ::= create_table create_table_args", + /* 321 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 322 */ "columnlist ::= columnname carglist", + /* 323 */ "nm ::= ID|INDEXED", + /* 324 */ "nm ::= STRING", + /* 325 */ "nm ::= JOIN_KW", + /* 326 */ "typetoken ::= typename", + /* 327 */ "typename ::= ID|STRING", + /* 328 */ "signed ::= plus_num", + /* 329 */ "signed ::= minus_num", + /* 330 */ "carglist ::= carglist ccons", + /* 331 */ "carglist ::=", + /* 332 */ "ccons ::= NULL onconf", + /* 333 */ "conslist_opt ::= COMMA conslist", + /* 334 */ "conslist ::= conslist tconscomma tcons", + /* 335 */ "conslist ::= tcons", + /* 336 */ "tconscomma ::=", + /* 337 */ "defer_subclause_opt ::= defer_subclause", + /* 338 */ "resolvetype ::= raisetype", + /* 339 */ "selectnowith ::= oneselect", + /* 340 */ "oneselect ::= values", + /* 341 */ "sclp ::= selcollist COMMA", + /* 342 */ "as ::= ID|STRING", + /* 343 */ "expr ::= term", + /* 344 */ "likeop ::= LIKE_KW|MATCH", + /* 345 */ "exprlist ::= nexprlist", + /* 346 */ "nmnum ::= plus_num", + /* 347 */ "nmnum ::= nm", + /* 348 */ "nmnum ::= ON", + /* 349 */ "nmnum ::= DELETE", + /* 350 */ "nmnum ::= DEFAULT", + /* 351 */ "plus_num ::= INTEGER|FLOAT", + /* 352 */ "foreach_clause ::=", + /* 353 */ "foreach_clause ::= FOR EACH ROW", + /* 354 */ "trnm ::= nm", + /* 355 */ "tridxby ::=", + /* 356 */ "database_kw_opt ::= DATABASE", + /* 357 */ "database_kw_opt ::=", + /* 358 */ "kwcolumn_opt ::=", + /* 359 */ "kwcolumn_opt ::= COLUMNKW", + /* 360 */ "vtabarglist ::= vtabarg", + /* 361 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 362 */ "vtabarg ::= vtabarg vtabargtoken", + /* 363 */ "anylist ::=", + /* 364 */ "anylist ::= anylist LP anylist RP", + /* 365 */ "anylist ::= anylist ANY", + /* 366 */ "with ::=", }; #endif /* NDEBUG */ @@ -141412,28 +148620,29 @@ static int yyGrowStack(yyParser *p){ /* Initialize a new parser that has already been allocated. */ -SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){ - yyParser *pParser = (yyParser*)yypParser; +SQLITE_PRIVATE void sqlite3ParserInit(void *yypRawParser sqlite3ParserCTX_PDECL){ + yyParser *yypParser = (yyParser*)yypRawParser; + sqlite3ParserCTX_STORE #ifdef YYTRACKMAXSTACKDEPTH - pParser->yyhwm = 0; + yypParser->yyhwm = 0; #endif #if YYSTACKDEPTH<=0 - pParser->yytos = NULL; - pParser->yystack = NULL; - pParser->yystksz = 0; - if( yyGrowStack(pParser) ){ - pParser->yystack = &pParser->yystk0; - pParser->yystksz = 1; + yypParser->yytos = NULL; + yypParser->yystack = NULL; + yypParser->yystksz = 0; + if( yyGrowStack(yypParser) ){ + yypParser->yystack = &yypParser->yystk0; + yypParser->yystksz = 1; } #endif #ifndef YYNOERRORRECOVERY - pParser->yyerrcnt = -1; + yypParser->yyerrcnt = -1; #endif - pParser->yytos = pParser->yystack; - pParser->yystack[0].stateno = 0; - pParser->yystack[0].major = 0; + yypParser->yytos = yypParser->yystack; + yypParser->yystack[0].stateno = 0; + yypParser->yystack[0].major = 0; #if YYSTACKDEPTH>0 - pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1]; + yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; #endif } @@ -141450,11 +148659,14 @@ SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){ ** A pointer to a parser. This pointer is used in subsequent calls ** to sqlite3Parser and sqlite3ParserFree. */ -SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ - yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); - if( pParser ) sqlite3ParserInit(pParser); - return pParser; +SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) sqlite3ParserCTX_PDECL){ + yyParser *yypParser; + yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); + if( yypParser ){ + sqlite3ParserCTX_STORE + sqlite3ParserInit(yypParser sqlite3ParserCTX_PARAM); + } + return (void*)yypParser; } #endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ @@ -141471,7 +148683,8 @@ static void yy_destructor( YYCODETYPE yymajor, /* Type code for object to destroy */ YYMINORTYPE *yypminor /* The object to be destroyed */ ){ - sqlite3ParserARG_FETCH; + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH switch( yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen @@ -141484,72 +148697,96 @@ static void yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 163: /* select */ - case 195: /* selectnowith */ - case 196: /* oneselect */ - case 207: /* values */ + case 174: /* select */ + case 206: /* selectnowith */ + case 207: /* oneselect */ + case 219: /* values */ { -sqlite3SelectDelete(pParse->db, (yypminor->yy387)); +sqlite3SelectDelete(pParse->db, (yypminor->yy489)); } break; - case 173: /* term */ - case 174: /* expr */ - case 202: /* where_opt */ - case 204: /* having_opt */ - case 216: /* on_opt */ - case 227: /* case_operand */ - case 229: /* case_else */ - case 238: /* when_clause */ - case 243: /* key_opt */ + case 184: /* term */ + case 185: /* expr */ + case 213: /* where_opt */ + case 215: /* having_opt */ + case 227: /* on_opt */ + case 242: /* case_operand */ + case 244: /* case_else */ + case 253: /* when_clause */ + case 258: /* key_opt */ + case 272: /* filter_opt */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy314)); +sqlite3ExprDelete(pParse->db, (yypminor->yy18)); } break; - case 178: /* eidlist_opt */ - case 187: /* sortlist */ - case 188: /* eidlist */ - case 200: /* selcollist */ - case 203: /* groupby_opt */ - case 205: /* orderby_opt */ - case 208: /* nexprlist */ - case 209: /* exprlist */ - case 210: /* sclp */ - case 220: /* setlist */ - case 226: /* paren_exprlist */ - case 228: /* case_exprlist */ + case 189: /* eidlist_opt */ + case 198: /* sortlist */ + case 199: /* eidlist */ + case 211: /* selcollist */ + case 214: /* groupby_opt */ + case 216: /* orderby_opt */ + case 220: /* nexprlist */ + case 221: /* sclp */ + case 229: /* exprlist */ + case 233: /* setlist */ + case 241: /* paren_exprlist */ + case 243: /* case_exprlist */ + case 271: /* part_opt */ { -sqlite3ExprListDelete(pParse->db, (yypminor->yy322)); +sqlite3ExprListDelete(pParse->db, (yypminor->yy420)); } break; - case 194: /* fullname */ - case 201: /* from */ - case 212: /* seltablist */ - case 213: /* stl_prefix */ + case 205: /* fullname */ + case 212: /* from */ + case 223: /* seltablist */ + case 224: /* stl_prefix */ + case 230: /* xfullname */ { -sqlite3SrcListDelete(pParse->db, (yypminor->yy259)); +sqlite3SrcListDelete(pParse->db, (yypminor->yy135)); } break; - case 197: /* wqlist */ + case 208: /* wqlist */ { -sqlite3WithDelete(pParse->db, (yypminor->yy451)); +sqlite3WithDelete(pParse->db, (yypminor->yy449)); } break; - case 217: /* using_opt */ - case 218: /* idlist */ - case 222: /* idlist_opt */ + case 218: /* window_clause */ + case 267: /* windowdefn_list */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy384)); +sqlite3WindowListDelete(pParse->db, (yypminor->yy327)); } break; - case 234: /* trigger_cmd_list */ - case 239: /* trigger_cmd */ + case 228: /* using_opt */ + case 231: /* idlist */ + case 235: /* idlist_opt */ { -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy203)); +sqlite3IdListDelete(pParse->db, (yypminor->yy48)); } break; - case 236: /* trigger_event */ + case 237: /* over_clause */ + case 268: /* windowdefn */ + case 269: /* window */ + case 270: /* frame_opt */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy90).b); +sqlite3WindowDelete(pParse->db, (yypminor->yy327)); +} + break; + case 249: /* trigger_cmd_list */ + case 254: /* trigger_cmd */ +{ +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy207)); +} + break; + case 251: /* trigger_event */ +{ +sqlite3IdListDelete(pParse->db, (yypminor->yy34).b); +} + break; + case 274: /* frame_bound */ + case 275: /* frame_bound_s */ + case 276: /* frame_bound_e */ +{ +sqlite3ExprDelete(pParse->db, (yypminor->yy119).pExpr); } break; /********* End destructor definitions *****************************************/ @@ -141661,13 +148898,12 @@ SQLITE_PRIVATE int sqlite3ParserCoverage(FILE *out){ ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. */ -static unsigned int yy_find_shift_action( - yyParser *pParser, /* The parser */ - YYCODETYPE iLookAhead /* The look-ahead token */ +static YYACTIONTYPE yy_find_shift_action( + YYCODETYPE iLookAhead, /* The look-ahead token */ + YYACTIONTYPE stateno /* Current state number */ ){ int i; - int stateno = pParser->yytos->stateno; - + if( stateno>YY_MAX_SHIFT ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) @@ -141676,11 +148912,11 @@ static unsigned int yy_find_shift_action( do{ i = yy_shift_ofst[stateno]; assert( i>=0 ); - assert( i+YYNTOKEN<=(int)sizeof(yy_lookahead)/sizeof(yy_lookahead[0]) ); + /* assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); */ assert( iLookAhead!=YYNOCODE ); assert( iLookAhead < YYNTOKEN ); i += iLookAhead; - if( yy_lookahead[i]!=iLookAhead ){ + if( i>=YY_NLOOKAHEAD || yy_lookahead[i]!=iLookAhead ){ #ifdef YYFALLBACK YYCODETYPE iFallback; /* Fallback token */ if( iLookAhead=YY_ACTTAB_COUNT j0 ){ #ifndef NDEBUG @@ -141730,8 +148967,8 @@ static unsigned int yy_find_shift_action( ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. */ -static int yy_find_reduce_action( - int stateno, /* Current state number */ +static YYACTIONTYPE yy_find_reduce_action( + YYACTIONTYPE stateno, /* Current state number */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; @@ -141760,7 +148997,8 @@ static int yy_find_reduce_action( ** The following routine is called if the stack overflows. */ static void yyStackOverflow(yyParser *yypParser){ - sqlite3ParserARG_FETCH; + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); @@ -141773,7 +149011,8 @@ static void yyStackOverflow(yyParser *yypParser){ sqlite3ErrorMsg(pParse, "parser stack overflow"); /******** End %stack_overflow code ********************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */ + sqlite3ParserCTX_STORE } /* @@ -141802,8 +149041,8 @@ static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){ */ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ - int yyNewState, /* The new state to shift in */ - int yyMajor, /* The major token to shift in */ + YYACTIONTYPE yyNewState, /* The new state to shift in */ + YYCODETYPE yyMajor, /* The major token to shift in */ sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; @@ -141833,8 +149072,8 @@ static void yy_shift( yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } yytos = yypParser->yytos; - yytos->stateno = (YYACTIONTYPE)yyNewState; - yytos->major = (YYCODETYPE)yyMajor; + yytos->stateno = yyNewState; + yytos->major = yyMajor; yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState, "Shift"); } @@ -141846,339 +149085,373 @@ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ signed char nrhs; /* Negative of the number of RHS symbols in the rule */ } yyRuleInfo[] = { - { 147, -1 }, /* (0) explain ::= EXPLAIN */ - { 147, -3 }, /* (1) explain ::= EXPLAIN QUERY PLAN */ - { 148, -1 }, /* (2) cmdx ::= cmd */ - { 149, -3 }, /* (3) cmd ::= BEGIN transtype trans_opt */ - { 150, 0 }, /* (4) transtype ::= */ - { 150, -1 }, /* (5) transtype ::= DEFERRED */ - { 150, -1 }, /* (6) transtype ::= IMMEDIATE */ - { 150, -1 }, /* (7) transtype ::= EXCLUSIVE */ - { 149, -2 }, /* (8) cmd ::= COMMIT|END trans_opt */ - { 149, -2 }, /* (9) cmd ::= ROLLBACK trans_opt */ - { 149, -2 }, /* (10) cmd ::= SAVEPOINT nm */ - { 149, -3 }, /* (11) cmd ::= RELEASE savepoint_opt nm */ - { 149, -5 }, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - { 154, -6 }, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - { 156, -1 }, /* (14) createkw ::= CREATE */ - { 158, 0 }, /* (15) ifnotexists ::= */ - { 158, -3 }, /* (16) ifnotexists ::= IF NOT EXISTS */ - { 157, -1 }, /* (17) temp ::= TEMP */ - { 157, 0 }, /* (18) temp ::= */ - { 155, -5 }, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */ - { 155, -2 }, /* (20) create_table_args ::= AS select */ - { 162, 0 }, /* (21) table_options ::= */ - { 162, -2 }, /* (22) table_options ::= WITHOUT nm */ - { 164, -2 }, /* (23) columnname ::= nm typetoken */ - { 166, 0 }, /* (24) typetoken ::= */ - { 166, -4 }, /* (25) typetoken ::= typename LP signed RP */ - { 166, -6 }, /* (26) typetoken ::= typename LP signed COMMA signed RP */ - { 167, -2 }, /* (27) typename ::= typename ID|STRING */ - { 171, 0 }, /* (28) scanpt ::= */ - { 172, -2 }, /* (29) ccons ::= CONSTRAINT nm */ - { 172, -4 }, /* (30) ccons ::= DEFAULT scanpt term scanpt */ - { 172, -4 }, /* (31) ccons ::= DEFAULT LP expr RP */ - { 172, -4 }, /* (32) ccons ::= DEFAULT PLUS term scanpt */ - { 172, -4 }, /* (33) ccons ::= DEFAULT MINUS term scanpt */ - { 172, -3 }, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */ - { 172, -3 }, /* (35) ccons ::= NOT NULL onconf */ - { 172, -5 }, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - { 172, -2 }, /* (37) ccons ::= UNIQUE onconf */ - { 172, -4 }, /* (38) ccons ::= CHECK LP expr RP */ - { 172, -4 }, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */ - { 172, -1 }, /* (40) ccons ::= defer_subclause */ - { 172, -2 }, /* (41) ccons ::= COLLATE ID|STRING */ - { 177, 0 }, /* (42) autoinc ::= */ - { 177, -1 }, /* (43) autoinc ::= AUTOINCR */ - { 179, 0 }, /* (44) refargs ::= */ - { 179, -2 }, /* (45) refargs ::= refargs refarg */ - { 181, -2 }, /* (46) refarg ::= MATCH nm */ - { 181, -3 }, /* (47) refarg ::= ON INSERT refact */ - { 181, -3 }, /* (48) refarg ::= ON DELETE refact */ - { 181, -3 }, /* (49) refarg ::= ON UPDATE refact */ - { 182, -2 }, /* (50) refact ::= SET NULL */ - { 182, -2 }, /* (51) refact ::= SET DEFAULT */ - { 182, -1 }, /* (52) refact ::= CASCADE */ - { 182, -1 }, /* (53) refact ::= RESTRICT */ - { 182, -2 }, /* (54) refact ::= NO ACTION */ - { 180, -3 }, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - { 180, -2 }, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - { 183, 0 }, /* (57) init_deferred_pred_opt ::= */ - { 183, -2 }, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - { 183, -2 }, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - { 161, 0 }, /* (60) conslist_opt ::= */ - { 185, -1 }, /* (61) tconscomma ::= COMMA */ - { 186, -2 }, /* (62) tcons ::= CONSTRAINT nm */ - { 186, -7 }, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - { 186, -5 }, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */ - { 186, -5 }, /* (65) tcons ::= CHECK LP expr RP onconf */ - { 186, -10 }, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - { 189, 0 }, /* (67) defer_subclause_opt ::= */ - { 175, 0 }, /* (68) onconf ::= */ - { 175, -3 }, /* (69) onconf ::= ON CONFLICT resolvetype */ - { 190, 0 }, /* (70) orconf ::= */ - { 190, -2 }, /* (71) orconf ::= OR resolvetype */ - { 191, -1 }, /* (72) resolvetype ::= IGNORE */ - { 191, -1 }, /* (73) resolvetype ::= REPLACE */ - { 149, -4 }, /* (74) cmd ::= DROP TABLE ifexists fullname */ - { 193, -2 }, /* (75) ifexists ::= IF EXISTS */ - { 193, 0 }, /* (76) ifexists ::= */ - { 149, -9 }, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - { 149, -4 }, /* (78) cmd ::= DROP VIEW ifexists fullname */ - { 149, -1 }, /* (79) cmd ::= select */ - { 163, -3 }, /* (80) select ::= WITH wqlist selectnowith */ - { 163, -4 }, /* (81) select ::= WITH RECURSIVE wqlist selectnowith */ - { 163, -1 }, /* (82) select ::= selectnowith */ - { 195, -3 }, /* (83) selectnowith ::= selectnowith multiselect_op oneselect */ - { 198, -1 }, /* (84) multiselect_op ::= UNION */ - { 198, -2 }, /* (85) multiselect_op ::= UNION ALL */ - { 198, -1 }, /* (86) multiselect_op ::= EXCEPT|INTERSECT */ - { 196, -9 }, /* (87) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - { 207, -4 }, /* (88) values ::= VALUES LP nexprlist RP */ - { 207, -5 }, /* (89) values ::= values COMMA LP exprlist RP */ - { 199, -1 }, /* (90) distinct ::= DISTINCT */ - { 199, -1 }, /* (91) distinct ::= ALL */ - { 199, 0 }, /* (92) distinct ::= */ - { 210, 0 }, /* (93) sclp ::= */ - { 200, -5 }, /* (94) selcollist ::= sclp scanpt expr scanpt as */ - { 200, -3 }, /* (95) selcollist ::= sclp scanpt STAR */ - { 200, -5 }, /* (96) selcollist ::= sclp scanpt nm DOT STAR */ - { 211, -2 }, /* (97) as ::= AS nm */ - { 211, 0 }, /* (98) as ::= */ - { 201, 0 }, /* (99) from ::= */ - { 201, -2 }, /* (100) from ::= FROM seltablist */ - { 213, -2 }, /* (101) stl_prefix ::= seltablist joinop */ - { 213, 0 }, /* (102) stl_prefix ::= */ - { 212, -7 }, /* (103) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ - { 212, -9 }, /* (104) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ - { 212, -7 }, /* (105) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ - { 212, -7 }, /* (106) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ - { 159, 0 }, /* (107) dbnm ::= */ - { 159, -2 }, /* (108) dbnm ::= DOT nm */ - { 194, -1 }, /* (109) fullname ::= nm */ - { 194, -3 }, /* (110) fullname ::= nm DOT nm */ - { 214, -1 }, /* (111) joinop ::= COMMA|JOIN */ - { 214, -2 }, /* (112) joinop ::= JOIN_KW JOIN */ - { 214, -3 }, /* (113) joinop ::= JOIN_KW nm JOIN */ - { 214, -4 }, /* (114) joinop ::= JOIN_KW nm nm JOIN */ - { 216, -2 }, /* (115) on_opt ::= ON expr */ - { 216, 0 }, /* (116) on_opt ::= */ - { 215, 0 }, /* (117) indexed_opt ::= */ - { 215, -3 }, /* (118) indexed_opt ::= INDEXED BY nm */ - { 215, -2 }, /* (119) indexed_opt ::= NOT INDEXED */ - { 217, -4 }, /* (120) using_opt ::= USING LP idlist RP */ - { 217, 0 }, /* (121) using_opt ::= */ - { 205, 0 }, /* (122) orderby_opt ::= */ - { 205, -3 }, /* (123) orderby_opt ::= ORDER BY sortlist */ - { 187, -4 }, /* (124) sortlist ::= sortlist COMMA expr sortorder */ - { 187, -2 }, /* (125) sortlist ::= expr sortorder */ - { 176, -1 }, /* (126) sortorder ::= ASC */ - { 176, -1 }, /* (127) sortorder ::= DESC */ - { 176, 0 }, /* (128) sortorder ::= */ - { 203, 0 }, /* (129) groupby_opt ::= */ - { 203, -3 }, /* (130) groupby_opt ::= GROUP BY nexprlist */ - { 204, 0 }, /* (131) having_opt ::= */ - { 204, -2 }, /* (132) having_opt ::= HAVING expr */ - { 206, 0 }, /* (133) limit_opt ::= */ - { 206, -2 }, /* (134) limit_opt ::= LIMIT expr */ - { 206, -4 }, /* (135) limit_opt ::= LIMIT expr OFFSET expr */ - { 206, -4 }, /* (136) limit_opt ::= LIMIT expr COMMA expr */ - { 149, -6 }, /* (137) cmd ::= with DELETE FROM fullname indexed_opt where_opt */ - { 202, 0 }, /* (138) where_opt ::= */ - { 202, -2 }, /* (139) where_opt ::= WHERE expr */ - { 149, -8 }, /* (140) cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ - { 220, -5 }, /* (141) setlist ::= setlist COMMA nm EQ expr */ - { 220, -7 }, /* (142) setlist ::= setlist COMMA LP idlist RP EQ expr */ - { 220, -3 }, /* (143) setlist ::= nm EQ expr */ - { 220, -5 }, /* (144) setlist ::= LP idlist RP EQ expr */ - { 149, -6 }, /* (145) cmd ::= with insert_cmd INTO fullname idlist_opt select */ - { 149, -7 }, /* (146) cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ - { 221, -2 }, /* (147) insert_cmd ::= INSERT orconf */ - { 221, -1 }, /* (148) insert_cmd ::= REPLACE */ - { 222, 0 }, /* (149) idlist_opt ::= */ - { 222, -3 }, /* (150) idlist_opt ::= LP idlist RP */ - { 218, -3 }, /* (151) idlist ::= idlist COMMA nm */ - { 218, -1 }, /* (152) idlist ::= nm */ - { 174, -3 }, /* (153) expr ::= LP expr RP */ - { 174, -1 }, /* (154) expr ::= ID|INDEXED */ - { 174, -1 }, /* (155) expr ::= JOIN_KW */ - { 174, -3 }, /* (156) expr ::= nm DOT nm */ - { 174, -5 }, /* (157) expr ::= nm DOT nm DOT nm */ - { 173, -1 }, /* (158) term ::= NULL|FLOAT|BLOB */ - { 173, -1 }, /* (159) term ::= STRING */ - { 173, -1 }, /* (160) term ::= INTEGER */ - { 174, -1 }, /* (161) expr ::= VARIABLE */ - { 174, -3 }, /* (162) expr ::= expr COLLATE ID|STRING */ - { 174, -6 }, /* (163) expr ::= CAST LP expr AS typetoken RP */ - { 174, -5 }, /* (164) expr ::= ID|INDEXED LP distinct exprlist RP */ - { 174, -4 }, /* (165) expr ::= ID|INDEXED LP STAR RP */ - { 173, -1 }, /* (166) term ::= CTIME_KW */ - { 174, -5 }, /* (167) expr ::= LP nexprlist COMMA expr RP */ - { 174, -3 }, /* (168) expr ::= expr AND expr */ - { 174, -3 }, /* (169) expr ::= expr OR expr */ - { 174, -3 }, /* (170) expr ::= expr LT|GT|GE|LE expr */ - { 174, -3 }, /* (171) expr ::= expr EQ|NE expr */ - { 174, -3 }, /* (172) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - { 174, -3 }, /* (173) expr ::= expr PLUS|MINUS expr */ - { 174, -3 }, /* (174) expr ::= expr STAR|SLASH|REM expr */ - { 174, -3 }, /* (175) expr ::= expr CONCAT expr */ - { 223, -2 }, /* (176) likeop ::= NOT LIKE_KW|MATCH */ - { 174, -3 }, /* (177) expr ::= expr likeop expr */ - { 174, -5 }, /* (178) expr ::= expr likeop expr ESCAPE expr */ - { 174, -2 }, /* (179) expr ::= expr ISNULL|NOTNULL */ - { 174, -3 }, /* (180) expr ::= expr NOT NULL */ - { 174, -3 }, /* (181) expr ::= expr IS expr */ - { 174, -4 }, /* (182) expr ::= expr IS NOT expr */ - { 174, -2 }, /* (183) expr ::= NOT expr */ - { 174, -2 }, /* (184) expr ::= BITNOT expr */ - { 174, -2 }, /* (185) expr ::= MINUS expr */ - { 174, -2 }, /* (186) expr ::= PLUS expr */ - { 224, -1 }, /* (187) between_op ::= BETWEEN */ - { 224, -2 }, /* (188) between_op ::= NOT BETWEEN */ - { 174, -5 }, /* (189) expr ::= expr between_op expr AND expr */ - { 225, -1 }, /* (190) in_op ::= IN */ - { 225, -2 }, /* (191) in_op ::= NOT IN */ - { 174, -5 }, /* (192) expr ::= expr in_op LP exprlist RP */ - { 174, -3 }, /* (193) expr ::= LP select RP */ - { 174, -5 }, /* (194) expr ::= expr in_op LP select RP */ - { 174, -5 }, /* (195) expr ::= expr in_op nm dbnm paren_exprlist */ - { 174, -4 }, /* (196) expr ::= EXISTS LP select RP */ - { 174, -5 }, /* (197) expr ::= CASE case_operand case_exprlist case_else END */ - { 228, -5 }, /* (198) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - { 228, -4 }, /* (199) case_exprlist ::= WHEN expr THEN expr */ - { 229, -2 }, /* (200) case_else ::= ELSE expr */ - { 229, 0 }, /* (201) case_else ::= */ - { 227, -1 }, /* (202) case_operand ::= expr */ - { 227, 0 }, /* (203) case_operand ::= */ - { 209, 0 }, /* (204) exprlist ::= */ - { 208, -3 }, /* (205) nexprlist ::= nexprlist COMMA expr */ - { 208, -1 }, /* (206) nexprlist ::= expr */ - { 226, 0 }, /* (207) paren_exprlist ::= */ - { 226, -3 }, /* (208) paren_exprlist ::= LP exprlist RP */ - { 149, -12 }, /* (209) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - { 230, -1 }, /* (210) uniqueflag ::= UNIQUE */ - { 230, 0 }, /* (211) uniqueflag ::= */ - { 178, 0 }, /* (212) eidlist_opt ::= */ - { 178, -3 }, /* (213) eidlist_opt ::= LP eidlist RP */ - { 188, -5 }, /* (214) eidlist ::= eidlist COMMA nm collate sortorder */ - { 188, -3 }, /* (215) eidlist ::= nm collate sortorder */ - { 231, 0 }, /* (216) collate ::= */ - { 231, -2 }, /* (217) collate ::= COLLATE ID|STRING */ - { 149, -4 }, /* (218) cmd ::= DROP INDEX ifexists fullname */ - { 149, -1 }, /* (219) cmd ::= VACUUM */ - { 149, -2 }, /* (220) cmd ::= VACUUM nm */ - { 149, -3 }, /* (221) cmd ::= PRAGMA nm dbnm */ - { 149, -5 }, /* (222) cmd ::= PRAGMA nm dbnm EQ nmnum */ - { 149, -6 }, /* (223) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - { 149, -5 }, /* (224) cmd ::= PRAGMA nm dbnm EQ minus_num */ - { 149, -6 }, /* (225) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - { 169, -2 }, /* (226) plus_num ::= PLUS INTEGER|FLOAT */ - { 170, -2 }, /* (227) minus_num ::= MINUS INTEGER|FLOAT */ - { 149, -5 }, /* (228) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - { 233, -11 }, /* (229) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - { 235, -1 }, /* (230) trigger_time ::= BEFORE|AFTER */ - { 235, -2 }, /* (231) trigger_time ::= INSTEAD OF */ - { 235, 0 }, /* (232) trigger_time ::= */ - { 236, -1 }, /* (233) trigger_event ::= DELETE|INSERT */ - { 236, -1 }, /* (234) trigger_event ::= UPDATE */ - { 236, -3 }, /* (235) trigger_event ::= UPDATE OF idlist */ - { 238, 0 }, /* (236) when_clause ::= */ - { 238, -2 }, /* (237) when_clause ::= WHEN expr */ - { 234, -3 }, /* (238) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - { 234, -2 }, /* (239) trigger_cmd_list ::= trigger_cmd SEMI */ - { 240, -3 }, /* (240) trnm ::= nm DOT nm */ - { 241, -3 }, /* (241) tridxby ::= INDEXED BY nm */ - { 241, -2 }, /* (242) tridxby ::= NOT INDEXED */ - { 239, -8 }, /* (243) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ - { 239, -7 }, /* (244) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt */ - { 239, -6 }, /* (245) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - { 239, -3 }, /* (246) trigger_cmd ::= scanpt select scanpt */ - { 174, -4 }, /* (247) expr ::= RAISE LP IGNORE RP */ - { 174, -6 }, /* (248) expr ::= RAISE LP raisetype COMMA nm RP */ - { 192, -1 }, /* (249) raisetype ::= ROLLBACK */ - { 192, -1 }, /* (250) raisetype ::= ABORT */ - { 192, -1 }, /* (251) raisetype ::= FAIL */ - { 149, -4 }, /* (252) cmd ::= DROP TRIGGER ifexists fullname */ - { 149, -6 }, /* (253) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - { 149, -3 }, /* (254) cmd ::= DETACH database_kw_opt expr */ - { 243, 0 }, /* (255) key_opt ::= */ - { 243, -2 }, /* (256) key_opt ::= KEY expr */ - { 149, -1 }, /* (257) cmd ::= REINDEX */ - { 149, -3 }, /* (258) cmd ::= REINDEX nm dbnm */ - { 149, -1 }, /* (259) cmd ::= ANALYZE */ - { 149, -3 }, /* (260) cmd ::= ANALYZE nm dbnm */ - { 149, -6 }, /* (261) cmd ::= ALTER TABLE fullname RENAME TO nm */ - { 149, -7 }, /* (262) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - { 244, -1 }, /* (263) add_column_fullname ::= fullname */ - { 149, -1 }, /* (264) cmd ::= create_vtab */ - { 149, -4 }, /* (265) cmd ::= create_vtab LP vtabarglist RP */ - { 246, -8 }, /* (266) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - { 248, 0 }, /* (267) vtabarg ::= */ - { 249, -1 }, /* (268) vtabargtoken ::= ANY */ - { 249, -3 }, /* (269) vtabargtoken ::= lp anylist RP */ - { 250, -1 }, /* (270) lp ::= LP */ - { 219, -2 }, /* (271) with ::= WITH wqlist */ - { 219, -3 }, /* (272) with ::= WITH RECURSIVE wqlist */ - { 197, -6 }, /* (273) wqlist ::= nm eidlist_opt AS LP select RP */ - { 197, -8 }, /* (274) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ - { 144, -1 }, /* (275) input ::= cmdlist */ - { 145, -2 }, /* (276) cmdlist ::= cmdlist ecmd */ - { 145, -1 }, /* (277) cmdlist ::= ecmd */ - { 146, -1 }, /* (278) ecmd ::= SEMI */ - { 146, -3 }, /* (279) ecmd ::= explain cmdx SEMI */ - { 147, 0 }, /* (280) explain ::= */ - { 151, 0 }, /* (281) trans_opt ::= */ - { 151, -1 }, /* (282) trans_opt ::= TRANSACTION */ - { 151, -2 }, /* (283) trans_opt ::= TRANSACTION nm */ - { 153, -1 }, /* (284) savepoint_opt ::= SAVEPOINT */ - { 153, 0 }, /* (285) savepoint_opt ::= */ - { 149, -2 }, /* (286) cmd ::= create_table create_table_args */ - { 160, -4 }, /* (287) columnlist ::= columnlist COMMA columnname carglist */ - { 160, -2 }, /* (288) columnlist ::= columnname carglist */ - { 152, -1 }, /* (289) nm ::= ID|INDEXED */ - { 152, -1 }, /* (290) nm ::= STRING */ - { 152, -1 }, /* (291) nm ::= JOIN_KW */ - { 166, -1 }, /* (292) typetoken ::= typename */ - { 167, -1 }, /* (293) typename ::= ID|STRING */ - { 168, -1 }, /* (294) signed ::= plus_num */ - { 168, -1 }, /* (295) signed ::= minus_num */ - { 165, -2 }, /* (296) carglist ::= carglist ccons */ - { 165, 0 }, /* (297) carglist ::= */ - { 172, -2 }, /* (298) ccons ::= NULL onconf */ - { 161, -2 }, /* (299) conslist_opt ::= COMMA conslist */ - { 184, -3 }, /* (300) conslist ::= conslist tconscomma tcons */ - { 184, -1 }, /* (301) conslist ::= tcons */ - { 185, 0 }, /* (302) tconscomma ::= */ - { 189, -1 }, /* (303) defer_subclause_opt ::= defer_subclause */ - { 191, -1 }, /* (304) resolvetype ::= raisetype */ - { 195, -1 }, /* (305) selectnowith ::= oneselect */ - { 196, -1 }, /* (306) oneselect ::= values */ - { 210, -2 }, /* (307) sclp ::= selcollist COMMA */ - { 211, -1 }, /* (308) as ::= ID|STRING */ - { 174, -1 }, /* (309) expr ::= term */ - { 223, -1 }, /* (310) likeop ::= LIKE_KW|MATCH */ - { 209, -1 }, /* (311) exprlist ::= nexprlist */ - { 232, -1 }, /* (312) nmnum ::= plus_num */ - { 232, -1 }, /* (313) nmnum ::= nm */ - { 232, -1 }, /* (314) nmnum ::= ON */ - { 232, -1 }, /* (315) nmnum ::= DELETE */ - { 232, -1 }, /* (316) nmnum ::= DEFAULT */ - { 169, -1 }, /* (317) plus_num ::= INTEGER|FLOAT */ - { 237, 0 }, /* (318) foreach_clause ::= */ - { 237, -3 }, /* (319) foreach_clause ::= FOR EACH ROW */ - { 240, -1 }, /* (320) trnm ::= nm */ - { 241, 0 }, /* (321) tridxby ::= */ - { 242, -1 }, /* (322) database_kw_opt ::= DATABASE */ - { 242, 0 }, /* (323) database_kw_opt ::= */ - { 245, 0 }, /* (324) kwcolumn_opt ::= */ - { 245, -1 }, /* (325) kwcolumn_opt ::= COLUMNKW */ - { 247, -1 }, /* (326) vtabarglist ::= vtabarg */ - { 247, -3 }, /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ - { 248, -2 }, /* (328) vtabarg ::= vtabarg vtabargtoken */ - { 251, 0 }, /* (329) anylist ::= */ - { 251, -4 }, /* (330) anylist ::= anylist LP anylist RP */ - { 251, -2 }, /* (331) anylist ::= anylist ANY */ - { 219, 0 }, /* (332) with ::= */ + { 159, -1 }, /* (0) explain ::= EXPLAIN */ + { 159, -3 }, /* (1) explain ::= EXPLAIN QUERY PLAN */ + { 158, -1 }, /* (2) cmdx ::= cmd */ + { 160, -3 }, /* (3) cmd ::= BEGIN transtype trans_opt */ + { 161, 0 }, /* (4) transtype ::= */ + { 161, -1 }, /* (5) transtype ::= DEFERRED */ + { 161, -1 }, /* (6) transtype ::= IMMEDIATE */ + { 161, -1 }, /* (7) transtype ::= EXCLUSIVE */ + { 160, -2 }, /* (8) cmd ::= COMMIT|END trans_opt */ + { 160, -2 }, /* (9) cmd ::= ROLLBACK trans_opt */ + { 160, -2 }, /* (10) cmd ::= SAVEPOINT nm */ + { 160, -3 }, /* (11) cmd ::= RELEASE savepoint_opt nm */ + { 160, -5 }, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + { 165, -6 }, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + { 167, -1 }, /* (14) createkw ::= CREATE */ + { 169, 0 }, /* (15) ifnotexists ::= */ + { 169, -3 }, /* (16) ifnotexists ::= IF NOT EXISTS */ + { 168, -1 }, /* (17) temp ::= TEMP */ + { 168, 0 }, /* (18) temp ::= */ + { 166, -5 }, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */ + { 166, -2 }, /* (20) create_table_args ::= AS select */ + { 173, 0 }, /* (21) table_options ::= */ + { 173, -2 }, /* (22) table_options ::= WITHOUT nm */ + { 175, -2 }, /* (23) columnname ::= nm typetoken */ + { 177, 0 }, /* (24) typetoken ::= */ + { 177, -4 }, /* (25) typetoken ::= typename LP signed RP */ + { 177, -6 }, /* (26) typetoken ::= typename LP signed COMMA signed RP */ + { 178, -2 }, /* (27) typename ::= typename ID|STRING */ + { 182, 0 }, /* (28) scanpt ::= */ + { 183, -2 }, /* (29) ccons ::= CONSTRAINT nm */ + { 183, -4 }, /* (30) ccons ::= DEFAULT scanpt term scanpt */ + { 183, -4 }, /* (31) ccons ::= DEFAULT LP expr RP */ + { 183, -4 }, /* (32) ccons ::= DEFAULT PLUS term scanpt */ + { 183, -4 }, /* (33) ccons ::= DEFAULT MINUS term scanpt */ + { 183, -3 }, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */ + { 183, -3 }, /* (35) ccons ::= NOT NULL onconf */ + { 183, -5 }, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + { 183, -2 }, /* (37) ccons ::= UNIQUE onconf */ + { 183, -4 }, /* (38) ccons ::= CHECK LP expr RP */ + { 183, -4 }, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */ + { 183, -1 }, /* (40) ccons ::= defer_subclause */ + { 183, -2 }, /* (41) ccons ::= COLLATE ID|STRING */ + { 188, 0 }, /* (42) autoinc ::= */ + { 188, -1 }, /* (43) autoinc ::= AUTOINCR */ + { 190, 0 }, /* (44) refargs ::= */ + { 190, -2 }, /* (45) refargs ::= refargs refarg */ + { 192, -2 }, /* (46) refarg ::= MATCH nm */ + { 192, -3 }, /* (47) refarg ::= ON INSERT refact */ + { 192, -3 }, /* (48) refarg ::= ON DELETE refact */ + { 192, -3 }, /* (49) refarg ::= ON UPDATE refact */ + { 193, -2 }, /* (50) refact ::= SET NULL */ + { 193, -2 }, /* (51) refact ::= SET DEFAULT */ + { 193, -1 }, /* (52) refact ::= CASCADE */ + { 193, -1 }, /* (53) refact ::= RESTRICT */ + { 193, -2 }, /* (54) refact ::= NO ACTION */ + { 191, -3 }, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + { 191, -2 }, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + { 194, 0 }, /* (57) init_deferred_pred_opt ::= */ + { 194, -2 }, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + { 194, -2 }, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + { 172, 0 }, /* (60) conslist_opt ::= */ + { 196, -1 }, /* (61) tconscomma ::= COMMA */ + { 197, -2 }, /* (62) tcons ::= CONSTRAINT nm */ + { 197, -7 }, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + { 197, -5 }, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */ + { 197, -5 }, /* (65) tcons ::= CHECK LP expr RP onconf */ + { 197, -10 }, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + { 200, 0 }, /* (67) defer_subclause_opt ::= */ + { 186, 0 }, /* (68) onconf ::= */ + { 186, -3 }, /* (69) onconf ::= ON CONFLICT resolvetype */ + { 201, 0 }, /* (70) orconf ::= */ + { 201, -2 }, /* (71) orconf ::= OR resolvetype */ + { 202, -1 }, /* (72) resolvetype ::= IGNORE */ + { 202, -1 }, /* (73) resolvetype ::= REPLACE */ + { 160, -4 }, /* (74) cmd ::= DROP TABLE ifexists fullname */ + { 204, -2 }, /* (75) ifexists ::= IF EXISTS */ + { 204, 0 }, /* (76) ifexists ::= */ + { 160, -9 }, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + { 160, -4 }, /* (78) cmd ::= DROP VIEW ifexists fullname */ + { 160, -1 }, /* (79) cmd ::= select */ + { 174, -3 }, /* (80) select ::= WITH wqlist selectnowith */ + { 174, -4 }, /* (81) select ::= WITH RECURSIVE wqlist selectnowith */ + { 174, -1 }, /* (82) select ::= selectnowith */ + { 206, -3 }, /* (83) selectnowith ::= selectnowith multiselect_op oneselect */ + { 209, -1 }, /* (84) multiselect_op ::= UNION */ + { 209, -2 }, /* (85) multiselect_op ::= UNION ALL */ + { 209, -1 }, /* (86) multiselect_op ::= EXCEPT|INTERSECT */ + { 207, -9 }, /* (87) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + { 207, -10 }, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + { 219, -4 }, /* (89) values ::= VALUES LP nexprlist RP */ + { 219, -5 }, /* (90) values ::= values COMMA LP nexprlist RP */ + { 210, -1 }, /* (91) distinct ::= DISTINCT */ + { 210, -1 }, /* (92) distinct ::= ALL */ + { 210, 0 }, /* (93) distinct ::= */ + { 221, 0 }, /* (94) sclp ::= */ + { 211, -5 }, /* (95) selcollist ::= sclp scanpt expr scanpt as */ + { 211, -3 }, /* (96) selcollist ::= sclp scanpt STAR */ + { 211, -5 }, /* (97) selcollist ::= sclp scanpt nm DOT STAR */ + { 222, -2 }, /* (98) as ::= AS nm */ + { 222, 0 }, /* (99) as ::= */ + { 212, 0 }, /* (100) from ::= */ + { 212, -2 }, /* (101) from ::= FROM seltablist */ + { 224, -2 }, /* (102) stl_prefix ::= seltablist joinop */ + { 224, 0 }, /* (103) stl_prefix ::= */ + { 223, -7 }, /* (104) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + { 223, -9 }, /* (105) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + { 223, -7 }, /* (106) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + { 223, -7 }, /* (107) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + { 170, 0 }, /* (108) dbnm ::= */ + { 170, -2 }, /* (109) dbnm ::= DOT nm */ + { 205, -1 }, /* (110) fullname ::= nm */ + { 205, -3 }, /* (111) fullname ::= nm DOT nm */ + { 230, -1 }, /* (112) xfullname ::= nm */ + { 230, -3 }, /* (113) xfullname ::= nm DOT nm */ + { 230, -5 }, /* (114) xfullname ::= nm DOT nm AS nm */ + { 230, -3 }, /* (115) xfullname ::= nm AS nm */ + { 225, -1 }, /* (116) joinop ::= COMMA|JOIN */ + { 225, -2 }, /* (117) joinop ::= JOIN_KW JOIN */ + { 225, -3 }, /* (118) joinop ::= JOIN_KW nm JOIN */ + { 225, -4 }, /* (119) joinop ::= JOIN_KW nm nm JOIN */ + { 227, -2 }, /* (120) on_opt ::= ON expr */ + { 227, 0 }, /* (121) on_opt ::= */ + { 226, 0 }, /* (122) indexed_opt ::= */ + { 226, -3 }, /* (123) indexed_opt ::= INDEXED BY nm */ + { 226, -2 }, /* (124) indexed_opt ::= NOT INDEXED */ + { 228, -4 }, /* (125) using_opt ::= USING LP idlist RP */ + { 228, 0 }, /* (126) using_opt ::= */ + { 216, 0 }, /* (127) orderby_opt ::= */ + { 216, -3 }, /* (128) orderby_opt ::= ORDER BY sortlist */ + { 198, -4 }, /* (129) sortlist ::= sortlist COMMA expr sortorder */ + { 198, -2 }, /* (130) sortlist ::= expr sortorder */ + { 187, -1 }, /* (131) sortorder ::= ASC */ + { 187, -1 }, /* (132) sortorder ::= DESC */ + { 187, 0 }, /* (133) sortorder ::= */ + { 214, 0 }, /* (134) groupby_opt ::= */ + { 214, -3 }, /* (135) groupby_opt ::= GROUP BY nexprlist */ + { 215, 0 }, /* (136) having_opt ::= */ + { 215, -2 }, /* (137) having_opt ::= HAVING expr */ + { 217, 0 }, /* (138) limit_opt ::= */ + { 217, -2 }, /* (139) limit_opt ::= LIMIT expr */ + { 217, -4 }, /* (140) limit_opt ::= LIMIT expr OFFSET expr */ + { 217, -4 }, /* (141) limit_opt ::= LIMIT expr COMMA expr */ + { 160, -6 }, /* (142) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ + { 213, 0 }, /* (143) where_opt ::= */ + { 213, -2 }, /* (144) where_opt ::= WHERE expr */ + { 160, -8 }, /* (145) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ + { 233, -5 }, /* (146) setlist ::= setlist COMMA nm EQ expr */ + { 233, -7 }, /* (147) setlist ::= setlist COMMA LP idlist RP EQ expr */ + { 233, -3 }, /* (148) setlist ::= nm EQ expr */ + { 233, -5 }, /* (149) setlist ::= LP idlist RP EQ expr */ + { 160, -7 }, /* (150) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + { 160, -7 }, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ + { 236, 0 }, /* (152) upsert ::= */ + { 236, -11 }, /* (153) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ + { 236, -8 }, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ + { 236, -4 }, /* (155) upsert ::= ON CONFLICT DO NOTHING */ + { 234, -2 }, /* (156) insert_cmd ::= INSERT orconf */ + { 234, -1 }, /* (157) insert_cmd ::= REPLACE */ + { 235, 0 }, /* (158) idlist_opt ::= */ + { 235, -3 }, /* (159) idlist_opt ::= LP idlist RP */ + { 231, -3 }, /* (160) idlist ::= idlist COMMA nm */ + { 231, -1 }, /* (161) idlist ::= nm */ + { 185, -3 }, /* (162) expr ::= LP expr RP */ + { 185, -1 }, /* (163) expr ::= ID|INDEXED */ + { 185, -1 }, /* (164) expr ::= JOIN_KW */ + { 185, -3 }, /* (165) expr ::= nm DOT nm */ + { 185, -5 }, /* (166) expr ::= nm DOT nm DOT nm */ + { 184, -1 }, /* (167) term ::= NULL|FLOAT|BLOB */ + { 184, -1 }, /* (168) term ::= STRING */ + { 184, -1 }, /* (169) term ::= INTEGER */ + { 185, -1 }, /* (170) expr ::= VARIABLE */ + { 185, -3 }, /* (171) expr ::= expr COLLATE ID|STRING */ + { 185, -6 }, /* (172) expr ::= CAST LP expr AS typetoken RP */ + { 185, -5 }, /* (173) expr ::= ID|INDEXED LP distinct exprlist RP */ + { 185, -4 }, /* (174) expr ::= ID|INDEXED LP STAR RP */ + { 185, -6 }, /* (175) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ + { 185, -5 }, /* (176) expr ::= ID|INDEXED LP STAR RP over_clause */ + { 184, -1 }, /* (177) term ::= CTIME_KW */ + { 185, -5 }, /* (178) expr ::= LP nexprlist COMMA expr RP */ + { 185, -3 }, /* (179) expr ::= expr AND expr */ + { 185, -3 }, /* (180) expr ::= expr OR expr */ + { 185, -3 }, /* (181) expr ::= expr LT|GT|GE|LE expr */ + { 185, -3 }, /* (182) expr ::= expr EQ|NE expr */ + { 185, -3 }, /* (183) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + { 185, -3 }, /* (184) expr ::= expr PLUS|MINUS expr */ + { 185, -3 }, /* (185) expr ::= expr STAR|SLASH|REM expr */ + { 185, -3 }, /* (186) expr ::= expr CONCAT expr */ + { 238, -2 }, /* (187) likeop ::= NOT LIKE_KW|MATCH */ + { 185, -3 }, /* (188) expr ::= expr likeop expr */ + { 185, -5 }, /* (189) expr ::= expr likeop expr ESCAPE expr */ + { 185, -2 }, /* (190) expr ::= expr ISNULL|NOTNULL */ + { 185, -3 }, /* (191) expr ::= expr NOT NULL */ + { 185, -3 }, /* (192) expr ::= expr IS expr */ + { 185, -4 }, /* (193) expr ::= expr IS NOT expr */ + { 185, -2 }, /* (194) expr ::= NOT expr */ + { 185, -2 }, /* (195) expr ::= BITNOT expr */ + { 185, -2 }, /* (196) expr ::= PLUS|MINUS expr */ + { 239, -1 }, /* (197) between_op ::= BETWEEN */ + { 239, -2 }, /* (198) between_op ::= NOT BETWEEN */ + { 185, -5 }, /* (199) expr ::= expr between_op expr AND expr */ + { 240, -1 }, /* (200) in_op ::= IN */ + { 240, -2 }, /* (201) in_op ::= NOT IN */ + { 185, -5 }, /* (202) expr ::= expr in_op LP exprlist RP */ + { 185, -3 }, /* (203) expr ::= LP select RP */ + { 185, -5 }, /* (204) expr ::= expr in_op LP select RP */ + { 185, -5 }, /* (205) expr ::= expr in_op nm dbnm paren_exprlist */ + { 185, -4 }, /* (206) expr ::= EXISTS LP select RP */ + { 185, -5 }, /* (207) expr ::= CASE case_operand case_exprlist case_else END */ + { 243, -5 }, /* (208) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + { 243, -4 }, /* (209) case_exprlist ::= WHEN expr THEN expr */ + { 244, -2 }, /* (210) case_else ::= ELSE expr */ + { 244, 0 }, /* (211) case_else ::= */ + { 242, -1 }, /* (212) case_operand ::= expr */ + { 242, 0 }, /* (213) case_operand ::= */ + { 229, 0 }, /* (214) exprlist ::= */ + { 220, -3 }, /* (215) nexprlist ::= nexprlist COMMA expr */ + { 220, -1 }, /* (216) nexprlist ::= expr */ + { 241, 0 }, /* (217) paren_exprlist ::= */ + { 241, -3 }, /* (218) paren_exprlist ::= LP exprlist RP */ + { 160, -12 }, /* (219) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + { 245, -1 }, /* (220) uniqueflag ::= UNIQUE */ + { 245, 0 }, /* (221) uniqueflag ::= */ + { 189, 0 }, /* (222) eidlist_opt ::= */ + { 189, -3 }, /* (223) eidlist_opt ::= LP eidlist RP */ + { 199, -5 }, /* (224) eidlist ::= eidlist COMMA nm collate sortorder */ + { 199, -3 }, /* (225) eidlist ::= nm collate sortorder */ + { 246, 0 }, /* (226) collate ::= */ + { 246, -2 }, /* (227) collate ::= COLLATE ID|STRING */ + { 160, -4 }, /* (228) cmd ::= DROP INDEX ifexists fullname */ + { 160, -1 }, /* (229) cmd ::= VACUUM */ + { 160, -2 }, /* (230) cmd ::= VACUUM nm */ + { 160, -3 }, /* (231) cmd ::= PRAGMA nm dbnm */ + { 160, -5 }, /* (232) cmd ::= PRAGMA nm dbnm EQ nmnum */ + { 160, -6 }, /* (233) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + { 160, -5 }, /* (234) cmd ::= PRAGMA nm dbnm EQ minus_num */ + { 160, -6 }, /* (235) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + { 180, -2 }, /* (236) plus_num ::= PLUS INTEGER|FLOAT */ + { 181, -2 }, /* (237) minus_num ::= MINUS INTEGER|FLOAT */ + { 160, -5 }, /* (238) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + { 248, -11 }, /* (239) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + { 250, -1 }, /* (240) trigger_time ::= BEFORE|AFTER */ + { 250, -2 }, /* (241) trigger_time ::= INSTEAD OF */ + { 250, 0 }, /* (242) trigger_time ::= */ + { 251, -1 }, /* (243) trigger_event ::= DELETE|INSERT */ + { 251, -1 }, /* (244) trigger_event ::= UPDATE */ + { 251, -3 }, /* (245) trigger_event ::= UPDATE OF idlist */ + { 253, 0 }, /* (246) when_clause ::= */ + { 253, -2 }, /* (247) when_clause ::= WHEN expr */ + { 249, -3 }, /* (248) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + { 249, -2 }, /* (249) trigger_cmd_list ::= trigger_cmd SEMI */ + { 255, -3 }, /* (250) trnm ::= nm DOT nm */ + { 256, -3 }, /* (251) tridxby ::= INDEXED BY nm */ + { 256, -2 }, /* (252) tridxby ::= NOT INDEXED */ + { 254, -8 }, /* (253) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ + { 254, -8 }, /* (254) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + { 254, -6 }, /* (255) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + { 254, -3 }, /* (256) trigger_cmd ::= scanpt select scanpt */ + { 185, -4 }, /* (257) expr ::= RAISE LP IGNORE RP */ + { 185, -6 }, /* (258) expr ::= RAISE LP raisetype COMMA nm RP */ + { 203, -1 }, /* (259) raisetype ::= ROLLBACK */ + { 203, -1 }, /* (260) raisetype ::= ABORT */ + { 203, -1 }, /* (261) raisetype ::= FAIL */ + { 160, -4 }, /* (262) cmd ::= DROP TRIGGER ifexists fullname */ + { 160, -6 }, /* (263) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + { 160, -3 }, /* (264) cmd ::= DETACH database_kw_opt expr */ + { 258, 0 }, /* (265) key_opt ::= */ + { 258, -2 }, /* (266) key_opt ::= KEY expr */ + { 160, -1 }, /* (267) cmd ::= REINDEX */ + { 160, -3 }, /* (268) cmd ::= REINDEX nm dbnm */ + { 160, -1 }, /* (269) cmd ::= ANALYZE */ + { 160, -3 }, /* (270) cmd ::= ANALYZE nm dbnm */ + { 160, -6 }, /* (271) cmd ::= ALTER TABLE fullname RENAME TO nm */ + { 160, -7 }, /* (272) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + { 259, -1 }, /* (273) add_column_fullname ::= fullname */ + { 160, -8 }, /* (274) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + { 160, -1 }, /* (275) cmd ::= create_vtab */ + { 160, -4 }, /* (276) cmd ::= create_vtab LP vtabarglist RP */ + { 261, -8 }, /* (277) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + { 263, 0 }, /* (278) vtabarg ::= */ + { 264, -1 }, /* (279) vtabargtoken ::= ANY */ + { 264, -3 }, /* (280) vtabargtoken ::= lp anylist RP */ + { 265, -1 }, /* (281) lp ::= LP */ + { 232, -2 }, /* (282) with ::= WITH wqlist */ + { 232, -3 }, /* (283) with ::= WITH RECURSIVE wqlist */ + { 208, -6 }, /* (284) wqlist ::= nm eidlist_opt AS LP select RP */ + { 208, -8 }, /* (285) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + { 267, -1 }, /* (286) windowdefn_list ::= windowdefn */ + { 267, -3 }, /* (287) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + { 268, -3 }, /* (288) windowdefn ::= nm AS window */ + { 269, -5 }, /* (289) window ::= LP part_opt orderby_opt frame_opt RP */ + { 271, -3 }, /* (290) part_opt ::= PARTITION BY nexprlist */ + { 271, 0 }, /* (291) part_opt ::= */ + { 270, 0 }, /* (292) frame_opt ::= */ + { 270, -2 }, /* (293) frame_opt ::= range_or_rows frame_bound_s */ + { 270, -5 }, /* (294) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */ + { 273, -1 }, /* (295) range_or_rows ::= RANGE */ + { 273, -1 }, /* (296) range_or_rows ::= ROWS */ + { 275, -1 }, /* (297) frame_bound_s ::= frame_bound */ + { 275, -2 }, /* (298) frame_bound_s ::= UNBOUNDED PRECEDING */ + { 276, -1 }, /* (299) frame_bound_e ::= frame_bound */ + { 276, -2 }, /* (300) frame_bound_e ::= UNBOUNDED FOLLOWING */ + { 274, -2 }, /* (301) frame_bound ::= expr PRECEDING */ + { 274, -2 }, /* (302) frame_bound ::= CURRENT ROW */ + { 274, -2 }, /* (303) frame_bound ::= expr FOLLOWING */ + { 218, -2 }, /* (304) window_clause ::= WINDOW windowdefn_list */ + { 237, -3 }, /* (305) over_clause ::= filter_opt OVER window */ + { 237, -3 }, /* (306) over_clause ::= filter_opt OVER nm */ + { 272, 0 }, /* (307) filter_opt ::= */ + { 272, -5 }, /* (308) filter_opt ::= FILTER LP WHERE expr RP */ + { 155, -1 }, /* (309) input ::= cmdlist */ + { 156, -2 }, /* (310) cmdlist ::= cmdlist ecmd */ + { 156, -1 }, /* (311) cmdlist ::= ecmd */ + { 157, -1 }, /* (312) ecmd ::= SEMI */ + { 157, -2 }, /* (313) ecmd ::= cmdx SEMI */ + { 157, -2 }, /* (314) ecmd ::= explain cmdx */ + { 162, 0 }, /* (315) trans_opt ::= */ + { 162, -1 }, /* (316) trans_opt ::= TRANSACTION */ + { 162, -2 }, /* (317) trans_opt ::= TRANSACTION nm */ + { 164, -1 }, /* (318) savepoint_opt ::= SAVEPOINT */ + { 164, 0 }, /* (319) savepoint_opt ::= */ + { 160, -2 }, /* (320) cmd ::= create_table create_table_args */ + { 171, -4 }, /* (321) columnlist ::= columnlist COMMA columnname carglist */ + { 171, -2 }, /* (322) columnlist ::= columnname carglist */ + { 163, -1 }, /* (323) nm ::= ID|INDEXED */ + { 163, -1 }, /* (324) nm ::= STRING */ + { 163, -1 }, /* (325) nm ::= JOIN_KW */ + { 177, -1 }, /* (326) typetoken ::= typename */ + { 178, -1 }, /* (327) typename ::= ID|STRING */ + { 179, -1 }, /* (328) signed ::= plus_num */ + { 179, -1 }, /* (329) signed ::= minus_num */ + { 176, -2 }, /* (330) carglist ::= carglist ccons */ + { 176, 0 }, /* (331) carglist ::= */ + { 183, -2 }, /* (332) ccons ::= NULL onconf */ + { 172, -2 }, /* (333) conslist_opt ::= COMMA conslist */ + { 195, -3 }, /* (334) conslist ::= conslist tconscomma tcons */ + { 195, -1 }, /* (335) conslist ::= tcons */ + { 196, 0 }, /* (336) tconscomma ::= */ + { 200, -1 }, /* (337) defer_subclause_opt ::= defer_subclause */ + { 202, -1 }, /* (338) resolvetype ::= raisetype */ + { 206, -1 }, /* (339) selectnowith ::= oneselect */ + { 207, -1 }, /* (340) oneselect ::= values */ + { 221, -2 }, /* (341) sclp ::= selcollist COMMA */ + { 222, -1 }, /* (342) as ::= ID|STRING */ + { 185, -1 }, /* (343) expr ::= term */ + { 238, -1 }, /* (344) likeop ::= LIKE_KW|MATCH */ + { 229, -1 }, /* (345) exprlist ::= nexprlist */ + { 247, -1 }, /* (346) nmnum ::= plus_num */ + { 247, -1 }, /* (347) nmnum ::= nm */ + { 247, -1 }, /* (348) nmnum ::= ON */ + { 247, -1 }, /* (349) nmnum ::= DELETE */ + { 247, -1 }, /* (350) nmnum ::= DEFAULT */ + { 180, -1 }, /* (351) plus_num ::= INTEGER|FLOAT */ + { 252, 0 }, /* (352) foreach_clause ::= */ + { 252, -3 }, /* (353) foreach_clause ::= FOR EACH ROW */ + { 255, -1 }, /* (354) trnm ::= nm */ + { 256, 0 }, /* (355) tridxby ::= */ + { 257, -1 }, /* (356) database_kw_opt ::= DATABASE */ + { 257, 0 }, /* (357) database_kw_opt ::= */ + { 260, 0 }, /* (358) kwcolumn_opt ::= */ + { 260, -1 }, /* (359) kwcolumn_opt ::= COLUMNKW */ + { 262, -1 }, /* (360) vtabarglist ::= vtabarg */ + { 262, -3 }, /* (361) vtabarglist ::= vtabarglist COMMA vtabarg */ + { 263, -2 }, /* (362) vtabarg ::= vtabarg vtabargtoken */ + { 266, 0 }, /* (363) anylist ::= */ + { 266, -4 }, /* (364) anylist ::= anylist LP anylist RP */ + { 266, -2 }, /* (365) anylist ::= anylist ANY */ + { 232, 0 }, /* (366) with ::= */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -142193,17 +149466,18 @@ static void yy_accept(yyParser*); /* Forward Declaration */ ** only called from one place, optimizing compilers will in-line it, which ** means that the extra parameters have no performance impact. */ -static void yy_reduce( +static YYACTIONTYPE yy_reduce( yyParser *yypParser, /* The parser */ unsigned int yyruleno, /* Number of the rule by which to reduce */ int yyLookahead, /* Lookahead token, or YYNOCODE if none */ sqlite3ParserTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ + sqlite3ParserCTX_PDECL /* %extra_context */ ){ int yygoto; /* The next state */ - int yyact; /* The next action */ + YYACTIONTYPE yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ - sqlite3ParserARG_FETCH; + sqlite3ParserARG_FETCH (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; @@ -142234,13 +149508,19 @@ static void yy_reduce( #if YYSTACKDEPTH>0 if( yypParser->yytos>=yypParser->yystackEnd ){ yyStackOverflow(yypParser); - return; + /* The call to yyStackOverflow() above pops the stack until it is + ** empty, causing the main parser loop to exit. So the return value + ** is never used and does not matter. */ + return 0; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); - return; + /* The call to yyStackOverflow() above pops the stack until it is + ** empty, causing the main parser loop to exit. So the return value + ** is never used and does not matter. */ + return 0; } yymsp = yypParser->yytos; } @@ -142268,15 +149548,15 @@ static void yy_reduce( { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy4);} +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy70);} break; case 4: /* transtype ::= */ -{yymsp[1].minor.yy4 = TK_DEFERRED;} +{yymsp[1].minor.yy70 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); -{yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-X*/} +{yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); @@ -142299,7 +149579,7 @@ static void yy_reduce( break; case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy4,0,0,yymsp[-2].minor.yy4); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy70,0,0,yymsp[-2].minor.yy70); } break; case 14: /* createkw ::= CREATE */ @@ -142312,34 +149592,34 @@ static void yy_reduce( case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); case 76: /* ifexists ::= */ yytestcase(yyruleno==76); - case 92: /* distinct ::= */ yytestcase(yyruleno==92); - case 216: /* collate ::= */ yytestcase(yyruleno==216); -{yymsp[1].minor.yy4 = 0;} + case 93: /* distinct ::= */ yytestcase(yyruleno==93); + case 226: /* collate ::= */ yytestcase(yyruleno==226); +{yymsp[1].minor.yy70 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy4 = 1;} +{yymsp[-2].minor.yy70 = 1;} break; case 17: /* temp ::= TEMP */ case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); -{yymsp[0].minor.yy4 = 1;} +{yymsp[0].minor.yy70 = 1;} break; case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy4,0); + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy70,0); } break; case 20: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy387); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy489); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy489); } break; case 22: /* table_options ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy4 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy70 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yymsp[-1].minor.yy4 = 0; + yymsp[-1].minor.yy70 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } @@ -142349,7 +149629,7 @@ static void yy_reduce( break; case 24: /* typetoken ::= */ case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60); - case 98: /* as ::= */ yytestcase(yyruleno==98); + case 99: /* as ::= */ yytestcase(yyruleno==99); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; case 25: /* typetoken ::= typename LP signed RP */ @@ -142368,7 +149648,7 @@ static void yy_reduce( case 28: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); - yymsp[1].minor.yy336 = yyLookaheadToken.z; + yymsp[1].minor.yy392 = yyLookaheadToken.z; } break; case 29: /* ccons ::= CONSTRAINT nm */ @@ -142376,18 +149656,18 @@ static void yy_reduce( {pParse->constraintName = yymsp[0].minor.yy0;} break; case 30: /* ccons ::= DEFAULT scanpt term scanpt */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy336,yymsp[0].minor.yy336);} +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy392,yymsp[0].minor.yy392);} break; case 31: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; case 32: /* ccons ::= DEFAULT PLUS term scanpt */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy314,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy336);} +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy392);} break; case 33: /* ccons ::= DEFAULT MINUS term scanpt */ { - Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy314, 0); - sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy336); + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy18, 0); + sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy392); } break; case 34: /* ccons ::= DEFAULT scanpt ID|INDEXED */ @@ -142397,174 +149677,174 @@ static void yy_reduce( sqlite3ExprIdToTrueFalse(p); testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) ); } - sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); + sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); } break; case 35: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy4);} +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy70);} break; case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy4,yymsp[0].minor.yy4,yymsp[-2].minor.yy4);} +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy70,yymsp[0].minor.yy70,yymsp[-2].minor.yy70);} break; case 37: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy4,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy70,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 38: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy314);} +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy18);} break; case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy4);} +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy420,yymsp[0].minor.yy70);} break; case 40: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy4);} +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy70);} break; case 41: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; case 44: /* refargs ::= */ -{ yymsp[1].minor.yy4 = OE_None*0x0101; /* EV: R-19803-45884 */} +{ yymsp[1].minor.yy70 = OE_None*0x0101; /* EV: R-19803-45884 */} break; case 45: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy4 = (yymsp[-1].minor.yy4 & ~yymsp[0].minor.yy215.mask) | yymsp[0].minor.yy215.value; } +{ yymsp[-1].minor.yy70 = (yymsp[-1].minor.yy70 & ~yymsp[0].minor.yy111.mask) | yymsp[0].minor.yy111.value; } break; case 46: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy215.value = 0; yymsp[-1].minor.yy215.mask = 0x000000; } +{ yymsp[-1].minor.yy111.value = 0; yymsp[-1].minor.yy111.mask = 0x000000; } break; case 47: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy215.value = 0; yymsp[-2].minor.yy215.mask = 0x000000; } +{ yymsp[-2].minor.yy111.value = 0; yymsp[-2].minor.yy111.mask = 0x000000; } break; case 48: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy215.value = yymsp[0].minor.yy4; yymsp[-2].minor.yy215.mask = 0x0000ff; } +{ yymsp[-2].minor.yy111.value = yymsp[0].minor.yy70; yymsp[-2].minor.yy111.mask = 0x0000ff; } break; case 49: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy215.value = yymsp[0].minor.yy4<<8; yymsp[-2].minor.yy215.mask = 0x00ff00; } +{ yymsp[-2].minor.yy111.value = yymsp[0].minor.yy70<<8; yymsp[-2].minor.yy111.mask = 0x00ff00; } break; case 50: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy4 = OE_SetNull; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy70 = OE_SetNull; /* EV: R-33326-45252 */} break; case 51: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy4 = OE_SetDflt; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy70 = OE_SetDflt; /* EV: R-33326-45252 */} break; case 52: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy4 = OE_Cascade; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy70 = OE_Cascade; /* EV: R-33326-45252 */} break; case 53: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy4 = OE_Restrict; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy70 = OE_Restrict; /* EV: R-33326-45252 */} break; case 54: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy4 = OE_None; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy70 = OE_None; /* EV: R-33326-45252 */} break; case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy4 = 0;} +{yymsp[-2].minor.yy70 = 0;} break; case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); - case 147: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==147); -{yymsp[-1].minor.yy4 = yymsp[0].minor.yy4;} + case 156: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==156); +{yymsp[-1].minor.yy70 = yymsp[0].minor.yy70;} break; case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); - case 188: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==188); - case 191: /* in_op ::= NOT IN */ yytestcase(yyruleno==191); - case 217: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==217); -{yymsp[-1].minor.yy4 = 1;} + case 198: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==198); + case 201: /* in_op ::= NOT IN */ yytestcase(yyruleno==201); + case 227: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==227); +{yymsp[-1].minor.yy70 = 1;} break; case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy4 = 0;} +{yymsp[-1].minor.yy70 = 0;} break; case 61: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy4,yymsp[-2].minor.yy4,0);} +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy420,yymsp[0].minor.yy70,yymsp[-2].minor.yy70,0);} break; case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy4,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy420,yymsp[0].minor.yy70,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 65: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy314);} +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy18);} break; case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy4); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy4); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy420, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy420, yymsp[-1].minor.yy70); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy70); } break; case 68: /* onconf ::= */ case 70: /* orconf ::= */ yytestcase(yyruleno==70); -{yymsp[1].minor.yy4 = OE_Default;} +{yymsp[1].minor.yy70 = OE_Default;} break; case 69: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy4 = yymsp[0].minor.yy4;} +{yymsp[-2].minor.yy70 = yymsp[0].minor.yy70;} break; case 72: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy4 = OE_Ignore;} +{yymsp[0].minor.yy70 = OE_Ignore;} break; case 73: /* resolvetype ::= REPLACE */ - case 148: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==148); -{yymsp[0].minor.yy4 = OE_Replace;} + case 157: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==157); +{yymsp[0].minor.yy70 = OE_Replace;} break; case 74: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0, yymsp[-1].minor.yy4); + sqlite3DropTable(pParse, yymsp[0].minor.yy135, 0, yymsp[-1].minor.yy70); } break; case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { - sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy387, yymsp[-7].minor.yy4, yymsp[-5].minor.yy4); + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy420, yymsp[0].minor.yy489, yymsp[-7].minor.yy70, yymsp[-5].minor.yy70); } break; case 78: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1, yymsp[-1].minor.yy4); + sqlite3DropTable(pParse, yymsp[0].minor.yy135, 1, yymsp[-1].minor.yy70); } break; case 79: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy387, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387); + sqlite3Select(pParse, yymsp[0].minor.yy489, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy489); } break; case 80: /* select ::= WITH wqlist selectnowith */ { - Select *p = yymsp[0].minor.yy387; + Select *p = yymsp[0].minor.yy489; if( p ){ - p->pWith = yymsp[-1].minor.yy451; + p->pWith = yymsp[-1].minor.yy449; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy451); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy449); } - yymsp[-2].minor.yy387 = p; + yymsp[-2].minor.yy489 = p; } break; case 81: /* select ::= WITH RECURSIVE wqlist selectnowith */ { - Select *p = yymsp[0].minor.yy387; + Select *p = yymsp[0].minor.yy489; if( p ){ - p->pWith = yymsp[-1].minor.yy451; + p->pWith = yymsp[-1].minor.yy449; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy451); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy449); } - yymsp[-3].minor.yy387 = p; + yymsp[-3].minor.yy489 = p; } break; case 82: /* select ::= selectnowith */ { - Select *p = yymsp[0].minor.yy387; + Select *p = yymsp[0].minor.yy489; if( p ){ parserDoubleLinkSelect(pParse, p); } - yymsp[0].minor.yy387 = p; /*A-overwrites-X*/ + yymsp[0].minor.yy489 = p; /*A-overwrites-X*/ } break; case 83: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy387; - Select *pLhs = yymsp[-2].minor.yy387; + Select *pRhs = yymsp[0].minor.yy489; + Select *pLhs = yymsp[-2].minor.yy489; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; @@ -142574,352 +149854,382 @@ static void yy_reduce( pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy4; + pRhs->op = (u8)yymsp[-1].minor.yy70; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy4!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy70!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yymsp[-2].minor.yy387 = pRhs; + yymsp[-2].minor.yy489 = pRhs; } break; case 84: /* multiselect_op ::= UNION */ case 86: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==86); -{yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-OP*/} +{yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-OP*/} break; case 85: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy4 = TK_ALL;} +{yymsp[-1].minor.yy70 = TK_ALL;} break; case 87: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { -#if SELECTTRACE_ENABLED - Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/ -#endif - yymsp[-8].minor.yy387 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy259,yymsp[-4].minor.yy314,yymsp[-3].minor.yy322,yymsp[-2].minor.yy314,yymsp[-1].minor.yy322,yymsp[-7].minor.yy4,yymsp[0].minor.yy314); -#if SELECTTRACE_ENABLED - /* Populate the Select.zSelName[] string that is used to help with - ** query planner debugging, to differentiate between multiple Select - ** objects in a complex query. - ** - ** If the SELECT keyword is immediately followed by a C-style comment - ** then extract the first few alphanumeric characters from within that - ** comment to be the zSelName value. Otherwise, the label is #N where - ** is an integer that is incremented with each SELECT statement seen. - */ - if( yymsp[-8].minor.yy387!=0 ){ - const char *z = s.z+6; - int i; - sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName,"#%d",++pParse->nSelect); - while( z[0]==' ' ) z++; - if( z[0]=='/' && z[1]=='*' ){ - z += 2; - while( z[0]==' ' ) z++; - for(i=0; sqlite3Isalnum(z[i]); i++){} - sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName, "%.*s", i, z); - } + yymsp[-8].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy420,yymsp[-5].minor.yy135,yymsp[-4].minor.yy18,yymsp[-3].minor.yy420,yymsp[-2].minor.yy18,yymsp[-1].minor.yy420,yymsp[-7].minor.yy70,yymsp[0].minor.yy18); +} + break; + case 88: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ +{ + yymsp[-9].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy420,yymsp[-6].minor.yy135,yymsp[-5].minor.yy18,yymsp[-4].minor.yy420,yymsp[-3].minor.yy18,yymsp[-1].minor.yy420,yymsp[-8].minor.yy70,yymsp[0].minor.yy18); + if( yymsp[-9].minor.yy489 ){ + yymsp[-9].minor.yy489->pWinDefn = yymsp[-2].minor.yy327; + }else{ + sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy327); } -#endif /* SELECTRACE_ENABLED */ } break; - case 88: /* values ::= VALUES LP nexprlist RP */ + case 89: /* values ::= VALUES LP nexprlist RP */ { - yymsp[-3].minor.yy387 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0); + yymsp[-3].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy420,0,0,0,0,0,SF_Values,0); } break; - case 89: /* values ::= values COMMA LP exprlist RP */ + case 90: /* values ::= values COMMA LP nexprlist RP */ { - Select *pRight, *pLeft = yymsp[-4].minor.yy387; - pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0); + Select *pRight, *pLeft = yymsp[-4].minor.yy489; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy420,0,0,0,0,0,SF_Values|SF_MultiValue,0); if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; pRight->pPrior = pLeft; - yymsp[-4].minor.yy387 = pRight; + yymsp[-4].minor.yy489 = pRight; }else{ - yymsp[-4].minor.yy387 = pLeft; + yymsp[-4].minor.yy489 = pLeft; } } break; - case 90: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy4 = SF_Distinct;} + case 91: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy70 = SF_Distinct;} break; - case 91: /* distinct ::= ALL */ -{yymsp[0].minor.yy4 = SF_All;} + case 92: /* distinct ::= ALL */ +{yymsp[0].minor.yy70 = SF_All;} break; - case 93: /* sclp ::= */ - case 122: /* orderby_opt ::= */ yytestcase(yyruleno==122); - case 129: /* groupby_opt ::= */ yytestcase(yyruleno==129); - case 204: /* exprlist ::= */ yytestcase(yyruleno==204); - case 207: /* paren_exprlist ::= */ yytestcase(yyruleno==207); - case 212: /* eidlist_opt ::= */ yytestcase(yyruleno==212); -{yymsp[1].minor.yy322 = 0;} + case 94: /* sclp ::= */ + case 127: /* orderby_opt ::= */ yytestcase(yyruleno==127); + case 134: /* groupby_opt ::= */ yytestcase(yyruleno==134); + case 214: /* exprlist ::= */ yytestcase(yyruleno==214); + case 217: /* paren_exprlist ::= */ yytestcase(yyruleno==217); + case 222: /* eidlist_opt ::= */ yytestcase(yyruleno==222); +{yymsp[1].minor.yy420 = 0;} break; - case 94: /* selcollist ::= sclp scanpt expr scanpt as */ + case 95: /* selcollist ::= sclp scanpt expr scanpt as */ { - yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy314); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy336,yymsp[-1].minor.yy336); + yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy420, yymsp[-2].minor.yy18); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy420, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy420,yymsp[-3].minor.yy392,yymsp[-1].minor.yy392); } break; - case 95: /* selcollist ::= sclp scanpt STAR */ + case 96: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p); + yymsp[-2].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy420, p); } break; - case 96: /* selcollist ::= sclp scanpt nm DOT STAR */ + case 97: /* selcollist ::= sclp scanpt nm DOT STAR */ { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot); + yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, pDot); } break; - case 97: /* as ::= AS nm */ - case 108: /* dbnm ::= DOT nm */ yytestcase(yyruleno==108); - case 226: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==226); - case 227: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==227); + case 98: /* as ::= AS nm */ + case 109: /* dbnm ::= DOT nm */ yytestcase(yyruleno==109); + case 236: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==236); + case 237: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==237); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 99: /* from ::= */ -{yymsp[1].minor.yy259 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy259));} + case 100: /* from ::= */ +{yymsp[1].minor.yy135 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy135));} break; - case 100: /* from ::= FROM seltablist */ + case 101: /* from ::= FROM seltablist */ { - yymsp[-1].minor.yy259 = yymsp[0].minor.yy259; - sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy259); + yymsp[-1].minor.yy135 = yymsp[0].minor.yy135; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy135); } break; - case 101: /* stl_prefix ::= seltablist joinop */ + case 102: /* stl_prefix ::= seltablist joinop */ { - if( ALWAYS(yymsp[-1].minor.yy259 && yymsp[-1].minor.yy259->nSrc>0) ) yymsp[-1].minor.yy259->a[yymsp[-1].minor.yy259->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy4; + if( ALWAYS(yymsp[-1].minor.yy135 && yymsp[-1].minor.yy135->nSrc>0) ) yymsp[-1].minor.yy135->a[yymsp[-1].minor.yy135->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy70; } break; - case 102: /* stl_prefix ::= */ -{yymsp[1].minor.yy259 = 0;} + case 103: /* stl_prefix ::= */ +{yymsp[1].minor.yy135 = 0;} break; - case 103: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + case 104: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ { - yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); - sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy259, &yymsp[-2].minor.yy0); + yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy135, &yymsp[-2].minor.yy0); } break; - case 104: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + case 105: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ { - yymsp[-8].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy259,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); - sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy259, yymsp[-4].minor.yy322); + yymsp[-8].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy135,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy135, yymsp[-4].minor.yy420); } break; - case 105: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + case 106: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ { - yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy387,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); + yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy489,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); } break; - case 106: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + case 107: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ { - if( yymsp[-6].minor.yy259==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy314==0 && yymsp[0].minor.yy384==0 ){ - yymsp[-6].minor.yy259 = yymsp[-4].minor.yy259; - }else if( yymsp[-4].minor.yy259->nSrc==1 ){ - yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); - if( yymsp[-6].minor.yy259 ){ - struct SrcList_item *pNew = &yymsp[-6].minor.yy259->a[yymsp[-6].minor.yy259->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy259->a; + if( yymsp[-6].minor.yy135==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy18==0 && yymsp[0].minor.yy48==0 ){ + yymsp[-6].minor.yy135 = yymsp[-4].minor.yy135; + }else if( yymsp[-4].minor.yy135->nSrc==1 ){ + yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); + if( yymsp[-6].minor.yy135 ){ + struct SrcList_item *pNew = &yymsp[-6].minor.yy135->a[yymsp[-6].minor.yy135->nSrc-1]; + struct SrcList_item *pOld = yymsp[-4].minor.yy135->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy259); + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy135); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy259); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy259,0,0,0,0,SF_NestedFrom,0); - yymsp[-6].minor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy314,yymsp[0].minor.yy384); + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy135); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy135,0,0,0,0,SF_NestedFrom,0); + yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy18,yymsp[0].minor.yy48); } } break; - case 107: /* dbnm ::= */ - case 117: /* indexed_opt ::= */ yytestcase(yyruleno==117); + case 108: /* dbnm ::= */ + case 122: /* indexed_opt ::= */ yytestcase(yyruleno==122); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 109: /* fullname ::= nm */ -{yymsp[0].minor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} + case 110: /* fullname ::= nm */ +{ + yylhsminor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0); + if( IN_RENAME_OBJECT && yylhsminor.yy135 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy135->a[0].zName, &yymsp[0].minor.yy0); +} + yymsp[0].minor.yy135 = yylhsminor.yy135; break; - case 110: /* fullname ::= nm DOT nm */ -{yymsp[-2].minor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 111: /* fullname ::= nm DOT nm */ +{ + yylhsminor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + if( IN_RENAME_OBJECT && yylhsminor.yy135 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy135->a[0].zName, &yymsp[0].minor.yy0); +} + yymsp[-2].minor.yy135 = yylhsminor.yy135; break; - case 111: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy4 = JT_INNER; } + case 112: /* xfullname ::= nm */ +{yymsp[0].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} break; - case 112: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} + case 113: /* xfullname ::= nm DOT nm */ +{yymsp[-2].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 113: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + case 114: /* xfullname ::= nm DOT nm AS nm */ +{ + yymsp[-4].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ + if( yymsp[-4].minor.yy135 ) yymsp[-4].minor.yy135->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); +} break; - case 114: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy4 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + case 115: /* xfullname ::= nm AS nm */ +{ + yymsp[-2].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ + if( yymsp[-2].minor.yy135 ) yymsp[-2].minor.yy135->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); +} break; - case 115: /* on_opt ::= ON expr */ - case 132: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==132); - case 139: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==139); - case 200: /* case_else ::= ELSE expr */ yytestcase(yyruleno==200); -{yymsp[-1].minor.yy314 = yymsp[0].minor.yy314;} + case 116: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy70 = JT_INNER; } break; - case 116: /* on_opt ::= */ - case 131: /* having_opt ::= */ yytestcase(yyruleno==131); - case 133: /* limit_opt ::= */ yytestcase(yyruleno==133); - case 138: /* where_opt ::= */ yytestcase(yyruleno==138); - case 201: /* case_else ::= */ yytestcase(yyruleno==201); - case 203: /* case_operand ::= */ yytestcase(yyruleno==203); -{yymsp[1].minor.yy314 = 0;} + case 117: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 118: /* indexed_opt ::= INDEXED BY nm */ + case 118: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + break; + case 119: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + break; + case 120: /* on_opt ::= ON expr */ + case 137: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==137); + case 144: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==144); + case 210: /* case_else ::= ELSE expr */ yytestcase(yyruleno==210); +{yymsp[-1].minor.yy18 = yymsp[0].minor.yy18;} + break; + case 121: /* on_opt ::= */ + case 136: /* having_opt ::= */ yytestcase(yyruleno==136); + case 138: /* limit_opt ::= */ yytestcase(yyruleno==138); + case 143: /* where_opt ::= */ yytestcase(yyruleno==143); + case 211: /* case_else ::= */ yytestcase(yyruleno==211); + case 213: /* case_operand ::= */ yytestcase(yyruleno==213); +{yymsp[1].minor.yy18 = 0;} + break; + case 123: /* indexed_opt ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 119: /* indexed_opt ::= NOT INDEXED */ + case 124: /* indexed_opt ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 120: /* using_opt ::= USING LP idlist RP */ -{yymsp[-3].minor.yy384 = yymsp[-1].minor.yy384;} + case 125: /* using_opt ::= USING LP idlist RP */ +{yymsp[-3].minor.yy48 = yymsp[-1].minor.yy48;} break; - case 121: /* using_opt ::= */ - case 149: /* idlist_opt ::= */ yytestcase(yyruleno==149); -{yymsp[1].minor.yy384 = 0;} + case 126: /* using_opt ::= */ + case 158: /* idlist_opt ::= */ yytestcase(yyruleno==158); +{yymsp[1].minor.yy48 = 0;} break; - case 123: /* orderby_opt ::= ORDER BY sortlist */ - case 130: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==130); -{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;} + case 128: /* orderby_opt ::= ORDER BY sortlist */ + case 135: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==135); +{yymsp[-2].minor.yy420 = yymsp[0].minor.yy420;} break; - case 124: /* sortlist ::= sortlist COMMA expr sortorder */ + case 129: /* sortlist ::= sortlist COMMA expr sortorder */ { - yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322,yymsp[-1].minor.yy314); - sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy322,yymsp[0].minor.yy4); + yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy420,yymsp[-1].minor.yy18); + sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy420,yymsp[0].minor.yy70); } break; - case 125: /* sortlist ::= expr sortorder */ + case 130: /* sortlist ::= expr sortorder */ { - yymsp[-1].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy314); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy322,yymsp[0].minor.yy4); + yymsp[-1].minor.yy420 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy18); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy420,yymsp[0].minor.yy70); } break; - case 126: /* sortorder ::= ASC */ -{yymsp[0].minor.yy4 = SQLITE_SO_ASC;} + case 131: /* sortorder ::= ASC */ +{yymsp[0].minor.yy70 = SQLITE_SO_ASC;} break; - case 127: /* sortorder ::= DESC */ -{yymsp[0].minor.yy4 = SQLITE_SO_DESC;} + case 132: /* sortorder ::= DESC */ +{yymsp[0].minor.yy70 = SQLITE_SO_DESC;} break; - case 128: /* sortorder ::= */ -{yymsp[1].minor.yy4 = SQLITE_SO_UNDEFINED;} + case 133: /* sortorder ::= */ +{yymsp[1].minor.yy70 = SQLITE_SO_UNDEFINED;} break; - case 134: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy314,0);} + case 139: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy18,0);} break; - case 135: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);} + case 140: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy18,yymsp[0].minor.yy18);} break; - case 136: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy314,yymsp[-2].minor.yy314);} + case 141: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy18,yymsp[-2].minor.yy18);} break; - case 137: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ + case 142: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy259, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy259,yymsp[0].minor.yy314,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy135, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy135,yymsp[0].minor.yy18,0,0); } break; - case 140: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ + case 145: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy259, &yymsp[-3].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy322,"set list"); - sqlite3Update(pParse,yymsp[-4].minor.yy259,yymsp[-1].minor.yy322,yymsp[0].minor.yy314,yymsp[-5].minor.yy4,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy135, &yymsp[-3].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy420,"set list"); + sqlite3Update(pParse,yymsp[-4].minor.yy135,yymsp[-1].minor.yy420,yymsp[0].minor.yy18,yymsp[-5].minor.yy70,0,0,0); } break; - case 141: /* setlist ::= setlist COMMA nm EQ expr */ + case 146: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy314); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1); + yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy420, yymsp[0].minor.yy18); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy420, &yymsp[-2].minor.yy0, 1); } break; - case 142: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ + case 147: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy384, yymsp[0].minor.yy314); + yymsp[-6].minor.yy420 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy420, yymsp[-3].minor.yy48, yymsp[0].minor.yy18); } break; - case 143: /* setlist ::= nm EQ expr */ + case 148: /* setlist ::= nm EQ expr */ { - yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy314); - sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1); + yylhsminor.yy420 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy18); + sqlite3ExprListSetName(pParse, yylhsminor.yy420, &yymsp[-2].minor.yy0, 1); } - yymsp[-2].minor.yy322 = yylhsminor.yy322; + yymsp[-2].minor.yy420 = yylhsminor.yy420; break; - case 144: /* setlist ::= LP idlist RP EQ expr */ + case 149: /* setlist ::= LP idlist RP EQ expr */ { - yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy384, yymsp[0].minor.yy314); + yymsp[-4].minor.yy420 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy48, yymsp[0].minor.yy18); } break; - case 145: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ + case 150: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { - sqlite3Insert(pParse, yymsp[-2].minor.yy259, yymsp[0].minor.yy387, yymsp[-1].minor.yy384, yymsp[-4].minor.yy4); + sqlite3Insert(pParse, yymsp[-3].minor.yy135, yymsp[-1].minor.yy489, yymsp[-2].minor.yy48, yymsp[-5].minor.yy70, yymsp[0].minor.yy340); } break; - case 146: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ + case 151: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ { - sqlite3Insert(pParse, yymsp[-3].minor.yy259, 0, yymsp[-2].minor.yy384, yymsp[-5].minor.yy4); + sqlite3Insert(pParse, yymsp[-3].minor.yy135, 0, yymsp[-2].minor.yy48, yymsp[-5].minor.yy70, 0); } break; - case 150: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy384 = yymsp[-1].minor.yy384;} + case 152: /* upsert ::= */ +{ yymsp[1].minor.yy340 = 0; } break; - case 151: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy384 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy384,&yymsp[0].minor.yy0);} + case 153: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ +{ yymsp[-10].minor.yy340 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy420,yymsp[-5].minor.yy18,yymsp[-1].minor.yy420,yymsp[0].minor.yy18);} break; - case 152: /* idlist ::= nm */ -{yymsp[0].minor.yy384 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + case 154: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ +{ yymsp[-7].minor.yy340 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy420,yymsp[-2].minor.yy18,0,0); } break; - case 153: /* expr ::= LP expr RP */ -{yymsp[-2].minor.yy314 = yymsp[-1].minor.yy314;} + case 155: /* upsert ::= ON CONFLICT DO NOTHING */ +{ yymsp[-3].minor.yy340 = sqlite3UpsertNew(pParse->db,0,0,0,0); } break; - case 154: /* expr ::= ID|INDEXED */ - case 155: /* expr ::= JOIN_KW */ yytestcase(yyruleno==155); -{yymsp[0].minor.yy314=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 159: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy48 = yymsp[-1].minor.yy48;} break; - case 156: /* expr ::= nm DOT nm */ + case 160: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy48 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy48,&yymsp[0].minor.yy0);} + break; + case 161: /* idlist ::= nm */ +{yymsp[0].minor.yy48 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + break; + case 162: /* expr ::= LP expr RP */ +{yymsp[-2].minor.yy18 = yymsp[-1].minor.yy18;} + break; + case 163: /* expr ::= ID|INDEXED */ + case 164: /* expr ::= JOIN_KW */ yytestcase(yyruleno==164); +{yymsp[0].minor.yy18=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 165: /* expr ::= nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); - yylhsminor.yy314 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0); + sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0); + } + yylhsminor.yy18 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } - yymsp[-2].minor.yy314 = yylhsminor.yy314; + yymsp[-2].minor.yy18 = yylhsminor.yy18; break; - case 157: /* expr ::= nm DOT nm DOT nm */ + case 166: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); - yylhsminor.yy314 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0); + sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0); + } + yylhsminor.yy18 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } - yymsp[-4].minor.yy314 = yylhsminor.yy314; + yymsp[-4].minor.yy18 = yylhsminor.yy18; break; - case 158: /* term ::= NULL|FLOAT|BLOB */ - case 159: /* term ::= STRING */ yytestcase(yyruleno==159); -{yymsp[0].minor.yy314=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 167: /* term ::= NULL|FLOAT|BLOB */ + case 168: /* term ::= STRING */ yytestcase(yyruleno==168); +{yymsp[0].minor.yy18=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 160: /* term ::= INTEGER */ + case 169: /* term ::= INTEGER */ { - yylhsminor.yy314 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + yylhsminor.yy18 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); } - yymsp[0].minor.yy314 = yylhsminor.yy314; + yymsp[0].minor.yy18 = yylhsminor.yy18; break; - case 161: /* expr ::= VARIABLE */ + case 170: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; - yymsp[0].minor.yy314 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy314, n); + yymsp[0].minor.yy18 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy18, n); }else{ /* When doing a nested parse, one can include terms in an expression ** that look like this: #1 #2 ... These terms refer to registers @@ -142928,146 +150238,154 @@ static void yy_reduce( assert( t.n>=2 ); if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); - yymsp[0].minor.yy314 = 0; + yymsp[0].minor.yy18 = 0; }else{ - yymsp[0].minor.yy314 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); - if( yymsp[0].minor.yy314 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy314->iTable); + yymsp[0].minor.yy18 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy18 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy18->iTable); } } } break; - case 162: /* expr ::= expr COLLATE ID|STRING */ + case 171: /* expr ::= expr COLLATE ID|STRING */ { - yymsp[-2].minor.yy314 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy314, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy18 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy18, &yymsp[0].minor.yy0, 1); } break; - case 163: /* expr ::= CAST LP expr AS typetoken RP */ + case 172: /* expr ::= CAST LP expr AS typetoken RP */ { - yymsp[-5].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); - sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy314, yymsp[-3].minor.yy314, 0); + yymsp[-5].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy18, yymsp[-3].minor.yy18, 0); } break; - case 164: /* expr ::= ID|INDEXED LP distinct exprlist RP */ + case 173: /* expr ::= ID|INDEXED LP distinct exprlist RP */ { - if( yymsp[-1].minor.yy322 && yymsp[-1].minor.yy322->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ - sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); - } - yylhsminor.yy314 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0); - if( yymsp[-2].minor.yy4==SF_Distinct && yylhsminor.yy314 ){ - yylhsminor.yy314->flags |= EP_Distinct; - } + yylhsminor.yy18 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy420, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy70); } - yymsp[-4].minor.yy314 = yylhsminor.yy314; + yymsp[-4].minor.yy18 = yylhsminor.yy18; break; - case 165: /* expr ::= ID|INDEXED LP STAR RP */ + case 174: /* expr ::= ID|INDEXED LP STAR RP */ { - yylhsminor.yy314 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); + yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } - yymsp[-3].minor.yy314 = yylhsminor.yy314; + yymsp[-3].minor.yy18 = yylhsminor.yy18; break; - case 166: /* term ::= CTIME_KW */ + case 175: /* expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ { - yylhsminor.yy314 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); + yylhsminor.yy18 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy420, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy70); + sqlite3WindowAttach(pParse, yylhsminor.yy18, yymsp[0].minor.yy327); } - yymsp[0].minor.yy314 = yylhsminor.yy314; + yymsp[-5].minor.yy18 = yylhsminor.yy18; break; - case 167: /* expr ::= LP nexprlist COMMA expr RP */ + case 176: /* expr ::= ID|INDEXED LP STAR RP over_clause */ { - ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy314); - yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( yymsp[-4].minor.yy314 ){ - yymsp[-4].minor.yy314->x.pList = pList; + yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); + sqlite3WindowAttach(pParse, yylhsminor.yy18, yymsp[0].minor.yy327); +} + yymsp[-4].minor.yy18 = yylhsminor.yy18; + break; + case 177: /* term ::= CTIME_KW */ +{ + yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); +} + yymsp[0].minor.yy18 = yylhsminor.yy18; + break; + case 178: /* expr ::= LP nexprlist COMMA expr RP */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy420, yymsp[-1].minor.yy18); + yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yymsp[-4].minor.yy18 ){ + yymsp[-4].minor.yy18->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } } break; - case 168: /* expr ::= expr AND expr */ - case 169: /* expr ::= expr OR expr */ yytestcase(yyruleno==169); - case 170: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==170); - case 171: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==171); - case 172: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==172); - case 173: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==173); - case 174: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==174); - case 175: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==175); -{yymsp[-2].minor.yy314=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy314,yymsp[0].minor.yy314);} + case 179: /* expr ::= expr AND expr */ + case 180: /* expr ::= expr OR expr */ yytestcase(yyruleno==180); + case 181: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==181); + case 182: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==182); + case 183: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==183); + case 184: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==184); + case 185: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==185); + case 186: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==186); +{yymsp[-2].minor.yy18=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy18,yymsp[0].minor.yy18);} break; - case 176: /* likeop ::= NOT LIKE_KW|MATCH */ + case 187: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 177: /* expr ::= expr likeop expr */ + case 188: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; yymsp[-1].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy314); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy314); - yymsp[-2].minor.yy314 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0); - if( bNot ) yymsp[-2].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy314, 0); - if( yymsp[-2].minor.yy314 ) yymsp[-2].minor.yy314->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy18); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy18); + yymsp[-2].minor.yy18 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + if( bNot ) yymsp[-2].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy18, 0); + if( yymsp[-2].minor.yy18 ) yymsp[-2].minor.yy18->flags |= EP_InfixFunc; } break; - case 178: /* expr ::= expr likeop expr ESCAPE expr */ + case 189: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; yymsp[-3].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy314); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy314); - yymsp[-4].minor.yy314 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0); - if( bNot ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0); - if( yymsp[-4].minor.yy314 ) yymsp[-4].minor.yy314->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy18); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy18); + yymsp[-4].minor.yy18 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); + if( bNot ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); + if( yymsp[-4].minor.yy18 ) yymsp[-4].minor.yy18->flags |= EP_InfixFunc; } break; - case 179: /* expr ::= expr ISNULL|NOTNULL */ -{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy314,0);} + case 190: /* expr ::= expr ISNULL|NOTNULL */ +{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy18,0);} break; - case 180: /* expr ::= expr NOT NULL */ -{yymsp[-2].minor.yy314 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy314,0);} + case 191: /* expr ::= expr NOT NULL */ +{yymsp[-2].minor.yy18 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy18,0);} break; - case 181: /* expr ::= expr IS expr */ + case 192: /* expr ::= expr IS expr */ { - yymsp[-2].minor.yy314 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy314,yymsp[0].minor.yy314); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy314, yymsp[-2].minor.yy314, TK_ISNULL); + yymsp[-2].minor.yy18 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy18,yymsp[0].minor.yy18); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy18, yymsp[-2].minor.yy18, TK_ISNULL); } break; - case 182: /* expr ::= expr IS NOT expr */ + case 193: /* expr ::= expr IS NOT expr */ { - yymsp[-3].minor.yy314 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy314,yymsp[0].minor.yy314); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy314, yymsp[-3].minor.yy314, TK_NOTNULL); + yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy18,yymsp[0].minor.yy18); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy18, yymsp[-3].minor.yy18, TK_NOTNULL); } break; - case 183: /* expr ::= NOT expr */ - case 184: /* expr ::= BITNOT expr */ yytestcase(yyruleno==184); -{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy314, 0);/*A-overwrites-B*/} + case 194: /* expr ::= NOT expr */ + case 195: /* expr ::= BITNOT expr */ yytestcase(yyruleno==195); +{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy18, 0);/*A-overwrites-B*/} break; - case 185: /* expr ::= MINUS expr */ -{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy314, 0);} - break; - case 186: /* expr ::= PLUS expr */ -{yymsp[-1].minor.yy314 = sqlite3PExpr(pParse, TK_UPLUS, yymsp[0].minor.yy314, 0);} - break; - case 187: /* between_op ::= BETWEEN */ - case 190: /* in_op ::= IN */ yytestcase(yyruleno==190); -{yymsp[0].minor.yy4 = 0;} - break; - case 189: /* expr ::= expr between_op expr AND expr */ + case 196: /* expr ::= PLUS|MINUS expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy314); - yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy314, 0); - if( yymsp[-4].minor.yy314 ){ - yymsp[-4].minor.yy314->x.pList = pList; + yymsp[-1].minor.yy18 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy18, 0); + /*A-overwrites-B*/ +} + break; + case 197: /* between_op ::= BETWEEN */ + case 200: /* in_op ::= IN */ yytestcase(yyruleno==200); +{yymsp[0].minor.yy70 = 0;} + break; + case 199: /* expr ::= expr between_op expr AND expr */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy18); + yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy18, 0); + if( yymsp[-4].minor.yy18 ){ + yymsp[-4].minor.yy18->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0); + if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); } break; - case 192: /* expr ::= expr in_op LP exprlist RP */ + case 202: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy322==0 ){ + if( yymsp[-1].minor.yy420==0 ){ /* Expressions of the form ** ** expr1 IN () @@ -143076,9 +150394,9 @@ static void yy_reduce( ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ - sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy314); - yymsp[-4].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy4],1); - }else if( yymsp[-1].minor.yy322->nExpr==1 ){ + sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy18); + yymsp[-4].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy70],1); + }else if( yymsp[-1].minor.yy420->nExpr==1 ){ /* Expressions of the form: ** ** expr1 IN (?1) @@ -143095,195 +150413,199 @@ static void yy_reduce( ** affinity or the collating sequence to use for comparison. Otherwise, ** the semantics would be subtly different from IN or NOT IN. */ - Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr; - yymsp[-1].minor.yy322->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); + Expr *pRHS = yymsp[-1].minor.yy420->a[0].pExpr; + yymsp[-1].minor.yy420->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy420); /* pRHS cannot be NULL because a malloc error would have been detected ** before now and control would have never reached this point */ if( ALWAYS(pRHS) ){ pRHS->flags &= ~EP_Collate; pRHS->flags |= EP_Generic; } - yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, yymsp[-3].minor.yy4 ? TK_NE : TK_EQ, yymsp[-4].minor.yy314, pRHS); + yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, yymsp[-3].minor.yy70 ? TK_NE : TK_EQ, yymsp[-4].minor.yy18, pRHS); }else{ - yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0); - if( yymsp[-4].minor.yy314 ){ - yymsp[-4].minor.yy314->x.pList = yymsp[-1].minor.yy322; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy314); + yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0); + if( yymsp[-4].minor.yy18 ){ + yymsp[-4].minor.yy18->x.pList = yymsp[-1].minor.yy420; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy18); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy420); } - if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0); + if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); } } break; - case 193: /* expr ::= LP select RP */ + case 203: /* expr ::= LP select RP */ { - yymsp[-2].minor.yy314 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy314, yymsp[-1].minor.yy387); + yymsp[-2].minor.yy18 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy18, yymsp[-1].minor.yy489); } break; - case 194: /* expr ::= expr in_op LP select RP */ + case 204: /* expr ::= expr in_op LP select RP */ { - yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy314, yymsp[-1].minor.yy387); - if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0); + yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy18, yymsp[-1].minor.yy489); + if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); } break; - case 195: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 205: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); - if( yymsp[0].minor.yy322 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322); - yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy314, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy314, pSelect); - if( yymsp[-3].minor.yy4 ) yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy314, 0); + if( yymsp[0].minor.yy420 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy420); + yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy18, pSelect); + if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0); } break; - case 196: /* expr ::= EXISTS LP select RP */ + case 206: /* expr ::= EXISTS LP select RP */ { Expr *p; - p = yymsp[-3].minor.yy314 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy387); + p = yymsp[-3].minor.yy18 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy489); } break; - case 197: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 207: /* expr ::= CASE case_operand case_exprlist case_else END */ { - yymsp[-4].minor.yy314 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy314, 0); - if( yymsp[-4].minor.yy314 ){ - yymsp[-4].minor.yy314->x.pList = yymsp[-1].minor.yy314 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy314) : yymsp[-2].minor.yy322; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy314); + yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy18, 0); + if( yymsp[-4].minor.yy18 ){ + yymsp[-4].minor.yy18->x.pList = yymsp[-1].minor.yy18 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy420,yymsp[-1].minor.yy18) : yymsp[-2].minor.yy420; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy18); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy314); + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy420); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy18); } } break; - case 198: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 208: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy314); - yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy314); + yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, yymsp[-2].minor.yy18); + yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, yymsp[0].minor.yy18); } break; - case 199: /* case_exprlist ::= WHEN expr THEN expr */ + case 209: /* case_exprlist ::= WHEN expr THEN expr */ { - yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy314); - yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy314); + yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18); + yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy420, yymsp[0].minor.yy18); } break; - case 202: /* case_operand ::= expr */ -{yymsp[0].minor.yy314 = yymsp[0].minor.yy314; /*A-overwrites-X*/} + case 212: /* case_operand ::= expr */ +{yymsp[0].minor.yy18 = yymsp[0].minor.yy18; /*A-overwrites-X*/} break; - case 205: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy314);} + case 215: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy420,yymsp[0].minor.yy18);} break; - case 206: /* nexprlist ::= expr */ -{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy314); /*A-overwrites-Y*/} + case 216: /* nexprlist ::= expr */ +{yymsp[0].minor.yy420 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy18); /*A-overwrites-Y*/} break; - case 208: /* paren_exprlist ::= LP exprlist RP */ - case 213: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==213); -{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;} + case 218: /* paren_exprlist ::= LP exprlist RP */ + case 223: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==223); +{yymsp[-2].minor.yy420 = yymsp[-1].minor.yy420;} break; - case 209: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 219: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy4, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy314, SQLITE_SO_ASC, yymsp[-8].minor.yy4, SQLITE_IDXTYPE_APPDEF); + sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy420, yymsp[-10].minor.yy70, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy18, SQLITE_SO_ASC, yymsp[-8].minor.yy70, SQLITE_IDXTYPE_APPDEF); + if( IN_RENAME_OBJECT && pParse->pNewIndex ){ + sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); + } } break; - case 210: /* uniqueflag ::= UNIQUE */ - case 250: /* raisetype ::= ABORT */ yytestcase(yyruleno==250); -{yymsp[0].minor.yy4 = OE_Abort;} + case 220: /* uniqueflag ::= UNIQUE */ + case 260: /* raisetype ::= ABORT */ yytestcase(yyruleno==260); +{yymsp[0].minor.yy70 = OE_Abort;} break; - case 211: /* uniqueflag ::= */ -{yymsp[1].minor.yy4 = OE_None;} + case 221: /* uniqueflag ::= */ +{yymsp[1].minor.yy70 = OE_None;} break; - case 214: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 224: /* eidlist ::= eidlist COMMA nm collate sortorder */ { - yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4); + yymsp[-4].minor.yy420 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy420, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy70, yymsp[0].minor.yy70); } break; - case 215: /* eidlist ::= nm collate sortorder */ + case 225: /* eidlist ::= nm collate sortorder */ { - yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4); /*A-overwrites-Y*/ + yymsp[-2].minor.yy420 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy70, yymsp[0].minor.yy70); /*A-overwrites-Y*/ } break; - case 218: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy259, yymsp[-1].minor.yy4);} + case 228: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy135, yymsp[-1].minor.yy70);} break; - case 219: /* cmd ::= VACUUM */ + case 229: /* cmd ::= VACUUM */ {sqlite3Vacuum(pParse,0);} break; - case 220: /* cmd ::= VACUUM nm */ + case 230: /* cmd ::= VACUUM nm */ {sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} break; - case 221: /* cmd ::= PRAGMA nm dbnm */ + case 231: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 222: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 232: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 223: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 233: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 224: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 234: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 225: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 235: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 228: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 238: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy203, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy207, &all); } break; - case 229: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 239: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy4, yymsp[-4].minor.yy90.a, yymsp[-4].minor.yy90.b, yymsp[-2].minor.yy259, yymsp[0].minor.yy314, yymsp[-10].minor.yy4, yymsp[-8].minor.yy4); + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy70, yymsp[-4].minor.yy34.a, yymsp[-4].minor.yy34.b, yymsp[-2].minor.yy135, yymsp[0].minor.yy18, yymsp[-10].minor.yy70, yymsp[-8].minor.yy70); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 230: /* trigger_time ::= BEFORE|AFTER */ -{ yymsp[0].minor.yy4 = yymsp[0].major; /*A-overwrites-X*/ } + case 240: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 231: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy4 = TK_INSTEAD;} + case 241: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy70 = TK_INSTEAD;} break; - case 232: /* trigger_time ::= */ -{ yymsp[1].minor.yy4 = TK_BEFORE; } + case 242: /* trigger_time ::= */ +{ yymsp[1].minor.yy70 = TK_BEFORE; } break; - case 233: /* trigger_event ::= DELETE|INSERT */ - case 234: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==234); -{yymsp[0].minor.yy90.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy90.b = 0;} + case 243: /* trigger_event ::= DELETE|INSERT */ + case 244: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==244); +{yymsp[0].minor.yy34.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy34.b = 0;} break; - case 235: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy90.a = TK_UPDATE; yymsp[-2].minor.yy90.b = yymsp[0].minor.yy384;} + case 245: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy34.a = TK_UPDATE; yymsp[-2].minor.yy34.b = yymsp[0].minor.yy48;} break; - case 236: /* when_clause ::= */ - case 255: /* key_opt ::= */ yytestcase(yyruleno==255); -{ yymsp[1].minor.yy314 = 0; } + case 246: /* when_clause ::= */ + case 265: /* key_opt ::= */ yytestcase(yyruleno==265); + case 307: /* filter_opt ::= */ yytestcase(yyruleno==307); +{ yymsp[1].minor.yy18 = 0; } break; - case 237: /* when_clause ::= WHEN expr */ - case 256: /* key_opt ::= KEY expr */ yytestcase(yyruleno==256); -{ yymsp[-1].minor.yy314 = yymsp[0].minor.yy314; } + case 247: /* when_clause ::= WHEN expr */ + case 266: /* key_opt ::= KEY expr */ yytestcase(yyruleno==266); +{ yymsp[-1].minor.yy18 = yymsp[0].minor.yy18; } break; - case 238: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 248: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - assert( yymsp[-2].minor.yy203!=0 ); - yymsp[-2].minor.yy203->pLast->pNext = yymsp[-1].minor.yy203; - yymsp[-2].minor.yy203->pLast = yymsp[-1].minor.yy203; + assert( yymsp[-2].minor.yy207!=0 ); + yymsp[-2].minor.yy207->pLast->pNext = yymsp[-1].minor.yy207; + yymsp[-2].minor.yy207->pLast = yymsp[-1].minor.yy207; } break; - case 239: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 249: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - assert( yymsp[-1].minor.yy203!=0 ); - yymsp[-1].minor.yy203->pLast = yymsp[-1].minor.yy203; + assert( yymsp[-1].minor.yy207!=0 ); + yymsp[-1].minor.yy207->pLast = yymsp[-1].minor.yy207; } break; - case 240: /* trnm ::= nm DOT nm */ + case 250: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -143291,194 +150613,306 @@ static void yy_reduce( "statements within triggers"); } break; - case 241: /* tridxby ::= INDEXED BY nm */ + case 251: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 242: /* tridxby ::= NOT INDEXED */ + case 252: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 243: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ -{yylhsminor.yy203 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy314, yymsp[-6].minor.yy4, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy336);} - yymsp[-7].minor.yy203 = yylhsminor.yy203; + case 253: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ +{yylhsminor.yy207 = sqlite3TriggerUpdateStep(pParse, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy420, yymsp[-1].minor.yy18, yymsp[-6].minor.yy70, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy392);} + yymsp[-7].minor.yy207 = yylhsminor.yy207; break; - case 244: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select scanpt */ -{yylhsminor.yy203 = sqlite3TriggerInsertStep(pParse->db,&yymsp[-3].minor.yy0,yymsp[-2].minor.yy384,yymsp[-1].minor.yy387,yymsp[-5].minor.yy4,yymsp[-6].minor.yy336,yymsp[0].minor.yy336);/*yylhsminor.yy203-overwrites-yymsp[-5].minor.yy4*/} - yymsp[-6].minor.yy203 = yylhsminor.yy203; - break; - case 245: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -{yylhsminor.yy203 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy314, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy336);} - yymsp[-5].minor.yy203 = yylhsminor.yy203; - break; - case 246: /* trigger_cmd ::= scanpt select scanpt */ -{yylhsminor.yy203 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy387, yymsp[-2].minor.yy336, yymsp[0].minor.yy336); /*yylhsminor.yy203-overwrites-yymsp[-1].minor.yy387*/} - yymsp[-2].minor.yy203 = yylhsminor.yy203; - break; - case 247: /* expr ::= RAISE LP IGNORE RP */ + case 254: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { - yymsp[-3].minor.yy314 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); - if( yymsp[-3].minor.yy314 ){ - yymsp[-3].minor.yy314->affinity = OE_Ignore; + yylhsminor.yy207 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy48,yymsp[-2].minor.yy489,yymsp[-6].minor.yy70,yymsp[-1].minor.yy340,yymsp[-7].minor.yy392,yymsp[0].minor.yy392);/*yylhsminor.yy207-overwrites-yymsp[-6].minor.yy70*/ +} + yymsp[-7].minor.yy207 = yylhsminor.yy207; + break; + case 255: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ +{yylhsminor.yy207 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy18, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy392);} + yymsp[-5].minor.yy207 = yylhsminor.yy207; + break; + case 256: /* trigger_cmd ::= scanpt select scanpt */ +{yylhsminor.yy207 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy489, yymsp[-2].minor.yy392, yymsp[0].minor.yy392); /*yylhsminor.yy207-overwrites-yymsp[-1].minor.yy489*/} + yymsp[-2].minor.yy207 = yylhsminor.yy207; + break; + case 257: /* expr ::= RAISE LP IGNORE RP */ +{ + yymsp[-3].minor.yy18 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy18 ){ + yymsp[-3].minor.yy18->affinity = OE_Ignore; } } break; - case 248: /* expr ::= RAISE LP raisetype COMMA nm RP */ + case 258: /* expr ::= RAISE LP raisetype COMMA nm RP */ { - yymsp[-5].minor.yy314 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); - if( yymsp[-5].minor.yy314 ) { - yymsp[-5].minor.yy314->affinity = (char)yymsp[-3].minor.yy4; + yymsp[-5].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); + if( yymsp[-5].minor.yy18 ) { + yymsp[-5].minor.yy18->affinity = (char)yymsp[-3].minor.yy70; } } break; - case 249: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy4 = OE_Rollback;} + case 259: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy70 = OE_Rollback;} break; - case 251: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy4 = OE_Fail;} + case 261: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy70 = OE_Fail;} break; - case 252: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 262: /* cmd ::= DROP TRIGGER ifexists fullname */ { - sqlite3DropTrigger(pParse,yymsp[0].minor.yy259,yymsp[-1].minor.yy4); + sqlite3DropTrigger(pParse,yymsp[0].minor.yy135,yymsp[-1].minor.yy70); } break; - case 253: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 263: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - sqlite3Attach(pParse, yymsp[-3].minor.yy314, yymsp[-1].minor.yy314, yymsp[0].minor.yy314); + sqlite3Attach(pParse, yymsp[-3].minor.yy18, yymsp[-1].minor.yy18, yymsp[0].minor.yy18); } break; - case 254: /* cmd ::= DETACH database_kw_opt expr */ + case 264: /* cmd ::= DETACH database_kw_opt expr */ { - sqlite3Detach(pParse, yymsp[0].minor.yy314); + sqlite3Detach(pParse, yymsp[0].minor.yy18); } break; - case 257: /* cmd ::= REINDEX */ + case 267: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 258: /* cmd ::= REINDEX nm dbnm */ + case 268: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 259: /* cmd ::= ANALYZE */ + case 269: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 260: /* cmd ::= ANALYZE nm dbnm */ + case 270: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 261: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 271: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy259,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy135,&yymsp[0].minor.yy0); } break; - case 262: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 272: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 263: /* add_column_fullname ::= fullname */ + case 273: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy259); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy135); } break; - case 264: /* cmd ::= create_vtab */ + case 274: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ +{ + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy135, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); +} + break; + case 275: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 265: /* cmd ::= create_vtab LP vtabarglist RP */ + case 276: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 266: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 277: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy4); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy70); } break; - case 267: /* vtabarg ::= */ + case 278: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 268: /* vtabargtoken ::= ANY */ - case 269: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==269); - case 270: /* lp ::= LP */ yytestcase(yyruleno==270); + case 279: /* vtabargtoken ::= ANY */ + case 280: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==280); + case 281: /* lp ::= LP */ yytestcase(yyruleno==281); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 271: /* with ::= WITH wqlist */ - case 272: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==272); -{ sqlite3WithPush(pParse, yymsp[0].minor.yy451, 1); } + case 282: /* with ::= WITH wqlist */ + case 283: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==283); +{ sqlite3WithPush(pParse, yymsp[0].minor.yy449, 1); } break; - case 273: /* wqlist ::= nm eidlist_opt AS LP select RP */ + case 284: /* wqlist ::= nm eidlist_opt AS LP select RP */ { - yymsp[-5].minor.yy451 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387); /*A-overwrites-X*/ + yymsp[-5].minor.yy449 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy420, yymsp[-1].minor.yy489); /*A-overwrites-X*/ } break; - case 274: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + case 285: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ { - yymsp[-7].minor.yy451 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy451, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387); + yymsp[-7].minor.yy449 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy449, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy420, yymsp[-1].minor.yy489); } break; + case 286: /* windowdefn_list ::= windowdefn */ +{ yylhsminor.yy327 = yymsp[0].minor.yy327; } + yymsp[0].minor.yy327 = yylhsminor.yy327; + break; + case 287: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ +{ + assert( yymsp[0].minor.yy327!=0 ); + yymsp[0].minor.yy327->pNextWin = yymsp[-2].minor.yy327; + yylhsminor.yy327 = yymsp[0].minor.yy327; +} + yymsp[-2].minor.yy327 = yylhsminor.yy327; + break; + case 288: /* windowdefn ::= nm AS window */ +{ + if( ALWAYS(yymsp[0].minor.yy327) ){ + yymsp[0].minor.yy327->zName = sqlite3DbStrNDup(pParse->db, yymsp[-2].minor.yy0.z, yymsp[-2].minor.yy0.n); + } + yylhsminor.yy327 = yymsp[0].minor.yy327; +} + yymsp[-2].minor.yy327 = yylhsminor.yy327; + break; + case 289: /* window ::= LP part_opt orderby_opt frame_opt RP */ +{ + yymsp[-4].minor.yy327 = yymsp[-1].minor.yy327; + if( ALWAYS(yymsp[-4].minor.yy327) ){ + yymsp[-4].minor.yy327->pPartition = yymsp[-3].minor.yy420; + yymsp[-4].minor.yy327->pOrderBy = yymsp[-2].minor.yy420; + } +} + break; + case 290: /* part_opt ::= PARTITION BY nexprlist */ +{ yymsp[-2].minor.yy420 = yymsp[0].minor.yy420; } + break; + case 291: /* part_opt ::= */ +{ yymsp[1].minor.yy420 = 0; } + break; + case 292: /* frame_opt ::= */ +{ + yymsp[1].minor.yy327 = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0); +} + break; + case 293: /* frame_opt ::= range_or_rows frame_bound_s */ +{ + yylhsminor.yy327 = sqlite3WindowAlloc(pParse, yymsp[-1].minor.yy70, yymsp[0].minor.yy119.eType, yymsp[0].minor.yy119.pExpr, TK_CURRENT, 0); +} + yymsp[-1].minor.yy327 = yylhsminor.yy327; + break; + case 294: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */ +{ + yylhsminor.yy327 = sqlite3WindowAlloc(pParse, yymsp[-4].minor.yy70, yymsp[-2].minor.yy119.eType, yymsp[-2].minor.yy119.pExpr, yymsp[0].minor.yy119.eType, yymsp[0].minor.yy119.pExpr); +} + yymsp[-4].minor.yy327 = yylhsminor.yy327; + break; + case 295: /* range_or_rows ::= RANGE */ +{ yymsp[0].minor.yy70 = TK_RANGE; } + break; + case 296: /* range_or_rows ::= ROWS */ +{ yymsp[0].minor.yy70 = TK_ROWS; } + break; + case 297: /* frame_bound_s ::= frame_bound */ + case 299: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==299); +{ yylhsminor.yy119 = yymsp[0].minor.yy119; } + yymsp[0].minor.yy119 = yylhsminor.yy119; + break; + case 298: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 300: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==300); +{yymsp[-1].minor.yy119.eType = TK_UNBOUNDED; yymsp[-1].minor.yy119.pExpr = 0;} + break; + case 301: /* frame_bound ::= expr PRECEDING */ +{ yylhsminor.yy119.eType = TK_PRECEDING; yylhsminor.yy119.pExpr = yymsp[-1].minor.yy18; } + yymsp[-1].minor.yy119 = yylhsminor.yy119; + break; + case 302: /* frame_bound ::= CURRENT ROW */ +{ yymsp[-1].minor.yy119.eType = TK_CURRENT ; yymsp[-1].minor.yy119.pExpr = 0; } + break; + case 303: /* frame_bound ::= expr FOLLOWING */ +{ yylhsminor.yy119.eType = TK_FOLLOWING; yylhsminor.yy119.pExpr = yymsp[-1].minor.yy18; } + yymsp[-1].minor.yy119 = yylhsminor.yy119; + break; + case 304: /* window_clause ::= WINDOW windowdefn_list */ +{ yymsp[-1].minor.yy327 = yymsp[0].minor.yy327; } + break; + case 305: /* over_clause ::= filter_opt OVER window */ +{ + yylhsminor.yy327 = yymsp[0].minor.yy327; + assert( yylhsminor.yy327!=0 ); + yylhsminor.yy327->pFilter = yymsp[-2].minor.yy18; +} + yymsp[-2].minor.yy327 = yylhsminor.yy327; + break; + case 306: /* over_clause ::= filter_opt OVER nm */ +{ + yylhsminor.yy327 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yylhsminor.yy327 ){ + yylhsminor.yy327->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); + yylhsminor.yy327->pFilter = yymsp[-2].minor.yy18; + }else{ + sqlite3ExprDelete(pParse->db, yymsp[-2].minor.yy18); + } +} + yymsp[-2].minor.yy327 = yylhsminor.yy327; + break; + case 308: /* filter_opt ::= FILTER LP WHERE expr RP */ +{ yymsp[-4].minor.yy18 = yymsp[-1].minor.yy18; } + break; default: - /* (275) input ::= cmdlist */ yytestcase(yyruleno==275); - /* (276) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==276); - /* (277) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=277); - /* (278) ecmd ::= SEMI */ yytestcase(yyruleno==278); - /* (279) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==279); - /* (280) explain ::= */ yytestcase(yyruleno==280); - /* (281) trans_opt ::= */ yytestcase(yyruleno==281); - /* (282) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==282); - /* (283) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==283); - /* (284) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==284); - /* (285) savepoint_opt ::= */ yytestcase(yyruleno==285); - /* (286) cmd ::= create_table create_table_args */ yytestcase(yyruleno==286); - /* (287) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==287); - /* (288) columnlist ::= columnname carglist */ yytestcase(yyruleno==288); - /* (289) nm ::= ID|INDEXED */ yytestcase(yyruleno==289); - /* (290) nm ::= STRING */ yytestcase(yyruleno==290); - /* (291) nm ::= JOIN_KW */ yytestcase(yyruleno==291); - /* (292) typetoken ::= typename */ yytestcase(yyruleno==292); - /* (293) typename ::= ID|STRING */ yytestcase(yyruleno==293); - /* (294) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=294); - /* (295) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=295); - /* (296) carglist ::= carglist ccons */ yytestcase(yyruleno==296); - /* (297) carglist ::= */ yytestcase(yyruleno==297); - /* (298) ccons ::= NULL onconf */ yytestcase(yyruleno==298); - /* (299) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==299); - /* (300) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==300); - /* (301) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=301); - /* (302) tconscomma ::= */ yytestcase(yyruleno==302); - /* (303) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=303); - /* (304) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=304); - /* (305) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=305); - /* (306) oneselect ::= values */ yytestcase(yyruleno==306); - /* (307) sclp ::= selcollist COMMA */ yytestcase(yyruleno==307); - /* (308) as ::= ID|STRING */ yytestcase(yyruleno==308); - /* (309) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=309); - /* (310) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==310); - /* (311) exprlist ::= nexprlist */ yytestcase(yyruleno==311); - /* (312) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=312); - /* (313) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=313); - /* (314) nmnum ::= ON */ yytestcase(yyruleno==314); - /* (315) nmnum ::= DELETE */ yytestcase(yyruleno==315); - /* (316) nmnum ::= DEFAULT */ yytestcase(yyruleno==316); - /* (317) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==317); - /* (318) foreach_clause ::= */ yytestcase(yyruleno==318); - /* (319) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==319); - /* (320) trnm ::= nm */ yytestcase(yyruleno==320); - /* (321) tridxby ::= */ yytestcase(yyruleno==321); - /* (322) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==322); - /* (323) database_kw_opt ::= */ yytestcase(yyruleno==323); - /* (324) kwcolumn_opt ::= */ yytestcase(yyruleno==324); - /* (325) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==325); - /* (326) vtabarglist ::= vtabarg */ yytestcase(yyruleno==326); - /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==327); - /* (328) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==328); - /* (329) anylist ::= */ yytestcase(yyruleno==329); - /* (330) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==330); - /* (331) anylist ::= anylist ANY */ yytestcase(yyruleno==331); - /* (332) with ::= */ yytestcase(yyruleno==332); + /* (309) input ::= cmdlist */ yytestcase(yyruleno==309); + /* (310) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==310); + /* (311) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=311); + /* (312) ecmd ::= SEMI */ yytestcase(yyruleno==312); + /* (313) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==313); + /* (314) ecmd ::= explain cmdx */ yytestcase(yyruleno==314); + /* (315) trans_opt ::= */ yytestcase(yyruleno==315); + /* (316) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==316); + /* (317) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==317); + /* (318) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==318); + /* (319) savepoint_opt ::= */ yytestcase(yyruleno==319); + /* (320) cmd ::= create_table create_table_args */ yytestcase(yyruleno==320); + /* (321) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==321); + /* (322) columnlist ::= columnname carglist */ yytestcase(yyruleno==322); + /* (323) nm ::= ID|INDEXED */ yytestcase(yyruleno==323); + /* (324) nm ::= STRING */ yytestcase(yyruleno==324); + /* (325) nm ::= JOIN_KW */ yytestcase(yyruleno==325); + /* (326) typetoken ::= typename */ yytestcase(yyruleno==326); + /* (327) typename ::= ID|STRING */ yytestcase(yyruleno==327); + /* (328) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=328); + /* (329) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=329); + /* (330) carglist ::= carglist ccons */ yytestcase(yyruleno==330); + /* (331) carglist ::= */ yytestcase(yyruleno==331); + /* (332) ccons ::= NULL onconf */ yytestcase(yyruleno==332); + /* (333) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==333); + /* (334) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==334); + /* (335) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=335); + /* (336) tconscomma ::= */ yytestcase(yyruleno==336); + /* (337) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=337); + /* (338) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=338); + /* (339) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=339); + /* (340) oneselect ::= values */ yytestcase(yyruleno==340); + /* (341) sclp ::= selcollist COMMA */ yytestcase(yyruleno==341); + /* (342) as ::= ID|STRING */ yytestcase(yyruleno==342); + /* (343) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=343); + /* (344) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==344); + /* (345) exprlist ::= nexprlist */ yytestcase(yyruleno==345); + /* (346) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=346); + /* (347) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=347); + /* (348) nmnum ::= ON */ yytestcase(yyruleno==348); + /* (349) nmnum ::= DELETE */ yytestcase(yyruleno==349); + /* (350) nmnum ::= DEFAULT */ yytestcase(yyruleno==350); + /* (351) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==351); + /* (352) foreach_clause ::= */ yytestcase(yyruleno==352); + /* (353) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==353); + /* (354) trnm ::= nm */ yytestcase(yyruleno==354); + /* (355) tridxby ::= */ yytestcase(yyruleno==355); + /* (356) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==356); + /* (357) database_kw_opt ::= */ yytestcase(yyruleno==357); + /* (358) kwcolumn_opt ::= */ yytestcase(yyruleno==358); + /* (359) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==359); + /* (360) vtabarglist ::= vtabarg */ yytestcase(yyruleno==360); + /* (361) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==361); + /* (362) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==362); + /* (363) anylist ::= */ yytestcase(yyruleno==363); + /* (364) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==364); + /* (365) anylist ::= anylist ANY */ yytestcase(yyruleno==365); + /* (366) with ::= */ yytestcase(yyruleno==366); break; /********** End reduce actions ************************************************/ }; @@ -143499,6 +150933,7 @@ static void yy_reduce( yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact, "... then shift"); + return yyact; } /* @@ -143508,7 +150943,8 @@ static void yy_reduce( static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ - sqlite3ParserARG_FETCH; + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); @@ -143519,7 +150955,8 @@ static void yy_parse_failed( ** parser fails */ /************ Begin %parse_failure code ***************************************/ /************ End %parse_failure code *****************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserCTX_STORE } #endif /* YYNOERRORRECOVERY */ @@ -143531,7 +150968,8 @@ static void yy_syntax_error( int yymajor, /* The major type of the error token */ sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */ ){ - sqlite3ParserARG_FETCH; + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH #define TOKEN yyminor /************ Begin %syntax_error code ****************************************/ @@ -143542,7 +150980,8 @@ static void yy_syntax_error( sqlite3ErrorMsg(pParse, "incomplete input"); } /************ End %syntax_error code ******************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserCTX_STORE } /* @@ -143551,7 +150990,8 @@ static void yy_syntax_error( static void yy_accept( yyParser *yypParser /* The parser */ ){ - sqlite3ParserARG_FETCH; + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); @@ -143565,7 +151005,8 @@ static void yy_accept( ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ /*********** End %parse_accept code *******************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserCTX_STORE } /* The main parser program. @@ -143594,45 +151035,47 @@ SQLITE_PRIVATE void sqlite3Parser( sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ ){ YYMINORTYPE yyminorunion; - unsigned int yyact; /* The parser action. */ + YYACTIONTYPE yyact; /* The parser action. */ #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) int yyendofinput; /* True if we are at the end of input */ #endif #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif - yyParser *yypParser; /* The parser */ + yyParser *yypParser = (yyParser*)yyp; /* The parser */ + sqlite3ParserCTX_FETCH + sqlite3ParserARG_STORE - yypParser = (yyParser*)yyp; assert( yypParser->yytos!=0 ); #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); #endif - sqlite3ParserARG_STORE; + yyact = yypParser->yytos->stateno; #ifndef NDEBUG if( yyTraceFILE ){ - int stateno = yypParser->yytos->stateno; - if( stateno < YY_MIN_REDUCE ){ + if( yyact < YY_MIN_REDUCE ){ fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", - yyTracePrompt,yyTokenName[yymajor],stateno); + yyTracePrompt,yyTokenName[yymajor],yyact); }else{ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", - yyTracePrompt,yyTokenName[yymajor],stateno-YY_MIN_REDUCE); + yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif do{ - yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); + assert( yyact==yypParser->yytos->stateno ); + yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); if( yyact >= YY_MIN_REDUCE ){ - yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,yyminor); + yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor, + yyminor sqlite3ParserCTX_PARAM); }else if( yyact <= YY_MAX_SHIFTREDUCE ){ - yy_shift(yypParser,yyact,yymajor,yyminor); + yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; #endif - yymajor = YYNOCODE; + break; }else if( yyact==YY_ACCEPT_ACTION ){ yypParser->yytos--; yy_accept(yypParser); @@ -143683,10 +151126,9 @@ SQLITE_PRIVATE void sqlite3Parser( yymajor = YYNOCODE; }else{ while( yypParser->yytos >= yypParser->yystack - && yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yytos->stateno, - YYERRORSYMBOL)) >= YY_MIN_REDUCE + YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE ){ yy_pop_parser_stack(yypParser); } @@ -143703,6 +151145,8 @@ SQLITE_PRIVATE void sqlite3Parser( } yypParser->yyerrcnt = 3; yyerrorhit = 1; + if( yymajor==YYNOCODE ) break; + yyact = yypParser->yytos->stateno; #elif defined(YYNOERRORRECOVERY) /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to ** do any kind of error recovery. Instead, simply invoke the syntax @@ -143713,8 +151157,7 @@ SQLITE_PRIVATE void sqlite3Parser( */ yy_syntax_error(yypParser,yymajor, yyminor); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - yymajor = YYNOCODE; - + break; #else /* YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** @@ -143736,10 +151179,10 @@ SQLITE_PRIVATE void sqlite3Parser( yypParser->yyerrcnt = -1; #endif } - yymajor = YYNOCODE; + break; #endif } - }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); + }while( yypParser->yytos>yypParser->yystack ); #ifndef NDEBUG if( yyTraceFILE ){ yyStackEntry *i; @@ -143755,6 +151198,21 @@ SQLITE_PRIVATE void sqlite3Parser( return; } +/* +** Return the fallback token corresponding to canonical token iToken, or +** 0 if iToken has no fallback. +*/ +SQLITE_PRIVATE int sqlite3ParserFallback(int iToken){ +#ifdef YYFALLBACK + if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){ + return yyFallback[iToken]; + } +#else + (void)iToken; +#endif + return 0; +} + /************** End of parse.c ***********************************************/ /************** Begin file tokenize.c ****************************************/ /* @@ -143813,11 +151271,12 @@ SQLITE_PRIVATE void sqlite3Parser( #define CC_TILDA 25 /* '~' */ #define CC_DOT 26 /* '.' */ #define CC_ILLEGAL 27 /* Illegal character */ +#define CC_NUL 28 /* 0x00 */ static const unsigned char aiClass[] = { #ifdef SQLITE_ASCII /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ -/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, +/* 0x */ 28, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, /* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, /* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, @@ -143916,19 +151375,20 @@ const unsigned char ebcdicToAscii[] = { ** is substantially reduced. This is important for embedded applications ** on platforms with limited memory. */ -/* Hash score: 182 */ -/* zKWText[] encodes 834 bytes of keyword text in 554 bytes */ +/* Hash score: 208 */ +/* zKWText[] encodes 923 bytes of keyword text in 614 bytes */ /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ -/* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ -/* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ -/* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ -/* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ -/* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ -/* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ -/* VACUUMVIEWINITIALLY */ -static const char zKWText[553] = { +/* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERANGEBETWEEN */ +/* OTHINGLOBYCASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ +/* IMMEDIATEJOINSERTLIKEMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMIT */ +/* WHENOTNULLWHERECURSIVEAFTERENAMEANDEFAULTAUTOINCREMENTCAST */ +/* COLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMPARTITIONDEFERRED */ +/* ISTINCTDROPRECEDINGFAILFILTEREPLACEFOLLOWINGFROMFULLIFISNULL */ +/* ORDERESTRICTOVERIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEW */ +/* INDOWINITIALLYPRIMARY */ +static const char zKWText[613] = { 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', @@ -143941,83 +151401,90 @@ static const char zKWText[553] = { 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', - 'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E', - 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A', - 'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A', - 'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A', - 'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J', - 'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L', - 'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E', - 'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H', - 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E', - 'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E', - 'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M', - 'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R', - 'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A', - 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', - 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', - 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', - 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', - 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', - 'V','I','E','W','I','N','I','T','I','A','L','L','Y', + 'T','E','B','E','G','I','N','N','E','R','A','N','G','E','B','E','T','W', + 'E','E','N','O','T','H','I','N','G','L','O','B','Y','C','A','S','C','A', + 'D','E','L','E','T','E','C','A','S','E','C','O','L','L','A','T','E','C', + 'R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E','D', + 'E','T','A','C','H','I','M','M','E','D','I','A','T','E','J','O','I','N', + 'S','E','R','T','L','I','K','E','M','A','T','C','H','P','L','A','N','A', + 'L','Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U', + 'E','S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','O', + 'T','N','U','L','L','W','H','E','R','E','C','U','R','S','I','V','E','A', + 'F','T','E','R','E','N','A','M','E','A','N','D','E','F','A','U','L','T', + 'A','U','T','O','I','N','C','R','E','M','E','N','T','C','A','S','T','C', + 'O','L','U','M','N','C','O','M','M','I','T','C','O','N','F','L','I','C', + 'T','C','R','O','S','S','C','U','R','R','E','N','T','_','T','I','M','E', + 'S','T','A','M','P','A','R','T','I','T','I','O','N','D','E','F','E','R', + 'R','E','D','I','S','T','I','N','C','T','D','R','O','P','R','E','C','E', + 'D','I','N','G','F','A','I','L','F','I','L','T','E','R','E','P','L','A', + 'C','E','F','O','L','L','O','W','I','N','G','F','R','O','M','F','U','L', + 'L','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T','R', + 'I','C','T','O','V','E','R','I','G','H','T','R','O','L','L','B','A','C', + 'K','R','O','W','S','U','N','B','O','U','N','D','E','D','U','N','I','O', + 'N','U','S','I','N','G','V','A','C','U','U','M','V','I','E','W','I','N', + 'D','O','W','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R', + 'Y', }; /* aKWHash[i] is the hash value for the i-th keyword */ static const unsigned char aKWHash[127] = { - 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, - 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, - 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, - 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, - 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, - 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, - 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, - 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, - 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, - 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, + 74, 109, 124, 72, 106, 45, 0, 0, 81, 0, 76, 61, 0, + 42, 12, 77, 15, 0, 123, 84, 54, 118, 125, 19, 0, 0, + 130, 0, 128, 121, 0, 22, 96, 0, 9, 0, 0, 115, 69, + 0, 67, 6, 0, 48, 93, 136, 0, 126, 104, 0, 0, 44, + 0, 107, 24, 0, 17, 0, 131, 53, 23, 0, 5, 62, 132, + 99, 0, 0, 135, 110, 60, 134, 57, 113, 55, 0, 94, 0, + 103, 26, 0, 102, 0, 0, 0, 98, 95, 100, 105, 117, 14, + 39, 116, 0, 80, 0, 133, 114, 92, 59, 0, 129, 79, 119, + 86, 46, 83, 0, 0, 97, 40, 122, 120, 0, 127, 0, 0, + 29, 0, 89, 87, 88, 0, 20, 85, 111, 56, }; /* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 ** then the i-th keyword has no more hash collisions. Otherwise, ** the next keyword with the same hash is aKWHash[i]-1. */ -static const unsigned char aKWNext[124] = { +static const unsigned char aKWNext[136] = { 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, - 0, 43, 3, 47, 0, 0, 0, 0, 30, 0, 58, 0, 38, - 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, - 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, - 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, - 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, - 73, 83, 0, 35, 68, 0, 0, + 0, 43, 3, 47, 0, 0, 32, 0, 0, 0, 0, 0, 0, + 0, 1, 64, 0, 0, 65, 0, 41, 0, 38, 0, 0, 0, + 0, 0, 49, 75, 0, 0, 30, 0, 58, 0, 0, 0, 31, + 63, 16, 34, 10, 0, 0, 0, 0, 0, 0, 0, 11, 70, + 91, 0, 0, 8, 0, 108, 0, 101, 28, 52, 68, 0, 112, + 0, 73, 51, 0, 90, 27, 37, 0, 71, 36, 82, 0, 35, + 66, 25, 18, 0, 0, 78, }; /* aKWLen[i] is the length (in bytes) of the i-th keyword */ -static const unsigned char aKWLen[124] = { +static const unsigned char aKWLen[136] = { 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, - 6, 6, 5, 6, 5, 5, 9, 7, 7, 3, 2, 4, 4, - 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, - 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, - 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, - 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, - 3, 5, 5, 6, 4, 9, 3, + 6, 6, 5, 6, 5, 5, 5, 7, 7, 4, 2, 7, 3, + 6, 4, 7, 6, 12, 6, 9, 4, 6, 4, 5, 4, 7, + 6, 5, 6, 7, 5, 4, 7, 3, 2, 4, 5, 9, 5, + 6, 3, 7, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, + 7, 9, 8, 8, 2, 4, 9, 4, 6, 7, 9, 4, 4, + 2, 6, 5, 8, 4, 5, 8, 4, 3, 9, 5, 5, 6, + 4, 6, 2, 9, 3, 7, }; /* aKWOffset[i] is the index into zKWText[] of the start of ** the text for the i-th keyword. */ -static const unsigned short int aKWOffset[124] = { +static const unsigned short int aKWOffset[136] = { 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, - 199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246, - 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, - 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, - 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, - 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, - 521, 524, 529, 534, 540, 544, 549, + 199, 204, 209, 212, 218, 221, 225, 230, 236, 242, 245, 247, 248, + 252, 258, 262, 269, 275, 287, 293, 302, 304, 310, 314, 319, 321, + 328, 333, 338, 344, 350, 355, 358, 358, 358, 361, 365, 368, 377, + 381, 387, 389, 396, 398, 400, 409, 413, 419, 425, 433, 438, 438, + 438, 454, 463, 470, 471, 478, 481, 490, 494, 499, 506, 515, 519, + 523, 525, 531, 535, 543, 546, 551, 559, 559, 563, 572, 577, 582, + 588, 591, 594, 597, 602, 606, }; /* aKWCode[i] is the parser symbol code for the i-th keyword */ -static const unsigned char aKWCode[124] = { +static const unsigned char aKWCode[136] = { TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, @@ -144029,20 +151496,23 @@ static const unsigned char aKWCode[124] = { TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, - TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RECURSIVE, TK_BETWEEN, - TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, - TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, - TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, - TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, - TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, - TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND, - TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, - TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, - TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, - TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, - TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, - TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, - TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, + TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RANGE, TK_BETWEEN, + TK_NOTHING, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC, + TK_DELETE, TK_CASE, TK_COLLATE, TK_CREATE, TK_CTIME_KW, + TK_DETACH, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_LIKE_KW, + TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_ABORT, + TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, TK_NOTNULL, + TK_NOT, TK_NO, TK_NULL, TK_WHERE, TK_RECURSIVE, + TK_AFTER, TK_RENAME, TK_AND, TK_DEFAULT, TK_AUTOINCR, + TK_TO, TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, + TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CURRENT, + TK_PARTITION, TK_DEFERRED, TK_DISTINCT, TK_IS, TK_DROP, + TK_PRECEDING, TK_FAIL, TK_FILTER, TK_REPLACE, TK_FOLLOWING, + TK_FROM, TK_JOIN_KW, TK_IF, TK_ISNULL, TK_ORDER, + TK_RESTRICT, TK_OVER, TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, + TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, TK_VACUUM, + TK_VIEW, TK_WINDOW, TK_DO, TK_INITIALLY, TK_ALL, + TK_PRIMARY, }; /* Check to see if z[0..n-1] is a keyword. If it is, write the ** parser symbol code for that keyword into *pType. Always @@ -144121,72 +151591,84 @@ static int keywordCode(const char *z, int n, int *pType){ testcase( i==55 ); /* UPDATE */ testcase( i==56 ); /* BEGIN */ testcase( i==57 ); /* INNER */ - testcase( i==58 ); /* RECURSIVE */ + testcase( i==58 ); /* RANGE */ testcase( i==59 ); /* BETWEEN */ - testcase( i==60 ); /* NOTNULL */ - testcase( i==61 ); /* NOT */ - testcase( i==62 ); /* NO */ - testcase( i==63 ); /* NULL */ - testcase( i==64 ); /* LIKE */ - testcase( i==65 ); /* CASCADE */ - testcase( i==66 ); /* ASC */ - testcase( i==67 ); /* DELETE */ - testcase( i==68 ); /* CASE */ - testcase( i==69 ); /* COLLATE */ - testcase( i==70 ); /* CREATE */ - testcase( i==71 ); /* CURRENT_DATE */ - testcase( i==72 ); /* DETACH */ - testcase( i==73 ); /* IMMEDIATE */ - testcase( i==74 ); /* JOIN */ - testcase( i==75 ); /* INSERT */ - testcase( i==76 ); /* MATCH */ - testcase( i==77 ); /* PLAN */ - testcase( i==78 ); /* ANALYZE */ - testcase( i==79 ); /* PRAGMA */ - testcase( i==80 ); /* ABORT */ - testcase( i==81 ); /* VALUES */ - testcase( i==82 ); /* VIRTUAL */ - testcase( i==83 ); /* LIMIT */ - testcase( i==84 ); /* WHEN */ - testcase( i==85 ); /* WHERE */ - testcase( i==86 ); /* RENAME */ - testcase( i==87 ); /* AFTER */ - testcase( i==88 ); /* REPLACE */ - testcase( i==89 ); /* AND */ - testcase( i==90 ); /* DEFAULT */ - testcase( i==91 ); /* AUTOINCREMENT */ - testcase( i==92 ); /* TO */ - testcase( i==93 ); /* IN */ - testcase( i==94 ); /* CAST */ - testcase( i==95 ); /* COLUMN */ - testcase( i==96 ); /* COMMIT */ - testcase( i==97 ); /* CONFLICT */ - testcase( i==98 ); /* CROSS */ - testcase( i==99 ); /* CURRENT_TIMESTAMP */ - testcase( i==100 ); /* CURRENT_TIME */ - testcase( i==101 ); /* PRIMARY */ - testcase( i==102 ); /* DEFERRED */ - testcase( i==103 ); /* DISTINCT */ - testcase( i==104 ); /* IS */ - testcase( i==105 ); /* DROP */ - testcase( i==106 ); /* FAIL */ - testcase( i==107 ); /* FROM */ - testcase( i==108 ); /* FULL */ - testcase( i==109 ); /* GLOB */ - testcase( i==110 ); /* BY */ - testcase( i==111 ); /* IF */ - testcase( i==112 ); /* ISNULL */ - testcase( i==113 ); /* ORDER */ - testcase( i==114 ); /* RESTRICT */ - testcase( i==115 ); /* RIGHT */ - testcase( i==116 ); /* ROLLBACK */ - testcase( i==117 ); /* ROW */ - testcase( i==118 ); /* UNION */ - testcase( i==119 ); /* USING */ - testcase( i==120 ); /* VACUUM */ - testcase( i==121 ); /* VIEW */ - testcase( i==122 ); /* INITIALLY */ - testcase( i==123 ); /* ALL */ + testcase( i==60 ); /* NOTHING */ + testcase( i==61 ); /* GLOB */ + testcase( i==62 ); /* BY */ + testcase( i==63 ); /* CASCADE */ + testcase( i==64 ); /* ASC */ + testcase( i==65 ); /* DELETE */ + testcase( i==66 ); /* CASE */ + testcase( i==67 ); /* COLLATE */ + testcase( i==68 ); /* CREATE */ + testcase( i==69 ); /* CURRENT_DATE */ + testcase( i==70 ); /* DETACH */ + testcase( i==71 ); /* IMMEDIATE */ + testcase( i==72 ); /* JOIN */ + testcase( i==73 ); /* INSERT */ + testcase( i==74 ); /* LIKE */ + testcase( i==75 ); /* MATCH */ + testcase( i==76 ); /* PLAN */ + testcase( i==77 ); /* ANALYZE */ + testcase( i==78 ); /* PRAGMA */ + testcase( i==79 ); /* ABORT */ + testcase( i==80 ); /* VALUES */ + testcase( i==81 ); /* VIRTUAL */ + testcase( i==82 ); /* LIMIT */ + testcase( i==83 ); /* WHEN */ + testcase( i==84 ); /* NOTNULL */ + testcase( i==85 ); /* NOT */ + testcase( i==86 ); /* NO */ + testcase( i==87 ); /* NULL */ + testcase( i==88 ); /* WHERE */ + testcase( i==89 ); /* RECURSIVE */ + testcase( i==90 ); /* AFTER */ + testcase( i==91 ); /* RENAME */ + testcase( i==92 ); /* AND */ + testcase( i==93 ); /* DEFAULT */ + testcase( i==94 ); /* AUTOINCREMENT */ + testcase( i==95 ); /* TO */ + testcase( i==96 ); /* IN */ + testcase( i==97 ); /* CAST */ + testcase( i==98 ); /* COLUMN */ + testcase( i==99 ); /* COMMIT */ + testcase( i==100 ); /* CONFLICT */ + testcase( i==101 ); /* CROSS */ + testcase( i==102 ); /* CURRENT_TIMESTAMP */ + testcase( i==103 ); /* CURRENT_TIME */ + testcase( i==104 ); /* CURRENT */ + testcase( i==105 ); /* PARTITION */ + testcase( i==106 ); /* DEFERRED */ + testcase( i==107 ); /* DISTINCT */ + testcase( i==108 ); /* IS */ + testcase( i==109 ); /* DROP */ + testcase( i==110 ); /* PRECEDING */ + testcase( i==111 ); /* FAIL */ + testcase( i==112 ); /* FILTER */ + testcase( i==113 ); /* REPLACE */ + testcase( i==114 ); /* FOLLOWING */ + testcase( i==115 ); /* FROM */ + testcase( i==116 ); /* FULL */ + testcase( i==117 ); /* IF */ + testcase( i==118 ); /* ISNULL */ + testcase( i==119 ); /* ORDER */ + testcase( i==120 ); /* RESTRICT */ + testcase( i==121 ); /* OVER */ + testcase( i==122 ); /* RIGHT */ + testcase( i==123 ); /* ROLLBACK */ + testcase( i==124 ); /* ROWS */ + testcase( i==125 ); /* ROW */ + testcase( i==126 ); /* UNBOUNDED */ + testcase( i==127 ); /* UNION */ + testcase( i==128 ); /* USING */ + testcase( i==129 ); /* VACUUM */ + testcase( i==130 ); /* VIEW */ + testcase( i==131 ); /* WINDOW */ + testcase( i==132 ); /* DO */ + testcase( i==133 ); /* INITIALLY */ + testcase( i==134 ); /* ALL */ + testcase( i==135 ); /* PRIMARY */ *pType = aKWCode[i]; break; } @@ -144198,7 +151680,17 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){ keywordCode((char*)z, n, &id); return id; } -#define SQLITE_N_KEYWORD 124 +#define SQLITE_N_KEYWORD 136 +SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){ + if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR; + *pzName = zKWText + aKWOffset[i]; + *pnName = aKWLen[i]; + return SQLITE_OK; +} +SQLITE_API int sqlite3_keyword_count(void){ return SQLITE_N_KEYWORD; } +SQLITE_API int sqlite3_keyword_check(const char *zName, int nName){ + return TK_ID!=sqlite3KeywordCode((const u8*)zName, nName); +} /************** End of keywordhash.h *****************************************/ /************** Continuing where we left off in tokenize.c *******************/ @@ -144242,11 +151734,85 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = { #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #endif -/* Make the IdChar function accessible from ctime.c */ -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +/* Make the IdChar function accessible from ctime.c and alter.c */ SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); } -#endif +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Return the id of the next token in string (*pz). Before returning, set +** (*pz) to point to the byte following the parsed token. +*/ +static int getToken(const unsigned char **pz){ + const unsigned char *z = *pz; + int t; /* Token type to return */ + do { + z += sqlite3GetToken(z, &t); + }while( t==TK_SPACE ); + if( t==TK_ID + || t==TK_STRING + || t==TK_JOIN_KW + || t==TK_WINDOW + || t==TK_OVER + || sqlite3ParserFallback(t)==TK_ID + ){ + t = TK_ID; + } + *pz = z; + return t; +} + +/* +** The following three functions are called immediately after the tokenizer +** reads the keywords WINDOW, OVER and FILTER, respectively, to determine +** whether the token should be treated as a keyword or an SQL identifier. +** This cannot be handled by the usual lemon %fallback method, due to +** the ambiguity in some constructions. e.g. +** +** SELECT sum(x) OVER ... +** +** In the above, "OVER" might be a keyword, or it might be an alias for the +** sum(x) expression. If a "%fallback ID OVER" directive were added to +** grammar, then SQLite would always treat "OVER" as an alias, making it +** impossible to call a window-function without a FILTER clause. +** +** WINDOW is treated as a keyword if: +** +** * the following token is an identifier, or a keyword that can fallback +** to being an identifier, and +** * the token after than one is TK_AS. +** +** OVER is a keyword if: +** +** * the previous token was TK_RP, and +** * the next token is either TK_LP or an identifier. +** +** FILTER is a keyword if: +** +** * the previous token was TK_RP, and +** * the next token is TK_LP. +*/ +static int analyzeWindowKeyword(const unsigned char *z){ + int t; + t = getToken(&z); + if( t!=TK_ID ) return TK_ID; + t = getToken(&z); + if( t!=TK_AS ) return TK_ID; + return TK_WINDOW; +} +static int analyzeOverKeyword(const unsigned char *z, int lastToken){ + if( lastToken==TK_RP ){ + int t = getToken(&z); + if( t==TK_LP || t==TK_ID ) return TK_OVER; + } + return TK_ID; +} +static int analyzeFilterKeyword(const unsigned char *z, int lastToken){ + if( lastToken==TK_RP && getToken(&z)==TK_LP ){ + return TK_FILTER; + } + return TK_ID; +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** Return the length (in bytes) of the token that begins at z[0]. @@ -144515,6 +152081,10 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ i = 1; break; } + case CC_NUL: { + *tokenType = TK_ILLEGAL; + return 0; + } default: { *tokenType = TK_ILLEGAL; return 1; @@ -144525,6 +152095,73 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ return i; } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Return the length (in bytes) of the token that begins at z[0]. +** Store the token type in *tokenType before returning. If flags has +** SQLITE_TOKEN_NORMALIZE flag enabled, use the identifier token type +** for keywords. Add SQLITE_TOKEN_QUOTED to flags if the token was +** actually a quoted identifier. Add SQLITE_TOKEN_KEYWORD to flags +** if the token was recognized as a keyword; this is useful when the +** SQLITE_TOKEN_NORMALIZE flag is used, because it enables the caller +** to differentiate between a keyword being treated as an identifier +** (for normalization purposes) and an actual identifier. +*/ +SQLITE_PRIVATE int sqlite3GetTokenNormalized( + const unsigned char *z, + int *tokenType, + int *flags +){ + int n; + unsigned char iClass = aiClass[*z]; + if( iClass==CC_KYWD ){ + int i; + for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} + if( IdChar(z[i]) ){ + /* This token started out using characters that can appear in keywords, + ** but z[i] is a character not allowed within keywords, so this must + ** be an identifier instead */ + i++; + while( IdChar(z[i]) ){ i++; } + *tokenType = TK_ID; + return i; + } + *tokenType = TK_ID; + n = keywordCode((char*)z, i, tokenType); + /* If the token is no longer considered to be an identifier, then it is a + ** keyword of some kind. Make the token back into an identifier and then + ** set the SQLITE_TOKEN_KEYWORD flag. Several non-identifier tokens are + ** used verbatim, including IN, IS, NOT, and NULL. */ + switch( *tokenType ){ + case TK_ID: { + /* do nothing, handled by caller */ + break; + } + case TK_IN: + case TK_IS: + case TK_NOT: + case TK_NULL: { + *flags |= SQLITE_TOKEN_KEYWORD; + break; + } + default: { + *tokenType = TK_ID; + *flags |= SQLITE_TOKEN_KEYWORD; + break; + } + } + }else{ + n = sqlite3GetToken(z, tokenType); + /* If the token is considered to be an identifier and the character class + ** of the first character is a quote, set the SQLITE_TOKEN_QUOTED flag. */ + if( *tokenType==TK_ID && (iClass==CC_QUOTE || iClass==CC_QUOTE2) ){ + *flags |= SQLITE_TOKEN_QUOTED; + } + } + return n; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + /* ** Run the parser on the given SQL string. The parser structure is ** passed in. An SQLITE_ status code is returned. If an error occurs @@ -144555,9 +152192,9 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr /* sqlite3ParserTrace(stdout, "parser: "); */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK pEngine = &sEngine; - sqlite3ParserInit(pEngine); + sqlite3ParserInit(pEngine, pParse); #else - pEngine = sqlite3ParserAlloc(sqlite3Malloc); + pEngine = sqlite3ParserAlloc(sqlite3Malloc, pParse); if( pEngine==0 ){ sqlite3OomFault(db); return SQLITE_NOMEM_BKPT; @@ -144568,47 +152205,64 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr assert( pParse->nVar==0 ); assert( pParse->pVList==0 ); while( 1 ){ - if( zSql[0]!=0 ){ - n = sqlite3GetToken((u8*)zSql, &tokenType); - mxSqlLen -= n; - if( mxSqlLen<0 ){ - pParse->rc = SQLITE_TOOBIG; - break; - } - }else{ - /* Upon reaching the end of input, call the parser two more times - ** with tokens TK_SEMI and 0, in that order. */ - if( lastTokenParsed==TK_SEMI ){ - tokenType = 0; - }else if( lastTokenParsed==0 ){ - break; - }else{ - tokenType = TK_SEMI; - } - n = 0; + n = sqlite3GetToken((u8*)zSql, &tokenType); + mxSqlLen -= n; + if( mxSqlLen<0 ){ + pParse->rc = SQLITE_TOOBIG; + break; } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( tokenType>=TK_WINDOW ){ + assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER + || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW + ); +#else if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); +#endif /* SQLITE_OMIT_WINDOWFUNC */ if( db->u1.isInterrupted ){ pParse->rc = SQLITE_INTERRUPT; break; } - if( tokenType==TK_ILLEGAL ){ + if( tokenType==TK_SPACE ){ + zSql += n; + continue; + } + if( zSql[0]==0 ){ + /* Upon reaching the end of input, call the parser two more times + ** with tokens TK_SEMI and 0, in that order. */ + if( lastTokenParsed==TK_SEMI ){ + tokenType = 0; + }else if( lastTokenParsed==0 ){ + break; + }else{ + tokenType = TK_SEMI; + } + n = 0; +#ifndef SQLITE_OMIT_WINDOWFUNC + }else if( tokenType==TK_WINDOW ){ + assert( n==6 ); + tokenType = analyzeWindowKeyword((const u8*)&zSql[6]); + }else if( tokenType==TK_OVER ){ + assert( n==4 ); + tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed); + }else if( tokenType==TK_FILTER ){ + assert( n==6 ); + tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); +#endif /* SQLITE_OMIT_WINDOWFUNC */ + }else{ sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql); break; } - zSql += n; - }else{ - pParse->sLastToken.z = zSql; - pParse->sLastToken.n = n; - sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); - lastTokenParsed = tokenType; - zSql += n; - if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; } + pParse->sLastToken.z = zSql; + pParse->sLastToken.n = n; + sqlite3Parser(pEngine, tokenType, pParse->sLastToken); + lastTokenParsed = tokenType; + zSql += n; + if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; } assert( nErr==0 ); - pParse->zTail = zSql; #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, @@ -144630,10 +152284,12 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr assert( pzErrMsg!=0 ); if( pParse->zErrMsg ){ *pzErrMsg = pParse->zErrMsg; - sqlite3_log(pParse->rc, "%s", *pzErrMsg); + sqlite3_log(pParse->rc, "%s in \"%s\"", + *pzErrMsg, pParse->zTail); pParse->zErrMsg = 0; nErr++; } + pParse->zTail = zSql; if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){ sqlite3VdbeDelete(pParse->pVdbe); pParse->pVdbe = 0; @@ -144649,16 +152305,18 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr sqlite3_free(pParse->apVtabLock); #endif - if( !IN_DECLARE_VTAB ){ + if( !IN_SPECIAL_PARSE ){ /* If the pParse->declareVtab flag is set, do not delete any table ** structure built up in pParse->pNewTable. The calling code (see vtab.c) ** will take responsibility for freeing the Table structure. */ sqlite3DeleteTable(db, pParse->pNewTable); } + if( !IN_RENAME_OBJECT ){ + sqlite3DeleteTrigger(db, pParse->pNewTrigger); + } if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); - sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DbFree(db, pParse->pVList); while( pParse->pAinc ){ AutoincInfo *p = pParse->pAinc; @@ -145708,6 +153366,17 @@ SQLITE_API int sqlite3_config(int op, ...){ break; } +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + case SQLITE_CONFIG_SORTERREF_SIZE: { + int iVal = va_arg(ap, int); + if( iVal<0 ){ + iVal = SQLITE_DEFAULT_SORTERREF_SIZE; + } + sqlite3GlobalConfig.szSorterRef = (u32)iVal; + break; + } +#endif /* SQLITE_ENABLE_SORTER_REFERENCES */ + default: { rc = SQLITE_ERROR; break; @@ -145889,6 +153558,8 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, + { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, + { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ @@ -145903,7 +153574,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ db->flags &= ~aFlagOp[i].mask; } if( oldFlags!=db->flags ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); } if( pRes ){ *pRes = (db->flags & aFlagOp[i].mask)!=0; @@ -145964,6 +153635,15 @@ static int binCollFunc( return rc; } +/* +** Return true if CollSeq is the default built-in BINARY. +*/ +SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq *p){ + assert( p==0 || p->xCmp!=binCollFunc || p->pUser!=0 + || strcmp(p->zName,"BINARY")==0 ); + return p==0 || (p->xCmp==binCollFunc && p->pUser==0); +} + /* ** Another built-in collating sequence: NOCASE. ** @@ -146085,7 +153765,7 @@ static void disconnectAllVtab(sqlite3 *db){ sqlite3BtreeEnterAll(db); for(i=0; inDb; i++){ Schema *pSchema = db->aDb[i].pSchema; - if( db->aDb[i].pSchema ){ + if( pSchema ){ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ Table *pTab = (Table *)sqliteHashData(p); if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); @@ -146345,8 +154025,8 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); - if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){ - sqlite3ExpirePreparedStatements(db); + if( schemaChange ){ + sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); } sqlite3BtreeLeaveAll(db); @@ -146374,6 +154054,7 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; + case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; @@ -146737,6 +154418,8 @@ SQLITE_PRIVATE int sqlite3CreateFunc( void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ){ FuncDef *p; @@ -146744,12 +154427,14 @@ SQLITE_PRIVATE int sqlite3CreateFunc( int extraFlags; assert( sqlite3_mutex_held(db->mutex) ); - if( zFunctionName==0 || - (xSFunc && (xFinal || xStep)) || - (!xSFunc && (xFinal && !xStep)) || - (!xSFunc && (!xFinal && xStep)) || - (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || - (255<(nName = sqlite3Strlen30( zFunctionName))) ){ + assert( xValue==0 || xSFunc==0 ); + if( zFunctionName==0 /* Must have a valid name */ + || (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */ + || ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */ + || ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */ + || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) + || (255<(nName = sqlite3Strlen30( zFunctionName))) + ){ return SQLITE_MISUSE_BKPT; } @@ -146770,10 +154455,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc( }else if( enc==SQLITE_ANY ){ int rc; rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags, - pUserData, xSFunc, xStep, xFinal, pDestructor); + pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); if( rc==SQLITE_OK ){ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags, - pUserData, xSFunc, xStep, xFinal, pDestructor); + pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); } if( rc!=SQLITE_OK ){ return rc; @@ -146790,14 +154475,14 @@ SQLITE_PRIVATE int sqlite3CreateFunc( ** operation to continue but invalidate all precompiled statements. */ p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0); - if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){ + if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); return SQLITE_BUSY; }else{ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); } } @@ -146819,11 +154504,68 @@ SQLITE_PRIVATE int sqlite3CreateFunc( testcase( p->funcFlags & SQLITE_DETERMINISTIC ); p->xSFunc = xSFunc ? xSFunc : xStep; p->xFinalize = xFinal; + p->xValue = xValue; + p->xInverse = xInverse; p->pUserData = pUserData; p->nArg = (u16)nArg; return SQLITE_OK; } +/* +** Worker function used by utf-8 APIs that create new functions: +** +** sqlite3_create_function() +** sqlite3_create_function_v2() +** sqlite3_create_window_function() +*/ +static int createFunctionApi( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) +){ + int rc = SQLITE_ERROR; + FuncDestructor *pArg = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( xDestroy ){ + pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor)); + if( !pArg ){ + sqlite3OomFault(db); + xDestroy(p); + goto out; + } + pArg->nRef = 0; + pArg->xDestroy = xDestroy; + pArg->pUserData = p; + } + rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, + xSFunc, xStep, xFinal, xValue, xInverse, pArg + ); + if( pArg && pArg->nRef==0 ){ + assert( rc!=SQLITE_OK ); + xDestroy(p); + sqlite3_free(pArg); + } + + out: + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + /* ** Create new user functions. */ @@ -146837,10 +154579,9 @@ SQLITE_API int sqlite3_create_function( void (*xStep)(sqlite3_context*,int,sqlite3_value **), void (*xFinal)(sqlite3_context*) ){ - return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep, - xFinal, 0); + return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep, + xFinal, 0, 0, 0); } - SQLITE_API int sqlite3_create_function_v2( sqlite3 *db, const char *zFunc, @@ -146852,35 +154593,23 @@ SQLITE_API int sqlite3_create_function_v2( void (*xFinal)(sqlite3_context*), void (*xDestroy)(void *) ){ - int rc = SQLITE_ERROR; - FuncDestructor *pArg = 0; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - return SQLITE_MISUSE_BKPT; - } -#endif - sqlite3_mutex_enter(db->mutex); - if( xDestroy ){ - pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor)); - if( !pArg ){ - xDestroy(p); - goto out; - } - pArg->xDestroy = xDestroy; - pArg->pUserData = p; - } - rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg); - if( pArg && pArg->nRef==0 ){ - assert( rc!=SQLITE_OK ); - xDestroy(p); - sqlite3DbFree(db, pArg); - } - - out: - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); - return rc; + return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep, + xFinal, 0, 0, xDestroy); +} +SQLITE_API int sqlite3_create_window_function( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value **), + void (*xDestroy)(void *) +){ + return createFunctionApi(db, zFunc, nArg, enc, p, 0, xStep, + xFinal, xValue, xInverse, xDestroy); } #ifndef SQLITE_OMIT_UTF16 @@ -146903,7 +154632,7 @@ SQLITE_API int sqlite3_create_function16( sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); - rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0); + rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0,0,0); sqlite3DbFree(db, zFunc8); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); @@ -146912,6 +154641,28 @@ SQLITE_API int sqlite3_create_function16( #endif +/* +** The following is the implementation of an SQL function that always +** fails with an error message stating that the function is used in the +** wrong context. The sqlite3_overload_function() API might construct +** SQL function that use this routine so that the functions will exist +** for name resolution but are actually overloaded by the xFindFunction +** method of virtual tables. +*/ +static void sqlite3InvalidFunction( + sqlite3_context *context, /* The function calling context */ + int NotUsed, /* Number of arguments to the function */ + sqlite3_value **NotUsed2 /* Value of each argument */ +){ + const char *zName = (const char*)sqlite3_user_data(context); + char *zErr; + UNUSED_PARAMETER2(NotUsed, NotUsed2); + zErr = sqlite3_mprintf( + "unable to use function %s in the requested context", zName); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); +} + /* ** Declare that a function has been overloaded by a virtual table. ** @@ -146929,7 +154680,8 @@ SQLITE_API int sqlite3_overload_function( const char *zName, int nArg ){ - int rc = SQLITE_OK; + int rc; + char *zCopy; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ @@ -146937,13 +154689,13 @@ SQLITE_API int sqlite3_overload_function( } #endif sqlite3_mutex_enter(db->mutex); - if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){ - rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, - 0, sqlite3InvalidFunction, 0, 0, 0); - } - rc = sqlite3ApiExit(db, rc); + rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; sqlite3_mutex_leave(db->mutex); - return rc; + if( rc ) return SQLITE_OK; + zCopy = sqlite3_mprintf(zName); + if( zCopy==0 ) return SQLITE_NOMEM; + return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8, + zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free); } #ifndef SQLITE_OMIT_TRACE @@ -147505,7 +155257,7 @@ static int createCollation( "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; } - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); /* If collation sequence pColl was created directly by a call to ** sqlite3_create_collation, and not generated by synthCollSeq(), @@ -147994,6 +155746,7 @@ static int openDatabase( db->nDb = 2; db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; + db->lookaside.bDisable = 1; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); @@ -148033,6 +155786,9 @@ static int openDatabase( #endif #if defined(SQLITE_ENABLE_QPSG) | SQLITE_EnableQPSG +#endif +#if defined(SQLITE_DEFAULT_DEFENSIVE) + | SQLITE_Defensive #endif ; sqlite3HashInit(&db->aCollSeq); @@ -148694,6 +156450,9 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_DATA_VERSION ){ + *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); + rc = SQLITE_OK; }else{ rc = sqlite3OsFileControl(fd, op, pArg); } @@ -148916,35 +156675,28 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } -#ifdef SQLITE_N_KEYWORD - /* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord) - ** - ** If zWord is a keyword recognized by the parser, then return the - ** number of keywords. Or if zWord is not a keyword, return 0. - ** - ** This test feature is only available in the amalgamation since - ** the SQLITE_N_KEYWORD macro is not defined in this file if SQLite - ** is built using separate source files. - */ - case SQLITE_TESTCTRL_ISKEYWORD: { - const char *zWord = va_arg(ap, const char*); - int n = sqlite3Strlen30(zWord); - rc = (sqlite3KeywordCode((u8*)zWord, n)!=TK_ID) ? SQLITE_N_KEYWORD : 0; - break; - } -#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff); ** - ** If parameter onoff is non-zero, configure the wrappers so that all - ** subsequent calls to localtime() and variants fail. If onoff is zero, - ** undo this setting. + ** If parameter onoff is non-zero, subsequent calls to localtime() + ** and its variants fail. If onoff is zero, undo this setting. */ case SQLITE_TESTCTRL_LOCALTIME_FAULT: { sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCS, int onoff); + ** + ** If parameter onoff is non-zero, internal-use-only SQL functions + ** are visible to ordinary SQL. This is useful for testing but is + ** unsafe because invalid parameters to those internal-use-only functions + ** can result in crashes or segfaults. + */ + case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: { + sqlite3GlobalConfig.bInternalFunctions = va_arg(ap, int); + break; + } + /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); ** ** Set or clear a flag that indicates that the database file is always well- @@ -148975,7 +156727,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){ */ case SQLITE_TESTCTRL_VDBE_COVERAGE: { #ifdef SQLITE_VDBE_COVERAGE - typedef void (*branch_callback)(void*,int,u8,u8); + typedef void (*branch_callback)(void*,unsigned int, + unsigned char,unsigned char); sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback); sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*); #endif @@ -149162,7 +156915,7 @@ SQLITE_API int sqlite3_snapshot_get( if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( 0==sqlite3BtreeIsInTrans(pBt) ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); } @@ -149197,11 +156950,29 @@ SQLITE_API int sqlite3_snapshot_open( iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ - rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot); + if( sqlite3BtreeIsInTrans(pBt)==0 ){ + Pager *pPager = sqlite3BtreePager(pBt); + int bUnlock = 0; + if( sqlite3BtreeIsInReadTrans(pBt) ){ + if( db->nVdbeActive==0 ){ + rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); + if( rc==SQLITE_OK ){ + bUnlock = 1; + rc = sqlite3BtreeCommit(pBt); + } + } + }else{ + rc = SQLITE_OK; + } if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); - sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0); + rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot); + } + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); + sqlite3PagerSnapshotOpen(pPager, 0); + } + if( bUnlock ){ + sqlite3PagerSnapshotUnlock(pPager); } } } @@ -149232,7 +157003,7 @@ SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); sqlite3BtreeCommit(pBt); @@ -150800,7 +158571,7 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, ); SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST -SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); +SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*); SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); #endif @@ -152368,7 +160139,7 @@ static int fts3ScanInteriorNode( const char *zCsr = zNode; /* Cursor to iterate through node */ const char *zEnd = &zCsr[nNode];/* End of interior node buffer */ char *zBuffer = 0; /* Buffer to load terms into */ - int nAlloc = 0; /* Size of allocated buffer */ + i64 nAlloc = 0; /* Size of allocated buffer */ int isFirstTerm = 1; /* True when processing first term on page */ sqlite3_int64 iChild; /* Block id of child node to descend to */ @@ -152406,14 +160177,14 @@ static int fts3ScanInteriorNode( zCsr += fts3GetVarint32(zCsr, &nSuffix); assert( nPrefix>=0 && nSuffix>=0 ); - if( &zCsr[nSuffix]>zEnd ){ + if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } - if( nPrefix+nSuffix>nAlloc ){ + if( (i64)nPrefix+nSuffix>nAlloc ){ char *zNew; - nAlloc = (nPrefix+nSuffix) * 2; - zNew = (char *)sqlite3_realloc(zBuffer, nAlloc); + nAlloc = ((i64)nPrefix+nSuffix) * 2; + zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc); if( !zNew ){ rc = SQLITE_NOMEM; goto finish_scan; @@ -154355,7 +162126,7 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ int rc = SQLITE_OK; UNUSED_PARAMETER(iSavepoint); assert( ((Fts3Table *)pVtab)->inTransaction ); - assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint ); + assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint ); TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint ); if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){ rc = fts3SyncMethod(pVtab); @@ -154393,8 +162164,23 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ return SQLITE_OK; } +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int fts3ShadowName(const char *zName){ + static const char *azName[] = { + "content", "docsize", "segdir", "segments", "stat", + }; + unsigned int i; + for(i=0; i */ -/* -** Function to query the hash-table of tokenizers (see README.tokenizers). -*/ -static int queryTestTokenizer( - sqlite3 *db, - const char *zName, - const sqlite3_tokenizer_module **pp -){ - int rc; - sqlite3_stmt *pStmt; - const char zSql[] = "SELECT fts3_tokenizer(?)"; - - *pp = 0; - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ){ - return rc; - } - - sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){ - memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); - } - } - - return sqlite3_finalize(pStmt); -} - /* ** Return a pointer to a buffer containing a text representation of the ** expression passed as the first argument. The buffer is obtained from @@ -158265,12 +166027,12 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){ ** ** SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2'); */ -static void fts3ExprTest( +static void fts3ExprTestCommon( + int bRebalance, sqlite3_context *context, int argc, sqlite3_value **argv ){ - sqlite3_tokenizer_module const *pModule = 0; sqlite3_tokenizer *pTokenizer = 0; int rc; char **azCol = 0; @@ -158280,7 +166042,9 @@ static void fts3ExprTest( int ii; Fts3Expr *pExpr; char *zBuf = 0; - sqlite3 *db = sqlite3_context_db_handle(context); + Fts3Hash *pHash = (Fts3Hash*)sqlite3_user_data(context); + const char *zTokenizer = 0; + char *zErr = 0; if( argc<3 ){ sqlite3_result_error(context, @@ -158289,24 +166053,18 @@ static void fts3ExprTest( return; } - rc = queryTestTokenizer(db, - (const char *)sqlite3_value_text(argv[0]), &pModule); - if( rc==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(context); - goto exprtest_out; - }else if( !pModule ){ - sqlite3_result_error(context, "No such tokenizer module", -1); - goto exprtest_out; + zTokenizer = (const char*)sqlite3_value_text(argv[0]); + rc = sqlite3Fts3InitTokenizer(pHash, zTokenizer, &pTokenizer, &zErr); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_error(context, zErr, -1); + } + sqlite3_free(zErr); + return; } - rc = pModule->xCreate(0, 0, &pTokenizer); - assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); - if( rc==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(context); - goto exprtest_out; - } - pTokenizer->pModule = pModule; - zExpr = (const char *)sqlite3_value_text(argv[1]); nExpr = sqlite3_value_bytes(argv[1]); nCol = argc-2; @@ -158319,7 +166077,7 @@ static void fts3ExprTest( azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); } - if( sqlite3_user_data(context) ){ + if( bRebalance ){ char *zDummy = 0; rc = sqlite3Fts3ExprParse( pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr, &zDummy @@ -158345,23 +166103,38 @@ static void fts3ExprTest( sqlite3Fts3ExprFree(pExpr); exprtest_out: - if( pModule && pTokenizer ){ - rc = pModule->xDestroy(pTokenizer); + if( pTokenizer ){ + rc = pTokenizer->pModule->xDestroy(pTokenizer); } sqlite3_free(azCol); } +static void fts3ExprTest( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + fts3ExprTestCommon(0, context, argc, argv); +} +static void fts3ExprTestRebalance( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + fts3ExprTestCommon(1, context, argc, argv); +} + /* ** Register the query expression parser test function fts3_exprtest() ** with database connection db. */ -SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){ +SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash *pHash){ int rc = sqlite3_create_function( - db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0 + db, "fts3_exprtest", -1, SQLITE_UTF8, (void*)pHash, fts3ExprTest, 0, 0 ); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "fts3_exprtest_rebalance", - -1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0 + -1, SQLITE_UTF8, (void*)pHash, fts3ExprTestRebalance, 0, 0 ); } return rc; @@ -160624,7 +168397,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; int rc; /* Return code */ @@ -162012,15 +169786,19 @@ static int fts3SegReaderNext( ** safe (no risk of overread) even if the node data is corrupted. */ pNext += fts3GetVarint32(pNext, &nPrefix); pNext += fts3GetVarint32(pNext, &nSuffix); - if( nPrefix<0 || nSuffix<=0 - || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] + if( nSuffix<=0 + || (&pReader->aNode[pReader->nNode] - pNext)pReader->nTermAlloc ){ return FTS_CORRUPT_VTAB; } - if( nPrefix+nSuffix>pReader->nTermAlloc ){ - int nNew = (nPrefix+nSuffix)*2; - char *zNew = sqlite3_realloc(pReader->zTerm, nNew); + /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are + ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer + ** overflow - hence the (i64) casts. */ + if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){ + i64 nNew = ((i64)nPrefix+nSuffix)*2; + char *zNew = sqlite3_realloc64(pReader->zTerm, nNew); if( !zNew ){ return SQLITE_NOMEM; } @@ -162042,7 +169820,7 @@ static int fts3SegReaderNext( ** b-tree node. And that the final byte of the doclist is 0x00. If either ** of these statements is untrue, then the data structure is corrupt. */ - if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] + if( (&pReader->aNode[pReader->nNode] - pReader->aDoclist)nDoclist || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) ){ return FTS_CORRUPT_VTAB; @@ -164368,6 +172146,9 @@ static int nodeReaderNext(NodeReader *p){ } p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); + if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){ + return SQLITE_CORRUPT_VTAB; + } blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); if( rc==SQLITE_OK ){ memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); @@ -164375,6 +172156,9 @@ static int nodeReaderNext(NodeReader *p){ p->iOff += nSuffix; if( p->iChild==0 ){ p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist); + if( (p->nNode-p->iOff)nDoclist ){ + return SQLITE_CORRUPT_VTAB; + } p->aDoclist = &p->aNode[p->iOff]; p->iOff += p->nDoclist; } @@ -164382,7 +172166,6 @@ static int nodeReaderNext(NodeReader *p){ } assert( p->iOff<=p->nNode ); - return rc; } @@ -168795,6 +176578,2550 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ #endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */ /************** End of fts3_unicode2.c ***************************************/ +/************** Begin file json1.c *******************************************/ +/* +** 2015-08-12 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This SQLite extension implements JSON functions. The interface is +** modeled after MySQL JSON functions: +** +** https://dev.mysql.com/doc/refman/5.7/en/json.html +** +** For the time being, all JSON is stored as pure text. (We might add +** a JSONB type in the future which stores a binary encoding of JSON in +** a BLOB, but there is no support for JSONB in the current implementation. +** This implementation parses JSON text at 250 MB/s, so it is hard to see +** how JSONB might improve on that.) +*/ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) +#if !defined(SQLITEINT_H) +/* #include "sqlite3ext.h" */ +#endif +SQLITE_EXTENSION_INIT1 +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +/* Mark a function parameter as unused, to suppress nuisance compiler +** warnings. */ +#ifndef UNUSED_PARAM +# define UNUSED_PARAM(X) (void)(X) +#endif + +#ifndef LARGEST_INT64 +# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) +# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) +#endif + +/* +** Versions of isspace(), isalnum() and isdigit() to which it is safe +** to pass signed char values. +*/ +#ifdef sqlite3Isdigit + /* Use the SQLite core versions if this routine is part of the + ** SQLite amalgamation */ +# define safe_isdigit(x) sqlite3Isdigit(x) +# define safe_isalnum(x) sqlite3Isalnum(x) +# define safe_isxdigit(x) sqlite3Isxdigit(x) +#else + /* Use the standard library for separate compilation */ +#include /* amalgamator: keep */ +# define safe_isdigit(x) isdigit((unsigned char)(x)) +# define safe_isalnum(x) isalnum((unsigned char)(x)) +# define safe_isxdigit(x) isxdigit((unsigned char)(x)) +#endif + +/* +** Growing our own isspace() routine this way is twice as fast as +** the library isspace() function, resulting in a 7% overall performance +** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). +*/ +static const char jsonIsSpace[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define safe_isspace(x) (jsonIsSpace[(unsigned char)x]) + +#ifndef SQLITE_AMALGAMATION + /* Unsigned integer types. These are already defined in the sqliteInt.h, + ** but the definitions need to be repeated for separate compilation. */ + typedef sqlite3_uint64 u64; + typedef unsigned int u32; + typedef unsigned short int u16; + typedef unsigned char u8; +#endif + +/* Objects */ +typedef struct JsonString JsonString; +typedef struct JsonNode JsonNode; +typedef struct JsonParse JsonParse; + +/* An instance of this object represents a JSON string +** under construction. Really, this is a generic string accumulator +** that can be and is used to create strings other than JSON. +*/ +struct JsonString { + sqlite3_context *pCtx; /* Function context - put error messages here */ + char *zBuf; /* Append JSON content here */ + u64 nAlloc; /* Bytes of storage available in zBuf[] */ + u64 nUsed; /* Bytes of zBuf[] currently used */ + u8 bStatic; /* True if zBuf is static space */ + u8 bErr; /* True if an error has been encountered */ + char zSpace[100]; /* Initial static space */ +}; + +/* JSON type values +*/ +#define JSON_NULL 0 +#define JSON_TRUE 1 +#define JSON_FALSE 2 +#define JSON_INT 3 +#define JSON_REAL 4 +#define JSON_STRING 5 +#define JSON_ARRAY 6 +#define JSON_OBJECT 7 + +/* The "subtype" set for JSON values */ +#define JSON_SUBTYPE 74 /* Ascii for "J" */ + +/* +** Names of the various JSON types: +*/ +static const char * const jsonType[] = { + "null", "true", "false", "integer", "real", "text", "array", "object" +}; + +/* Bit values for the JsonNode.jnFlag field +*/ +#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ +#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ +#define JNODE_REMOVE 0x04 /* Do not output */ +#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */ +#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */ +#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */ +#define JNODE_LABEL 0x40 /* Is a label of an object */ + + +/* A single node of parsed JSON +*/ +struct JsonNode { + u8 eType; /* One of the JSON_ type values */ + u8 jnFlags; /* JNODE flags */ + u32 n; /* Bytes of content, or number of sub-nodes */ + union { + const char *zJContent; /* Content for INT, REAL, and STRING */ + u32 iAppend; /* More terms for ARRAY and OBJECT */ + u32 iKey; /* Key for ARRAY objects in json_tree() */ + u32 iReplace; /* Replacement content for JNODE_REPLACE */ + JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */ + } u; +}; + +/* A completely parsed JSON string +*/ +struct JsonParse { + u32 nNode; /* Number of slots of aNode[] used */ + u32 nAlloc; /* Number of slots of aNode[] allocated */ + JsonNode *aNode; /* Array of nodes containing the parse */ + const char *zJson; /* Original JSON string */ + u32 *aUp; /* Index of parent of each node */ + u8 oom; /* Set to true if out of memory */ + u8 nErr; /* Number of errors seen */ + u16 iDepth; /* Nesting depth */ + int nJson; /* Length of the zJson string in bytes */ + u32 iHold; /* Replace cache line with the lowest iHold value */ +}; + +/* +** Maximum nesting depth of JSON for this implementation. +** +** This limit is needed to avoid a stack overflow in the recursive +** descent parser. A depth of 2000 is far deeper than any sane JSON +** should go. +*/ +#define JSON_MAX_DEPTH 2000 + +/************************************************************************** +** Utility routines for dealing with JsonString objects +**************************************************************************/ + +/* Set the JsonString object to an empty string +*/ +static void jsonZero(JsonString *p){ + p->zBuf = p->zSpace; + p->nAlloc = sizeof(p->zSpace); + p->nUsed = 0; + p->bStatic = 1; +} + +/* Initialize the JsonString object +*/ +static void jsonInit(JsonString *p, sqlite3_context *pCtx){ + p->pCtx = pCtx; + p->bErr = 0; + jsonZero(p); +} + + +/* Free all allocated memory and reset the JsonString object back to its +** initial state. +*/ +static void jsonReset(JsonString *p){ + if( !p->bStatic ) sqlite3_free(p->zBuf); + jsonZero(p); +} + + +/* Report an out-of-memory (OOM) condition +*/ +static void jsonOom(JsonString *p){ + p->bErr = 1; + sqlite3_result_error_nomem(p->pCtx); + jsonReset(p); +} + +/* Enlarge pJson->zBuf so that it can hold at least N more bytes. +** Return zero on success. Return non-zero on an OOM error +*/ +static int jsonGrow(JsonString *p, u32 N){ + u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; + char *zNew; + if( p->bStatic ){ + if( p->bErr ) return 1; + zNew = sqlite3_malloc64(nTotal); + if( zNew==0 ){ + jsonOom(p); + return SQLITE_NOMEM; + } + memcpy(zNew, p->zBuf, (size_t)p->nUsed); + p->zBuf = zNew; + p->bStatic = 0; + }else{ + zNew = sqlite3_realloc64(p->zBuf, nTotal); + if( zNew==0 ){ + jsonOom(p); + return SQLITE_NOMEM; + } + p->zBuf = zNew; + } + p->nAlloc = nTotal; + return SQLITE_OK; +} + +/* Append N bytes from zIn onto the end of the JsonString string. +*/ +static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ + if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; + memcpy(p->zBuf+p->nUsed, zIn, N); + p->nUsed += N; +} + +/* Append formatted text (not to exceed N bytes) to the JsonString. +*/ +static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ + va_list ap; + if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; + va_start(ap, zFormat); + sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); + va_end(ap); + p->nUsed += (int)strlen(p->zBuf+p->nUsed); +} + +/* Append a single character +*/ +static void jsonAppendChar(JsonString *p, char c){ + if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; + p->zBuf[p->nUsed++] = c; +} + +/* Append a comma separator to the output buffer, if the previous +** character is not '[' or '{'. +*/ +static void jsonAppendSeparator(JsonString *p){ + char c; + if( p->nUsed==0 ) return; + c = p->zBuf[p->nUsed-1]; + if( c!='[' && c!='{' ) jsonAppendChar(p, ','); +} + +/* Append the N-byte string in zIn to the end of the JsonString string +** under construction. Enclose the string in "..." and escape +** any double-quotes or backslash characters contained within the +** string. +*/ +static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ + u32 i; + if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; + p->zBuf[p->nUsed++] = '"'; + for(i=0; inUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + }else if( c<=0x1f ){ + static const char aSpecial[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + assert( sizeof(aSpecial)==32 ); + assert( aSpecial['\b']=='b' ); + assert( aSpecial['\f']=='f' ); + assert( aSpecial['\n']=='n' ); + assert( aSpecial['\r']=='r' ); + assert( aSpecial['\t']=='t' ); + if( aSpecial[c] ){ + c = aSpecial[c]; + goto json_simple_escape; + } + if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + p->zBuf[p->nUsed++] = 'u'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0' + (c>>4); + c = "0123456789abcdef"[c&0xf]; + } + p->zBuf[p->nUsed++] = c; + } + p->zBuf[p->nUsed++] = '"'; + assert( p->nUsednAlloc ); +} + +/* +** Append a function parameter value to the JSON string under +** construction. +*/ +static void jsonAppendValue( + JsonString *p, /* Append to this JSON string */ + sqlite3_value *pValue /* Value to append */ +){ + switch( sqlite3_value_type(pValue) ){ + case SQLITE_NULL: { + jsonAppendRaw(p, "null", 4); + break; + } + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + const char *z = (const char*)sqlite3_value_text(pValue); + u32 n = (u32)sqlite3_value_bytes(pValue); + jsonAppendRaw(p, z, n); + break; + } + case SQLITE_TEXT: { + const char *z = (const char*)sqlite3_value_text(pValue); + u32 n = (u32)sqlite3_value_bytes(pValue); + if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ + jsonAppendRaw(p, z, n); + }else{ + jsonAppendString(p, z, n); + } + break; + } + default: { + if( p->bErr==0 ){ + sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); + p->bErr = 2; + jsonReset(p); + } + break; + } + } +} + + +/* Make the JSON in p the result of the SQL function. +*/ +static void jsonResult(JsonString *p){ + if( p->bErr==0 ){ + sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, + p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, + SQLITE_UTF8); + jsonZero(p); + } + assert( p->bStatic ); +} + +/************************************************************************** +** Utility routines for dealing with JsonNode and JsonParse objects +**************************************************************************/ + +/* +** Return the number of consecutive JsonNode slots need to represent +** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and +** OBJECT types, the number might be larger. +** +** Appended elements are not counted. The value returned is the number +** by which the JsonNode counter should increment in order to go to the +** next peer value. +*/ +static u32 jsonNodeSize(JsonNode *pNode){ + return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; +} + +/* +** Reclaim all memory allocated by a JsonParse object. But do not +** delete the JsonParse object itself. +*/ +static void jsonParseReset(JsonParse *pParse){ + sqlite3_free(pParse->aNode); + pParse->aNode = 0; + pParse->nNode = 0; + pParse->nAlloc = 0; + sqlite3_free(pParse->aUp); + pParse->aUp = 0; +} + +/* +** Free a JsonParse object that was obtained from sqlite3_malloc(). +*/ +static void jsonParseFree(JsonParse *pParse){ + jsonParseReset(pParse); + sqlite3_free(pParse); +} + +/* +** Convert the JsonNode pNode into a pure JSON string and +** append to pOut. Subsubstructure is also included. Return +** the number of JsonNode objects that are encoded. +*/ +static void jsonRenderNode( + JsonNode *pNode, /* The node to render */ + JsonString *pOut, /* Write JSON here */ + sqlite3_value **aReplace /* Replacement values */ +){ + if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){ + if( pNode->jnFlags & JNODE_REPLACE ){ + jsonAppendValue(pOut, aReplace[pNode->u.iReplace]); + return; + } + pNode = pNode->u.pPatch; + } + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + jsonAppendRaw(pOut, "null", 4); + break; + } + case JSON_TRUE: { + jsonAppendRaw(pOut, "true", 4); + break; + } + case JSON_FALSE: { + jsonAppendRaw(pOut, "false", 5); + break; + } + case JSON_STRING: { + if( pNode->jnFlags & JNODE_RAW ){ + jsonAppendString(pOut, pNode->u.zJContent, pNode->n); + break; + } + /* Fall through into the next case */ + } + case JSON_REAL: + case JSON_INT: { + jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); + break; + } + case JSON_ARRAY: { + u32 j = 1; + jsonAppendChar(pOut, '['); + for(;;){ + while( j<=pNode->n ){ + if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){ + jsonAppendSeparator(pOut); + jsonRenderNode(&pNode[j], pOut, aReplace); + } + j += jsonNodeSize(&pNode[j]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + pNode = &pNode[pNode->u.iAppend]; + j = 1; + } + jsonAppendChar(pOut, ']'); + break; + } + case JSON_OBJECT: { + u32 j = 1; + jsonAppendChar(pOut, '{'); + for(;;){ + while( j<=pNode->n ){ + if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){ + jsonAppendSeparator(pOut); + jsonRenderNode(&pNode[j], pOut, aReplace); + jsonAppendChar(pOut, ':'); + jsonRenderNode(&pNode[j+1], pOut, aReplace); + } + j += 1 + jsonNodeSize(&pNode[j+1]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + pNode = &pNode[pNode->u.iAppend]; + j = 1; + } + jsonAppendChar(pOut, '}'); + break; + } + } +} + +/* +** Return a JsonNode and all its descendents as a JSON string. +*/ +static void jsonReturnJson( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ +){ + JsonString s; + jsonInit(&s, pCtx); + jsonRenderNode(pNode, &s, aReplace); + jsonResult(&s); + sqlite3_result_subtype(pCtx, JSON_SUBTYPE); +} + +/* +** Make the JsonNode the return value of the function. +*/ +static void jsonReturn( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ +){ + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + sqlite3_result_null(pCtx); + break; + } + case JSON_TRUE: { + sqlite3_result_int(pCtx, 1); + break; + } + case JSON_FALSE: { + sqlite3_result_int(pCtx, 0); + break; + } + case JSON_INT: { + sqlite3_int64 i = 0; + const char *z = pNode->u.zJContent; + if( z[0]=='-' ){ z++; } + while( z[0]>='0' && z[0]<='9' ){ + unsigned v = *(z++) - '0'; + if( i>=LARGEST_INT64/10 ){ + if( i>LARGEST_INT64/10 ) goto int_as_real; + if( z[0]>='0' && z[0]<='9' ) goto int_as_real; + if( v==9 ) goto int_as_real; + if( v==8 ){ + if( pNode->u.zJContent[0]=='-' ){ + sqlite3_result_int64(pCtx, SMALLEST_INT64); + goto int_done; + }else{ + goto int_as_real; + } + } + } + i = i*10 + v; + } + if( pNode->u.zJContent[0]=='-' ){ i = -i; } + sqlite3_result_int64(pCtx, i); + int_done: + break; + int_as_real: /* fall through to real */; + } + case JSON_REAL: { + double r; +#ifdef SQLITE_AMALGAMATION + const char *z = pNode->u.zJContent; + sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); +#else + r = strtod(pNode->u.zJContent, 0); +#endif + sqlite3_result_double(pCtx, r); + break; + } + case JSON_STRING: { +#if 0 /* Never happens because JNODE_RAW is only set by json_set(), + ** json_insert() and json_replace() and those routines do not + ** call jsonReturn() */ + if( pNode->jnFlags & JNODE_RAW ){ + sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, + SQLITE_TRANSIENT); + }else +#endif + assert( (pNode->jnFlags & JNODE_RAW)==0 ); + if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ + /* JSON formatted without any backslash-escapes */ + sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, + SQLITE_TRANSIENT); + }else{ + /* Translate JSON formatted string into raw text */ + u32 i; + u32 n = pNode->n; + const char *z = pNode->u.zJContent; + char *zOut; + u32 j; + zOut = sqlite3_malloc( n+1 ); + if( zOut==0 ){ + sqlite3_result_error_nomem(pCtx); + break; + } + for(i=1, j=0; i>6)); + zOut[j++] = 0x80 | (v&0x3f); + }else{ + zOut[j++] = (char)(0xe0 | (v>>12)); + zOut[j++] = 0x80 | ((v>>6)&0x3f); + zOut[j++] = 0x80 | (v&0x3f); + } + }else{ + if( c=='b' ){ + c = '\b'; + }else if( c=='f' ){ + c = '\f'; + }else if( c=='n' ){ + c = '\n'; + }else if( c=='r' ){ + c = '\r'; + }else if( c=='t' ){ + c = '\t'; + } + zOut[j++] = c; + } + } + } + zOut[j] = 0; + sqlite3_result_text(pCtx, zOut, j, sqlite3_free); + } + break; + } + case JSON_ARRAY: + case JSON_OBJECT: { + jsonReturnJson(pNode, pCtx, aReplace); + break; + } + } +} + +/* Forward reference */ +static int jsonParseAddNode(JsonParse*,u32,u32,const char*); + +/* +** A macro to hint to the compiler that a function should not be +** inlined. +*/ +#if defined(__GNUC__) +# define JSON_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define JSON_NOINLINE __declspec(noinline) +#else +# define JSON_NOINLINE +#endif + + +static JSON_NOINLINE int jsonParseAddNodeExpand( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + u32 nNew; + JsonNode *pNew; + assert( pParse->nNode>=pParse->nAlloc ); + if( pParse->oom ) return -1; + nNew = pParse->nAlloc*2 + 10; + pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); + if( pNew==0 ){ + pParse->oom = 1; + return -1; + } + pParse->nAlloc = nNew; + pParse->aNode = pNew; + assert( pParse->nNodenAlloc ); + return jsonParseAddNode(pParse, eType, n, zContent); +} + +/* +** Create a new JsonNode instance based on the arguments and append that +** instance to the JsonParse. Return the index in pParse->aNode[] of the +** new node, or -1 if a memory allocation fails. +*/ +static int jsonParseAddNode( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + JsonNode *p; + if( pParse->nNode>=pParse->nAlloc ){ + return jsonParseAddNodeExpand(pParse, eType, n, zContent); + } + p = &pParse->aNode[pParse->nNode]; + p->eType = (u8)eType; + p->jnFlags = 0; + p->n = n; + p->u.zJContent = zContent; + return pParse->nNode++; +} + +/* +** Return true if z[] begins with 4 (or more) hexadecimal digits +*/ +static int jsonIs4Hex(const char *z){ + int i; + for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0; + return 1; +} + +/* +** Parse a single JSON value which begins at pParse->zJson[i]. Return the +** index of the first character past the end of the value parsed. +** +** Return negative for a syntax error. Special cases: return -2 if the +** first non-whitespace character is '}' and return -3 if the first +** non-whitespace character is ']'. +*/ +static int jsonParseValue(JsonParse *pParse, u32 i){ + char c; + u32 j; + int iThis; + int x; + JsonNode *pNode; + const char *z = pParse->zJson; + while( safe_isspace(z[i]) ){ i++; } + if( (c = z[i])=='{' ){ + /* Parse object */ + iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + if( iThis<0 ) return -1; + for(j=i+1;;j++){ + while( safe_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; + x = jsonParseValue(pParse, j); + if( x<0 ){ + pParse->iDepth--; + if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } + if( pParse->oom ) return -1; + pNode = &pParse->aNode[pParse->nNode-1]; + if( pNode->eType!=JSON_STRING ) return -1; + pNode->jnFlags |= JNODE_LABEL; + j = x; + while( safe_isspace(z[j]) ){ j++; } + if( z[j]!=':' ) return -1; + j++; + x = jsonParseValue(pParse, j); + pParse->iDepth--; + if( x<0 ) return -1; + j = x; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; + if( c==',' ) continue; + if( c!='}' ) return -1; + break; + } + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; + return j+1; + }else if( c=='[' ){ + /* Parse array */ + iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + if( iThis<0 ) return -1; + for(j=i+1;;j++){ + while( safe_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; + x = jsonParseValue(pParse, j); + pParse->iDepth--; + if( x<0 ){ + if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } + j = x; + while( safe_isspace(z[j]) ){ j++; } + c = z[j]; + if( c==',' ) continue; + if( c!=']' ) return -1; + break; + } + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; + return j+1; + }else if( c=='"' ){ + /* Parse string */ + u8 jnFlags = 0; + j = i+1; + for(;;){ + c = z[j]; + if( (c & ~0x1f)==0 ){ + /* Control characters are not allowed in strings */ + return -1; + } + if( c=='\\' ){ + c = z[++j]; + if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' + || c=='n' || c=='r' || c=='t' + || (c=='u' && jsonIs4Hex(z+j+1)) ){ + jnFlags = JNODE_ESCAPE; + }else{ + return -1; + } + }else if( c=='"' ){ + break; + } + j++; + } + jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); + if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; + return j+1; + }else if( c=='n' + && strncmp(z+i,"null",4)==0 + && !safe_isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return i+4; + }else if( c=='t' + && strncmp(z+i,"true",4)==0 + && !safe_isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + return i+4; + }else if( c=='f' + && strncmp(z+i,"false",5)==0 + && !safe_isalnum(z[i+5]) ){ + jsonParseAddNode(pParse, JSON_FALSE, 0, 0); + return i+5; + }else if( c=='-' || (c>='0' && c<='9') ){ + /* Parse number */ + u8 seenDP = 0; + u8 seenE = 0; + assert( '-' < '0' ); + if( c<='0' ){ + j = c=='-' ? i+1 : i; + if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; + } + j = i+1; + for(;; j++){ + c = z[j]; + if( c>='0' && c<='9' ) continue; + if( c=='.' ){ + if( z[j-1]=='-' ) return -1; + if( seenDP ) return -1; + seenDP = 1; + continue; + } + if( c=='e' || c=='E' ){ + if( z[j-1]<'0' ) return -1; + if( seenE ) return -1; + seenDP = seenE = 1; + c = z[j+1]; + if( c=='+' || c=='-' ){ + j++; + c = z[j+1]; + } + if( c<'0' || c>'9' ) return -1; + continue; + } + break; + } + if( z[j-1]<'0' ) return -1; + jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, + j - i, &z[i]); + return j; + }else if( c=='}' ){ + return -2; /* End of {...} */ + }else if( c==']' ){ + return -3; /* End of [...] */ + }else if( c==0 ){ + return 0; /* End of file */ + }else{ + return -1; /* Syntax error */ + } +} + +/* +** Parse a complete JSON string. Return 0 on success or non-zero if there +** are any errors. If an error occurs, free all memory associated with +** pParse. +** +** pParse is uninitialized when this routine is called. +*/ +static int jsonParse( + JsonParse *pParse, /* Initialize and fill this JsonParse object */ + sqlite3_context *pCtx, /* Report errors here */ + const char *zJson /* Input JSON text to be parsed */ +){ + int i; + memset(pParse, 0, sizeof(*pParse)); + if( zJson==0 ) return 1; + pParse->zJson = zJson; + i = jsonParseValue(pParse, 0); + if( pParse->oom ) i = -1; + if( i>0 ){ + assert( pParse->iDepth==0 ); + while( safe_isspace(zJson[i]) ) i++; + if( zJson[i] ) i = -1; + } + if( i<=0 ){ + if( pCtx!=0 ){ + if( pParse->oom ){ + sqlite3_result_error_nomem(pCtx); + }else{ + sqlite3_result_error(pCtx, "malformed JSON", -1); + } + } + jsonParseReset(pParse); + return 1; + } + return 0; +} + +/* Mark node i of pParse as being a child of iParent. Call recursively +** to fill in all the descendants of node i. +*/ +static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ + JsonNode *pNode = &pParse->aNode[i]; + u32 j; + pParse->aUp[i] = iParent; + switch( pNode->eType ){ + case JSON_ARRAY: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ + jsonParseFillInParentage(pParse, i+j, i); + } + break; + } + case JSON_OBJECT: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ + pParse->aUp[i+j] = i; + jsonParseFillInParentage(pParse, i+j+1, i); + } + break; + } + default: { + break; + } + } +} + +/* +** Compute the parentage of all nodes in a completed parse. +*/ +static int jsonParseFindParents(JsonParse *pParse){ + u32 *aUp; + assert( pParse->aUp==0 ); + aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode ); + if( aUp==0 ){ + pParse->oom = 1; + return SQLITE_NOMEM; + } + jsonParseFillInParentage(pParse, 0, 0); + return SQLITE_OK; +} + +/* +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() +*/ +#define JSON_CACHE_ID (-429938) /* First cache entry */ +#define JSON_CACHE_SZ 4 /* Max number of cache entries */ + +/* +** Obtain a complete parse of the JSON found in the first argument +** of the argv array. Use the sqlite3_get_auxdata() cache for this +** parse if it is available. If the cache is not available or if it +** is no longer valid, parse the JSON again and return the new parse, +** and also register the new parse so that it will be available for +** future sqlite3_get_auxdata() calls. +*/ +static JsonParse *jsonParseCached( + sqlite3_context *pCtx, + sqlite3_value **argv, + sqlite3_context *pErrCtx +){ + const char *zJson = (const char*)sqlite3_value_text(argv[0]); + int nJson = sqlite3_value_bytes(argv[0]); + JsonParse *p; + JsonParse *pMatch = 0; + int iKey; + int iMinKey = 0; + u32 iMinHold = 0xffffffff; + u32 iMaxHold = 0; + if( zJson==0 ) return 0; + for(iKey=0; iKeynJson==nJson + && memcmp(p->zJson,zJson,nJson)==0 + ){ + p->nErr = 0; + pMatch = p; + }else if( p->iHoldiHold; + iMinKey = iKey; + } + if( p->iHold>iMaxHold ){ + iMaxHold = p->iHold; + } + } + if( pMatch ){ + pMatch->nErr = 0; + pMatch->iHold = iMaxHold+1; + return pMatch; + } + p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } + memset(p, 0, sizeof(*p)); + p->zJson = (char*)&p[1]; + memcpy((char*)p->zJson, zJson, nJson+1); + if( jsonParse(p, pErrCtx, p->zJson) ){ + sqlite3_free(p); + return 0; + } + p->nJson = nJson; + p->iHold = iMaxHold+1; + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, + (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); +} + +/* +** Compare the OBJECT label at pNode against zKey,nKey. Return true on +** a match. +*/ +static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ + if( pNode->jnFlags & JNODE_RAW ){ + if( pNode->n!=nKey ) return 0; + return strncmp(pNode->u.zJContent, zKey, nKey)==0; + }else{ + if( pNode->n!=nKey+2 ) return 0; + return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; + } +} + +/* forward declaration */ +static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); + +/* +** Search along zPath to find the node specified. Return a pointer +** to that node, or NULL if zPath is malformed or if there is no such +** node. +** +** If pApnd!=0, then try to append new nodes to complete zPath if it is +** possible to do so and if no existing node corresponds to zPath. If +** new nodes are appended *pApnd is set to 1. +*/ +static JsonNode *jsonLookupStep( + JsonParse *pParse, /* The JSON to search */ + u32 iRoot, /* Begin the search at this node */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + const char **pzErr /* Make *pzErr point to any syntax error in zPath */ +){ + u32 i, j, nKey; + const char *zKey; + JsonNode *pRoot = &pParse->aNode[iRoot]; + if( zPath[0]==0 ) return pRoot; + if( zPath[0]=='.' ){ + if( pRoot->eType!=JSON_OBJECT ) return 0; + zPath++; + if( zPath[0]=='"' ){ + zKey = zPath + 1; + for(i=1; zPath[i] && zPath[i]!='"'; i++){} + nKey = i-1; + if( zPath[i] ){ + i++; + }else{ + *pzErr = zPath; + return 0; + } + }else{ + zKey = zPath; + for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} + nKey = i; + } + if( nKey==0 ){ + *pzErr = zPath; + return 0; + } + j = 1; + for(;;){ + while( j<=pRoot->n ){ + if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ + return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); + } + j++; + j += jsonNodeSize(&pRoot[j]); + } + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + iRoot += pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; + } + if( pApnd ){ + u32 iStart, iLabel; + JsonNode *pNode; + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); + iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); + zPath += i; + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + pRoot->u.iAppend = iStart - iRoot; + pRoot->jnFlags |= JNODE_APPEND; + pParse->aNode[iLabel].jnFlags |= JNODE_RAW; + } + return pNode; + } + }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){ + if( pRoot->eType!=JSON_ARRAY ) return 0; + i = 0; + j = 1; + while( safe_isdigit(zPath[j]) ){ + i = i*10 + zPath[j] - '0'; + j++; + } + if( zPath[j]!=']' ){ + *pzErr = zPath; + return 0; + } + zPath += j + 1; + j = 1; + for(;;){ + while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ + if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--; + j += jsonNodeSize(&pRoot[j]); + } + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + iRoot += pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; + } + if( j<=pRoot->n ){ + return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); + } + if( i==0 && pApnd ){ + u32 iStart; + JsonNode *pNode; + iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + pRoot->u.iAppend = iStart - iRoot; + pRoot->jnFlags |= JNODE_APPEND; + } + return pNode; + } + }else{ + *pzErr = zPath; + } + return 0; +} + +/* +** Append content to pParse that will complete zPath. Return a pointer +** to the inserted node, or return NULL if the append fails. +*/ +static JsonNode *jsonLookupAppend( + JsonParse *pParse, /* Append content to the JSON parse */ + const char *zPath, /* Description of content to append */ + int *pApnd, /* Set this flag to 1 */ + const char **pzErr /* Make this point to any syntax error */ +){ + *pApnd = 1; + if( zPath[0]==0 ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; + } + if( zPath[0]=='.' ){ + jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + }else if( strncmp(zPath,"[0]",3)==0 ){ + jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + }else{ + return 0; + } + if( pParse->oom ) return 0; + return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); +} + +/* +** Return the text of a syntax error message on a JSON path. Space is +** obtained from sqlite3_malloc(). +*/ +static char *jsonPathSyntaxError(const char *zErr){ + return sqlite3_mprintf("JSON path error near '%q'", zErr); +} + +/* +** Do a node lookup using zPath. Return a pointer to the node on success. +** Return NULL if not found or if there is an error. +** +** On an error, write an error message into pCtx and increment the +** pParse->nErr counter. +** +** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if +** nodes are appended. +*/ +static JsonNode *jsonLookup( + JsonParse *pParse, /* The JSON to search */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + sqlite3_context *pCtx /* Report errors here, if not NULL */ +){ + const char *zErr = 0; + JsonNode *pNode = 0; + char *zMsg; + + if( zPath==0 ) return 0; + if( zPath[0]!='$' ){ + zErr = zPath; + goto lookup_err; + } + zPath++; + pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); + if( zErr==0 ) return pNode; + +lookup_err: + pParse->nErr++; + assert( zErr!=0 && pCtx!=0 ); + zMsg = jsonPathSyntaxError(zErr); + if( zMsg ){ + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); + }else{ + sqlite3_result_error_nomem(pCtx); + } + return 0; +} + + +/* +** Report the wrong number of arguments for json_insert(), json_replace() +** or json_set(). +*/ +static void jsonWrongNumArgs( + sqlite3_context *pCtx, + const char *zFuncName +){ + char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", + zFuncName); + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); +} + +/* +** Mark all NULL entries in the Object passed in as JNODE_REMOVE. +*/ +static void jsonRemoveAllNulls(JsonNode *pNode){ + int i, n; + assert( pNode->eType==JSON_OBJECT ); + n = pNode->n; + for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){ + switch( pNode[i].eType ){ + case JSON_NULL: + pNode[i].jnFlags |= JNODE_REMOVE; + break; + case JSON_OBJECT: + jsonRemoveAllNulls(&pNode[i]); + break; + } + } +} + + +/**************************************************************************** +** SQL functions used for testing and debugging +****************************************************************************/ + +#ifdef SQLITE_DEBUG +/* +** The json_parse(JSON) function returns a string which describes +** a parse of the JSON provided. Or it returns NULL if JSON is not +** well-formed. +*/ +static void jsonParseFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString s; /* Output string - not real JSON */ + JsonParse x; /* The parse */ + u32 i; + + assert( argc==1 ); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + jsonParseFindParents(&x); + jsonInit(&s, ctx); + for(i=0; inNode ); + if( argc==2 ){ + const char *zPath = (const char*)sqlite3_value_text(argv[1]); + pNode = jsonLookup(p, zPath, 0, ctx); + }else{ + pNode = p->aNode; + } + if( pNode==0 ){ + return; + } + if( pNode->eType==JSON_ARRAY ){ + assert( (pNode->jnFlags & JNODE_APPEND)==0 ); + for(i=1; i<=pNode->n; n++){ + i += jsonNodeSize(&pNode[i]); + } + } + sqlite3_result_int64(ctx, n); +} + +/* +** json_extract(JSON, PATH, ...) +** +** Return the element described by PATH. Return NULL if there is no +** PATH element. If there are multiple PATHs, then return a JSON array +** with the result from each path. Throw an error if the JSON or any PATH +** is malformed. +*/ +static void jsonExtractFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse *p; /* The parse */ + JsonNode *pNode; + const char *zPath; + JsonString jx; + int i; + + if( argc<2 ) return; + p = jsonParseCached(ctx, argv, ctx); + if( p==0 ) return; + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '['); + for(i=1; inErr ) break; + if( argc>2 ){ + jsonAppendSeparator(&jx); + if( pNode ){ + jsonRenderNode(pNode, &jx, 0); + }else{ + jsonAppendRaw(&jx, "null", 4); + } + }else if( pNode ){ + jsonReturn(pNode, ctx, 0); + } + } + if( argc>2 && i==argc ){ + jsonAppendChar(&jx, ']'); + jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); + } + jsonReset(&jx); +} + +/* This is the RFC 7396 MergePatch algorithm. +*/ +static JsonNode *jsonMergePatch( + JsonParse *pParse, /* The JSON parser that contains the TARGET */ + u32 iTarget, /* Node of the TARGET in pParse */ + JsonNode *pPatch /* The PATCH */ +){ + u32 i, j; + u32 iRoot; + JsonNode *pTarget; + if( pPatch->eType!=JSON_OBJECT ){ + return pPatch; + } + assert( iTarget>=0 && iTargetnNode ); + pTarget = &pParse->aNode[iTarget]; + assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); + if( pTarget->eType!=JSON_OBJECT ){ + jsonRemoveAllNulls(pPatch); + return pPatch; + } + iRoot = iTarget; + for(i=1; in; i += jsonNodeSize(&pPatch[i+1])+1){ + u32 nKey; + const char *zKey; + assert( pPatch[i].eType==JSON_STRING ); + assert( pPatch[i].jnFlags & JNODE_LABEL ); + nKey = pPatch[i].n; + zKey = pPatch[i].u.zJContent; + assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); + for(j=1; jn; j += jsonNodeSize(&pTarget[j+1])+1 ){ + assert( pTarget[j].eType==JSON_STRING ); + assert( pTarget[j].jnFlags & JNODE_LABEL ); + assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); + if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){ + if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break; + if( pPatch[i+1].eType==JSON_NULL ){ + pTarget[j+1].jnFlags |= JNODE_REMOVE; + }else{ + JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); + if( pNew==0 ) return 0; + pTarget = &pParse->aNode[iTarget]; + if( pNew!=&pTarget[j+1] ){ + pTarget[j+1].u.pPatch = pNew; + pTarget[j+1].jnFlags |= JNODE_PATCH; + } + } + break; + } + } + if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ + int iStart, iPatch; + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); + jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); + iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + if( pParse->oom ) return 0; + jsonRemoveAllNulls(pPatch); + pTarget = &pParse->aNode[iTarget]; + pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; + pParse->aNode[iRoot].u.iAppend = iStart - iRoot; + iRoot = iStart; + pParse->aNode[iPatch].jnFlags |= JNODE_PATCH; + pParse->aNode[iPatch].u.pPatch = &pPatch[i+1]; + } + } + return pTarget; +} + +/* +** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON +** object that is the result of running the RFC 7396 MergePatch() algorithm +** on the two arguments. +*/ +static void jsonPatchFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The JSON that is being patched */ + JsonParse y; /* The patch */ + JsonNode *pResult; /* The result of the merge */ + + UNUSED_PARAM(argc); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){ + jsonParseReset(&x); + return; + } + pResult = jsonMergePatch(&x, 0, y.aNode); + assert( pResult!=0 || x.oom ); + if( pResult ){ + jsonReturnJson(pResult, ctx, 0); + }else{ + sqlite3_result_error_nomem(ctx); + } + jsonParseReset(&x); + jsonParseReset(&y); +} + + +/* +** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON +** object that contains all name/value given in arguments. Or if any name +** is not a string or if any value is a BLOB, throw an error. +*/ +static void jsonObjectFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + int i; + JsonString jx; + const char *z; + u32 n; + + if( argc&1 ){ + sqlite3_result_error(ctx, "json_object() requires an even number " + "of arguments", -1); + return; + } + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '{'); + for(i=0; ijnFlags |= JNODE_REMOVE; + } + if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ + jsonReturnJson(x.aNode, ctx, 0); + } +remove_done: + jsonParseReset(&x); +} + +/* +** json_replace(JSON, PATH, VALUE, ...) +** +** Replace the value at PATH with VALUE. If PATH does not already exist, +** this routine is a no-op. If JSON or PATH is malformed, throw an error. +*/ +static void jsonReplaceFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + + if( argc<1 ) return; + if( (argc&1)==0 ) { + jsonWrongNumArgs(ctx, "replace"); + return; + } + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto replace_err; + if( pNode ){ + pNode->jnFlags |= (u8)JNODE_REPLACE; + pNode->u.iReplace = i + 1; + } + } + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +replace_err: + jsonParseReset(&x); +} + +/* +** json_set(JSON, PATH, VALUE, ...) +** +** Set the value at PATH to VALUE. Create the PATH if it does not already +** exist. Overwrite existing values that do exist. +** If JSON or PATH is malformed, throw an error. +** +** json_insert(JSON, PATH, VALUE, ...) +** +** Create PATH and initialize it to VALUE. If PATH already exists, this +** routine is a no-op. If JSON or PATH is malformed, throw an error. +*/ +static void jsonSetFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + int bApnd; + int bIsSet = *(int*)sqlite3_user_data(ctx); + + if( argc<1 ) return; + if( (argc&1)==0 ) { + jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); + return; + } + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + bApnd = 0; + pNode = jsonLookup(&x, zPath, &bApnd, ctx); + if( x.oom ){ + sqlite3_result_error_nomem(ctx); + goto jsonSetDone; + }else if( x.nErr ){ + goto jsonSetDone; + }else if( pNode && (bApnd || bIsSet) ){ + pNode->jnFlags |= (u8)JNODE_REPLACE; + pNode->u.iReplace = i + 1; + } + } + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +jsonSetDone: + jsonParseReset(&x); +} + +/* +** json_type(JSON) +** json_type(JSON, PATH) +** +** Return the top-level "type" of a JSON string. Throw an error if +** either the JSON or PATH inputs are not well-formed. +*/ +static void jsonTypeFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse *p; /* The parse */ + const char *zPath; + JsonNode *pNode; + + p = jsonParseCached(ctx, argv, ctx); + if( p==0 ) return; + if( argc==2 ){ + zPath = (const char*)sqlite3_value_text(argv[1]); + pNode = jsonLookup(p, zPath, 0, ctx); + }else{ + pNode = p->aNode; + } + if( pNode ){ + sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); + } +} + +/* +** json_valid(JSON) +** +** Return 1 if JSON is a well-formed JSON string according to RFC-7159. +** Return 0 otherwise. +*/ +static void jsonValidFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse *p; /* The parse */ + UNUSED_PARAM(argc); + p = jsonParseCached(ctx, argv, 0); + sqlite3_result_int(ctx, p!=0); +} + + +/**************************************************************************** +** Aggregate SQL function implementations +****************************************************************************/ +/* +** json_group_array(VALUE) +** +** Return a JSON array composed of all values in the aggregate. +*/ +static void jsonArrayStep( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString *pStr; + UNUSED_PARAM(argc); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); + if( pStr ){ + if( pStr->zBuf==0 ){ + jsonInit(pStr, ctx); + jsonAppendChar(pStr, '['); + }else{ + jsonAppendChar(pStr, ','); + pStr->pCtx = ctx; + } + jsonAppendValue(pStr, argv[0]); + } +} +static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ + JsonString *pStr; + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); + if( pStr ){ + pStr->pCtx = ctx; + jsonAppendChar(pStr, ']'); + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); + }else if( isFinal ){ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); + pStr->bStatic = 1; + }else{ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); + pStr->nUsed--; + } + }else{ + sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); + } + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} +static void jsonArrayValue(sqlite3_context *ctx){ + jsonArrayCompute(ctx, 0); +} +static void jsonArrayFinal(sqlite3_context *ctx){ + jsonArrayCompute(ctx, 1); +} + +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** This method works for both json_group_array() and json_group_object(). +** It works by removing the first element of the group by searching forward +** to the first comma (",") that is not within a string and deleting all +** text through that comma. +*/ +static void jsonGroupInverse( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + int i; + int inStr = 0; + char *z; + JsonString *pStr; + UNUSED_PARAM(argc); + UNUSED_PARAM(argv); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); +#ifdef NEVER + /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will + ** always have been called to initalize it */ + if( NEVER(!pStr) ) return; +#endif + z = pStr->zBuf; + for(i=1; z[i]!=',' || inStr; i++){ + assert( inUsed ); + if( z[i]=='"' ){ + inStr = !inStr; + }else if( z[i]=='\\' ){ + i++; + } + } + pStr->nUsed -= i; + memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); +} +#else +# define jsonGroupInverse 0 +#endif + + +/* +** json_group_obj(NAME,VALUE) +** +** Return a JSON object composed of all names and values in the aggregate. +*/ +static void jsonObjectStep( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString *pStr; + const char *z; + u32 n; + UNUSED_PARAM(argc); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); + if( pStr ){ + if( pStr->zBuf==0 ){ + jsonInit(pStr, ctx); + jsonAppendChar(pStr, '{'); + }else{ + jsonAppendChar(pStr, ','); + pStr->pCtx = ctx; + } + z = (const char*)sqlite3_value_text(argv[0]); + n = (u32)sqlite3_value_bytes(argv[0]); + jsonAppendString(pStr, z, n); + jsonAppendChar(pStr, ':'); + jsonAppendValue(pStr, argv[1]); + } +} +static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ + JsonString *pStr; + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); + if( pStr ){ + jsonAppendChar(pStr, '}'); + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); + }else if( isFinal ){ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); + pStr->bStatic = 1; + }else{ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); + pStr->nUsed--; + } + }else{ + sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); + } + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} +static void jsonObjectValue(sqlite3_context *ctx){ + jsonObjectCompute(ctx, 0); +} +static void jsonObjectFinal(sqlite3_context *ctx){ + jsonObjectCompute(ctx, 1); +} + + + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/**************************************************************************** +** The json_each virtual table +****************************************************************************/ +typedef struct JsonEachCursor JsonEachCursor; +struct JsonEachCursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + u32 iRowid; /* The rowid */ + u32 iBegin; /* The first node of the scan */ + u32 i; /* Index in sParse.aNode[] of current row */ + u32 iEnd; /* EOF when i equals or exceeds this value */ + u8 eType; /* Type of top-level element */ + u8 bRecursive; /* True for json_tree(). False for json_each() */ + char *zJson; /* Input JSON */ + char *zRoot; /* Path by which to filter zJson */ + JsonParse sParse; /* Parse of the input JSON */ +}; + +/* Constructor for the json_each virtual table */ +static int jsonEachConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + sqlite3_vtab *pNew; + int rc; + +/* Column numbers */ +#define JEACH_KEY 0 +#define JEACH_VALUE 1 +#define JEACH_TYPE 2 +#define JEACH_ATOM 3 +#define JEACH_ID 4 +#define JEACH_PARENT 5 +#define JEACH_FULLKEY 6 +#define JEACH_PATH 7 +/* The xBestIndex method assumes that the JSON and ROOT columns are +** the last two columns in the table. Should this ever changes, be +** sure to update the xBestIndex method. */ +#define JEACH_JSON 8 +#define JEACH_ROOT 9 + + UNUSED_PARAM(pzErr); + UNUSED_PARAM(argv); + UNUSED_PARAM(argc); + UNUSED_PARAM(pAux); + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," + "json HIDDEN,root HIDDEN)"); + if( rc==SQLITE_OK ){ + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + } + return rc; +} + +/* destructor for json_each virtual table */ +static int jsonEachDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* constructor for a JsonEachCursor object for json_each(). */ +static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + JsonEachCursor *pCur; + + UNUSED_PARAM(p); + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* constructor for a JsonEachCursor object for json_tree(). */ +static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + int rc = jsonEachOpenEach(p, ppCursor); + if( rc==SQLITE_OK ){ + JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; + pCur->bRecursive = 1; + } + return rc; +} + +/* Reset a JsonEachCursor back to its original state. Free any memory +** held. */ +static void jsonEachCursorReset(JsonEachCursor *p){ + sqlite3_free(p->zJson); + sqlite3_free(p->zRoot); + jsonParseReset(&p->sParse); + p->iRowid = 0; + p->i = 0; + p->iEnd = 0; + p->eType = 0; + p->zJson = 0; + p->zRoot = 0; +} + +/* Destructor for a jsonEachCursor object */ +static int jsonEachClose(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + jsonEachCursorReset(p); + sqlite3_free(cur); + return SQLITE_OK; +} + +/* Return TRUE if the jsonEachCursor object has been advanced off the end +** of the JSON object */ +static int jsonEachEof(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + return p->i >= p->iEnd; +} + +/* Advance the cursor to the next element for json_tree() */ +static int jsonEachNext(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + if( p->bRecursive ){ + if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; + p->i++; + p->iRowid++; + if( p->iiEnd ){ + u32 iUp = p->sParse.aUp[p->i]; + JsonNode *pUp = &p->sParse.aNode[iUp]; + p->eType = pUp->eType; + if( pUp->eType==JSON_ARRAY ){ + if( iUp==p->i-1 ){ + pUp->u.iKey = 0; + }else{ + pUp->u.iKey++; + } + } + } + }else{ + switch( p->eType ){ + case JSON_ARRAY: { + p->i += jsonNodeSize(&p->sParse.aNode[p->i]); + p->iRowid++; + break; + } + case JSON_OBJECT: { + p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); + p->iRowid++; + break; + } + default: { + p->i = p->iEnd; + break; + } + } + } + return SQLITE_OK; +} + +/* Append the name of the path for element i to pStr +*/ +static void jsonEachComputePath( + JsonEachCursor *p, /* The cursor */ + JsonString *pStr, /* Write the path here */ + u32 i /* Path to this element */ +){ + JsonNode *pNode, *pUp; + u32 iUp; + if( i==0 ){ + jsonAppendChar(pStr, '$'); + return; + } + iUp = p->sParse.aUp[i]; + jsonEachComputePath(p, pStr, iUp); + pNode = &p->sParse.aNode[i]; + pUp = &p->sParse.aNode[iUp]; + if( pUp->eType==JSON_ARRAY ){ + jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); + }else{ + assert( pUp->eType==JSON_OBJECT ); + if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; + assert( pNode->eType==JSON_STRING ); + assert( pNode->jnFlags & JNODE_LABEL ); + jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); + } +} + +/* Return the value of a column */ +static int jsonEachColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + JsonEachCursor *p = (JsonEachCursor*)cur; + JsonNode *pThis = &p->sParse.aNode[p->i]; + switch( i ){ + case JEACH_KEY: { + if( p->i==0 ) break; + if( p->eType==JSON_OBJECT ){ + jsonReturn(pThis, ctx, 0); + }else if( p->eType==JSON_ARRAY ){ + u32 iKey; + if( p->bRecursive ){ + if( p->iRowid==0 ) break; + iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; + }else{ + iKey = p->iRowid; + } + sqlite3_result_int64(ctx, (sqlite3_int64)iKey); + } + break; + } + case JEACH_VALUE: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_TYPE: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); + break; + } + case JEACH_ATOM: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + if( pThis->eType>=JSON_ARRAY ) break; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_ID: { + sqlite3_result_int64(ctx, + (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); + break; + } + case JEACH_PARENT: { + if( p->i>p->iBegin && p->bRecursive ){ + sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); + } + break; + } + case JEACH_FULLKEY: { + JsonString x; + jsonInit(&x, ctx); + if( p->bRecursive ){ + jsonEachComputePath(p, &x, p->i); + }else{ + if( p->zRoot ){ + jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); + }else{ + jsonAppendChar(&x, '$'); + } + if( p->eType==JSON_ARRAY ){ + jsonPrintf(30, &x, "[%d]", p->iRowid); + }else if( p->eType==JSON_OBJECT ){ + jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); + } + } + jsonResult(&x); + break; + } + case JEACH_PATH: { + if( p->bRecursive ){ + JsonString x; + jsonInit(&x, ctx); + jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); + jsonResult(&x); + break; + } + /* For json_each() path and root are the same so fall through + ** into the root case */ + } + default: { + const char *zRoot = p->zRoot; + if( zRoot==0 ) zRoot = "$"; + sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); + break; + } + case JEACH_JSON: { + assert( i==JEACH_JSON ); + sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); + break; + } + } + return SQLITE_OK; +} + +/* Return the current rowid value */ +static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + JsonEachCursor *p = (JsonEachCursor*)cur; + *pRowid = p->iRowid; + return SQLITE_OK; +} + +/* The query strategy is to look for an equality constraint on the json +** column. Without such a constraint, the table cannot operate. idxNum is +** 1 if the constraint is found, 3 if the constraint and zRoot are found, +** and 0 otherwise. +*/ +static int jsonEachBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + int i; /* Loop counter or computed array index */ + int aIdx[2]; /* Index of constraints for JSON and ROOT */ + int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */ + int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */ + const struct sqlite3_index_constraint *pConstraint; + + /* This implementation assumes that JSON and ROOT are the last two + ** columns in the table */ + assert( JEACH_ROOT == JEACH_JSON+1 ); + UNUSED_PARAM(tab); + aIdx[0] = aIdx[1] = -1; + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + int iCol; + int iMask; + if( pConstraint->iColumn < JEACH_JSON ) continue; + iCol = pConstraint->iColumn - JEACH_JSON; + assert( iCol==0 || iCol==1 ); + iMask = 1 << iCol; + if( pConstraint->usable==0 ){ + unusableMask |= iMask; + }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + aIdx[iCol] = i; + idxMask |= iMask; + } + } + if( (unusableMask & ~idxMask)!=0 ){ + /* If there are any unusable constraints on JSON or ROOT, then reject + ** this entire plan */ + return SQLITE_CONSTRAINT; + } + if( aIdx[0]<0 ){ + /* No JSON input. Leave estimatedCost at the huge value that it was + ** initialized to to discourage the query planner from selecting this + ** plan. */ + pIdxInfo->idxNum = 0; + }else{ + pIdxInfo->estimatedCost = 1.0; + i = aIdx[0]; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + if( aIdx[1]<0 ){ + pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */ + }else{ + i = aIdx[1]; + pIdxInfo->aConstraintUsage[i].argvIndex = 2; + pIdxInfo->aConstraintUsage[i].omit = 1; + pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */ + } + } + return SQLITE_OK; +} + +/* Start a search on a new JSON string */ +static int jsonEachFilter( + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + JsonEachCursor *p = (JsonEachCursor*)cur; + const char *z; + const char *zRoot = 0; + sqlite3_int64 n; + + UNUSED_PARAM(idxStr); + UNUSED_PARAM(argc); + jsonEachCursorReset(p); + if( idxNum==0 ) return SQLITE_OK; + z = (const char*)sqlite3_value_text(argv[0]); + if( z==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[0]); + p->zJson = sqlite3_malloc64( n+1 ); + if( p->zJson==0 ) return SQLITE_NOMEM; + memcpy(p->zJson, z, (size_t)n+1); + if( jsonParse(&p->sParse, 0, p->zJson) ){ + int rc = SQLITE_NOMEM; + if( p->sParse.oom==0 ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); + if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; + } + jsonEachCursorReset(p); + return rc; + }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ + jsonEachCursorReset(p); + return SQLITE_NOMEM; + }else{ + JsonNode *pNode = 0; + if( idxNum==3 ){ + const char *zErr = 0; + zRoot = (const char*)sqlite3_value_text(argv[1]); + if( zRoot==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[1]); + p->zRoot = sqlite3_malloc64( n+1 ); + if( p->zRoot==0 ) return SQLITE_NOMEM; + memcpy(p->zRoot, zRoot, (size_t)n+1); + if( zRoot[0]!='$' ){ + zErr = zRoot; + }else{ + pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); + } + if( zErr ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); + jsonEachCursorReset(p); + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; + }else if( pNode==0 ){ + return SQLITE_OK; + } + }else{ + pNode = p->sParse.aNode; + } + p->iBegin = p->i = (int)(pNode - p->sParse.aNode); + p->eType = pNode->eType; + if( p->eType>=JSON_ARRAY ){ + pNode->u.iKey = 0; + p->iEnd = p->i + pNode->n + 1; + if( p->bRecursive ){ + p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; + if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ + p->i--; + } + }else{ + p->i++; + } + }else{ + p->iEnd = p->i+1; + } + } + return SQLITE_OK; +} + +/* The methods of the json_each virtual table */ +static sqlite3_module jsonEachModule = { + 0, /* iVersion */ + 0, /* xCreate */ + jsonEachConnect, /* xConnect */ + jsonEachBestIndex, /* xBestIndex */ + jsonEachDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + jsonEachOpenEach, /* xOpen - open a cursor */ + jsonEachClose, /* xClose - close a cursor */ + jsonEachFilter, /* xFilter - configure scan constraints */ + jsonEachNext, /* xNext - advance a cursor */ + jsonEachEof, /* xEof - check for end of scan */ + jsonEachColumn, /* xColumn - read data */ + jsonEachRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ +}; + +/* The methods of the json_tree virtual table. */ +static sqlite3_module jsonTreeModule = { + 0, /* iVersion */ + 0, /* xCreate */ + jsonEachConnect, /* xConnect */ + jsonEachBestIndex, /* xBestIndex */ + jsonEachDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + jsonEachOpenTree, /* xOpen - open a cursor */ + jsonEachClose, /* xClose - close a cursor */ + jsonEachFilter, /* xFilter - configure scan constraints */ + jsonEachNext, /* xNext - advance a cursor */ + jsonEachEof, /* xEof - check for end of scan */ + jsonEachColumn, /* xColumn - read data */ + jsonEachRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ +}; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +/**************************************************************************** +** The following routines are the only publically visible identifiers in this +** file. Call the following routines in order to register the various SQL +** functions and the virtual table implemented by this file. +****************************************************************************/ + +SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){ + int rc = SQLITE_OK; + unsigned int i; + static const struct { + const char *zName; + int nArg; + int flag; + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } aFunc[] = { + { "json", 1, 0, jsonRemoveFunc }, + { "json_array", -1, 0, jsonArrayFunc }, + { "json_array_length", 1, 0, jsonArrayLengthFunc }, + { "json_array_length", 2, 0, jsonArrayLengthFunc }, + { "json_extract", -1, 0, jsonExtractFunc }, + { "json_insert", -1, 0, jsonSetFunc }, + { "json_object", -1, 0, jsonObjectFunc }, + { "json_patch", 2, 0, jsonPatchFunc }, + { "json_quote", 1, 0, jsonQuoteFunc }, + { "json_remove", -1, 0, jsonRemoveFunc }, + { "json_replace", -1, 0, jsonReplaceFunc }, + { "json_set", -1, 1, jsonSetFunc }, + { "json_type", 1, 0, jsonTypeFunc }, + { "json_type", 2, 0, jsonTypeFunc }, + { "json_valid", 1, 0, jsonValidFunc }, + +#if SQLITE_DEBUG + /* DEBUG and TESTING functions */ + { "json_parse", 1, 0, jsonParseFunc }, + { "json_test1", 1, 0, jsonTest1Func }, +#endif + }; + static const struct { + const char *zName; + int nArg; + void (*xStep)(sqlite3_context*,int,sqlite3_value**); + void (*xFinal)(sqlite3_context*); + void (*xValue)(sqlite3_context*); + } aAgg[] = { + { "json_group_array", 1, + jsonArrayStep, jsonArrayFinal, jsonArrayValue }, + { "json_group_object", 2, + jsonObjectStep, jsonObjectFinal, jsonObjectValue }, + }; +#ifndef SQLITE_OMIT_VIRTUALTABLE + static const struct { + const char *zName; + sqlite3_module *pModule; + } aMod[] = { + { "json_each", &jsonEachModule }, + { "json_tree", &jsonTreeModule }, + }; +#endif + for(i=0; inRef>0 ); p->nRef++; } } @@ -169388,6 +179729,7 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; + pRtree->nNodeRef++; pNode->pParent = pParent; pNode->isDirty = 1; nodeReference(pParent); @@ -169421,10 +179763,10 @@ static int nodeAcquire( /* Check if the requested node is already in the hash table. If so, ** increase its reference count and return it. */ - if( (pNode = nodeHashLookup(pRtree, iNode)) ){ + if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ assert( !pParent || !pNode->pParent || pNode->pParent==pParent ); if( pParent && !pNode->pParent ){ - nodeReference(pParent); + pParent->nRef++; pNode->pParent = pParent; } pNode->nRef++; @@ -169463,6 +179805,7 @@ static int nodeAcquire( pNode->pParent = pParent; pNode->zData = (u8 *)&pNode[1]; pNode->nRef = 1; + pRtree->nNodeRef++; pNode->iNode = iNode; pNode->isDirty = 0; pNode->pNext = 0; @@ -169503,7 +179846,10 @@ static int nodeAcquire( } *ppNode = pNode; }else{ - sqlite3_free(pNode); + if( pNode ){ + pRtree->nNodeRef--; + sqlite3_free(pNode); + } *ppNode = 0; } @@ -169600,8 +179946,10 @@ static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; if( pNode ){ assert( pNode->nRef>0 ); + assert( pRtree->nNodeRef>0 ); pNode->nRef--; if( pNode->nRef==0 ){ + pRtree->nNodeRef--; if( pNode->iNode==1 ){ pRtree->iDepth = -1; } @@ -169718,8 +180066,9 @@ static void rtreeRelease(Rtree *pRtree){ pRtree->nBusy--; if( pRtree->nBusy==0 ){ pRtree->inWrTrans = 0; - pRtree->nCursor = 0; + assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); + assert( pRtree->nNodeRef==0 ); sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); @@ -169728,6 +180077,8 @@ static void rtreeRelease(Rtree *pRtree){ sqlite3_finalize(pRtree->pReadParent); sqlite3_finalize(pRtree->pWriteParent); sqlite3_finalize(pRtree->pDeleteParent); + sqlite3_finalize(pRtree->pWriteAux); + sqlite3_free(pRtree->zReadAuxSql); sqlite3_free(pRtree); } } @@ -169816,6 +180167,7 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){ RtreeCursor *pCsr = (RtreeCursor *)cur; assert( pRtree->nCursor>0 ); freeCursorConstraints(pCsr); + sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr->aPoint); for(ii=0; iiaNode[ii]); sqlite3_free(pCsr); @@ -170187,7 +180539,7 @@ static RtreeSearchPoint *rtreeSearchPointNew( if( iiaNode[ii]==0 ); pCur->aNode[ii] = pCur->aNode[0]; - }else{ + }else{ nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); } pCur->aNode[0] = 0; @@ -170358,6 +180710,10 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ /* Move to the next entry that matches the configured constraints. */ RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); + if( pCsr->bAuxValid ){ + pCsr->bAuxValid = 0; + sqlite3_reset(pCsr->pReadAux); + } rtreeSearchPointPop(pCsr); rc = rtreeStepToLeaf(pCsr); return rc; @@ -170392,7 +180748,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ if( p==0 ) return SQLITE_OK; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); - }else{ + }else if( i<=pRtree->nDim2 ){ nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ @@ -170403,7 +180759,27 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ assert( pRtree->eCoordType==RTREE_COORD_INT32 ); sqlite3_result_int(ctx, c.i); } - } + }else{ + if( !pCsr->bAuxValid ){ + if( pCsr->pReadAux==0 ){ + rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, + &pCsr->pReadAux, 0); + if( rc ) return rc; + } + sqlite3_bind_int64(pCsr->pReadAux, 1, + nodeGetRowid(pRtree, pNode, p->iCell)); + rc = sqlite3_step(pCsr->pReadAux); + if( rc==SQLITE_ROW ){ + pCsr->bAuxValid = 1; + }else{ + sqlite3_reset(pCsr->pReadAux); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; + } + } + sqlite3_result_value(ctx, + sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1)); + } return SQLITE_OK; } @@ -170481,14 +180857,17 @@ static int rtreeFilter( int ii; int rc = SQLITE_OK; int iCell = 0; + sqlite3_stmt *pStmt; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); + pStmt = pCsr->pReadAux; memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; + pCsr->pReadAux = pStmt; pCsr->iStrategy = idxNum; if( idxNum==1 ){ @@ -170651,10 +181030,14 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ */ pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; return SQLITE_OK; } - if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ + if( p->usable + && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) + || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) + ){ u8 op; switch( p->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; @@ -171227,7 +181610,7 @@ static int SplitNode( }else{ pLeft = pNode; pRight = nodeNew(pRtree, pLeft->pParent); - nodeReference(pLeft); + pLeft->nRef++; } if( !pLeft || !pRight ){ @@ -171636,7 +182019,7 @@ static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){ /* ** Select a currently unused rowid for a new r-tree record. */ -static int newRowid(Rtree *pRtree, i64 *piRowid){ +static int rtreeNewRowid(Rtree *pRtree, i64 *piRowid){ int rc; sqlite3_bind_null(pRtree->pWriteRowid, 1); sqlite3_bind_null(pRtree->pWriteRowid, 2); @@ -171717,6 +182100,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ rc = reinsertNodeContent(pRtree, pLeaf); } pRtree->pDeleted = pLeaf->pNext; + pRtree->nNodeRef--; sqlite3_free(pLeaf); } @@ -171813,7 +182197,7 @@ static int rtreeConstraintError(Rtree *pRtree, int iCol){ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, - sqlite3_value **azData, + sqlite3_value **aData, sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; @@ -171821,6 +182205,12 @@ static int rtreeUpdate( RtreeCell cell; /* New cell to insert if nData>1 */ int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ + if( pRtree->nNodeRef ){ + /* Unable to write to the btree while another cursor is reading from it, + ** since the write might do a rebalance which would disrupt the read + ** cursor. */ + return SQLITE_LOCKED_VTAB; + } rtreeReference(pRtree); assert(nData>=1); @@ -171839,8 +182229,10 @@ static int rtreeUpdate( */ if( nData>1 ){ int ii; + int nn = nData - 4; - /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. + if( nn > pRtree->nDim2 ) nn = pRtree->nDim2; + /* Populate the cell.aCoord[] array. The first coordinate is aData[3]. ** ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared ** with "column" that are interpreted as table constraints. @@ -171848,13 +182240,12 @@ static int rtreeUpdate( ** This problem was discovered after years of use, so we silently ignore ** these kinds of misdeclared tables to avoid breaking any legacy. */ - assert( nData<=(pRtree->nDim2 + 3) ); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ - for(ii=0; iicell.aCoord[ii+1].f ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; @@ -171863,9 +182254,9 @@ static int rtreeUpdate( }else #endif { - for(ii=0; iicell.aCoord[ii+1].i ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; @@ -171875,10 +182266,10 @@ static int rtreeUpdate( /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ - if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ - cell.iRowid = sqlite3_value_int64(azData[2]); - if( sqlite3_value_type(azData[0])==SQLITE_NULL - || sqlite3_value_int64(azData[0])!=cell.iRowid + if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){ + cell.iRowid = sqlite3_value_int64(aData[2]); + if( sqlite3_value_type(aData[0])==SQLITE_NULL + || sqlite3_value_int64(aData[0])!=cell.iRowid ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); @@ -171897,16 +182288,16 @@ static int rtreeUpdate( } } - /* If azData[0] is not an SQL NULL value, it is the rowid of a + /* If aData[0] is not an SQL NULL value, it is the rowid of a ** record to delete from the r-tree table. The following block does ** just that. */ - if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ - rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0])); + if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){ + rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0])); } - /* If the azData[] array contains more than one element, elements - ** (azData[2]..azData[argc-1]) contain a new record to insert into + /* If the aData[] array contains more than one element, elements + ** (aData[2]..aData[argc-1]) contain a new record to insert into ** the r-tree structure. */ if( rc==SQLITE_OK && nData>1 ){ @@ -171915,7 +182306,7 @@ static int rtreeUpdate( /* Figure out the rowid of the new row. */ if( bHaveRowid==0 ){ - rc = newRowid(pRtree, &cell.iRowid); + rc = rtreeNewRowid(pRtree, &cell.iRowid); } *pRowid = cell.iRowid; @@ -171931,6 +182322,16 @@ static int rtreeUpdate( rc = rc2; } } + if( pRtree->nAux ){ + sqlite3_stmt *pUp = pRtree->pWriteAux; + int jj; + sqlite3_bind_int64(pUp, 1, *pRowid); + for(jj=0; jjnAux; jj++){ + sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]); + } + sqlite3_step(pUp); + rc = sqlite3_reset(pUp); + } } constraint: @@ -171997,7 +182398,7 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ */ static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ Rtree *pRtree = (Rtree *)pVtab; - int iwt = pRtree->inWrTrans; + u8 iwt = pRtree->inWrTrans; UNUSED_PARAMETER(iSavepoint); pRtree->inWrTrans = 0; nodeBlobReset(pRtree); @@ -172049,8 +182450,24 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ return rc; } + +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int rtreeShadowName(const char *zName){ + static const char *azName[] = { + "node", "parent", "rowid" + }; + unsigned int i; + for(i=0; idb = db; if( isCreate ){ - char *zCreate = sqlite3_mprintf( -"CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);" -"CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);" -"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY," - " parentnode INTEGER);" -"INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))", - zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize - ); + char *zCreate; + sqlite3_str *p = sqlite3_str_new(db); + int ii; + sqlite3_str_appendf(p, + "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno", + zDb, zPrefix); + for(ii=0; iinAux; ii++){ + sqlite3_str_appendf(p,",a%d",ii); + } + sqlite3_str_appendf(p, + ");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);", + zDb, zPrefix); + sqlite3_str_appendf(p, + "CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);", + zDb, zPrefix); + sqlite3_str_appendf(p, + "INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))", + zDb, zPrefix, pRtree->iNodeSize); + zCreate = sqlite3_str_finish(p); if( !zCreate ){ return SQLITE_NOMEM; } @@ -172135,7 +182564,17 @@ static int rtreeSqlInit( rc = rtreeQueryStat1(db, pRtree); for(i=0; inAux==0 ){ + zFormat = azSql[i]; + }else { + /* An UPSERT is very slightly slower than REPLACE, but it is needed + ** if there are auxiliary columns */ + zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)" + "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno"; + } + zSql = sqlite3_mprintf(zFormat, zDb, zPrefix); if( zSql ){ rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, appStmt[i], 0); @@ -172144,6 +182583,36 @@ static int rtreeSqlInit( } sqlite3_free(zSql); } + if( pRtree->nAux ){ + pRtree->zReadAuxSql = sqlite3_mprintf( + "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1", + zDb, zPrefix); + if( pRtree->zReadAuxSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_str *p = sqlite3_str_new(db); + int ii; + char *zSql; + sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); + for(ii=0; iinAux; ii++){ + if( ii ) sqlite3_str_append(p, ",", 1); + if( iinAuxNotNull ){ + sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); + }else{ + sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); + } + } + sqlite3_str_appendf(p, " WHERE rowid=?1"); + zSql = sqlite3_str_finish(p); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, + &pRtree->pWriteAux, 0); + sqlite3_free(zSql); + } + } + } return rc; } @@ -172246,17 +182715,22 @@ static int rtreeInit( int nDb; /* Length of string argv[1] */ int nName; /* Length of string argv[2] */ int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32); + sqlite3_str *pSql; + char *zSql; + int ii = 4; + int iErr; const char *aErrMsg[] = { 0, /* 0 */ "Wrong number of columns for an rtree table", /* 1 */ "Too few columns for an rtree table", /* 2 */ - "Too many columns for an rtree table" /* 3 */ + "Too many columns for an rtree table", /* 3 */ + "Auxiliary rtree columns must be last" /* 4 */ }; - int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2; - if( aErrMsg[iErr] ){ - *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); + assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ + if( argc>RTREE_MAX_AUX_COLUMN+3 ){ + *pzErr = sqlite3_mprintf("%s", aErrMsg[3]); return SQLITE_ERROR; } @@ -172274,53 +182748,73 @@ static int rtreeInit( pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; - pRtree->nDim = (u8)((argc-4)/2); - pRtree->nDim2 = pRtree->nDim*2; - pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; pRtree->eCoordType = (u8)eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); - /* Figure out the node size to use. */ - rc = getNodeSize(db, pRtree, isCreate, pzErr); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ - if( rc==SQLITE_OK ){ - if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){ - *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + pSql = sqlite3_str_new(db); + sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]); + for(ii=4; iinAux++; + sqlite3_str_appendf(pSql, ",%s", argv[ii]+1); + }else if( pRtree->nAux>0 ){ + break; }else{ - char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]); - char *zTmp; - int ii; - for(ii=4; zSql && iinDim2++; + sqlite3_str_appendf(pSql, ",%s", argv[ii]); } } - - if( rc==SQLITE_OK ){ - *ppVtab = (sqlite3_vtab *)pRtree; - }else{ - assert( *ppVtab==0 ); - assert( pRtree->nBusy==1 ); - rtreeRelease(pRtree); + sqlite3_str_appendf(pSql, ");"); + zSql = sqlite3_str_finish(pSql); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else if( iinDim = pRtree->nDim2/2; + if( pRtree->nDim<1 ){ + iErr = 2; + }else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){ + iErr = 3; + }else if( pRtree->nDim2 % 2 ){ + iErr = 1; + }else{ + iErr = 0; + } + if( iErr ){ + *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); + goto rtreeInit_fail; + } + pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; + + /* Figure out the node size to use. */ + rc = getNodeSize(db, pRtree, isCreate, pzErr); + if( rc ) goto rtreeInit_fail; + rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); + if( rc ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + goto rtreeInit_fail; + } + + *ppVtab = (sqlite3_vtab *)pRtree; + return SQLITE_OK; + +rtreeInit_fail: + if( rc==SQLITE_OK ) rc = SQLITE_ERROR; + assert( *ppVtab==0 ); + assert( pRtree->nBusy==1 ); + rtreeRelease(pRtree); return rc; } @@ -172549,7 +183043,7 @@ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){ ** two tables are: ** ** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) -** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER) +** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...) ** ** In both cases, this function checks that there exists an entry with ** IPK value iKey and the second column set to iVal. @@ -172564,8 +183058,8 @@ static void rtreeCheckMapping( int rc; sqlite3_stmt *pStmt; const char *azSql[2] = { - "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?", - "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?" + "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1", + "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1" }; assert( bLeaf==0 || bLeaf==1 ); @@ -172749,6 +183243,7 @@ static int rtreeCheckTable( RtreeCheck check; /* Common context for various routines */ sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */ int bEnd = 0; /* True if transaction should be closed */ + int nAux = 0; /* Number of extra columns. */ /* Initialize the context object */ memset(&check, 0, sizeof(check)); @@ -172764,11 +183259,21 @@ static int rtreeCheckTable( bEnd = 1; } + /* Find the number of auxiliary columns */ + if( check.rc==SQLITE_OK ){ + pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); + if( pStmt ){ + nAux = sqlite3_column_count(pStmt) - 2; + sqlite3_finalize(pStmt); + } + check.rc = SQLITE_OK; + } + /* Find number of dimensions in the rtree table. */ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab); if( pStmt ){ int rc; - check.nDim = (sqlite3_column_count(pStmt) - 1) / 2; + check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2; if( check.nDim<1 ){ rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree"); }else if( SQLITE_ROW==sqlite3_step(pStmt) ){ @@ -172864,6 +183369,1811 @@ static void rtreecheck( } } +/* Conditionally include the geopoly code */ +#ifdef SQLITE_ENABLE_GEOPOLY +/************** Include geopoly.c in the middle of rtree.c *******************/ +/************** Begin file geopoly.c *****************************************/ +/* +** 2018-05-25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file implements an alternative R-Tree virtual table that +** uses polygons to express the boundaries of 2-dimensional objects. +** +** This file is #include-ed onto the end of "rtree.c" so that it has +** access to all of the R-Tree internals. +*/ +/* #include */ + +/* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */ +#ifdef GEOPOLY_ENABLE_DEBUG + static int geo_debug = 0; +# define GEODEBUG(X) if(geo_debug)printf X +#else +# define GEODEBUG(X) +#endif + +#ifndef JSON_NULL /* The following stuff repeats things found in json1 */ +/* +** Versions of isspace(), isalnum() and isdigit() to which it is safe +** to pass signed char values. +*/ +#ifdef sqlite3Isdigit + /* Use the SQLite core versions if this routine is part of the + ** SQLite amalgamation */ +# define safe_isdigit(x) sqlite3Isdigit(x) +# define safe_isalnum(x) sqlite3Isalnum(x) +# define safe_isxdigit(x) sqlite3Isxdigit(x) +#else + /* Use the standard library for separate compilation */ +#include /* amalgamator: keep */ +# define safe_isdigit(x) isdigit((unsigned char)(x)) +# define safe_isalnum(x) isalnum((unsigned char)(x)) +# define safe_isxdigit(x) isxdigit((unsigned char)(x)) +#endif + +/* +** Growing our own isspace() routine this way is twice as fast as +** the library isspace() function. +*/ +static const char geopolyIsSpace[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define safe_isspace(x) (geopolyIsSpace[(unsigned char)x]) +#endif /* JSON NULL - back to original code */ + +/* Compiler and version */ +#ifndef GCC_VERSION +#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) +# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) +#else +# define GCC_VERSION 0 +#endif +#endif +#ifndef MSVC_VERSION +#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) +# define MSVC_VERSION _MSC_VER +#else +# define MSVC_VERSION 0 +#endif +#endif + +/* Datatype for coordinates +*/ +typedef float GeoCoord; + +/* +** Internal representation of a polygon. +** +** The polygon consists of a sequence of vertexes. There is a line +** segment between each pair of vertexes, and one final segment from +** the last vertex back to the first. (This differs from the GeoJSON +** standard in which the final vertex is a repeat of the first.) +** +** The polygon follows the right-hand rule. The area to the right of +** each segment is "outside" and the area to the left is "inside". +** +** The on-disk representation consists of a 4-byte header followed by +** the values. The 4-byte header is: +** +** encoding (1 byte) 0=big-endian, 1=little-endian +** nvertex (3 bytes) Number of vertexes as a big-endian integer +** +** Enough space is allocated for 4 coordinates, to work around over-zealous +** warnings coming from some compiler (notably, clang). In reality, the size +** of each GeoPoly memory allocate is adjusted as necessary so that the +** GeoPoly.a[] array at the end is the appropriate size. +*/ +typedef struct GeoPoly GeoPoly; +struct GeoPoly { + int nVertex; /* Number of vertexes */ + unsigned char hdr[4]; /* Header for on-disk representation */ + GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */ +}; + +/* The size of a memory allocation needed for a GeoPoly object sufficient +** to hold N coordinate pairs. +*/ +#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4)) + +/* +** State of a parse of a GeoJSON input. +*/ +typedef struct GeoParse GeoParse; +struct GeoParse { + const unsigned char *z; /* Unparsed input */ + int nVertex; /* Number of vertexes in a[] */ + int nAlloc; /* Space allocated to a[] */ + int nErr; /* Number of errors encountered */ + GeoCoord *a; /* Array of vertexes. From sqlite3_malloc64() */ +}; + +/* Do a 4-byte byte swap */ +static void geopolySwab32(unsigned char *a){ + unsigned char t = a[0]; + a[0] = a[3]; + a[3] = t; + t = a[1]; + a[1] = a[2]; + a[2] = t; +} + +/* Skip whitespace. Return the next non-whitespace character. */ +static char geopolySkipSpace(GeoParse *p){ + while( safe_isspace(p->z[0]) ) p->z++; + return p->z[0]; +} + +/* Parse out a number. Write the value into *pVal if pVal!=0. +** return non-zero on success and zero if the next token is not a number. +*/ +static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ + char c = geopolySkipSpace(p); + const unsigned char *z = p->z; + int j = 0; + int seenDP = 0; + int seenE = 0; + if( c=='-' ){ + j = 1; + c = z[j]; + } + if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0; + for(;; j++){ + c = z[j]; + if( safe_isdigit(c) ) continue; + if( c=='.' ){ + if( z[j-1]=='-' ) return 0; + if( seenDP ) return 0; + seenDP = 1; + continue; + } + if( c=='e' || c=='E' ){ + if( z[j-1]<'0' ) return 0; + if( seenE ) return -1; + seenDP = seenE = 1; + c = z[j+1]; + if( c=='+' || c=='-' ){ + j++; + c = z[j+1]; + } + if( c<'0' || c>'9' ) return 0; + continue; + } + break; + } + if( z[j-1]<'0' ) return 0; + if( pVal ){ +#ifdef SQLITE_AMALGAMATION + /* The sqlite3AtoF() routine is much much faster than atof(), if it + ** is available */ + double r; + (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8); + *pVal = r; +#else + *pVal = (GeoCoord)atof((const char*)p->z); +#endif + } + p->z += j; + return 1; +} + +/* +** If the input is a well-formed JSON array of coordinates with at least +** four coordinates and where each coordinate is itself a two-value array, +** then convert the JSON into a GeoPoly object and return a pointer to +** that object. +** +** If any error occurs, return NULL. +*/ +static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ + GeoParse s; + int rc = SQLITE_OK; + memset(&s, 0, sizeof(s)); + s.z = z; + if( geopolySkipSpace(&s)=='[' ){ + s.z++; + while( geopolySkipSpace(&s)=='[' ){ + int ii = 0; + char c; + s.z++; + if( s.nVertex>=s.nAlloc ){ + GeoCoord *aNew; + s.nAlloc = s.nAlloc*2 + 16; + aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 ); + if( aNew==0 ){ + rc = SQLITE_NOMEM; + s.nErr++; + break; + } + s.a = aNew; + } + while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){ + ii++; + if( ii==2 ) s.nVertex++; + c = geopolySkipSpace(&s); + s.z++; + if( c==',' ) continue; + if( c==']' && ii>=2 ) break; + s.nErr++; + rc = SQLITE_ERROR; + goto parse_json_err; + } + if( geopolySkipSpace(&s)==',' ){ + s.z++; + continue; + } + break; + } + if( geopolySkipSpace(&s)==']' + && s.nVertex>=4 + && s.a[0]==s.a[s.nVertex*2-2] + && s.a[1]==s.a[s.nVertex*2-1] + && (s.z++, geopolySkipSpace(&s)==0) + ){ + GeoPoly *pOut; + int x = 1; + s.nVertex--; /* Remove the redundant vertex at the end */ + pOut = sqlite3_malloc64( GEOPOLY_SZ(s.nVertex) ); + x = 1; + if( pOut==0 ) goto parse_json_err; + pOut->nVertex = s.nVertex; + memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord)); + pOut->hdr[0] = *(unsigned char*)&x; + pOut->hdr[1] = (s.nVertex>>16)&0xff; + pOut->hdr[2] = (s.nVertex>>8)&0xff; + pOut->hdr[3] = s.nVertex&0xff; + sqlite3_free(s.a); + if( pRc ) *pRc = SQLITE_OK; + return pOut; + }else{ + s.nErr++; + rc = SQLITE_ERROR; + } + } +parse_json_err: + if( pRc ) *pRc = rc; + sqlite3_free(s.a); + return 0; +} + +/* +** Given a function parameter, try to interpret it as a polygon, either +** in the binary format or JSON text. Compute a GeoPoly object and +** return a pointer to that object. Or if the input is not a well-formed +** polygon, put an error message in sqlite3_context and return NULL. +*/ +static GeoPoly *geopolyFuncParam( + sqlite3_context *pCtx, /* Context for error messages */ + sqlite3_value *pVal, /* The value to decode */ + int *pRc /* Write error here */ +){ + GeoPoly *p = 0; + int nByte; + if( sqlite3_value_type(pVal)==SQLITE_BLOB + && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) + ){ + const unsigned char *a = sqlite3_value_blob(pVal); + int nVertex; + nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; + if( (a[0]==0 || a[0]==1) + && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte + ){ + p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); + if( p==0 ){ + if( pRc ) *pRc = SQLITE_NOMEM; + if( pCtx ) sqlite3_result_error_nomem(pCtx); + }else{ + int x = 1; + p->nVertex = nVertex; + memcpy(p->hdr, a, nByte); + if( a[0] != *(unsigned char*)&x ){ + int ii; + for(ii=0; iia[ii]); + } + p->hdr[0] ^= 1; + } + } + } + if( pRc ) *pRc = SQLITE_OK; + return p; + }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){ + const unsigned char *zJson = sqlite3_value_text(pVal); + if( zJson==0 ){ + if( pRc ) *pRc = SQLITE_NOMEM; + return 0; + } + return geopolyParseJson(zJson, pRc); + }else{ + if( pRc ) *pRc = SQLITE_ERROR; + return 0; + } +} + +/* +** Implementation of the geopoly_blob(X) function. +** +** If the input is a well-formed Geopoly BLOB or JSON string +** then return the BLOB representation of the polygon. Otherwise +** return NULL. +*/ +static void geopolyBlobFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + +/* +** SQL function: geopoly_json(X) +** +** Interpret X as a polygon and render it as a JSON array +** of coordinates. Or, if X is not a valid polygon, return NULL. +*/ +static void geopolyJsonFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_str *x = sqlite3_str_new(db); + int i; + sqlite3_str_append(x, "[", 1); + for(i=0; inVertex; i++){ + sqlite3_str_appendf(x, "[%!g,%!g],", p->a[i*2], p->a[i*2+1]); + } + sqlite3_str_appendf(x, "[%!g,%!g]]", p->a[0], p->a[1]); + sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); + sqlite3_free(p); + } +} + +/* +** SQL function: geopoly_svg(X, ....) +** +** Interpret X as a polygon and render it as a SVG . +** Additional arguments are added as attributes to the . +*/ +static void geopolySvgFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_str *x = sqlite3_str_new(db); + int i; + char cSep = '\''; + sqlite3_str_appendf(x, "a[i*2], p->a[i*2+1]); + cSep = ' '; + } + sqlite3_str_appendf(x, " %g,%g'", p->a[0], p->a[1]); + for(i=1; i"); + sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); + sqlite3_free(p); + } +} + +/* +** SQL Function: geopoly_xform(poly, A, B, C, D, E, F) +** +** Transform and/or translate a polygon as follows: +** +** x1 = A*x0 + B*y0 + E +** y1 = C*x0 + D*y0 + F +** +** For a translation: +** +** geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset) +** +** Rotate by R around the point (0,0): +** +** geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0) +*/ +static void geopolyXformFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + double A = sqlite3_value_double(argv[1]); + double B = sqlite3_value_double(argv[2]); + double C = sqlite3_value_double(argv[3]); + double D = sqlite3_value_double(argv[4]); + double E = sqlite3_value_double(argv[5]); + double F = sqlite3_value_double(argv[6]); + GeoCoord x1, y1, x0, y0; + int ii; + if( p ){ + for(ii=0; iinVertex; ii++){ + x0 = p->a[ii*2]; + y0 = p->a[ii*2+1]; + x1 = (GeoCoord)(A*x0 + B*y0 + E); + y1 = (GeoCoord)(C*x0 + D*y0 + F); + p->a[ii*2] = x1; + p->a[ii*2+1] = y1; + } + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + +/* +** Compute the area enclosed by the polygon. +** +** This routine can also be used to detect polygons that rotate in +** the wrong direction. Polygons are suppose to be counter-clockwise (CCW). +** This routine returns a negative value for clockwise (CW) polygons. +*/ +static double geopolyArea(GeoPoly *p){ + double rArea = 0.0; + int ii; + for(ii=0; iinVertex-1; ii++){ + rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */ + * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */ + * 0.5; + } + rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */ + * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */ + * 0.5; + return rArea; +} + +/* +** Implementation of the geopoly_area(X) function. +** +** If the input is a well-formed Geopoly BLOB then return the area +** enclosed by the polygon. If the polygon circulates clockwise instead +** of counterclockwise (as it should) then return the negative of the +** enclosed area. Otherwise return NULL. +*/ +static void geopolyAreaFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3_result_double(context, geopolyArea(p)); + sqlite3_free(p); + } +} + +/* +** Implementation of the geopoly_ccw(X) function. +** +** If the rotation of polygon X is clockwise (incorrect) instead of +** counter-clockwise (the correct winding order according to RFC7946) +** then reverse the order of the vertexes in polygon X. +** +** In other words, this routine returns a CCW polygon regardless of the +** winding order of its input. +** +** Use this routine to sanitize historical inputs that that sometimes +** contain polygons that wind in the wrong direction. +*/ +static void geopolyCcwFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + if( geopolyArea(p)<0.0 ){ + int ii, jj; + for(ii=2, jj=p->nVertex*2 - 2; iia[ii]; + p->a[ii] = p->a[jj]; + p->a[jj] = t; + t = p->a[ii+1]; + p->a[ii+1] = p->a[jj+1]; + p->a[jj+1] = t; + } + } + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + +#define GEOPOLY_PI 3.1415926535897932385 + +/* Fast approximation for sine(X) for X between -0.5*pi and 2*pi +*/ +static double geopolySine(double r){ + assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI ); + if( r>=1.5*GEOPOLY_PI ){ + r -= 2.0*GEOPOLY_PI; + } + if( r>=0.5*GEOPOLY_PI ){ + return -geopolySine(r-GEOPOLY_PI); + }else{ + double r2 = r*r; + double r3 = r2*r; + double r5 = r3*r2; + return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5; + } +} + +/* +** Function: geopoly_regular(X,Y,R,N) +** +** Construct a simple, convex, regular polygon centered at X, Y +** with circumradius R and with N sides. +*/ +static void geopolyRegularFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + double x = sqlite3_value_double(argv[0]); + double y = sqlite3_value_double(argv[1]); + double r = sqlite3_value_double(argv[2]); + int n = sqlite3_value_int(argv[3]); + int i; + GeoPoly *p; + + if( n<3 || r<=0.0 ) return; + if( n>1000 ) n = 1000; + p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); + if( p==0 ){ + sqlite3_result_error_nomem(context); + return; + } + i = 1; + p->hdr[0] = *(unsigned char*)&i; + p->hdr[1] = 0; + p->hdr[2] = (n>>8)&0xff; + p->hdr[3] = n&0xff; + for(i=0; ia[i*2] = x - r*geopolySine(rAngle-0.5*GEOPOLY_PI); + p->a[i*2+1] = y + r*geopolySine(rAngle); + } + sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT); + sqlite3_free(p); +} + +/* +** If pPoly is a polygon, compute its bounding box. Then: +** +** (1) if aCoord!=0 store the bounding box in aCoord, returning NULL +** (2) otherwise, compute a GeoPoly for the bounding box and return the +** new GeoPoly +** +** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from +** the bounding box in aCoord and return a pointer to that GeoPoly. +*/ +static GeoPoly *geopolyBBox( + sqlite3_context *context, /* For recording the error */ + sqlite3_value *pPoly, /* The polygon */ + RtreeCoord *aCoord, /* Results here */ + int *pRc /* Error code here */ +){ + GeoPoly *pOut = 0; + GeoPoly *p; + float mnX, mxX, mnY, mxY; + if( pPoly==0 && aCoord!=0 ){ + p = 0; + mnX = aCoord[0].f; + mxX = aCoord[1].f; + mnY = aCoord[2].f; + mxY = aCoord[3].f; + goto geopolyBboxFill; + }else{ + p = geopolyFuncParam(context, pPoly, pRc); + } + if( p ){ + int ii; + mnX = mxX = p->a[0]; + mnY = mxY = p->a[1]; + for(ii=1; iinVertex; ii++){ + double r = p->a[ii*2]; + if( rmxX ) mxX = (float)r; + r = p->a[ii*2+1]; + if( rmxY ) mxY = (float)r; + } + if( pRc ) *pRc = SQLITE_OK; + if( aCoord==0 ){ + geopolyBboxFill: + pOut = sqlite3_realloc(p, GEOPOLY_SZ(4)); + if( pOut==0 ){ + sqlite3_free(p); + if( context ) sqlite3_result_error_nomem(context); + if( pRc ) *pRc = SQLITE_NOMEM; + return 0; + } + pOut->nVertex = 4; + ii = 1; + pOut->hdr[0] = *(unsigned char*)ⅈ + pOut->hdr[1] = 0; + pOut->hdr[2] = 0; + pOut->hdr[3] = 4; + pOut->a[0] = mnX; + pOut->a[1] = mnY; + pOut->a[2] = mxX; + pOut->a[3] = mnY; + pOut->a[4] = mxX; + pOut->a[5] = mxY; + pOut->a[6] = mnX; + pOut->a[7] = mxY; + }else{ + sqlite3_free(p); + aCoord[0].f = mnX; + aCoord[1].f = mxX; + aCoord[2].f = mnY; + aCoord[3].f = mxY; + } + } + return pOut; +} + +/* +** Implementation of the geopoly_bbox(X) SQL function. +*/ +static void geopolyBBoxFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + +/* +** State vector for the geopoly_group_bbox() aggregate function. +*/ +typedef struct GeoBBox GeoBBox; +struct GeoBBox { + int isInit; + RtreeCoord a[4]; +}; + + +/* +** Implementation of the geopoly_group_bbox(X) aggregate SQL function. +*/ +static void geopolyBBoxStep( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + RtreeCoord a[4]; + int rc = SQLITE_OK; + (void)geopolyBBox(context, argv[0], a, &rc); + if( rc==SQLITE_OK ){ + GeoBBox *pBBox; + pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox)); + if( pBBox==0 ) return; + if( pBBox->isInit==0 ){ + pBBox->isInit = 1; + memcpy(pBBox->a, a, sizeof(RtreeCoord)*4); + }else{ + if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0]; + if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1]; + if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2]; + if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3]; + } + } +} +static void geopolyBBoxFinal( + sqlite3_context *context +){ + GeoPoly *p; + GeoBBox *pBBox; + pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0); + if( pBBox==0 ) return; + p = geopolyBBox(context, 0, pBBox->a, 0); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + + +/* +** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). +** Returns: +** +** +2 x0,y0 is on the line segement +** +** +1 x0,y0 is beneath line segment +** +** 0 x0,y0 is not on or beneath the line segment or the line segment +** is vertical and x0,y0 is not on the line segment +** +** The left-most coordinate min(x1,x2) is not considered to be part of +** the line segment for the purposes of this analysis. +*/ +static int pointBeneathLine( + double x0, double y0, + double x1, double y1, + double x2, double y2 +){ + double y; + if( x0==x1 && y0==y1 ) return 2; + if( x1x2 ) return 0; + }else if( x1>x2 ){ + if( x0<=x2 || x0>x1 ) return 0; + }else{ + /* Vertical line segment */ + if( x0!=x1 ) return 0; + if( y0y1 && y0>y2 ) return 0; + return 2; + } + y = y1 + (y2-y1)*(x0-x1)/(x2-x1); + if( y0==y ) return 2; + if( y0nVertex-1; ii++){ + v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], + p1->a[ii*2+2],p1->a[ii*2+3]); + if( v==2 ) break; + cnt += v; + } + if( v!=2 ){ + v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], + p1->a[0],p1->a[1]); + } + if( v==2 ){ + sqlite3_result_int(context, 1); + }else if( ((v+cnt)&1)==0 ){ + sqlite3_result_int(context, 0); + }else{ + sqlite3_result_int(context, 2); + } + sqlite3_free(p1); +} + +/* Forward declaration */ +static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2); + +/* +** SQL function: geopoly_within(P1,P2) +** +** Return +2 if P1 and P2 are the same polygon +** Return +1 if P2 is contained within P1 +** Return 0 if any part of P2 is on the outside of P1 +** +*/ +static void geopolyWithinFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); + GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); + if( p1 && p2 ){ + int x = geopolyOverlap(p1, p2); + if( x<0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); + } + } + sqlite3_free(p1); + sqlite3_free(p2); +} + +/* Objects used by the overlap algorihm. */ +typedef struct GeoEvent GeoEvent; +typedef struct GeoSegment GeoSegment; +typedef struct GeoOverlap GeoOverlap; +struct GeoEvent { + double x; /* X coordinate at which event occurs */ + int eType; /* 0 for ADD, 1 for REMOVE */ + GeoSegment *pSeg; /* The segment to be added or removed */ + GeoEvent *pNext; /* Next event in the sorted list */ +}; +struct GeoSegment { + double C, B; /* y = C*x + B */ + double y; /* Current y value */ + float y0; /* Initial y value */ + unsigned char side; /* 1 for p1, 2 for p2 */ + unsigned int idx; /* Which segment within the side */ + GeoSegment *pNext; /* Next segment in a list sorted by y */ +}; +struct GeoOverlap { + GeoEvent *aEvent; /* Array of all events */ + GeoSegment *aSegment; /* Array of all segments */ + int nEvent; /* Number of events */ + int nSegment; /* Number of segments */ +}; + +/* +** Add a single segment and its associated events. +*/ +static void geopolyAddOneSegment( + GeoOverlap *p, + GeoCoord x0, + GeoCoord y0, + GeoCoord x1, + GeoCoord y1, + unsigned char side, + unsigned int idx +){ + GeoSegment *pSeg; + GeoEvent *pEvent; + if( x0==x1 ) return; /* Ignore vertical segments */ + if( x0>x1 ){ + GeoCoord t = x0; + x0 = x1; + x1 = t; + t = y0; + y0 = y1; + y1 = t; + } + pSeg = p->aSegment + p->nSegment; + p->nSegment++; + pSeg->C = (y1-y0)/(x1-x0); + pSeg->B = y1 - x1*pSeg->C; + pSeg->y0 = y0; + pSeg->side = side; + pSeg->idx = idx; + pEvent = p->aEvent + p->nEvent; + p->nEvent++; + pEvent->x = x0; + pEvent->eType = 0; + pEvent->pSeg = pSeg; + pEvent = p->aEvent + p->nEvent; + p->nEvent++; + pEvent->x = x1; + pEvent->eType = 1; + pEvent->pSeg = pSeg; +} + + + +/* +** Insert all segments and events for polygon pPoly. +*/ +static void geopolyAddSegments( + GeoOverlap *p, /* Add segments to this Overlap object */ + GeoPoly *pPoly, /* Take all segments from this polygon */ + unsigned char side /* The side of pPoly */ +){ + unsigned int i; + GeoCoord *x; + for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ + x = pPoly->a + (i*2); + geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); + } + x = pPoly->a + (i*2); + geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i); +} + +/* +** Merge two lists of sorted events by X coordinate +*/ +static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){ + GeoEvent head, *pLast; + head.pNext = 0; + pLast = &head; + while( pRight && pLeft ){ + if( pRight->x <= pLeft->x ){ + pLast->pNext = pRight; + pLast = pRight; + pRight = pRight->pNext; + }else{ + pLast->pNext = pLeft; + pLast = pLeft; + pLeft = pLeft->pNext; + } + } + pLast->pNext = pRight ? pRight : pLeft; + return head.pNext; +} + +/* +** Sort an array of nEvent event objects into a list. +*/ +static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){ + int mx = 0; + int i, j; + GeoEvent *p; + GeoEvent *a[50]; + for(i=0; ipNext = 0; + for(j=0; j=mx ) mx = j+1; + } + p = 0; + for(i=0; iy - pLeft->y; + if( r==0.0 ) r = pRight->C - pLeft->C; + if( r<0.0 ){ + pLast->pNext = pRight; + pLast = pRight; + pRight = pRight->pNext; + }else{ + pLast->pNext = pLeft; + pLast = pLeft; + pLeft = pLeft->pNext; + } + } + pLast->pNext = pRight ? pRight : pLeft; + return head.pNext; +} + +/* +** Sort a list of GeoSegments in order of increasing Y and in the event of +** a tie, increasing C (slope). +*/ +static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){ + int mx = 0; + int i; + GeoSegment *p; + GeoSegment *a[50]; + while( pList ){ + p = pList; + pList = pList->pNext; + p->pNext = 0; + for(i=0; i=mx ) mx = i+1; + } + p = 0; + for(i=0; inVertex + p2->nVertex + 2; + GeoOverlap *p; + int nByte; + GeoEvent *pThisEvent; + double rX; + int rc = 0; + int needSort = 0; + GeoSegment *pActive = 0; + GeoSegment *pSeg; + unsigned char aOverlap[4]; + + nByte = sizeof(GeoEvent)*nVertex*2 + + sizeof(GeoSegment)*nVertex + + sizeof(GeoOverlap); + p = sqlite3_malloc( nByte ); + if( p==0 ) return -1; + p->aEvent = (GeoEvent*)&p[1]; + p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; + p->nEvent = p->nSegment = 0; + geopolyAddSegments(p, p1, 1); + geopolyAddSegments(p, p2, 2); + pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent); + rX = pThisEvent->x==0.0 ? -1.0 : 0.0; + memset(aOverlap, 0, sizeof(aOverlap)); + while( pThisEvent ){ + if( pThisEvent->x!=rX ){ + GeoSegment *pPrev = 0; + int iMask = 0; + GEODEBUG(("Distinct X: %g\n", pThisEvent->x)); + rX = pThisEvent->x; + if( needSort ){ + GEODEBUG(("SORT\n")); + pActive = geopolySortSegmentsByYAndC(pActive); + needSort = 0; + } + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + if( pPrev ){ + if( pPrev->y!=pSeg->y ){ + GEODEBUG(("MASK: %d\n", iMask)); + aOverlap[iMask] = 1; + } + } + iMask ^= pSeg->side; + pPrev = pSeg; + } + pPrev = 0; + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + double y = pSeg->C*rX + pSeg->B; + GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y)); + pSeg->y = y; + if( pPrev ){ + if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){ + rc = 1; + GEODEBUG(("Crossing: %d.%d and %d.%d\n", + pPrev->side, pPrev->idx, + pSeg->side, pSeg->idx)); + goto geopolyOverlapDone; + }else if( pPrev->y!=pSeg->y ){ + GEODEBUG(("MASK: %d\n", iMask)); + aOverlap[iMask] = 1; + } + } + iMask ^= pSeg->side; + pPrev = pSeg; + } + } + GEODEBUG(("%s %d.%d C=%g B=%g\n", + pThisEvent->eType ? "RM " : "ADD", + pThisEvent->pSeg->side, pThisEvent->pSeg->idx, + pThisEvent->pSeg->C, + pThisEvent->pSeg->B)); + if( pThisEvent->eType==0 ){ + /* Add a segment */ + pSeg = pThisEvent->pSeg; + pSeg->y = pSeg->y0; + pSeg->pNext = pActive; + pActive = pSeg; + needSort = 1; + }else{ + /* Remove a segment */ + if( pActive==pThisEvent->pSeg ){ + pActive = pActive->pNext; + }else{ + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + if( pSeg->pNext==pThisEvent->pSeg ){ + pSeg->pNext = pSeg->pNext->pNext; + break; + } + } + } + } + pThisEvent = pThisEvent->pNext; + } + if( aOverlap[3]==0 ){ + rc = 0; + }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){ + rc = 3; + }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){ + rc = 2; + }else if( aOverlap[1]==0 && aOverlap[2]==0 ){ + rc = 4; + }else{ + rc = 1; + } + +geopolyOverlapDone: + sqlite3_free(p); + return rc; +} + +/* +** SQL function: geopoly_overlap(P1,P2) +** +** Determine whether or not P1 and P2 overlap. Return value: +** +** 0 The two polygons are disjoint +** 1 They overlap +** 2 P1 is completely contained within P2 +** 3 P2 is completely contained within P1 +** 4 P1 and P2 are the same polygon +** NULL Either P1 or P2 or both are not valid polygons +*/ +static void geopolyOverlapFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); + GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); + if( p1 && p2 ){ + int x = geopolyOverlap(p1, p2); + if( x<0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_int(context, x); + } + } + sqlite3_free(p1); + sqlite3_free(p2); +} + +/* +** Enable or disable debugging output +*/ +static void geopolyDebugFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ +#ifdef GEOPOLY_ENABLE_DEBUG + geo_debug = sqlite3_value_int(argv[0]); +#endif +} + +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the geopoly virtual table. +** +** argv[0] -> module name +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> column names... +*/ +static int geopolyInit( + sqlite3 *db, /* Database connection */ + void *pAux, /* One of the RTREE_COORD_* constants */ + int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ + sqlite3_vtab **ppVtab, /* OUT: New virtual table */ + char **pzErr, /* OUT: Error message, if any */ + int isCreate /* True for xCreate, false for xConnect */ +){ + int rc = SQLITE_OK; + Rtree *pRtree; + int nDb; /* Length of string argv[1] */ + int nName; /* Length of string argv[2] */ + sqlite3_str *pSql; + char *zSql; + int ii; + + sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + + /* Allocate the sqlite3_vtab structure */ + nDb = (int)strlen(argv[1]); + nName = (int)strlen(argv[2]); + pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); + if( !pRtree ){ + return SQLITE_NOMEM; + } + memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); + pRtree->nBusy = 1; + pRtree->base.pModule = &rtreeModule; + pRtree->zDb = (char *)&pRtree[1]; + pRtree->zName = &pRtree->zDb[nDb+1]; + pRtree->eCoordType = RTREE_COORD_REAL32; + pRtree->nDim = 2; + pRtree->nDim2 = 4; + memcpy(pRtree->zDb, argv[1], nDb); + memcpy(pRtree->zName, argv[2], nName); + + + /* Create/Connect to the underlying relational database schema. If + ** that is successful, call sqlite3_declare_vtab() to configure + ** the r-tree table schema. + */ + pSql = sqlite3_str_new(db); + sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape"); + pRtree->nAux = 1; /* Add one for _shape */ + pRtree->nAuxNotNull = 1; /* The _shape column is always not-null */ + for(ii=3; iinAux++; + sqlite3_str_appendf(pSql, ",%s", argv[ii]); + } + sqlite3_str_appendf(pSql, ");"); + zSql = sqlite3_str_finish(pSql); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + sqlite3_free(zSql); + if( rc ) goto geopolyInit_fail; + pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; + + /* Figure out the node size to use. */ + rc = getNodeSize(db, pRtree, isCreate, pzErr); + if( rc ) goto geopolyInit_fail; + rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); + if( rc ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + goto geopolyInit_fail; + } + + *ppVtab = (sqlite3_vtab *)pRtree; + return SQLITE_OK; + +geopolyInit_fail: + if( rc==SQLITE_OK ) rc = SQLITE_ERROR; + assert( *ppVtab==0 ); + assert( pRtree->nBusy==1 ); + rtreeRelease(pRtree); + return rc; +} + + +/* +** GEOPOLY virtual table module xCreate method. +*/ +static int geopolyCreate( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1); +} + +/* +** GEOPOLY virtual table module xConnect method. +*/ +static int geopolyConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0); +} + + +/* +** GEOPOLY virtual table module xFilter method. +** +** Query plans: +** +** 1 rowid lookup +** 2 search for objects overlapping the same bounding box +** that contains polygon argv[0] +** 3 search for objects overlapping the same bounding box +** that contains polygon argv[0] +** 4 full table scan +*/ +static int geopolyFilter( + sqlite3_vtab_cursor *pVtabCursor, /* The cursor to initialize */ + int idxNum, /* Query plan */ + const char *idxStr, /* Not Used */ + int argc, sqlite3_value **argv /* Parameters to the query plan */ +){ + Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeNode *pRoot = 0; + int rc = SQLITE_OK; + int iCell = 0; + sqlite3_stmt *pStmt; + + rtreeReference(pRtree); + + /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ + freeCursorConstraints(pCsr); + sqlite3_free(pCsr->aPoint); + pStmt = pCsr->pReadAux; + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = (sqlite3_vtab*)pRtree; + pCsr->pReadAux = pStmt; + + pCsr->iStrategy = idxNum; + if( idxNum==1 ){ + /* Special case - lookup by rowid. */ + RtreeNode *pLeaf; /* Leaf on which the required cell resides */ + RtreeSearchPoint *p; /* Search point for the leaf */ + i64 iRowid = sqlite3_value_int64(argv[0]); + i64 iNode = 0; + rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); + if( rc==SQLITE_OK && pLeaf!=0 ){ + p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); + assert( p!=0 ); /* Always returns pCsr->sPoint */ + pCsr->aNode[0] = pLeaf; + p->id = iNode; + p->eWithin = PARTLY_WITHIN; + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); + p->iCell = (u8)iCell; + RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); + }else{ + pCsr->atEOF = 1; + } + }else{ + /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array + ** with the configured constraints. + */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + if( rc==SQLITE_OK && idxNum<=3 ){ + RtreeCoord bbox[4]; + RtreeConstraint *p; + assert( argc==1 ); + geopolyBBox(0, argv[0], bbox, &rc); + if( rc ){ + goto geopoly_filter_end; + } + pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4); + pCsr->nConstraint = 4; + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4); + memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); + if( idxNum==2 ){ + /* Overlap query */ + p->op = 'B'; + p->iCoord = 0; + p->u.rValue = bbox[1].f; + p++; + p->op = 'D'; + p->iCoord = 1; + p->u.rValue = bbox[0].f; + p++; + p->op = 'B'; + p->iCoord = 2; + p->u.rValue = bbox[3].f; + p++; + p->op = 'D'; + p->iCoord = 3; + p->u.rValue = bbox[2].f; + }else{ + /* Within query */ + p->op = 'D'; + p->iCoord = 0; + p->u.rValue = bbox[0].f; + p++; + p->op = 'B'; + p->iCoord = 1; + p->u.rValue = bbox[1].f; + p++; + p->op = 'D'; + p->iCoord = 2; + p->u.rValue = bbox[2].f; + p++; + p->op = 'B'; + p->iCoord = 3; + p->u.rValue = bbox[3].f; + } + } + } + if( rc==SQLITE_OK ){ + RtreeSearchPoint *pNew; + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + goto geopoly_filter_end; + } + pNew->id = 1; + pNew->iCell = 0; + pNew->eWithin = PARTLY_WITHIN; + assert( pCsr->bPoint==1 ); + pCsr->aNode[0] = pRoot; + pRoot = 0; + RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); + rc = rtreeStepToLeaf(pCsr); + } + } + +geopoly_filter_end: + nodeRelease(pRtree, pRoot); + rtreeRelease(pRtree); + return rc; +} + +/* +** Rtree virtual table module xBestIndex method. There are three +** table scan strategies to choose from (in order from most to +** least desirable): +** +** idxNum idxStr Strategy +** ------------------------------------------------ +** 1 "rowid" Direct lookup by rowid. +** 2 "rtree" R-tree overlap query using geopoly_overlap() +** 3 "rtree" R-tree within query using geopoly_within() +** 4 "fullscan" full-table scan. +** ------------------------------------------------ +*/ +static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + int ii; + int iRowidTerm = -1; + int iFuncTerm = -1; + int idxNum = 0; + + for(ii=0; iinConstraint; ii++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; + if( !p->usable ) continue; + if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + iRowidTerm = ii; + break; + } + if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ + /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap() + ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within(). + ** See geopolyFindFunction() */ + iFuncTerm = ii; + idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2; + } + } + + if( iRowidTerm>=0 ){ + pIdxInfo->idxNum = 1; + pIdxInfo->idxStr = "rowid"; + pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; + pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; + pIdxInfo->estimatedCost = 30.0; + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + return SQLITE_OK; + } + if( iFuncTerm>=0 ){ + pIdxInfo->idxNum = idxNum; + pIdxInfo->idxStr = "rtree"; + pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1; + pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0; + pIdxInfo->estimatedCost = 300.0; + pIdxInfo->estimatedRows = 10; + return SQLITE_OK; + } + pIdxInfo->idxNum = 4; + pIdxInfo->idxStr = "fullscan"; + pIdxInfo->estimatedCost = 3000000.0; + pIdxInfo->estimatedRows = 100000; + return SQLITE_OK; +} + + +/* +** GEOPOLY virtual table module xColumn method. +*/ +static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ + Rtree *pRtree = (Rtree *)cur->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)cur; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + + if( rc ) return rc; + if( p==0 ) return SQLITE_OK; + if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK; + if( i<=pRtree->nAux ){ + if( !pCsr->bAuxValid ){ + if( pCsr->pReadAux==0 ){ + rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, + &pCsr->pReadAux, 0); + if( rc ) return rc; + } + sqlite3_bind_int64(pCsr->pReadAux, 1, + nodeGetRowid(pRtree, pNode, p->iCell)); + rc = sqlite3_step(pCsr->pReadAux); + if( rc==SQLITE_ROW ){ + pCsr->bAuxValid = 1; + }else{ + sqlite3_reset(pCsr->pReadAux); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; + } + } + sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2)); + } + return SQLITE_OK; +} + + +/* +** The xUpdate method for GEOPOLY module virtual tables. +** +** For DELETE: +** +** argv[0] = the rowid to be deleted +** +** For INSERT: +** +** argv[0] = SQL NULL +** argv[1] = rowid to insert, or an SQL NULL to select automatically +** argv[2] = _shape column +** argv[3] = first application-defined column.... +** +** For UPDATE: +** +** argv[0] = rowid to modify. Never NULL +** argv[1] = rowid after the change. Never NULL +** argv[2] = new value for _shape +** argv[3] = new value for first application-defined column.... +*/ +static int geopolyUpdate( + sqlite3_vtab *pVtab, + int nData, + sqlite3_value **aData, + sqlite_int64 *pRowid +){ + Rtree *pRtree = (Rtree *)pVtab; + int rc = SQLITE_OK; + RtreeCell cell; /* New cell to insert if nData>1 */ + i64 oldRowid; /* The old rowid */ + int oldRowidValid; /* True if oldRowid is valid */ + i64 newRowid; /* The new rowid */ + int newRowidValid; /* True if newRowid is valid */ + int coordChange = 0; /* Change in coordinates */ + + if( pRtree->nNodeRef ){ + /* Unable to write to the btree while another cursor is reading from it, + ** since the write might do a rebalance which would disrupt the read + ** cursor. */ + return SQLITE_LOCKED_VTAB; + } + rtreeReference(pRtree); + assert(nData>=1); + + oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;; + oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0; + newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL; + newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0; + cell.iRowid = newRowid; + + if( nData>1 /* not a DELETE */ + && (!oldRowidValid /* INSERT */ + || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ + || oldRowid!=newRowid) /* Rowid change */ + ){ + geopolyBBox(0, aData[2], cell.aCoord, &rc); + if( rc ){ + if( rc==SQLITE_ERROR ){ + pVtab->zErrMsg = + sqlite3_mprintf("_shape does not contain a valid polygon"); + } + goto geopoly_update_end; + } + coordChange = 1; + + /* If a rowid value was supplied, check if it is already present in + ** the table. If so, the constraint has failed. */ + if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){ + int steprc; + sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); + steprc = sqlite3_step(pRtree->pReadRowid); + rc = sqlite3_reset(pRtree->pReadRowid); + if( SQLITE_ROW==steprc ){ + if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ + rc = rtreeDeleteRowid(pRtree, cell.iRowid); + }else{ + rc = rtreeConstraintError(pRtree, 0); + } + } + } + } + + /* If aData[0] is not an SQL NULL value, it is the rowid of a + ** record to delete from the r-tree table. The following block does + ** just that. + */ + if( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){ + rc = rtreeDeleteRowid(pRtree, oldRowid); + } + + /* If the aData[] array contains more than one element, elements + ** (aData[2]..aData[argc-1]) contain a new record to insert into + ** the r-tree structure. + */ + if( rc==SQLITE_OK && nData>1 && coordChange ){ + /* Insert the new record into the r-tree */ + RtreeNode *pLeaf = 0; + if( !newRowidValid ){ + rc = rtreeNewRowid(pRtree, &cell.iRowid); + } + *pRowid = cell.iRowid; + if( rc==SQLITE_OK ){ + rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); + } + if( rc==SQLITE_OK ){ + int rc2; + pRtree->iReinsertHeight = -1; + rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + + /* Change the data */ + if( rc==SQLITE_OK && nData>1 ){ + sqlite3_stmt *pUp = pRtree->pWriteAux; + int jj; + int nChange = 0; + sqlite3_bind_int64(pUp, 1, cell.iRowid); + assert( pRtree->nAux>=1 ); + if( sqlite3_value_nochange(aData[2]) ){ + sqlite3_bind_null(pUp, 2); + }else{ + GeoPoly *p = 0; + if( sqlite3_value_type(aData[2])==SQLITE_TEXT + && (p = geopolyFuncParam(0, aData[2], &rc))!=0 + && rc==SQLITE_OK + ){ + sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); + }else{ + sqlite3_bind_value(pUp, 2, aData[2]); + } + sqlite3_free(p); + nChange = 1; + } + for(jj=1; jjnAux; jj++){ + nChange++; + sqlite3_bind_value(pUp, jj+2, aData[jj+2]); + } + if( nChange ){ + sqlite3_step(pUp); + rc = sqlite3_reset(pUp); + } + } + +geopoly_update_end: + rtreeRelease(pRtree); + return rc; +} + +/* +** Report that geopoly_overlap() is an overloaded function suitable +** for use in xBestIndex. +*/ +static int geopolyFindFunction( + sqlite3_vtab *pVtab, + int nArg, + const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg +){ + if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ + *pxFunc = geopolyOverlapFunc; + *ppArg = 0; + return SQLITE_INDEX_CONSTRAINT_FUNCTION; + } + if( sqlite3_stricmp(zName, "geopoly_within")==0 ){ + *pxFunc = geopolyWithinFunc; + *ppArg = 0; + return SQLITE_INDEX_CONSTRAINT_FUNCTION+1; + } + return 0; +} + + +static sqlite3_module geopolyModule = { + 3, /* iVersion */ + geopolyCreate, /* xCreate - create a table */ + geopolyConnect, /* xConnect - connect to an existing table */ + geopolyBestIndex, /* xBestIndex - Determine search strategy */ + rtreeDisconnect, /* xDisconnect - Disconnect from a table */ + rtreeDestroy, /* xDestroy - Drop a table */ + rtreeOpen, /* xOpen - open a cursor */ + rtreeClose, /* xClose - close a cursor */ + geopolyFilter, /* xFilter - configure scan constraints */ + rtreeNext, /* xNext - advance a cursor */ + rtreeEof, /* xEof */ + geopolyColumn, /* xColumn - read data */ + rtreeRowid, /* xRowid - read data */ + geopolyUpdate, /* xUpdate - write data */ + rtreeBeginTransaction, /* xBegin - begin transaction */ + rtreeEndTransaction, /* xSync - sync transaction */ + rtreeEndTransaction, /* xCommit - commit transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ + geopolyFindFunction, /* xFindFunction - function overloading */ + rtreeRename, /* xRename - rename the table */ + rtreeSavepoint, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + rtreeShadowName /* xShadowName */ +}; + +static int sqlite3_geopoly_init(sqlite3 *db){ + int rc = SQLITE_OK; + static const struct { + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + signed char nArg; + unsigned char bPure; + const char *zName; + } aFunc[] = { + { geopolyAreaFunc, 1, 1, "geopoly_area" }, + { geopolyBlobFunc, 1, 1, "geopoly_blob" }, + { geopolyJsonFunc, 1, 1, "geopoly_json" }, + { geopolySvgFunc, -1, 1, "geopoly_svg" }, + { geopolyWithinFunc, 2, 1, "geopoly_within" }, + { geopolyContainsPointFunc, 3, 1, "geopoly_contains_point" }, + { geopolyOverlapFunc, 2, 1, "geopoly_overlap" }, + { geopolyDebugFunc, 1, 0, "geopoly_debug" }, + { geopolyBBoxFunc, 1, 1, "geopoly_bbox" }, + { geopolyXformFunc, 7, 1, "geopoly_xform" }, + { geopolyRegularFunc, 4, 1, "geopoly_regular" }, + { geopolyCcwFunc, 1, 1, "geopoly_ccw" }, + }; + static const struct { + void (*xStep)(sqlite3_context*,int,sqlite3_value**); + void (*xFinal)(sqlite3_context*); + const char *zName; + } aAgg[] = { + { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, + }; + int i; + for(i=0; izTbl); + sqlite3_free(p->zDataTbl); sqlite3_free(p->zIdx); sqlite3_free(p); } @@ -176803,6 +189127,10 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1); break; + case RBU_STATE_DATATBL: + pRet->zDataTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); + break; + default: rc = SQLITE_CORRUPT; break; @@ -177577,7 +189905,8 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ "(%d, %lld), " "(%d, %lld), " "(%d, %lld), " - "(%d, %lld) ", + "(%d, %lld), " + "(%d, %Q) ", p->zStateDb, RBU_STATE_STAGE, eStage, RBU_STATE_TBL, p->objiter.zTbl, @@ -177587,7 +189916,8 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ RBU_STATE_CKPT, p->iWalCksum, RBU_STATE_COOKIE, (i64)pFd->iCookie, RBU_STATE_OALSZ, p->iOalSz, - RBU_STATE_PHASEONESTEP, p->nPhaseOneStep + RBU_STATE_PHASEONESTEP, p->nPhaseOneStep, + RBU_STATE_DATATBL, p->objiter.zDataTbl ) ); assert( pInsert==0 || rc==SQLITE_OK ); @@ -177843,7 +190173,8 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){ while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup || rbuStrCompare(pIter->zIdx, pState->zIdx) - || rbuStrCompare(pIter->zTbl, pState->zTbl) + || (pState->zDataTbl==0 && rbuStrCompare(pIter->zTbl, pState->zTbl)) + || (pState->zDataTbl && rbuStrCompare(pIter->zDataTbl, pState->zDataTbl)) )){ rc = rbuObjIterNext(p, pIter); } @@ -178481,6 +190812,69 @@ static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){ return SQLITE_OK; } +/* +** Add an item to the main-db lists, if it is not already present. +** +** There are two main-db lists. One for all file descriptors, and one +** for all file descriptors with rbu_file.pDb!=0. If the argument has +** rbu_file.pDb!=0, then it is assumed to already be present on the +** main list and is only added to the pDb!=0 list. +*/ +static void rbuMainlistAdd(rbu_file *p){ + rbu_vfs *pRbuVfs = p->pRbuVfs; + rbu_file *pIter; + assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) ); + sqlite3_mutex_enter(pRbuVfs->mutex); + if( p->pRbu==0 ){ + for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext); + p->pMainNext = pRbuVfs->pMain; + pRbuVfs->pMain = p; + }else{ + for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){} + if( pIter==0 ){ + p->pMainRbuNext = pRbuVfs->pMainRbu; + pRbuVfs->pMainRbu = p; + } + } + sqlite3_mutex_leave(pRbuVfs->mutex); +} + +/* +** Remove an item from the main-db lists. +*/ +static void rbuMainlistRemove(rbu_file *p){ + rbu_file **pp; + sqlite3_mutex_enter(p->pRbuVfs->mutex); + for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){} + if( *pp ) *pp = p->pMainNext; + p->pMainNext = 0; + for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){} + if( *pp ) *pp = p->pMainRbuNext; + p->pMainRbuNext = 0; + sqlite3_mutex_leave(p->pRbuVfs->mutex); +} + +/* +** Given that zWal points to a buffer containing a wal file name passed to +** either the xOpen() or xAccess() VFS method, search the main-db list for +** a file-handle opened by the same database connection on the corresponding +** database file. +** +** If parameter bRbu is true, only search for file-descriptors with +** rbu_file.pDb!=0. +*/ +static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){ + rbu_file *pDb; + sqlite3_mutex_enter(pRbuVfs->mutex); + if( bRbu ){ + for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){} + }else{ + for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} + } + sqlite3_mutex_leave(pRbuVfs->mutex); + return pDb; +} + /* ** Close an rbu file. */ @@ -178498,17 +190892,14 @@ static int rbuVfsClose(sqlite3_file *pFile){ sqlite3_free(p->zDel); if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ - rbu_file **pp; - sqlite3_mutex_enter(p->pRbuVfs->mutex); - for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext)); - *pp = p->pMainNext; - sqlite3_mutex_leave(p->pRbuVfs->mutex); + rbuMainlistRemove(p); rbuUnlockShm(p); p->pReal->pMethods->xShmUnmap(p->pReal, 0); } else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ rbuUpdateTempSize(p, 0); } + assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p ); /* Close the underlying file handle */ rc = p->pReal->pMethods->xClose(p->pReal); @@ -178767,6 +191158,9 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){ }else if( rc==SQLITE_NOTFOUND ){ pRbu->pTargetFd = p; p->pRbu = pRbu; + if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ + rbuMainlistAdd(p); + } if( p->pWalFd ) p->pWalFd->pRbu = pRbu; rc = SQLITE_OK; } @@ -178928,20 +191322,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){ return rc; } -/* -** Given that zWal points to a buffer containing a wal file name passed to -** either the xOpen() or xAccess() VFS method, return a pointer to the -** file-handle opened by the same database connection on the corresponding -** database file. -*/ -static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){ - rbu_file *pDb; - sqlite3_mutex_enter(pRbuVfs->mutex); - for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} - sqlite3_mutex_leave(pRbuVfs->mutex); - return pDb; -} - /* ** A main database named zName has just been opened. The following ** function returns a pointer to a buffer owned by SQLite that contains @@ -179020,7 +191400,7 @@ static int rbuVfsOpen( pFd->zWal = rbuMainToWal(zName, flags); } else if( flags & SQLITE_OPEN_WAL ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName); + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0); if( pDb ){ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ /* This call is to open a *-wal file. Intead, open the *-oal. This @@ -179072,10 +191452,7 @@ static int rbuVfsOpen( ** mutex protected linked list of all such files. */ pFile->pMethods = &rbuvfs_io_methods; if( flags & SQLITE_OPEN_MAIN_DB ){ - sqlite3_mutex_enter(pRbuVfs->mutex); - pFd->pMainNext = pRbuVfs->pMain; - pRbuVfs->pMain = pFd; - sqlite3_mutex_leave(pRbuVfs->mutex); + rbuMainlistAdd(pFd); } }else{ sqlite3_free(pFd->zDel); @@ -179123,7 +191500,7 @@ static int rbuVfsAccess( ** file opened instead. */ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath); + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1); if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ if( *pResOut ){ rc = SQLITE_CANTOPEN; @@ -179536,17 +191913,15 @@ static int statDisconnect(sqlite3_vtab *pVtab){ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; - pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */ - /* Look for a valid schema=? constraint. If found, change the idxNum to ** 1 and request the value of that constraint be sent to xFilter. And ** lower the cost estimate to encourage the constrained version to be ** used. */ for(i=0; inConstraint; i++){ - if( pIdxInfo->aConstraint[i].usable==0 ) continue; - if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue; + if( pIdxInfo->aConstraint[i].usable==0 ) return SQLITE_CONSTRAINT; + if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; pIdxInfo->idxNum = 1; pIdxInfo->estimatedCost = 1.0; pIdxInfo->aConstraintUsage[i].argvIndex = 1; @@ -179596,7 +191971,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ return SQLITE_OK; } -static void statClearPage(StatPage *p){ +static void statClearCells(StatPage *p){ int i; if( p->aCell ){ for(i=0; inCell; i++){ @@ -179604,6 +191979,12 @@ static void statClearPage(StatPage *p){ } sqlite3_free(p->aCell); } + p->nCell = 0; + p->aCell = 0; +} + +static void statClearPage(StatPage *p){ + statClearCells(p); sqlite3PagerUnref(p->pPg); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); @@ -179666,22 +192047,33 @@ static int statDecodePage(Btree *pBt, StatPage *p){ u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; + if( p->flags==0x0A || p->flags==0x0D ){ + isLeaf = 1; + nHdr = 8; + }else if( p->flags==0x05 || p->flags==0x02 ){ + isLeaf = 0; + nHdr = 12; + }else{ + goto statPageIsCorrupt; + } + if( p->iPgno==1 ) nHdr += 100; p->nCell = get2byte(&aHdr[3]); p->nMxPayload = 0; - - isLeaf = (p->flags==0x0A || p->flags==0x0D); - nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; + szPage = sqlite3BtreeGetPageSize(pBt); nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; nUnused += (int)aHdr[7]; iOff = get2byte(&aHdr[1]); while( iOff ){ + int iNext; + if( iOff>=szPage ) goto statPageIsCorrupt; nUnused += get2byte(&aData[iOff+2]); - iOff = get2byte(&aData[iOff]); + iNext = get2byte(&aData[iOff]); + if( iNext0 ) goto statPageIsCorrupt; + iOff = iNext; } p->nUnused = nUnused; p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); - szPage = sqlite3BtreeGetPageSize(pBt); if( p->nCell ){ int i; /* Used to iterate through cells */ @@ -179698,6 +192090,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ StatCell *pCell = &p->aCell[i]; iOff = get2byte(&aData[nHdr+i*2]); + if( iOff=szPage ) goto statPageIsCorrupt; if( !isLeaf ){ pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); iOff += 4; @@ -179714,13 +192107,14 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; getLocalPayload(nUsable, p->flags, nPayload, &nLocal); + if( nLocal<0 ) goto statPageIsCorrupt; pCell->nLocal = nLocal; - assert( nLocal>=0 ); assert( nPayload>=(u32)nLocal ); assert( nLocal<=(nUsable-35) ); if( nPayload>(u32)nLocal ){ int j; int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); + if( iOff+nLocal>nUsable ) goto statPageIsCorrupt; pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl); @@ -179744,6 +192138,11 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } return SQLITE_OK; + +statPageIsCorrupt: + p->flags = 0; + statClearCells(p); + return SQLITE_OK; } /* @@ -180039,6 +192438,7 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } @@ -180169,9 +192569,8 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue; if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; if( !p->usable ){ - /* No solution. Use the default SQLITE_BIG_DBL cost */ - pIdxInfo->estimatedRows = 0x7fffffff; - return SQLITE_OK; + /* No solution. */ + return SQLITE_CONSTRAINT; } iPlan = 2; pIdxInfo->aConstraintUsage[i].argvIndex = 1; @@ -180363,6 +192762,10 @@ static int dbpageUpdate( Pager *pPager; int szPage; + if( pTab->db->flags & SQLITE_Defensive ){ + zErr = "read-only"; + goto update_fail; + } if( argc==1 ){ zErr = "cannot delete"; goto update_fail; @@ -180419,7 +192822,7 @@ static int dbpageBegin(sqlite3_vtab *pVtab){ int i; for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( pBt ) sqlite3BtreeBeginTrans(pBt, 1); + if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0); } return SQLITE_OK; } @@ -180453,6 +192856,7 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); } @@ -180489,6 +192893,8 @@ typedef struct SessionInput SessionInput; # endif #endif +static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE; + typedef struct SessionHook SessionHook; struct SessionHook { void *pCtx; @@ -180551,6 +192957,7 @@ struct sqlite3_changeset_iter { SessionInput in; /* Input buffer or stream */ SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */ int bPatchset; /* True if this is a patchset */ + int bInvert; /* True to invert changeset */ int rc; /* Iterator error code */ sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ char *zTab; /* Current table */ @@ -180707,6 +193114,42 @@ struct SessionTable { ** The records associated with INSERT changes are in the same format as for ** changesets. It is not possible for a record associated with an INSERT ** change to contain a field set to "undefined". +** +** REBASE BLOB FORMAT: +** +** A rebase blob may be output by sqlite3changeset_apply_v2() and its +** streaming equivalent for use with the sqlite3_rebaser APIs to rebase +** existing changesets. A rebase blob contains one entry for each conflict +** resolved using either the OMIT or REPLACE strategies within the apply_v2() +** call. +** +** The format used for a rebase blob is very similar to that used for +** changesets. All entries related to a single table are grouped together. +** +** Each group of entries begins with a table header in changeset format: +** +** 1 byte: Constant 0x54 (capital 'T') +** Varint: Number of columns in the table. +** nCol bytes: 0x01 for PK columns, 0x00 otherwise. +** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated. +** +** Followed by one or more entries associated with the table. +** +** 1 byte: Either SQLITE_INSERT (0x12), DELETE (0x09). +** 1 byte: Flag. 0x01 for REPLACE, 0x00 for OMIT. +** record: (in the record format defined above). +** +** In a rebase blob, the first field is set to SQLITE_INSERT if the change +** that caused the conflict was an INSERT or UPDATE, or to SQLITE_DELETE if +** it was a DELETE. The second field is set to 0x01 if the conflict +** resolution strategy was REPLACE, or 0x00 if it was OMIT. +** +** If the change that caused the conflict was a DELETE, then the single +** record is a copy of the old.* record from the original changeset. If it +** was an INSERT, then the single record is a copy of the new.* record. If +** the conflicting change was an UPDATE, then the single record is a copy +** of the new.* record with the PK fields filled in based on the original +** old.* record. */ /* @@ -182257,12 +194700,12 @@ SQLITE_API int sqlite3session_attach( static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ if( *pRc==SQLITE_OK && p->nAlloc-p->nBufnAlloc ? p->nAlloc : 128; + i64 nNew = p->nAlloc ? p->nAlloc : 128; do { nNew = nNew*2; - }while( nNew<(p->nBuf+nByte) ); + }while( (nNew-p->nBuf)aBuf, nNew); + aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew); if( 0==aNew ){ *pRc = SQLITE_NOMEM; }else{ @@ -182860,12 +195303,12 @@ static int sessionGenerateChangeset( rc = sqlite3_reset(pSel); } - /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass + /* If the buffer is now larger than sessions_strm_chunk_size, pass ** its contents to the xOutput() callback. */ if( xOutput && rc==SQLITE_OK && buf.nBuf>nNoop - && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE + && buf.nBuf>sessions_strm_chunk_size ){ rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf); nNoop = -1; @@ -183004,7 +195447,8 @@ static int sessionChangesetStart( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int nChangeset, /* Size of buffer pChangeset in bytes */ - void *pChangeset /* Pointer to buffer containing changeset */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int bInvert /* True to invert changeset */ ){ sqlite3_changeset_iter *pRet; /* Iterator to return */ int nByte; /* Number of bytes to allocate for iterator */ @@ -183024,6 +195468,7 @@ static int sessionChangesetStart( pRet->in.xInput = xInput; pRet->in.pIn = pIn; pRet->in.bEof = (xInput ? 0 : 1); + pRet->bInvert = bInvert; /* Populate the output variable and return success. */ *pp = pRet; @@ -183038,7 +195483,16 @@ SQLITE_API int sqlite3changeset_start( int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset /* Pointer to buffer containing changeset */ ){ - return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0); +} +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int nChangeset, /* Size of buffer pChangeset in bytes */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert); } /* @@ -183049,7 +195503,16 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ){ - return sessionChangesetStart(pp, xInput, pIn, 0, 0); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0); +} +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert); } /* @@ -183057,7 +195520,7 @@ SQLITE_API int sqlite3changeset_start_strm( ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ - if( pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){ + if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){ int nMove = pIn->buf.nBuf - pIn->iNext; assert( nMove>=0 ); if( nMove>0 ){ @@ -183080,7 +195543,7 @@ static int sessionInputBuffer(SessionInput *pIn, int nByte){ int rc = SQLITE_OK; if( pIn->xInput ){ while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){ - int nNew = SESSIONS_STRM_CHUNK_SIZE; + int nNew = sessions_strm_chunk_size; if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn); if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){ @@ -183428,10 +195891,10 @@ static int sessionChangesetNext( op = p->in.aData[p->in.iNext++]; } - if( p->zTab==0 ){ + if( p->zTab==0 || (p->bPatchset && p->bInvert) ){ /* The first record in the changeset is not a table header. Must be a ** corrupt changeset. */ - assert( p->in.iNext==1 ); + assert( p->in.iNext==1 || p->zTab ); return (p->rc = SQLITE_CORRUPT_BKPT); } @@ -183456,33 +195919,39 @@ static int sessionChangesetNext( *paRec = &p->in.aData[p->in.iNext]; p->in.iNext += *pnRec; }else{ + sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue); + sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]); /* If this is an UPDATE or DELETE, read the old.* record. */ if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){ u8 *abPK = p->bPatchset ? p->abPK : 0; - p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue); + p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld); if( p->rc!=SQLITE_OK ) return p->rc; } /* If this is an INSERT or UPDATE, read the new.* record. */ if( p->op!=SQLITE_DELETE ){ - p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]); + p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew); if( p->rc!=SQLITE_OK ) return p->rc; } - if( p->bPatchset && p->op==SQLITE_UPDATE ){ + if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){ /* If this is an UPDATE that is part of a patchset, then all PK and ** modified fields are present in the new.* record. The old.* record ** is currently completely empty. This block shifts the PK fields from ** new.* to old.*, to accommodate the code that reads these arrays. */ for(i=0; inCol; i++){ - assert( p->apValue[i]==0 ); + assert( p->bPatchset==0 || p->apValue[i]==0 ); if( p->abPK[i] ){ + assert( p->apValue[i]==0 ); p->apValue[i] = p->apValue[i+p->nCol]; if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT); p->apValue[i+p->nCol] = 0; } } + }else if( p->bInvert ){ + if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; + else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } } @@ -183799,7 +196268,7 @@ static int sessionChangesetInvert( } assert( rc==SQLITE_OK ); - if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ + if( xOutput && sOut.nBuf>=sessions_strm_chunk_size ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; @@ -183878,7 +196347,8 @@ struct SessionApplyCtx { int bDeferConstraints; /* True to defer constraints */ SessionBuffer constraints; /* Deferred constraints are stored here */ SessionBuffer rebase; /* Rebase information (if any) here */ - int bRebaseStarted; /* If table header is already in rebase */ + u8 bRebaseStarted; /* If table header is already in rebase */ + u8 bRebase; /* True to collect rebase information */ }; /* @@ -184275,35 +196745,36 @@ static int sessionRebaseAdd( sqlite3_changeset_iter *pIter /* Iterator pointing at current change */ ){ int rc = SQLITE_OK; - int i; - int eOp = pIter->op; - if( p->bRebaseStarted==0 ){ - /* Append a table-header to the rebase buffer */ - const char *zTab = pIter->zTab; - sessionAppendByte(&p->rebase, 'T', &rc); - sessionAppendVarint(&p->rebase, p->nCol, &rc); - sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc); - sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc); - p->bRebaseStarted = 1; - } - - assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT ); - assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE ); - - sessionAppendByte(&p->rebase, - (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc - ); - sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc); - for(i=0; inCol; i++){ - sqlite3_value *pVal = 0; - if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){ - sqlite3changeset_old(pIter, i, &pVal); - }else{ - sqlite3changeset_new(pIter, i, &pVal); + if( p->bRebase ){ + int i; + int eOp = pIter->op; + if( p->bRebaseStarted==0 ){ + /* Append a table-header to the rebase buffer */ + const char *zTab = pIter->zTab; + sessionAppendByte(&p->rebase, 'T', &rc); + sessionAppendVarint(&p->rebase, p->nCol, &rc); + sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc); + sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc); + p->bRebaseStarted = 1; } - sessionAppendValue(&p->rebase, pVal, &rc); - } + assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT ); + assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE ); + + sessionAppendByte(&p->rebase, + (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc + ); + sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc); + for(i=0; inCol; i++){ + sqlite3_value *pVal = 0; + if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){ + sqlite3changeset_old(pIter, i, &pVal); + }else{ + sqlite3changeset_new(pIter, i, &pVal); + } + sessionAppendValue(&p->rebase, pVal, &rc); + } + } return rc; } @@ -184646,7 +197117,7 @@ static int sessionRetryConstraints( SessionBuffer cons = pApply->constraints; memset(&pApply->constraints, 0, sizeof(SessionBuffer)); - rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf); + rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0); if( rc==SQLITE_OK ){ int nByte = 2*pApply->nCol*sizeof(sqlite3_value*); int rc2; @@ -184712,6 +197183,7 @@ static int sessionChangesetApply( pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); + sApply.bRebase = (ppRebase && pnRebase); sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); @@ -184862,7 +197334,8 @@ static int sessionChangesetApply( } } - if( rc==SQLITE_OK && bPatchset==0 && ppRebase && pnRebase ){ + assert( sApply.bRebase || sApply.rebase.nBuf==0 ); + if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ *ppRebase = (void*)sApply.rebase.aBuf; *pnRebase = sApply.rebase.nBuf; sApply.rebase.aBuf = 0; @@ -184900,7 +197373,8 @@ SQLITE_API int sqlite3changeset_apply_v2( int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags @@ -184957,7 +197431,8 @@ SQLITE_API int sqlite3changeset_apply_v2_strm( int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags @@ -185330,13 +197805,12 @@ static int sessionChangegroupOutput( sessionAppendByte(&buf, p->op, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); + if( rc==SQLITE_OK && xOutput && buf.nBuf>=sessions_strm_chunk_size ){ + rc = xOutput(pOut, buf.aBuf, buf.nBuf); + buf.nBuf = 0; + } } } - - if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ - rc = xOutput(pOut, buf.aBuf, buf.nBuf); - buf.nBuf = 0; - } } if( rc==SQLITE_OK ){ @@ -185727,7 +198201,7 @@ static int sessionRebase( sessionAppendByte(&sOut, pIter->bIndirect, &rc); sessionAppendBlob(&sOut, aRec, nRec, &rc); } - if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){ + if( rc==SQLITE_OK && xOutput && sOut.nBuf>sessions_strm_chunk_size ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; } @@ -185838,2439 +198312,30 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){ } } +/* +** Global configuration +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg){ + int rc = SQLITE_OK; + switch( op ){ + case SQLITE_SESSION_CONFIG_STRMSIZE: { + int *pInt = (int*)pArg; + if( *pInt>0 ){ + sessions_strm_chunk_size = *pInt; + } + *pInt = sessions_strm_chunk_size; + break; + } + default: + rc = SQLITE_MISUSE; + break; + } + return rc; +} + #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ /************** End of sqlite3session.c **************************************/ -/************** Begin file json1.c *******************************************/ -/* -** 2015-08-12 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This SQLite extension implements JSON functions. The interface is -** modeled after MySQL JSON functions: -** -** https://dev.mysql.com/doc/refman/5.7/en/json.html -** -** For the time being, all JSON is stored as pure text. (We might add -** a JSONB type in the future which stores a binary encoding of JSON in -** a BLOB, but there is no support for JSONB in the current implementation. -** This implementation parses JSON text at 250 MB/s, so it is hard to see -** how JSONB might improve on that.) -*/ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) -#if !defined(SQLITEINT_H) -/* #include "sqlite3ext.h" */ -#endif -SQLITE_EXTENSION_INIT1 -/* #include */ -/* #include */ -/* #include */ -/* #include */ - -/* Mark a function parameter as unused, to suppress nuisance compiler -** warnings. */ -#ifndef UNUSED_PARAM -# define UNUSED_PARAM(X) (void)(X) -#endif - -#ifndef LARGEST_INT64 -# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) -# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) -#endif - -/* -** Versions of isspace(), isalnum() and isdigit() to which it is safe -** to pass signed char values. -*/ -#ifdef sqlite3Isdigit - /* Use the SQLite core versions if this routine is part of the - ** SQLite amalgamation */ -# define safe_isdigit(x) sqlite3Isdigit(x) -# define safe_isalnum(x) sqlite3Isalnum(x) -# define safe_isxdigit(x) sqlite3Isxdigit(x) -#else - /* Use the standard library for separate compilation */ -#include /* amalgamator: keep */ -# define safe_isdigit(x) isdigit((unsigned char)(x)) -# define safe_isalnum(x) isalnum((unsigned char)(x)) -# define safe_isxdigit(x) isxdigit((unsigned char)(x)) -#endif - -/* -** Growing our own isspace() routine this way is twice as fast as -** the library isspace() function, resulting in a 7% overall performance -** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). -*/ -static const char jsonIsSpace[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; -#define safe_isspace(x) (jsonIsSpace[(unsigned char)x]) - -#ifndef SQLITE_AMALGAMATION - /* Unsigned integer types. These are already defined in the sqliteInt.h, - ** but the definitions need to be repeated for separate compilation. */ - typedef sqlite3_uint64 u64; - typedef unsigned int u32; - typedef unsigned short int u16; - typedef unsigned char u8; -#endif - -/* Objects */ -typedef struct JsonString JsonString; -typedef struct JsonNode JsonNode; -typedef struct JsonParse JsonParse; - -/* An instance of this object represents a JSON string -** under construction. Really, this is a generic string accumulator -** that can be and is used to create strings other than JSON. -*/ -struct JsonString { - sqlite3_context *pCtx; /* Function context - put error messages here */ - char *zBuf; /* Append JSON content here */ - u64 nAlloc; /* Bytes of storage available in zBuf[] */ - u64 nUsed; /* Bytes of zBuf[] currently used */ - u8 bStatic; /* True if zBuf is static space */ - u8 bErr; /* True if an error has been encountered */ - char zSpace[100]; /* Initial static space */ -}; - -/* JSON type values -*/ -#define JSON_NULL 0 -#define JSON_TRUE 1 -#define JSON_FALSE 2 -#define JSON_INT 3 -#define JSON_REAL 4 -#define JSON_STRING 5 -#define JSON_ARRAY 6 -#define JSON_OBJECT 7 - -/* The "subtype" set for JSON values */ -#define JSON_SUBTYPE 74 /* Ascii for "J" */ - -/* -** Names of the various JSON types: -*/ -static const char * const jsonType[] = { - "null", "true", "false", "integer", "real", "text", "array", "object" -}; - -/* Bit values for the JsonNode.jnFlag field -*/ -#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ -#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ -#define JNODE_REMOVE 0x04 /* Do not output */ -#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */ -#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */ -#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */ -#define JNODE_LABEL 0x40 /* Is a label of an object */ - - -/* A single node of parsed JSON -*/ -struct JsonNode { - u8 eType; /* One of the JSON_ type values */ - u8 jnFlags; /* JNODE flags */ - u32 n; /* Bytes of content, or number of sub-nodes */ - union { - const char *zJContent; /* Content for INT, REAL, and STRING */ - u32 iAppend; /* More terms for ARRAY and OBJECT */ - u32 iKey; /* Key for ARRAY objects in json_tree() */ - u32 iReplace; /* Replacement content for JNODE_REPLACE */ - JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */ - } u; -}; - -/* A completely parsed JSON string -*/ -struct JsonParse { - u32 nNode; /* Number of slots of aNode[] used */ - u32 nAlloc; /* Number of slots of aNode[] allocated */ - JsonNode *aNode; /* Array of nodes containing the parse */ - const char *zJson; /* Original JSON string */ - u32 *aUp; /* Index of parent of each node */ - u8 oom; /* Set to true if out of memory */ - u8 nErr; /* Number of errors seen */ - u16 iDepth; /* Nesting depth */ - int nJson; /* Length of the zJson string in bytes */ -}; - -/* -** Maximum nesting depth of JSON for this implementation. -** -** This limit is needed to avoid a stack overflow in the recursive -** descent parser. A depth of 2000 is far deeper than any sane JSON -** should go. -*/ -#define JSON_MAX_DEPTH 2000 - -/************************************************************************** -** Utility routines for dealing with JsonString objects -**************************************************************************/ - -/* Set the JsonString object to an empty string -*/ -static void jsonZero(JsonString *p){ - p->zBuf = p->zSpace; - p->nAlloc = sizeof(p->zSpace); - p->nUsed = 0; - p->bStatic = 1; -} - -/* Initialize the JsonString object -*/ -static void jsonInit(JsonString *p, sqlite3_context *pCtx){ - p->pCtx = pCtx; - p->bErr = 0; - jsonZero(p); -} - - -/* Free all allocated memory and reset the JsonString object back to its -** initial state. -*/ -static void jsonReset(JsonString *p){ - if( !p->bStatic ) sqlite3_free(p->zBuf); - jsonZero(p); -} - - -/* Report an out-of-memory (OOM) condition -*/ -static void jsonOom(JsonString *p){ - p->bErr = 1; - sqlite3_result_error_nomem(p->pCtx); - jsonReset(p); -} - -/* Enlarge pJson->zBuf so that it can hold at least N more bytes. -** Return zero on success. Return non-zero on an OOM error -*/ -static int jsonGrow(JsonString *p, u32 N){ - u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; - char *zNew; - if( p->bStatic ){ - if( p->bErr ) return 1; - zNew = sqlite3_malloc64(nTotal); - if( zNew==0 ){ - jsonOom(p); - return SQLITE_NOMEM; - } - memcpy(zNew, p->zBuf, (size_t)p->nUsed); - p->zBuf = zNew; - p->bStatic = 0; - }else{ - zNew = sqlite3_realloc64(p->zBuf, nTotal); - if( zNew==0 ){ - jsonOom(p); - return SQLITE_NOMEM; - } - p->zBuf = zNew; - } - p->nAlloc = nTotal; - return SQLITE_OK; -} - -/* Append N bytes from zIn onto the end of the JsonString string. -*/ -static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ - if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; - memcpy(p->zBuf+p->nUsed, zIn, N); - p->nUsed += N; -} - -/* Append formatted text (not to exceed N bytes) to the JsonString. -*/ -static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ - va_list ap; - if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; - va_start(ap, zFormat); - sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); - va_end(ap); - p->nUsed += (int)strlen(p->zBuf+p->nUsed); -} - -/* Append a single character -*/ -static void jsonAppendChar(JsonString *p, char c){ - if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; - p->zBuf[p->nUsed++] = c; -} - -/* Append a comma separator to the output buffer, if the previous -** character is not '[' or '{'. -*/ -static void jsonAppendSeparator(JsonString *p){ - char c; - if( p->nUsed==0 ) return; - c = p->zBuf[p->nUsed-1]; - if( c!='[' && c!='{' ) jsonAppendChar(p, ','); -} - -/* Append the N-byte string in zIn to the end of the JsonString string -** under construction. Enclose the string in "..." and escape -** any double-quotes or backslash characters contained within the -** string. -*/ -static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ - u32 i; - if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; - p->zBuf[p->nUsed++] = '"'; - for(i=0; inUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; - p->zBuf[p->nUsed++] = '\\'; - }else if( c<=0x1f ){ - static const char aSpecial[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - assert( sizeof(aSpecial)==32 ); - assert( aSpecial['\b']=='b' ); - assert( aSpecial['\f']=='f' ); - assert( aSpecial['\n']=='n' ); - assert( aSpecial['\r']=='r' ); - assert( aSpecial['\t']=='t' ); - if( aSpecial[c] ){ - c = aSpecial[c]; - goto json_simple_escape; - } - if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; - p->zBuf[p->nUsed++] = '\\'; - p->zBuf[p->nUsed++] = 'u'; - p->zBuf[p->nUsed++] = '0'; - p->zBuf[p->nUsed++] = '0'; - p->zBuf[p->nUsed++] = '0' + (c>>4); - c = "0123456789abcdef"[c&0xf]; - } - p->zBuf[p->nUsed++] = c; - } - p->zBuf[p->nUsed++] = '"'; - assert( p->nUsednAlloc ); -} - -/* -** Append a function parameter value to the JSON string under -** construction. -*/ -static void jsonAppendValue( - JsonString *p, /* Append to this JSON string */ - sqlite3_value *pValue /* Value to append */ -){ - switch( sqlite3_value_type(pValue) ){ - case SQLITE_NULL: { - jsonAppendRaw(p, "null", 4); - break; - } - case SQLITE_INTEGER: - case SQLITE_FLOAT: { - const char *z = (const char*)sqlite3_value_text(pValue); - u32 n = (u32)sqlite3_value_bytes(pValue); - jsonAppendRaw(p, z, n); - break; - } - case SQLITE_TEXT: { - const char *z = (const char*)sqlite3_value_text(pValue); - u32 n = (u32)sqlite3_value_bytes(pValue); - if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ - jsonAppendRaw(p, z, n); - }else{ - jsonAppendString(p, z, n); - } - break; - } - default: { - if( p->bErr==0 ){ - sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); - p->bErr = 2; - jsonReset(p); - } - break; - } - } -} - - -/* Make the JSON in p the result of the SQL function. -*/ -static void jsonResult(JsonString *p){ - if( p->bErr==0 ){ - sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, - p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, - SQLITE_UTF8); - jsonZero(p); - } - assert( p->bStatic ); -} - -/************************************************************************** -** Utility routines for dealing with JsonNode and JsonParse objects -**************************************************************************/ - -/* -** Return the number of consecutive JsonNode slots need to represent -** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and -** OBJECT types, the number might be larger. -** -** Appended elements are not counted. The value returned is the number -** by which the JsonNode counter should increment in order to go to the -** next peer value. -*/ -static u32 jsonNodeSize(JsonNode *pNode){ - return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; -} - -/* -** Reclaim all memory allocated by a JsonParse object. But do not -** delete the JsonParse object itself. -*/ -static void jsonParseReset(JsonParse *pParse){ - sqlite3_free(pParse->aNode); - pParse->aNode = 0; - pParse->nNode = 0; - pParse->nAlloc = 0; - sqlite3_free(pParse->aUp); - pParse->aUp = 0; -} - -/* -** Free a JsonParse object that was obtained from sqlite3_malloc(). -*/ -static void jsonParseFree(JsonParse *pParse){ - jsonParseReset(pParse); - sqlite3_free(pParse); -} - -/* -** Convert the JsonNode pNode into a pure JSON string and -** append to pOut. Subsubstructure is also included. Return -** the number of JsonNode objects that are encoded. -*/ -static void jsonRenderNode( - JsonNode *pNode, /* The node to render */ - JsonString *pOut, /* Write JSON here */ - sqlite3_value **aReplace /* Replacement values */ -){ - if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){ - if( pNode->jnFlags & JNODE_REPLACE ){ - jsonAppendValue(pOut, aReplace[pNode->u.iReplace]); - return; - } - pNode = pNode->u.pPatch; - } - switch( pNode->eType ){ - default: { - assert( pNode->eType==JSON_NULL ); - jsonAppendRaw(pOut, "null", 4); - break; - } - case JSON_TRUE: { - jsonAppendRaw(pOut, "true", 4); - break; - } - case JSON_FALSE: { - jsonAppendRaw(pOut, "false", 5); - break; - } - case JSON_STRING: { - if( pNode->jnFlags & JNODE_RAW ){ - jsonAppendString(pOut, pNode->u.zJContent, pNode->n); - break; - } - /* Fall through into the next case */ - } - case JSON_REAL: - case JSON_INT: { - jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); - break; - } - case JSON_ARRAY: { - u32 j = 1; - jsonAppendChar(pOut, '['); - for(;;){ - while( j<=pNode->n ){ - if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){ - jsonAppendSeparator(pOut); - jsonRenderNode(&pNode[j], pOut, aReplace); - } - j += jsonNodeSize(&pNode[j]); - } - if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; - pNode = &pNode[pNode->u.iAppend]; - j = 1; - } - jsonAppendChar(pOut, ']'); - break; - } - case JSON_OBJECT: { - u32 j = 1; - jsonAppendChar(pOut, '{'); - for(;;){ - while( j<=pNode->n ){ - if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){ - jsonAppendSeparator(pOut); - jsonRenderNode(&pNode[j], pOut, aReplace); - jsonAppendChar(pOut, ':'); - jsonRenderNode(&pNode[j+1], pOut, aReplace); - } - j += 1 + jsonNodeSize(&pNode[j+1]); - } - if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; - pNode = &pNode[pNode->u.iAppend]; - j = 1; - } - jsonAppendChar(pOut, '}'); - break; - } - } -} - -/* -** Return a JsonNode and all its descendents as a JSON string. -*/ -static void jsonReturnJson( - JsonNode *pNode, /* Node to return */ - sqlite3_context *pCtx, /* Return value for this function */ - sqlite3_value **aReplace /* Array of replacement values */ -){ - JsonString s; - jsonInit(&s, pCtx); - jsonRenderNode(pNode, &s, aReplace); - jsonResult(&s); - sqlite3_result_subtype(pCtx, JSON_SUBTYPE); -} - -/* -** Make the JsonNode the return value of the function. -*/ -static void jsonReturn( - JsonNode *pNode, /* Node to return */ - sqlite3_context *pCtx, /* Return value for this function */ - sqlite3_value **aReplace /* Array of replacement values */ -){ - switch( pNode->eType ){ - default: { - assert( pNode->eType==JSON_NULL ); - sqlite3_result_null(pCtx); - break; - } - case JSON_TRUE: { - sqlite3_result_int(pCtx, 1); - break; - } - case JSON_FALSE: { - sqlite3_result_int(pCtx, 0); - break; - } - case JSON_INT: { - sqlite3_int64 i = 0; - const char *z = pNode->u.zJContent; - if( z[0]=='-' ){ z++; } - while( z[0]>='0' && z[0]<='9' ){ - unsigned v = *(z++) - '0'; - if( i>=LARGEST_INT64/10 ){ - if( i>LARGEST_INT64/10 ) goto int_as_real; - if( z[0]>='0' && z[0]<='9' ) goto int_as_real; - if( v==9 ) goto int_as_real; - if( v==8 ){ - if( pNode->u.zJContent[0]=='-' ){ - sqlite3_result_int64(pCtx, SMALLEST_INT64); - goto int_done; - }else{ - goto int_as_real; - } - } - } - i = i*10 + v; - } - if( pNode->u.zJContent[0]=='-' ){ i = -i; } - sqlite3_result_int64(pCtx, i); - int_done: - break; - int_as_real: /* fall through to real */; - } - case JSON_REAL: { - double r; -#ifdef SQLITE_AMALGAMATION - const char *z = pNode->u.zJContent; - sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); -#else - r = strtod(pNode->u.zJContent, 0); -#endif - sqlite3_result_double(pCtx, r); - break; - } - case JSON_STRING: { -#if 0 /* Never happens because JNODE_RAW is only set by json_set(), - ** json_insert() and json_replace() and those routines do not - ** call jsonReturn() */ - if( pNode->jnFlags & JNODE_RAW ){ - sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, - SQLITE_TRANSIENT); - }else -#endif - assert( (pNode->jnFlags & JNODE_RAW)==0 ); - if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ - /* JSON formatted without any backslash-escapes */ - sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, - SQLITE_TRANSIENT); - }else{ - /* Translate JSON formatted string into raw text */ - u32 i; - u32 n = pNode->n; - const char *z = pNode->u.zJContent; - char *zOut; - u32 j; - zOut = sqlite3_malloc( n+1 ); - if( zOut==0 ){ - sqlite3_result_error_nomem(pCtx); - break; - } - for(i=1, j=0; i>6)); - zOut[j++] = 0x80 | (v&0x3f); - }else{ - zOut[j++] = (char)(0xe0 | (v>>12)); - zOut[j++] = 0x80 | ((v>>6)&0x3f); - zOut[j++] = 0x80 | (v&0x3f); - } - }else{ - if( c=='b' ){ - c = '\b'; - }else if( c=='f' ){ - c = '\f'; - }else if( c=='n' ){ - c = '\n'; - }else if( c=='r' ){ - c = '\r'; - }else if( c=='t' ){ - c = '\t'; - } - zOut[j++] = c; - } - } - } - zOut[j] = 0; - sqlite3_result_text(pCtx, zOut, j, sqlite3_free); - } - break; - } - case JSON_ARRAY: - case JSON_OBJECT: { - jsonReturnJson(pNode, pCtx, aReplace); - break; - } - } -} - -/* Forward reference */ -static int jsonParseAddNode(JsonParse*,u32,u32,const char*); - -/* -** A macro to hint to the compiler that a function should not be -** inlined. -*/ -#if defined(__GNUC__) -# define JSON_NOINLINE __attribute__((noinline)) -#elif defined(_MSC_VER) && _MSC_VER>=1310 -# define JSON_NOINLINE __declspec(noinline) -#else -# define JSON_NOINLINE -#endif - - -static JSON_NOINLINE int jsonParseAddNodeExpand( - JsonParse *pParse, /* Append the node to this object */ - u32 eType, /* Node type */ - u32 n, /* Content size or sub-node count */ - const char *zContent /* Content */ -){ - u32 nNew; - JsonNode *pNew; - assert( pParse->nNode>=pParse->nAlloc ); - if( pParse->oom ) return -1; - nNew = pParse->nAlloc*2 + 10; - pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); - if( pNew==0 ){ - pParse->oom = 1; - return -1; - } - pParse->nAlloc = nNew; - pParse->aNode = pNew; - assert( pParse->nNodenAlloc ); - return jsonParseAddNode(pParse, eType, n, zContent); -} - -/* -** Create a new JsonNode instance based on the arguments and append that -** instance to the JsonParse. Return the index in pParse->aNode[] of the -** new node, or -1 if a memory allocation fails. -*/ -static int jsonParseAddNode( - JsonParse *pParse, /* Append the node to this object */ - u32 eType, /* Node type */ - u32 n, /* Content size or sub-node count */ - const char *zContent /* Content */ -){ - JsonNode *p; - if( pParse->nNode>=pParse->nAlloc ){ - return jsonParseAddNodeExpand(pParse, eType, n, zContent); - } - p = &pParse->aNode[pParse->nNode]; - p->eType = (u8)eType; - p->jnFlags = 0; - p->n = n; - p->u.zJContent = zContent; - return pParse->nNode++; -} - -/* -** Return true if z[] begins with 4 (or more) hexadecimal digits -*/ -static int jsonIs4Hex(const char *z){ - int i; - for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0; - return 1; -} - -/* -** Parse a single JSON value which begins at pParse->zJson[i]. Return the -** index of the first character past the end of the value parsed. -** -** Return negative for a syntax error. Special cases: return -2 if the -** first non-whitespace character is '}' and return -3 if the first -** non-whitespace character is ']'. -*/ -static int jsonParseValue(JsonParse *pParse, u32 i){ - char c; - u32 j; - int iThis; - int x; - JsonNode *pNode; - const char *z = pParse->zJson; - while( safe_isspace(z[i]) ){ i++; } - if( (c = z[i])=='{' ){ - /* Parse object */ - iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); - if( iThis<0 ) return -1; - for(j=i+1;;j++){ - while( safe_isspace(z[j]) ){ j++; } - if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; - x = jsonParseValue(pParse, j); - if( x<0 ){ - pParse->iDepth--; - if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; - return -1; - } - if( pParse->oom ) return -1; - pNode = &pParse->aNode[pParse->nNode-1]; - if( pNode->eType!=JSON_STRING ) return -1; - pNode->jnFlags |= JNODE_LABEL; - j = x; - while( safe_isspace(z[j]) ){ j++; } - if( z[j]!=':' ) return -1; - j++; - x = jsonParseValue(pParse, j); - pParse->iDepth--; - if( x<0 ) return -1; - j = x; - while( safe_isspace(z[j]) ){ j++; } - c = z[j]; - if( c==',' ) continue; - if( c!='}' ) return -1; - break; - } - pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; - return j+1; - }else if( c=='[' ){ - /* Parse array */ - iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); - if( iThis<0 ) return -1; - for(j=i+1;;j++){ - while( safe_isspace(z[j]) ){ j++; } - if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; - x = jsonParseValue(pParse, j); - pParse->iDepth--; - if( x<0 ){ - if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; - return -1; - } - j = x; - while( safe_isspace(z[j]) ){ j++; } - c = z[j]; - if( c==',' ) continue; - if( c!=']' ) return -1; - break; - } - pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; - return j+1; - }else if( c=='"' ){ - /* Parse string */ - u8 jnFlags = 0; - j = i+1; - for(;;){ - c = z[j]; - if( (c & ~0x1f)==0 ){ - /* Control characters are not allowed in strings */ - return -1; - } - if( c=='\\' ){ - c = z[++j]; - if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' - || c=='n' || c=='r' || c=='t' - || (c=='u' && jsonIs4Hex(z+j+1)) ){ - jnFlags = JNODE_ESCAPE; - }else{ - return -1; - } - }else if( c=='"' ){ - break; - } - j++; - } - jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); - if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; - return j+1; - }else if( c=='n' - && strncmp(z+i,"null",4)==0 - && !safe_isalnum(z[i+4]) ){ - jsonParseAddNode(pParse, JSON_NULL, 0, 0); - return i+4; - }else if( c=='t' - && strncmp(z+i,"true",4)==0 - && !safe_isalnum(z[i+4]) ){ - jsonParseAddNode(pParse, JSON_TRUE, 0, 0); - return i+4; - }else if( c=='f' - && strncmp(z+i,"false",5)==0 - && !safe_isalnum(z[i+5]) ){ - jsonParseAddNode(pParse, JSON_FALSE, 0, 0); - return i+5; - }else if( c=='-' || (c>='0' && c<='9') ){ - /* Parse number */ - u8 seenDP = 0; - u8 seenE = 0; - assert( '-' < '0' ); - if( c<='0' ){ - j = c=='-' ? i+1 : i; - if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; - } - j = i+1; - for(;; j++){ - c = z[j]; - if( c>='0' && c<='9' ) continue; - if( c=='.' ){ - if( z[j-1]=='-' ) return -1; - if( seenDP ) return -1; - seenDP = 1; - continue; - } - if( c=='e' || c=='E' ){ - if( z[j-1]<'0' ) return -1; - if( seenE ) return -1; - seenDP = seenE = 1; - c = z[j+1]; - if( c=='+' || c=='-' ){ - j++; - c = z[j+1]; - } - if( c<'0' || c>'9' ) return -1; - continue; - } - break; - } - if( z[j-1]<'0' ) return -1; - jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, - j - i, &z[i]); - return j; - }else if( c=='}' ){ - return -2; /* End of {...} */ - }else if( c==']' ){ - return -3; /* End of [...] */ - }else if( c==0 ){ - return 0; /* End of file */ - }else{ - return -1; /* Syntax error */ - } -} - -/* -** Parse a complete JSON string. Return 0 on success or non-zero if there -** are any errors. If an error occurs, free all memory associated with -** pParse. -** -** pParse is uninitialized when this routine is called. -*/ -static int jsonParse( - JsonParse *pParse, /* Initialize and fill this JsonParse object */ - sqlite3_context *pCtx, /* Report errors here */ - const char *zJson /* Input JSON text to be parsed */ -){ - int i; - memset(pParse, 0, sizeof(*pParse)); - if( zJson==0 ) return 1; - pParse->zJson = zJson; - i = jsonParseValue(pParse, 0); - if( pParse->oom ) i = -1; - if( i>0 ){ - assert( pParse->iDepth==0 ); - while( safe_isspace(zJson[i]) ) i++; - if( zJson[i] ) i = -1; - } - if( i<=0 ){ - if( pCtx!=0 ){ - if( pParse->oom ){ - sqlite3_result_error_nomem(pCtx); - }else{ - sqlite3_result_error(pCtx, "malformed JSON", -1); - } - } - jsonParseReset(pParse); - return 1; - } - return 0; -} - -/* Mark node i of pParse as being a child of iParent. Call recursively -** to fill in all the descendants of node i. -*/ -static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ - JsonNode *pNode = &pParse->aNode[i]; - u32 j; - pParse->aUp[i] = iParent; - switch( pNode->eType ){ - case JSON_ARRAY: { - for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ - jsonParseFillInParentage(pParse, i+j, i); - } - break; - } - case JSON_OBJECT: { - for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ - pParse->aUp[i+j] = i; - jsonParseFillInParentage(pParse, i+j+1, i); - } - break; - } - default: { - break; - } - } -} - -/* -** Compute the parentage of all nodes in a completed parse. -*/ -static int jsonParseFindParents(JsonParse *pParse){ - u32 *aUp; - assert( pParse->aUp==0 ); - aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode ); - if( aUp==0 ){ - pParse->oom = 1; - return SQLITE_NOMEM; - } - jsonParseFillInParentage(pParse, 0, 0); - return SQLITE_OK; -} - -/* -** Magic number used for the JSON parse cache in sqlite3_get_auxdata() -*/ -#define JSON_CACHE_ID (-429938) - -/* -** Obtain a complete parse of the JSON found in the first argument -** of the argv array. Use the sqlite3_get_auxdata() cache for this -** parse if it is available. If the cache is not available or if it -** is no longer valid, parse the JSON again and return the new parse, -** and also register the new parse so that it will be available for -** future sqlite3_get_auxdata() calls. -*/ -static JsonParse *jsonParseCached( - sqlite3_context *pCtx, - sqlite3_value **argv -){ - const char *zJson = (const char*)sqlite3_value_text(argv[0]); - int nJson = sqlite3_value_bytes(argv[0]); - JsonParse *p; - if( zJson==0 ) return 0; - p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); - if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){ - p->nErr = 0; - return p; /* The cached entry matches, so return it */ - } - p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); - if( p==0 ){ - sqlite3_result_error_nomem(pCtx); - return 0; - } - memset(p, 0, sizeof(*p)); - p->zJson = (char*)&p[1]; - memcpy((char*)p->zJson, zJson, nJson+1); - if( jsonParse(p, pCtx, p->zJson) ){ - sqlite3_free(p); - return 0; - } - p->nJson = nJson; - sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree); - return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); -} - -/* -** Compare the OBJECT label at pNode against zKey,nKey. Return true on -** a match. -*/ -static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ - if( pNode->jnFlags & JNODE_RAW ){ - if( pNode->n!=nKey ) return 0; - return strncmp(pNode->u.zJContent, zKey, nKey)==0; - }else{ - if( pNode->n!=nKey+2 ) return 0; - return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; - } -} - -/* forward declaration */ -static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); - -/* -** Search along zPath to find the node specified. Return a pointer -** to that node, or NULL if zPath is malformed or if there is no such -** node. -** -** If pApnd!=0, then try to append new nodes to complete zPath if it is -** possible to do so and if no existing node corresponds to zPath. If -** new nodes are appended *pApnd is set to 1. -*/ -static JsonNode *jsonLookupStep( - JsonParse *pParse, /* The JSON to search */ - u32 iRoot, /* Begin the search at this node */ - const char *zPath, /* The path to search */ - int *pApnd, /* Append nodes to complete path if not NULL */ - const char **pzErr /* Make *pzErr point to any syntax error in zPath */ -){ - u32 i, j, nKey; - const char *zKey; - JsonNode *pRoot = &pParse->aNode[iRoot]; - if( zPath[0]==0 ) return pRoot; - if( zPath[0]=='.' ){ - if( pRoot->eType!=JSON_OBJECT ) return 0; - zPath++; - if( zPath[0]=='"' ){ - zKey = zPath + 1; - for(i=1; zPath[i] && zPath[i]!='"'; i++){} - nKey = i-1; - if( zPath[i] ){ - i++; - }else{ - *pzErr = zPath; - return 0; - } - }else{ - zKey = zPath; - for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} - nKey = i; - } - if( nKey==0 ){ - *pzErr = zPath; - return 0; - } - j = 1; - for(;;){ - while( j<=pRoot->n ){ - if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ - return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); - } - j++; - j += jsonNodeSize(&pRoot[j]); - } - if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; - iRoot += pRoot->u.iAppend; - pRoot = &pParse->aNode[iRoot]; - j = 1; - } - if( pApnd ){ - u32 iStart, iLabel; - JsonNode *pNode; - iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); - iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); - zPath += i; - pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); - if( pParse->oom ) return 0; - if( pNode ){ - pRoot = &pParse->aNode[iRoot]; - pRoot->u.iAppend = iStart - iRoot; - pRoot->jnFlags |= JNODE_APPEND; - pParse->aNode[iLabel].jnFlags |= JNODE_RAW; - } - return pNode; - } - }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){ - if( pRoot->eType!=JSON_ARRAY ) return 0; - i = 0; - j = 1; - while( safe_isdigit(zPath[j]) ){ - i = i*10 + zPath[j] - '0'; - j++; - } - if( zPath[j]!=']' ){ - *pzErr = zPath; - return 0; - } - zPath += j + 1; - j = 1; - for(;;){ - while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ - if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--; - j += jsonNodeSize(&pRoot[j]); - } - if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; - iRoot += pRoot->u.iAppend; - pRoot = &pParse->aNode[iRoot]; - j = 1; - } - if( j<=pRoot->n ){ - return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); - } - if( i==0 && pApnd ){ - u32 iStart; - JsonNode *pNode; - iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); - pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); - if( pParse->oom ) return 0; - if( pNode ){ - pRoot = &pParse->aNode[iRoot]; - pRoot->u.iAppend = iStart - iRoot; - pRoot->jnFlags |= JNODE_APPEND; - } - return pNode; - } - }else{ - *pzErr = zPath; - } - return 0; -} - -/* -** Append content to pParse that will complete zPath. Return a pointer -** to the inserted node, or return NULL if the append fails. -*/ -static JsonNode *jsonLookupAppend( - JsonParse *pParse, /* Append content to the JSON parse */ - const char *zPath, /* Description of content to append */ - int *pApnd, /* Set this flag to 1 */ - const char **pzErr /* Make this point to any syntax error */ -){ - *pApnd = 1; - if( zPath[0]==0 ){ - jsonParseAddNode(pParse, JSON_NULL, 0, 0); - return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; - } - if( zPath[0]=='.' ){ - jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); - }else if( strncmp(zPath,"[0]",3)==0 ){ - jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); - }else{ - return 0; - } - if( pParse->oom ) return 0; - return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); -} - -/* -** Return the text of a syntax error message on a JSON path. Space is -** obtained from sqlite3_malloc(). -*/ -static char *jsonPathSyntaxError(const char *zErr){ - return sqlite3_mprintf("JSON path error near '%q'", zErr); -} - -/* -** Do a node lookup using zPath. Return a pointer to the node on success. -** Return NULL if not found or if there is an error. -** -** On an error, write an error message into pCtx and increment the -** pParse->nErr counter. -** -** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if -** nodes are appended. -*/ -static JsonNode *jsonLookup( - JsonParse *pParse, /* The JSON to search */ - const char *zPath, /* The path to search */ - int *pApnd, /* Append nodes to complete path if not NULL */ - sqlite3_context *pCtx /* Report errors here, if not NULL */ -){ - const char *zErr = 0; - JsonNode *pNode = 0; - char *zMsg; - - if( zPath==0 ) return 0; - if( zPath[0]!='$' ){ - zErr = zPath; - goto lookup_err; - } - zPath++; - pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); - if( zErr==0 ) return pNode; - -lookup_err: - pParse->nErr++; - assert( zErr!=0 && pCtx!=0 ); - zMsg = jsonPathSyntaxError(zErr); - if( zMsg ){ - sqlite3_result_error(pCtx, zMsg, -1); - sqlite3_free(zMsg); - }else{ - sqlite3_result_error_nomem(pCtx); - } - return 0; -} - - -/* -** Report the wrong number of arguments for json_insert(), json_replace() -** or json_set(). -*/ -static void jsonWrongNumArgs( - sqlite3_context *pCtx, - const char *zFuncName -){ - char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", - zFuncName); - sqlite3_result_error(pCtx, zMsg, -1); - sqlite3_free(zMsg); -} - -/* -** Mark all NULL entries in the Object passed in as JNODE_REMOVE. -*/ -static void jsonRemoveAllNulls(JsonNode *pNode){ - int i, n; - assert( pNode->eType==JSON_OBJECT ); - n = pNode->n; - for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){ - switch( pNode[i].eType ){ - case JSON_NULL: - pNode[i].jnFlags |= JNODE_REMOVE; - break; - case JSON_OBJECT: - jsonRemoveAllNulls(&pNode[i]); - break; - } - } -} - - -/**************************************************************************** -** SQL functions used for testing and debugging -****************************************************************************/ - -#ifdef SQLITE_DEBUG -/* -** The json_parse(JSON) function returns a string which describes -** a parse of the JSON provided. Or it returns NULL if JSON is not -** well-formed. -*/ -static void jsonParseFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonString s; /* Output string - not real JSON */ - JsonParse x; /* The parse */ - u32 i; - - assert( argc==1 ); - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - jsonParseFindParents(&x); - jsonInit(&s, ctx); - for(i=0; inNode ); - if( argc==2 ){ - const char *zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(p, zPath, 0, ctx); - }else{ - pNode = p->aNode; - } - if( pNode==0 ){ - return; - } - if( pNode->eType==JSON_ARRAY ){ - assert( (pNode->jnFlags & JNODE_APPEND)==0 ); - for(i=1; i<=pNode->n; n++){ - i += jsonNodeSize(&pNode[i]); - } - } - sqlite3_result_int64(ctx, n); -} - -/* -** json_extract(JSON, PATH, ...) -** -** Return the element described by PATH. Return NULL if there is no -** PATH element. If there are multiple PATHs, then return a JSON array -** with the result from each path. Throw an error if the JSON or any PATH -** is malformed. -*/ -static void jsonExtractFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse *p; /* The parse */ - JsonNode *pNode; - const char *zPath; - JsonString jx; - int i; - - if( argc<2 ) return; - p = jsonParseCached(ctx, argv); - if( p==0 ) return; - jsonInit(&jx, ctx); - jsonAppendChar(&jx, '['); - for(i=1; inErr ) break; - if( argc>2 ){ - jsonAppendSeparator(&jx); - if( pNode ){ - jsonRenderNode(pNode, &jx, 0); - }else{ - jsonAppendRaw(&jx, "null", 4); - } - }else if( pNode ){ - jsonReturn(pNode, ctx, 0); - } - } - if( argc>2 && i==argc ){ - jsonAppendChar(&jx, ']'); - jsonResult(&jx); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } - jsonReset(&jx); -} - -/* This is the RFC 7396 MergePatch algorithm. -*/ -static JsonNode *jsonMergePatch( - JsonParse *pParse, /* The JSON parser that contains the TARGET */ - u32 iTarget, /* Node of the TARGET in pParse */ - JsonNode *pPatch /* The PATCH */ -){ - u32 i, j; - u32 iRoot; - JsonNode *pTarget; - if( pPatch->eType!=JSON_OBJECT ){ - return pPatch; - } - assert( iTarget>=0 && iTargetnNode ); - pTarget = &pParse->aNode[iTarget]; - assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); - if( pTarget->eType!=JSON_OBJECT ){ - jsonRemoveAllNulls(pPatch); - return pPatch; - } - iRoot = iTarget; - for(i=1; in; i += jsonNodeSize(&pPatch[i+1])+1){ - u32 nKey; - const char *zKey; - assert( pPatch[i].eType==JSON_STRING ); - assert( pPatch[i].jnFlags & JNODE_LABEL ); - nKey = pPatch[i].n; - zKey = pPatch[i].u.zJContent; - assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); - for(j=1; jn; j += jsonNodeSize(&pTarget[j+1])+1 ){ - assert( pTarget[j].eType==JSON_STRING ); - assert( pTarget[j].jnFlags & JNODE_LABEL ); - assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); - if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){ - if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break; - if( pPatch[i+1].eType==JSON_NULL ){ - pTarget[j+1].jnFlags |= JNODE_REMOVE; - }else{ - JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); - if( pNew==0 ) return 0; - pTarget = &pParse->aNode[iTarget]; - if( pNew!=&pTarget[j+1] ){ - pTarget[j+1].u.pPatch = pNew; - pTarget[j+1].jnFlags |= JNODE_PATCH; - } - } - break; - } - } - if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ - int iStart, iPatch; - iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); - jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); - iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0); - if( pParse->oom ) return 0; - jsonRemoveAllNulls(pPatch); - pTarget = &pParse->aNode[iTarget]; - pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; - pParse->aNode[iRoot].u.iAppend = iStart - iRoot; - iRoot = iStart; - pParse->aNode[iPatch].jnFlags |= JNODE_PATCH; - pParse->aNode[iPatch].u.pPatch = &pPatch[i+1]; - } - } - return pTarget; -} - -/* -** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON -** object that is the result of running the RFC 7396 MergePatch() algorithm -** on the two arguments. -*/ -static void jsonPatchFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse x; /* The JSON that is being patched */ - JsonParse y; /* The patch */ - JsonNode *pResult; /* The result of the merge */ - - UNUSED_PARAM(argc); - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){ - jsonParseReset(&x); - return; - } - pResult = jsonMergePatch(&x, 0, y.aNode); - assert( pResult!=0 || x.oom ); - if( pResult ){ - jsonReturnJson(pResult, ctx, 0); - }else{ - sqlite3_result_error_nomem(ctx); - } - jsonParseReset(&x); - jsonParseReset(&y); -} - - -/* -** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON -** object that contains all name/value given in arguments. Or if any name -** is not a string or if any value is a BLOB, throw an error. -*/ -static void jsonObjectFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - int i; - JsonString jx; - const char *z; - u32 n; - - if( argc&1 ){ - sqlite3_result_error(ctx, "json_object() requires an even number " - "of arguments", -1); - return; - } - jsonInit(&jx, ctx); - jsonAppendChar(&jx, '{'); - for(i=0; ijnFlags |= JNODE_REMOVE; - } - if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ - jsonReturnJson(x.aNode, ctx, 0); - } -remove_done: - jsonParseReset(&x); -} - -/* -** json_replace(JSON, PATH, VALUE, ...) -** -** Replace the value at PATH with VALUE. If PATH does not already exist, -** this routine is a no-op. If JSON or PATH is malformed, throw an error. -*/ -static void jsonReplaceFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse x; /* The parse */ - JsonNode *pNode; - const char *zPath; - u32 i; - - if( argc<1 ) return; - if( (argc&1)==0 ) { - jsonWrongNumArgs(ctx, "replace"); - return; - } - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); - for(i=1; i<(u32)argc; i+=2){ - zPath = (const char*)sqlite3_value_text(argv[i]); - pNode = jsonLookup(&x, zPath, 0, ctx); - if( x.nErr ) goto replace_err; - if( pNode ){ - pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->u.iReplace = i + 1; - } - } - if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); - }else{ - jsonReturnJson(x.aNode, ctx, argv); - } -replace_err: - jsonParseReset(&x); -} - -/* -** json_set(JSON, PATH, VALUE, ...) -** -** Set the value at PATH to VALUE. Create the PATH if it does not already -** exist. Overwrite existing values that do exist. -** If JSON or PATH is malformed, throw an error. -** -** json_insert(JSON, PATH, VALUE, ...) -** -** Create PATH and initialize it to VALUE. If PATH already exists, this -** routine is a no-op. If JSON or PATH is malformed, throw an error. -*/ -static void jsonSetFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse x; /* The parse */ - JsonNode *pNode; - const char *zPath; - u32 i; - int bApnd; - int bIsSet = *(int*)sqlite3_user_data(ctx); - - if( argc<1 ) return; - if( (argc&1)==0 ) { - jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); - return; - } - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); - for(i=1; i<(u32)argc; i+=2){ - zPath = (const char*)sqlite3_value_text(argv[i]); - bApnd = 0; - pNode = jsonLookup(&x, zPath, &bApnd, ctx); - if( x.oom ){ - sqlite3_result_error_nomem(ctx); - goto jsonSetDone; - }else if( x.nErr ){ - goto jsonSetDone; - }else if( pNode && (bApnd || bIsSet) ){ - pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->u.iReplace = i + 1; - } - } - if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); - }else{ - jsonReturnJson(x.aNode, ctx, argv); - } -jsonSetDone: - jsonParseReset(&x); -} - -/* -** json_type(JSON) -** json_type(JSON, PATH) -** -** Return the top-level "type" of a JSON string. Throw an error if -** either the JSON or PATH inputs are not well-formed. -*/ -static void jsonTypeFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse x; /* The parse */ - const char *zPath; - JsonNode *pNode; - - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); - if( argc==2 ){ - zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); - }else{ - pNode = x.aNode; - } - if( pNode ){ - sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); - } - jsonParseReset(&x); -} - -/* -** json_valid(JSON) -** -** Return 1 if JSON is a well-formed JSON string according to RFC-7159. -** Return 0 otherwise. -*/ -static void jsonValidFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse x; /* The parse */ - int rc = 0; - - UNUSED_PARAM(argc); - if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){ - rc = 1; - } - jsonParseReset(&x); - sqlite3_result_int(ctx, rc); -} - - -/**************************************************************************** -** Aggregate SQL function implementations -****************************************************************************/ -/* -** json_group_array(VALUE) -** -** Return a JSON array composed of all values in the aggregate. -*/ -static void jsonArrayStep( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonString *pStr; - UNUSED_PARAM(argc); - pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); - if( pStr ){ - if( pStr->zBuf==0 ){ - jsonInit(pStr, ctx); - jsonAppendChar(pStr, '['); - }else{ - jsonAppendChar(pStr, ','); - pStr->pCtx = ctx; - } - jsonAppendValue(pStr, argv[0]); - } -} -static void jsonArrayFinal(sqlite3_context *ctx){ - JsonString *pStr; - pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); - if( pStr ){ - pStr->pCtx = ctx; - jsonAppendChar(pStr, ']'); - if( pStr->bErr ){ - if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); - assert( pStr->bStatic ); - }else{ - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, - pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); - pStr->bStatic = 1; - } - }else{ - sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); - } - sqlite3_result_subtype(ctx, JSON_SUBTYPE); -} - -/* -** json_group_obj(NAME,VALUE) -** -** Return a JSON object composed of all names and values in the aggregate. -*/ -static void jsonObjectStep( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonString *pStr; - const char *z; - u32 n; - UNUSED_PARAM(argc); - pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); - if( pStr ){ - if( pStr->zBuf==0 ){ - jsonInit(pStr, ctx); - jsonAppendChar(pStr, '{'); - }else{ - jsonAppendChar(pStr, ','); - pStr->pCtx = ctx; - } - z = (const char*)sqlite3_value_text(argv[0]); - n = (u32)sqlite3_value_bytes(argv[0]); - jsonAppendString(pStr, z, n); - jsonAppendChar(pStr, ':'); - jsonAppendValue(pStr, argv[1]); - } -} -static void jsonObjectFinal(sqlite3_context *ctx){ - JsonString *pStr; - pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); - if( pStr ){ - jsonAppendChar(pStr, '}'); - if( pStr->bErr ){ - if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); - assert( pStr->bStatic ); - }else{ - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, - pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); - pStr->bStatic = 1; - } - }else{ - sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); - } - sqlite3_result_subtype(ctx, JSON_SUBTYPE); -} - - -#ifndef SQLITE_OMIT_VIRTUALTABLE -/**************************************************************************** -** The json_each virtual table -****************************************************************************/ -typedef struct JsonEachCursor JsonEachCursor; -struct JsonEachCursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - u32 iRowid; /* The rowid */ - u32 iBegin; /* The first node of the scan */ - u32 i; /* Index in sParse.aNode[] of current row */ - u32 iEnd; /* EOF when i equals or exceeds this value */ - u8 eType; /* Type of top-level element */ - u8 bRecursive; /* True for json_tree(). False for json_each() */ - char *zJson; /* Input JSON */ - char *zRoot; /* Path by which to filter zJson */ - JsonParse sParse; /* Parse of the input JSON */ -}; - -/* Constructor for the json_each virtual table */ -static int jsonEachConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - sqlite3_vtab *pNew; - int rc; - -/* Column numbers */ -#define JEACH_KEY 0 -#define JEACH_VALUE 1 -#define JEACH_TYPE 2 -#define JEACH_ATOM 3 -#define JEACH_ID 4 -#define JEACH_PARENT 5 -#define JEACH_FULLKEY 6 -#define JEACH_PATH 7 -#define JEACH_JSON 8 -#define JEACH_ROOT 9 - - UNUSED_PARAM(pzErr); - UNUSED_PARAM(argv); - UNUSED_PARAM(argc); - UNUSED_PARAM(pAux); - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," - "json HIDDEN,root HIDDEN)"); - if( rc==SQLITE_OK ){ - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - } - return rc; -} - -/* destructor for json_each virtual table */ -static int jsonEachDisconnect(sqlite3_vtab *pVtab){ - sqlite3_free(pVtab); - return SQLITE_OK; -} - -/* constructor for a JsonEachCursor object for json_each(). */ -static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - JsonEachCursor *pCur; - - UNUSED_PARAM(p); - pCur = sqlite3_malloc( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - *ppCursor = &pCur->base; - return SQLITE_OK; -} - -/* constructor for a JsonEachCursor object for json_tree(). */ -static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - int rc = jsonEachOpenEach(p, ppCursor); - if( rc==SQLITE_OK ){ - JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; - pCur->bRecursive = 1; - } - return rc; -} - -/* Reset a JsonEachCursor back to its original state. Free any memory -** held. */ -static void jsonEachCursorReset(JsonEachCursor *p){ - sqlite3_free(p->zJson); - sqlite3_free(p->zRoot); - jsonParseReset(&p->sParse); - p->iRowid = 0; - p->i = 0; - p->iEnd = 0; - p->eType = 0; - p->zJson = 0; - p->zRoot = 0; -} - -/* Destructor for a jsonEachCursor object */ -static int jsonEachClose(sqlite3_vtab_cursor *cur){ - JsonEachCursor *p = (JsonEachCursor*)cur; - jsonEachCursorReset(p); - sqlite3_free(cur); - return SQLITE_OK; -} - -/* Return TRUE if the jsonEachCursor object has been advanced off the end -** of the JSON object */ -static int jsonEachEof(sqlite3_vtab_cursor *cur){ - JsonEachCursor *p = (JsonEachCursor*)cur; - return p->i >= p->iEnd; -} - -/* Advance the cursor to the next element for json_tree() */ -static int jsonEachNext(sqlite3_vtab_cursor *cur){ - JsonEachCursor *p = (JsonEachCursor*)cur; - if( p->bRecursive ){ - if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; - p->i++; - p->iRowid++; - if( p->iiEnd ){ - u32 iUp = p->sParse.aUp[p->i]; - JsonNode *pUp = &p->sParse.aNode[iUp]; - p->eType = pUp->eType; - if( pUp->eType==JSON_ARRAY ){ - if( iUp==p->i-1 ){ - pUp->u.iKey = 0; - }else{ - pUp->u.iKey++; - } - } - } - }else{ - switch( p->eType ){ - case JSON_ARRAY: { - p->i += jsonNodeSize(&p->sParse.aNode[p->i]); - p->iRowid++; - break; - } - case JSON_OBJECT: { - p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); - p->iRowid++; - break; - } - default: { - p->i = p->iEnd; - break; - } - } - } - return SQLITE_OK; -} - -/* Append the name of the path for element i to pStr -*/ -static void jsonEachComputePath( - JsonEachCursor *p, /* The cursor */ - JsonString *pStr, /* Write the path here */ - u32 i /* Path to this element */ -){ - JsonNode *pNode, *pUp; - u32 iUp; - if( i==0 ){ - jsonAppendChar(pStr, '$'); - return; - } - iUp = p->sParse.aUp[i]; - jsonEachComputePath(p, pStr, iUp); - pNode = &p->sParse.aNode[i]; - pUp = &p->sParse.aNode[iUp]; - if( pUp->eType==JSON_ARRAY ){ - jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); - }else{ - assert( pUp->eType==JSON_OBJECT ); - if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; - assert( pNode->eType==JSON_STRING ); - assert( pNode->jnFlags & JNODE_LABEL ); - jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); - } -} - -/* Return the value of a column */ -static int jsonEachColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ -){ - JsonEachCursor *p = (JsonEachCursor*)cur; - JsonNode *pThis = &p->sParse.aNode[p->i]; - switch( i ){ - case JEACH_KEY: { - if( p->i==0 ) break; - if( p->eType==JSON_OBJECT ){ - jsonReturn(pThis, ctx, 0); - }else if( p->eType==JSON_ARRAY ){ - u32 iKey; - if( p->bRecursive ){ - if( p->iRowid==0 ) break; - iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; - }else{ - iKey = p->iRowid; - } - sqlite3_result_int64(ctx, (sqlite3_int64)iKey); - } - break; - } - case JEACH_VALUE: { - if( pThis->jnFlags & JNODE_LABEL ) pThis++; - jsonReturn(pThis, ctx, 0); - break; - } - case JEACH_TYPE: { - if( pThis->jnFlags & JNODE_LABEL ) pThis++; - sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); - break; - } - case JEACH_ATOM: { - if( pThis->jnFlags & JNODE_LABEL ) pThis++; - if( pThis->eType>=JSON_ARRAY ) break; - jsonReturn(pThis, ctx, 0); - break; - } - case JEACH_ID: { - sqlite3_result_int64(ctx, - (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); - break; - } - case JEACH_PARENT: { - if( p->i>p->iBegin && p->bRecursive ){ - sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); - } - break; - } - case JEACH_FULLKEY: { - JsonString x; - jsonInit(&x, ctx); - if( p->bRecursive ){ - jsonEachComputePath(p, &x, p->i); - }else{ - if( p->zRoot ){ - jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); - }else{ - jsonAppendChar(&x, '$'); - } - if( p->eType==JSON_ARRAY ){ - jsonPrintf(30, &x, "[%d]", p->iRowid); - }else{ - jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); - } - } - jsonResult(&x); - break; - } - case JEACH_PATH: { - if( p->bRecursive ){ - JsonString x; - jsonInit(&x, ctx); - jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); - jsonResult(&x); - break; - } - /* For json_each() path and root are the same so fall through - ** into the root case */ - } - default: { - const char *zRoot = p->zRoot; - if( zRoot==0 ) zRoot = "$"; - sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); - break; - } - case JEACH_JSON: { - assert( i==JEACH_JSON ); - sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); - break; - } - } - return SQLITE_OK; -} - -/* Return the current rowid value */ -static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - JsonEachCursor *p = (JsonEachCursor*)cur; - *pRowid = p->iRowid; - return SQLITE_OK; -} - -/* The query strategy is to look for an equality constraint on the json -** column. Without such a constraint, the table cannot operate. idxNum is -** 1 if the constraint is found, 3 if the constraint and zRoot are found, -** and 0 otherwise. -*/ -static int jsonEachBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo -){ - int i; - int jsonIdx = -1; - int rootIdx = -1; - const struct sqlite3_index_constraint *pConstraint; - - UNUSED_PARAM(tab); - pConstraint = pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->usable==0 ) continue; - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case JEACH_JSON: jsonIdx = i; break; - case JEACH_ROOT: rootIdx = i; break; - default: /* no-op */ break; - } - } - if( jsonIdx<0 ){ - pIdxInfo->idxNum = 0; - pIdxInfo->estimatedCost = 1e99; - }else{ - pIdxInfo->estimatedCost = 1.0; - pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1; - pIdxInfo->aConstraintUsage[jsonIdx].omit = 1; - if( rootIdx<0 ){ - pIdxInfo->idxNum = 1; - }else{ - pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2; - pIdxInfo->aConstraintUsage[rootIdx].omit = 1; - pIdxInfo->idxNum = 3; - } - } - return SQLITE_OK; -} - -/* Start a search on a new JSON string */ -static int jsonEachFilter( - sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - JsonEachCursor *p = (JsonEachCursor*)cur; - const char *z; - const char *zRoot = 0; - sqlite3_int64 n; - - UNUSED_PARAM(idxStr); - UNUSED_PARAM(argc); - jsonEachCursorReset(p); - if( idxNum==0 ) return SQLITE_OK; - z = (const char*)sqlite3_value_text(argv[0]); - if( z==0 ) return SQLITE_OK; - n = sqlite3_value_bytes(argv[0]); - p->zJson = sqlite3_malloc64( n+1 ); - if( p->zJson==0 ) return SQLITE_NOMEM; - memcpy(p->zJson, z, (size_t)n+1); - if( jsonParse(&p->sParse, 0, p->zJson) ){ - int rc = SQLITE_NOMEM; - if( p->sParse.oom==0 ){ - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); - if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; - } - jsonEachCursorReset(p); - return rc; - }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ - jsonEachCursorReset(p); - return SQLITE_NOMEM; - }else{ - JsonNode *pNode = 0; - if( idxNum==3 ){ - const char *zErr = 0; - zRoot = (const char*)sqlite3_value_text(argv[1]); - if( zRoot==0 ) return SQLITE_OK; - n = sqlite3_value_bytes(argv[1]); - p->zRoot = sqlite3_malloc64( n+1 ); - if( p->zRoot==0 ) return SQLITE_NOMEM; - memcpy(p->zRoot, zRoot, (size_t)n+1); - if( zRoot[0]!='$' ){ - zErr = zRoot; - }else{ - pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); - } - if( zErr ){ - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); - jsonEachCursorReset(p); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; - }else if( pNode==0 ){ - return SQLITE_OK; - } - }else{ - pNode = p->sParse.aNode; - } - p->iBegin = p->i = (int)(pNode - p->sParse.aNode); - p->eType = pNode->eType; - if( p->eType>=JSON_ARRAY ){ - pNode->u.iKey = 0; - p->iEnd = p->i + pNode->n + 1; - if( p->bRecursive ){ - p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; - if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ - p->i--; - } - }else{ - p->i++; - } - }else{ - p->iEnd = p->i+1; - } - } - return SQLITE_OK; -} - -/* The methods of the json_each virtual table */ -static sqlite3_module jsonEachModule = { - 0, /* iVersion */ - 0, /* xCreate */ - jsonEachConnect, /* xConnect */ - jsonEachBestIndex, /* xBestIndex */ - jsonEachDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - jsonEachOpenEach, /* xOpen - open a cursor */ - jsonEachClose, /* xClose - close a cursor */ - jsonEachFilter, /* xFilter - configure scan constraints */ - jsonEachNext, /* xNext - advance a cursor */ - jsonEachEof, /* xEof - check for end of scan */ - jsonEachColumn, /* xColumn - read data */ - jsonEachRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ -}; - -/* The methods of the json_tree virtual table. */ -static sqlite3_module jsonTreeModule = { - 0, /* iVersion */ - 0, /* xCreate */ - jsonEachConnect, /* xConnect */ - jsonEachBestIndex, /* xBestIndex */ - jsonEachDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - jsonEachOpenTree, /* xOpen - open a cursor */ - jsonEachClose, /* xClose - close a cursor */ - jsonEachFilter, /* xFilter - configure scan constraints */ - jsonEachNext, /* xNext - advance a cursor */ - jsonEachEof, /* xEof - check for end of scan */ - jsonEachColumn, /* xColumn - read data */ - jsonEachRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ -}; -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - -/**************************************************************************** -** The following routines are the only publically visible identifiers in this -** file. Call the following routines in order to register the various SQL -** functions and the virtual table implemented by this file. -****************************************************************************/ - -SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){ - int rc = SQLITE_OK; - unsigned int i; - static const struct { - const char *zName; - int nArg; - int flag; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "json", 1, 0, jsonRemoveFunc }, - { "json_array", -1, 0, jsonArrayFunc }, - { "json_array_length", 1, 0, jsonArrayLengthFunc }, - { "json_array_length", 2, 0, jsonArrayLengthFunc }, - { "json_extract", -1, 0, jsonExtractFunc }, - { "json_insert", -1, 0, jsonSetFunc }, - { "json_object", -1, 0, jsonObjectFunc }, - { "json_patch", 2, 0, jsonPatchFunc }, - { "json_quote", 1, 0, jsonQuoteFunc }, - { "json_remove", -1, 0, jsonRemoveFunc }, - { "json_replace", -1, 0, jsonReplaceFunc }, - { "json_set", -1, 1, jsonSetFunc }, - { "json_type", 1, 0, jsonTypeFunc }, - { "json_type", 2, 0, jsonTypeFunc }, - { "json_valid", 1, 0, jsonValidFunc }, - -#if SQLITE_DEBUG - /* DEBUG and TESTING functions */ - { "json_parse", 1, 0, jsonParseFunc }, - { "json_test1", 1, 0, jsonTest1Func }, -#endif - }; - static const struct { - const char *zName; - int nArg; - void (*xStep)(sqlite3_context*,int,sqlite3_value**); - void (*xFinal)(sqlite3_context*); - } aAgg[] = { - { "json_group_array", 1, jsonArrayStep, jsonArrayFinal }, - { "json_group_object", 2, jsonObjectStep, jsonObjectFinal }, - }; -#ifndef SQLITE_OMIT_VIRTUALTABLE - static const struct { - const char *zName; - sqlite3_module *pModule; - } aMod[] = { - { "json_each", &jsonEachModule }, - { "json_tree", &jsonTreeModule }, - }; -#endif - for(i=0; i ** @@ -188757,7 +198822,7 @@ struct Fts5ExtensionApi { ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the -** token "first" is subsituted for "1st" by the tokenizer, then the query: +** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** ** ... MATCH '1s*' @@ -189649,9 +199714,12 @@ static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*); /************************************************************************** ** Interface to automatically generated code in fts5_unicode2.c. */ -static int sqlite3Fts5UnicodeIsalnum(int c); static int sqlite3Fts5UnicodeIsdiacritic(int c); static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); + +static int sqlite3Fts5UnicodeCatParse(const char*, u8*); +static int sqlite3Fts5UnicodeCategory(int iCode); +static void sqlite3Fts5UnicodeAscii(u8*, u8*); /* ** End of interface to code in fts5_unicode2.c. **************************************************************************/ @@ -189699,6 +199767,7 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); ** input grammar file: */ /* #include */ +/* #include */ /************ Begin %include sections from the grammar ************************/ /* #include "fts5Int.h" */ @@ -189767,8 +199836,10 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); ** zero the stack is dynamically sized using realloc() ** sqlite3Fts5ParserARG_SDECL A static variable declaration for the %extra_argument ** sqlite3Fts5ParserARG_PDECL A parameter declaration for the %extra_argument +** sqlite3Fts5ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter ** sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser ** sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser +** sqlite3Fts5ParserCTX_* As sqlite3Fts5ParserARG_ except for %extra_context ** fts5YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** fts5YYNSTATE the combined number of states. @@ -189788,25 +199859,31 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); #endif /************* Begin control #defines *****************************************/ #define fts5YYCODETYPE unsigned char -#define fts5YYNOCODE 29 +#define fts5YYNOCODE 27 #define fts5YYACTIONTYPE unsigned char #define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token typedef union { int fts5yyinit; sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0; int fts5yy4; - Fts5ExprPhrase* fts5yy11; - Fts5ExprNearset* fts5yy14; - Fts5Colset* fts5yy43; - Fts5ExprNode* fts5yy54; + Fts5Colset* fts5yy11; + Fts5ExprNode* fts5yy24; + Fts5ExprNearset* fts5yy46; + Fts5ExprPhrase* fts5yy53; } fts5YYMINORTYPE; #ifndef fts5YYSTACKDEPTH #define fts5YYSTACKDEPTH 100 #endif #define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse; #define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse -#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse -#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse +#define sqlite3Fts5ParserARG_PARAM ,pParse +#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse; +#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse; +#define sqlite3Fts5ParserCTX_SDECL +#define sqlite3Fts5ParserCTX_PDECL +#define sqlite3Fts5ParserCTX_PARAM +#define sqlite3Fts5ParserCTX_FETCH +#define sqlite3Fts5ParserCTX_STORE #define fts5YYNSTATE 35 #define fts5YYNRULE 28 #define fts5YYNFTS5TOKEN 16 @@ -189819,6 +199896,7 @@ typedef union { #define fts5YY_MIN_REDUCE 83 #define fts5YY_MAX_REDUCE 110 /************* End control #defines *******************************************/ +#define fts5YY_NLOOKAHEAD ((int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0]))) /* Define the fts5yytestcase() macro to be a no-op if is not already defined ** otherwise. @@ -189887,46 +199965,46 @@ typedef union { static const fts5YYACTIONTYPE fts5yy_action[] = { /* 0 */ 81, 20, 96, 6, 28, 99, 98, 26, 26, 18, /* 10 */ 96, 6, 28, 17, 98, 56, 26, 19, 96, 6, - /* 20 */ 28, 14, 98, 108, 26, 92, 96, 6, 28, 25, - /* 30 */ 98, 78, 26, 21, 96, 6, 28, 107, 98, 58, - /* 40 */ 26, 29, 96, 6, 28, 32, 98, 22, 26, 24, - /* 50 */ 16, 23, 11, 1, 14, 13, 24, 16, 31, 11, - /* 60 */ 3, 97, 13, 27, 8, 98, 82, 26, 7, 4, - /* 70 */ 5, 3, 4, 5, 3, 83, 4, 5, 3, 63, - /* 80 */ 33, 34, 62, 12, 2, 86, 13, 10, 12, 71, - /* 90 */ 10, 13, 78, 5, 3, 78, 9, 30, 75, 82, - /* 100 */ 54, 57, 53, 57, 15, + /* 20 */ 28, 14, 98, 14, 26, 31, 92, 96, 6, 28, + /* 30 */ 108, 98, 25, 26, 21, 96, 6, 28, 78, 98, + /* 40 */ 58, 26, 29, 96, 6, 28, 107, 98, 22, 26, + /* 50 */ 24, 16, 12, 11, 1, 13, 13, 24, 16, 23, + /* 60 */ 11, 33, 34, 13, 97, 8, 27, 32, 98, 7, + /* 70 */ 26, 3, 4, 5, 3, 4, 5, 3, 83, 4, + /* 80 */ 5, 3, 63, 5, 3, 62, 12, 2, 86, 13, + /* 90 */ 9, 30, 10, 10, 54, 57, 75, 78, 78, 53, + /* 100 */ 57, 15, 82, 82, 71, }; static const fts5YYCODETYPE fts5yy_lookahead[] = { - /* 0 */ 17, 18, 19, 20, 21, 23, 23, 25, 25, 18, - /* 10 */ 19, 20, 21, 7, 23, 9, 25, 18, 19, 20, - /* 20 */ 21, 9, 23, 27, 25, 18, 19, 20, 21, 25, - /* 30 */ 23, 15, 25, 18, 19, 20, 21, 27, 23, 9, - /* 40 */ 25, 18, 19, 20, 21, 14, 23, 22, 25, 6, - /* 50 */ 7, 22, 9, 10, 9, 12, 6, 7, 13, 9, - /* 60 */ 3, 19, 12, 21, 5, 23, 28, 25, 5, 1, - /* 70 */ 2, 3, 1, 2, 3, 0, 1, 2, 3, 11, - /* 80 */ 25, 26, 11, 9, 10, 5, 12, 10, 9, 11, - /* 90 */ 10, 12, 15, 2, 3, 15, 24, 25, 9, 28, - /* 100 */ 8, 9, 8, 9, 9, 28, 28, 28, 28, 28, - /* 110 */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - /* 120 */ 28, + /* 0 */ 16, 17, 18, 19, 20, 22, 22, 24, 24, 17, + /* 10 */ 18, 19, 20, 7, 22, 9, 24, 17, 18, 19, + /* 20 */ 20, 9, 22, 9, 24, 13, 17, 18, 19, 20, + /* 30 */ 26, 22, 24, 24, 17, 18, 19, 20, 15, 22, + /* 40 */ 9, 24, 17, 18, 19, 20, 26, 22, 21, 24, + /* 50 */ 6, 7, 9, 9, 10, 12, 12, 6, 7, 21, + /* 60 */ 9, 24, 25, 12, 18, 5, 20, 14, 22, 5, + /* 70 */ 24, 3, 1, 2, 3, 1, 2, 3, 0, 1, + /* 80 */ 2, 3, 11, 2, 3, 11, 9, 10, 5, 12, + /* 90 */ 23, 24, 10, 10, 8, 9, 9, 15, 15, 8, + /* 100 */ 9, 9, 27, 27, 11, 27, 27, 27, 27, 27, + /* 110 */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + /* 120 */ 27, }; #define fts5YY_SHIFT_COUNT (34) #define fts5YY_SHIFT_MIN (0) -#define fts5YY_SHIFT_MAX (95) +#define fts5YY_SHIFT_MAX (93) static const unsigned char fts5yy_shift_ofst[] = { - /* 0 */ 43, 43, 43, 43, 43, 43, 50, 74, 79, 45, - /* 10 */ 12, 80, 77, 12, 16, 16, 30, 30, 68, 71, - /* 20 */ 75, 91, 92, 94, 6, 31, 31, 59, 63, 57, - /* 30 */ 31, 89, 95, 31, 78, + /* 0 */ 44, 44, 44, 44, 44, 44, 51, 77, 43, 12, + /* 10 */ 14, 83, 82, 14, 23, 23, 31, 31, 71, 74, + /* 20 */ 78, 81, 86, 91, 6, 53, 53, 60, 64, 68, + /* 30 */ 53, 87, 92, 53, 93, }; #define fts5YY_REDUCE_COUNT (17) -#define fts5YY_REDUCE_MIN (-18) -#define fts5YY_REDUCE_MAX (72) +#define fts5YY_REDUCE_MIN (-17) +#define fts5YY_REDUCE_MAX (67) static const signed char fts5yy_reduce_ofst[] = { - /* 0 */ -17, -9, -1, 7, 15, 23, 42, -18, -18, 55, - /* 10 */ 72, -4, -4, 4, -4, 10, 25, 29, + /* 0 */ -16, -8, 0, 9, 17, 25, 46, -17, -17, 37, + /* 10 */ 67, 4, 4, 8, 4, 20, 27, 38, }; static const fts5YYACTIONTYPE fts5yy_default[] = { /* 0 */ 80, 80, 80, 80, 80, 80, 95, 80, 80, 105, @@ -189991,6 +200069,7 @@ struct fts5yyParser { int fts5yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */ + sqlite3Fts5ParserCTX_SDECL /* A place to hold %extra_context */ #if fts5YYSTACKDEPTH<=0 int fts5yystksz; /* Current side of the stack */ fts5yyStackEntry *fts5yystack; /* The parser's stack */ @@ -190054,18 +200133,17 @@ static const char *const fts5yyTokenName[] = { /* 13 */ "COMMA", /* 14 */ "PLUS", /* 15 */ "STAR", - /* 16 */ "error", - /* 17 */ "input", - /* 18 */ "expr", - /* 19 */ "cnearset", - /* 20 */ "exprlist", - /* 21 */ "colset", - /* 22 */ "colsetlist", - /* 23 */ "nearset", - /* 24 */ "nearphrases", - /* 25 */ "phrase", - /* 26 */ "neardist_opt", - /* 27 */ "star_opt", + /* 16 */ "input", + /* 17 */ "expr", + /* 18 */ "cnearset", + /* 19 */ "exprlist", + /* 20 */ "colset", + /* 21 */ "colsetlist", + /* 22 */ "nearset", + /* 23 */ "nearphrases", + /* 24 */ "phrase", + /* 25 */ "neardist_opt", + /* 26 */ "star_opt", }; #endif /* defined(fts5YYCOVERAGE) || !defined(NDEBUG) */ @@ -190149,28 +200227,29 @@ static int fts5yyGrowStack(fts5yyParser *p){ /* Initialize a new parser that has already been allocated. */ -static void sqlite3Fts5ParserInit(void *fts5yypParser){ - fts5yyParser *pParser = (fts5yyParser*)fts5yypParser; +static void sqlite3Fts5ParserInit(void *fts5yypRawParser sqlite3Fts5ParserCTX_PDECL){ + fts5yyParser *fts5yypParser = (fts5yyParser*)fts5yypRawParser; + sqlite3Fts5ParserCTX_STORE #ifdef fts5YYTRACKMAXSTACKDEPTH - pParser->fts5yyhwm = 0; + fts5yypParser->fts5yyhwm = 0; #endif #if fts5YYSTACKDEPTH<=0 - pParser->fts5yytos = NULL; - pParser->fts5yystack = NULL; - pParser->fts5yystksz = 0; - if( fts5yyGrowStack(pParser) ){ - pParser->fts5yystack = &pParser->fts5yystk0; - pParser->fts5yystksz = 1; + fts5yypParser->fts5yytos = NULL; + fts5yypParser->fts5yystack = NULL; + fts5yypParser->fts5yystksz = 0; + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yypParser->fts5yystack = &fts5yypParser->fts5yystk0; + fts5yypParser->fts5yystksz = 1; } #endif #ifndef fts5YYNOERRORRECOVERY - pParser->fts5yyerrcnt = -1; + fts5yypParser->fts5yyerrcnt = -1; #endif - pParser->fts5yytos = pParser->fts5yystack; - pParser->fts5yystack[0].stateno = 0; - pParser->fts5yystack[0].major = 0; + fts5yypParser->fts5yytos = fts5yypParser->fts5yystack; + fts5yypParser->fts5yystack[0].stateno = 0; + fts5yypParser->fts5yystack[0].major = 0; #if fts5YYSTACKDEPTH>0 - pParser->fts5yystackEnd = &pParser->fts5yystack[fts5YYSTACKDEPTH-1]; + fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1]; #endif } @@ -190187,11 +200266,14 @@ static void sqlite3Fts5ParserInit(void *fts5yypParser){ ** A pointer to a parser. This pointer is used in subsequent calls ** to sqlite3Fts5Parser and sqlite3Fts5ParserFree. */ -static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){ - fts5yyParser *pParser; - pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) ); - if( pParser ) sqlite3Fts5ParserInit(pParser); - return pParser; +static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE) sqlite3Fts5ParserCTX_PDECL){ + fts5yyParser *fts5yypParser; + fts5yypParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) ); + if( fts5yypParser ){ + sqlite3Fts5ParserCTX_STORE + sqlite3Fts5ParserInit(fts5yypParser sqlite3Fts5ParserCTX_PARAM); + } + return (void*)fts5yypParser; } #endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */ @@ -190208,7 +200290,8 @@ static void fts5yy_destructor( fts5YYCODETYPE fts5yymajor, /* Type code for object to destroy */ fts5YYMINORTYPE *fts5yypminor /* The object to be destroyed */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH switch( fts5yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen @@ -190221,33 +200304,33 @@ static void fts5yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 17: /* input */ + case 16: /* input */ { (void)pParse; } break; - case 18: /* expr */ - case 19: /* cnearset */ - case 20: /* exprlist */ + case 17: /* expr */ + case 18: /* cnearset */ + case 19: /* exprlist */ { - sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy54)); + sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24)); } break; - case 21: /* colset */ - case 22: /* colsetlist */ + case 20: /* colset */ + case 21: /* colsetlist */ { - sqlite3_free((fts5yypminor->fts5yy43)); + sqlite3_free((fts5yypminor->fts5yy11)); } break; - case 23: /* nearset */ - case 24: /* nearphrases */ + case 22: /* nearset */ + case 23: /* nearphrases */ { - sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy14)); + sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46)); } break; - case 25: /* phrase */ + case 24: /* phrase */ { - sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11)); + sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53)); } break; /********* End destructor definitions *****************************************/ @@ -190359,13 +200442,12 @@ static int sqlite3Fts5ParserCoverage(FILE *out){ ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. */ -static unsigned int fts5yy_find_shift_action( - fts5yyParser *pParser, /* The parser */ - fts5YYCODETYPE iLookAhead /* The look-ahead token */ +static fts5YYACTIONTYPE fts5yy_find_shift_action( + fts5YYCODETYPE iLookAhead, /* The look-ahead token */ + fts5YYACTIONTYPE stateno /* Current state number */ ){ int i; - int stateno = pParser->fts5yytos->stateno; - + if( stateno>fts5YY_MAX_SHIFT ) return stateno; assert( stateno <= fts5YY_SHIFT_COUNT ); #if defined(fts5YYCOVERAGE) @@ -190374,11 +200456,11 @@ static unsigned int fts5yy_find_shift_action( do{ i = fts5yy_shift_ofst[stateno]; assert( i>=0 ); - assert( i+fts5YYNFTS5TOKEN<=(int)sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0]) ); + /* assert( i+fts5YYNFTS5TOKEN<=(int)fts5YY_NLOOKAHEAD ); */ assert( iLookAhead!=fts5YYNOCODE ); assert( iLookAhead < fts5YYNFTS5TOKEN ); i += iLookAhead; - if( fts5yy_lookahead[i]!=iLookAhead ){ + if( i>=fts5YY_NLOOKAHEAD || fts5yy_lookahead[i]!=iLookAhead ){ #ifdef fts5YYFALLBACK fts5YYCODETYPE iFallback; /* Fallback token */ if( iLookAhead=fts5YY_ACTTAB_COUNT j0 ){ #ifndef NDEBUG @@ -190428,8 +200511,8 @@ static unsigned int fts5yy_find_shift_action( ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. */ -static int fts5yy_find_reduce_action( - int stateno, /* Current state number */ +static fts5YYACTIONTYPE fts5yy_find_reduce_action( + fts5YYACTIONTYPE stateno, /* Current state number */ fts5YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; @@ -190458,7 +200541,8 @@ static int fts5yy_find_reduce_action( ** The following routine is called if the stack overflows. */ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt); @@ -190471,7 +200555,8 @@ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){ sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow"); /******** End %stack_overflow code ********************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument var */ + sqlite3Fts5ParserCTX_STORE } /* @@ -190500,8 +200585,8 @@ static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState, co */ static void fts5yy_shift( fts5yyParser *fts5yypParser, /* The parser to be shifted */ - int fts5yyNewState, /* The new state to shift in */ - int fts5yyMajor, /* The major token to shift in */ + fts5YYACTIONTYPE fts5yyNewState, /* The new state to shift in */ + fts5YYCODETYPE fts5yyMajor, /* The major token to shift in */ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */ ){ fts5yyStackEntry *fts5yytos; @@ -190531,8 +200616,8 @@ static void fts5yy_shift( fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; } fts5yytos = fts5yypParser->fts5yytos; - fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState; - fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor; + fts5yytos->stateno = fts5yyNewState; + fts5yytos->major = fts5yyMajor; fts5yytos->minor.fts5yy0 = fts5yyMinor; fts5yyTraceShift(fts5yypParser, fts5yyNewState, "Shift"); } @@ -190544,34 +200629,34 @@ static const struct { fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ signed char nrhs; /* Negative of the number of RHS symbols in the rule */ } fts5yyRuleInfo[] = { - { 17, -1 }, /* (0) input ::= expr */ - { 21, -4 }, /* (1) colset ::= MINUS LCP colsetlist RCP */ - { 21, -3 }, /* (2) colset ::= LCP colsetlist RCP */ - { 21, -1 }, /* (3) colset ::= STRING */ - { 21, -2 }, /* (4) colset ::= MINUS STRING */ - { 22, -2 }, /* (5) colsetlist ::= colsetlist STRING */ - { 22, -1 }, /* (6) colsetlist ::= STRING */ - { 18, -3 }, /* (7) expr ::= expr AND expr */ - { 18, -3 }, /* (8) expr ::= expr OR expr */ - { 18, -3 }, /* (9) expr ::= expr NOT expr */ - { 18, -5 }, /* (10) expr ::= colset COLON LP expr RP */ - { 18, -3 }, /* (11) expr ::= LP expr RP */ - { 18, -1 }, /* (12) expr ::= exprlist */ - { 20, -1 }, /* (13) exprlist ::= cnearset */ - { 20, -2 }, /* (14) exprlist ::= exprlist cnearset */ - { 19, -1 }, /* (15) cnearset ::= nearset */ - { 19, -3 }, /* (16) cnearset ::= colset COLON nearset */ - { 23, -1 }, /* (17) nearset ::= phrase */ - { 23, -2 }, /* (18) nearset ::= CARET phrase */ - { 23, -5 }, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */ - { 24, -1 }, /* (20) nearphrases ::= phrase */ - { 24, -2 }, /* (21) nearphrases ::= nearphrases phrase */ - { 26, 0 }, /* (22) neardist_opt ::= */ - { 26, -2 }, /* (23) neardist_opt ::= COMMA STRING */ - { 25, -4 }, /* (24) phrase ::= phrase PLUS STRING star_opt */ - { 25, -2 }, /* (25) phrase ::= STRING star_opt */ - { 27, -1 }, /* (26) star_opt ::= STAR */ - { 27, 0 }, /* (27) star_opt ::= */ + { 16, -1 }, /* (0) input ::= expr */ + { 20, -4 }, /* (1) colset ::= MINUS LCP colsetlist RCP */ + { 20, -3 }, /* (2) colset ::= LCP colsetlist RCP */ + { 20, -1 }, /* (3) colset ::= STRING */ + { 20, -2 }, /* (4) colset ::= MINUS STRING */ + { 21, -2 }, /* (5) colsetlist ::= colsetlist STRING */ + { 21, -1 }, /* (6) colsetlist ::= STRING */ + { 17, -3 }, /* (7) expr ::= expr AND expr */ + { 17, -3 }, /* (8) expr ::= expr OR expr */ + { 17, -3 }, /* (9) expr ::= expr NOT expr */ + { 17, -5 }, /* (10) expr ::= colset COLON LP expr RP */ + { 17, -3 }, /* (11) expr ::= LP expr RP */ + { 17, -1 }, /* (12) expr ::= exprlist */ + { 19, -1 }, /* (13) exprlist ::= cnearset */ + { 19, -2 }, /* (14) exprlist ::= exprlist cnearset */ + { 18, -1 }, /* (15) cnearset ::= nearset */ + { 18, -3 }, /* (16) cnearset ::= colset COLON nearset */ + { 22, -1 }, /* (17) nearset ::= phrase */ + { 22, -2 }, /* (18) nearset ::= CARET phrase */ + { 22, -5 }, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */ + { 23, -1 }, /* (20) nearphrases ::= phrase */ + { 23, -2 }, /* (21) nearphrases ::= nearphrases phrase */ + { 25, 0 }, /* (22) neardist_opt ::= */ + { 25, -2 }, /* (23) neardist_opt ::= COMMA STRING */ + { 24, -4 }, /* (24) phrase ::= phrase PLUS STRING star_opt */ + { 24, -2 }, /* (25) phrase ::= STRING star_opt */ + { 26, -1 }, /* (26) star_opt ::= STAR */ + { 26, 0 }, /* (27) star_opt ::= */ }; static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ @@ -190586,17 +200671,18 @@ static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ ** only called from one place, optimizing compilers will in-line it, which ** means that the extra parameters have no performance impact. */ -static void fts5yy_reduce( +static fts5YYACTIONTYPE fts5yy_reduce( fts5yyParser *fts5yypParser, /* The parser */ unsigned int fts5yyruleno, /* Number of the rule by which to reduce */ int fts5yyLookahead, /* Lookahead token, or fts5YYNOCODE if none */ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyLookaheadToken /* Value of the lookahead token */ + sqlite3Fts5ParserCTX_PDECL /* %extra_context */ ){ int fts5yygoto; /* The next state */ - int fts5yyact; /* The next action */ + fts5YYACTIONTYPE fts5yyact; /* The next action */ fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */ int fts5yysize; /* Amount to pop the stack */ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH (void)fts5yyLookahead; (void)fts5yyLookaheadToken; fts5yymsp = fts5yypParser->fts5yytos; @@ -190627,13 +200713,19 @@ static void fts5yy_reduce( #if fts5YYSTACKDEPTH>0 if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){ fts5yyStackOverflow(fts5yypParser); - return; + /* The call to fts5yyStackOverflow() above pops the stack until it is + ** empty, causing the main parser loop to exit. So the return value + ** is never used and does not matter. */ + return 0; } #else if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){ if( fts5yyGrowStack(fts5yypParser) ){ fts5yyStackOverflow(fts5yypParser); - return; + /* The call to fts5yyStackOverflow() above pops the stack until it is + ** empty, causing the main parser loop to exit. So the return value + ** is never used and does not matter. */ + return 0; } fts5yymsp = fts5yypParser->fts5yytos; } @@ -190652,120 +200744,120 @@ static void fts5yy_reduce( /********** Begin reduce actions **********************************************/ fts5YYMINORTYPE fts5yylhsminor; case 0: /* input ::= expr */ -{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy54); } +{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); } break; case 1: /* colset ::= MINUS LCP colsetlist RCP */ { - fts5yymsp[-3].minor.fts5yy43 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy43); + fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); } break; case 2: /* colset ::= LCP colsetlist RCP */ -{ fts5yymsp[-2].minor.fts5yy43 = fts5yymsp[-1].minor.fts5yy43; } +{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; } break; case 3: /* colset ::= STRING */ { - fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); } - fts5yymsp[0].minor.fts5yy43 = fts5yylhsminor.fts5yy43; + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; break; case 4: /* colset ::= MINUS STRING */ { - fts5yymsp[-1].minor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); - fts5yymsp[-1].minor.fts5yy43 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy43); + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); } break; case 5: /* colsetlist ::= colsetlist STRING */ { - fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy43, &fts5yymsp[0].minor.fts5yy0); } - fts5yymsp[-1].minor.fts5yy43 = fts5yylhsminor.fts5yy43; + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); } + fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; break; case 6: /* colsetlist ::= STRING */ { - fts5yylhsminor.fts5yy43 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); } - fts5yymsp[0].minor.fts5yy43 = fts5yylhsminor.fts5yy43; + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; break; case 7: /* expr ::= expr AND expr */ { - fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } - fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54; + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 8: /* expr ::= expr OR expr */ { - fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } - fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54; + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 9: /* expr ::= expr NOT expr */ { - fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54, 0); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } - fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54; + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 10: /* expr ::= colset COLON LP expr RP */ { - sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy54, fts5yymsp[-4].minor.fts5yy43); - fts5yylhsminor.fts5yy54 = fts5yymsp[-1].minor.fts5yy54; + sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[-4].minor.fts5yy11); + fts5yylhsminor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24; } - fts5yymsp[-4].minor.fts5yy54 = fts5yylhsminor.fts5yy54; + fts5yymsp[-4].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 11: /* expr ::= LP expr RP */ -{fts5yymsp[-2].minor.fts5yy54 = fts5yymsp[-1].minor.fts5yy54;} +{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;} break; case 12: /* expr ::= exprlist */ case 13: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==13); -{fts5yylhsminor.fts5yy54 = fts5yymsp[0].minor.fts5yy54;} - fts5yymsp[0].minor.fts5yy54 = fts5yylhsminor.fts5yy54; +{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;} + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 14: /* exprlist ::= exprlist cnearset */ { - fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy54, fts5yymsp[0].minor.fts5yy54); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24); } - fts5yymsp[-1].minor.fts5yy54 = fts5yylhsminor.fts5yy54; + fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 15: /* cnearset ::= nearset */ { - fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy14); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); } - fts5yymsp[0].minor.fts5yy54 = fts5yylhsminor.fts5yy54; + fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 16: /* cnearset ::= colset COLON nearset */ { - fts5yylhsminor.fts5yy54 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy14); - sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy54, fts5yymsp[-2].minor.fts5yy43); + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); + sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy24, fts5yymsp[-2].minor.fts5yy11); } - fts5yymsp[-2].minor.fts5yy54 = fts5yylhsminor.fts5yy54; + fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; case 17: /* nearset ::= phrase */ -{ fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); } - fts5yymsp[0].minor.fts5yy14 = fts5yylhsminor.fts5yy14; +{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; case 18: /* nearset ::= CARET phrase */ { - sqlite3Fts5ParseSetCaret(fts5yymsp[0].minor.fts5yy11); - fts5yymsp[-1].minor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); + sqlite3Fts5ParseSetCaret(fts5yymsp[0].minor.fts5yy53); + fts5yymsp[-1].minor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } break; case 19: /* nearset ::= STRING LP nearphrases neardist_opt RP */ { sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0); - sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy14, &fts5yymsp[-1].minor.fts5yy0); - fts5yylhsminor.fts5yy14 = fts5yymsp[-2].minor.fts5yy14; + sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0); + fts5yylhsminor.fts5yy46 = fts5yymsp[-2].minor.fts5yy46; } - fts5yymsp[-4].minor.fts5yy14 = fts5yylhsminor.fts5yy14; + fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; case 20: /* nearphrases ::= phrase */ { - fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } - fts5yymsp[0].minor.fts5yy14 = fts5yylhsminor.fts5yy14; + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; case 21: /* nearphrases ::= nearphrases phrase */ { - fts5yylhsminor.fts5yy14 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy14, fts5yymsp[0].minor.fts5yy11); + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53); } - fts5yymsp[-1].minor.fts5yy14 = fts5yylhsminor.fts5yy14; + fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; case 22: /* neardist_opt ::= */ { fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; } @@ -190775,15 +200867,15 @@ static void fts5yy_reduce( break; case 24: /* phrase ::= phrase PLUS STRING star_opt */ { - fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); } - fts5yymsp[-3].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53; break; case 25: /* phrase ::= STRING star_opt */ { - fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); + fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); } - fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53; break; case 26: /* star_opt ::= STAR */ { fts5yymsp[0].minor.fts5yy4 = 1; } @@ -190812,6 +200904,7 @@ static void fts5yy_reduce( fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; fts5yyTraceShift(fts5yypParser, fts5yyact, "... then shift"); + return fts5yyact; } /* @@ -190821,7 +200914,8 @@ static void fts5yy_reduce( static void fts5yy_parse_failed( fts5yyParser *fts5yypParser /* The parser */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt); @@ -190832,7 +200926,8 @@ static void fts5yy_parse_failed( ** parser fails */ /************ Begin %parse_failure code ***************************************/ /************ End %parse_failure code *****************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserCTX_STORE } #endif /* fts5YYNOERRORRECOVERY */ @@ -190844,7 +200939,8 @@ static void fts5yy_syntax_error( int fts5yymajor, /* The major type of the error token */ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The minor type of the error token */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #define FTS5TOKEN fts5yyminor /************ Begin %syntax_error code ****************************************/ @@ -190853,7 +200949,8 @@ static void fts5yy_syntax_error( pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p ); /************ End %syntax_error code ******************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserCTX_STORE } /* @@ -190862,7 +200959,8 @@ static void fts5yy_syntax_error( static void fts5yy_accept( fts5yyParser *fts5yypParser /* The parser */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt); @@ -190876,7 +200974,8 @@ static void fts5yy_accept( ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ /*********** End %parse_accept code *******************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserCTX_STORE } /* The main parser program. @@ -190905,45 +201004,47 @@ static void sqlite3Fts5Parser( sqlite3Fts5ParserARG_PDECL /* Optional %extra_argument parameter */ ){ fts5YYMINORTYPE fts5yyminorunion; - unsigned int fts5yyact; /* The parser action. */ + fts5YYACTIONTYPE fts5yyact; /* The parser action. */ #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) int fts5yyendofinput; /* True if we are at the end of input */ #endif #ifdef fts5YYERRORSYMBOL int fts5yyerrorhit = 0; /* True if fts5yymajor has invoked an error */ #endif - fts5yyParser *fts5yypParser; /* The parser */ + fts5yyParser *fts5yypParser = (fts5yyParser*)fts5yyp; /* The parser */ + sqlite3Fts5ParserCTX_FETCH + sqlite3Fts5ParserARG_STORE - fts5yypParser = (fts5yyParser*)fts5yyp; assert( fts5yypParser->fts5yytos!=0 ); #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) fts5yyendofinput = (fts5yymajor==0); #endif - sqlite3Fts5ParserARG_STORE; + fts5yyact = fts5yypParser->fts5yytos->stateno; #ifndef NDEBUG if( fts5yyTraceFILE ){ - int stateno = fts5yypParser->fts5yytos->stateno; - if( stateno < fts5YY_MIN_REDUCE ){ + if( fts5yyact < fts5YY_MIN_REDUCE ){ fprintf(fts5yyTraceFILE,"%sInput '%s' in state %d\n", - fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],stateno); + fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],fts5yyact); }else{ fprintf(fts5yyTraceFILE,"%sInput '%s' with pending reduce %d\n", - fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],stateno-fts5YY_MIN_REDUCE); + fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],fts5yyact-fts5YY_MIN_REDUCE); } } #endif do{ - fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor); + assert( fts5yyact==fts5yypParser->fts5yytos->stateno ); + fts5yyact = fts5yy_find_shift_action((fts5YYCODETYPE)fts5yymajor,fts5yyact); if( fts5yyact >= fts5YY_MIN_REDUCE ){ - fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE,fts5yymajor,fts5yyminor); + fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE,fts5yymajor, + fts5yyminor sqlite3Fts5ParserCTX_PARAM); }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ - fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor); + fts5yy_shift(fts5yypParser,fts5yyact,(fts5YYCODETYPE)fts5yymajor,fts5yyminor); #ifndef fts5YYNOERRORRECOVERY fts5yypParser->fts5yyerrcnt--; #endif - fts5yymajor = fts5YYNOCODE; + break; }else if( fts5yyact==fts5YY_ACCEPT_ACTION ){ fts5yypParser->fts5yytos--; fts5yy_accept(fts5yypParser); @@ -190994,10 +201095,9 @@ static void sqlite3Fts5Parser( fts5yymajor = fts5YYNOCODE; }else{ while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack - && fts5yymx != fts5YYERRORSYMBOL && (fts5yyact = fts5yy_find_reduce_action( fts5yypParser->fts5yytos->stateno, - fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE + fts5YYERRORSYMBOL)) > fts5YY_MAX_SHIFTREDUCE ){ fts5yy_pop_parser_stack(fts5yypParser); } @@ -191014,6 +201114,8 @@ static void sqlite3Fts5Parser( } fts5yypParser->fts5yyerrcnt = 3; fts5yyerrorhit = 1; + if( fts5yymajor==fts5YYNOCODE ) break; + fts5yyact = fts5yypParser->fts5yytos->stateno; #elif defined(fts5YYNOERRORRECOVERY) /* If the fts5YYNOERRORRECOVERY macro is defined, then do not attempt to ** do any kind of error recovery. Instead, simply invoke the syntax @@ -191024,8 +201126,7 @@ static void sqlite3Fts5Parser( */ fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor); fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); - fts5yymajor = fts5YYNOCODE; - + break; #else /* fts5YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** @@ -191047,10 +201148,10 @@ static void sqlite3Fts5Parser( fts5yypParser->fts5yyerrcnt = -1; #endif } - fts5yymajor = fts5YYNOCODE; + break; #endif } - }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ); + }while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ); #ifndef NDEBUG if( fts5yyTraceFILE ){ fts5yyStackEntry *i; @@ -191066,6 +201167,21 @@ static void sqlite3Fts5Parser( return; } +/* +** Return the fallback token corresponding to canonical token iToken, or +** 0 if iToken has no fallback. +*/ +static int sqlite3Fts5ParserFallback(int iToken){ +#ifdef fts5YYFALLBACK + if( iToken<(int)(sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])) ){ + return fts5yyFallback[iToken]; + } +#else + (void)iToken; +#endif + return 0; +} + /* ** 2014 May 31 ** @@ -193176,6 +203292,7 @@ static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); /* #include */ static void sqlite3Fts5ParserTrace(FILE*, char*); #endif +static int sqlite3Fts5ParserFallback(int); struct Fts5Expr { @@ -195680,14 +205797,19 @@ static void fts5ExprIsAlnum( sqlite3_value **apVal /* Function arguments */ ){ int iCode; + u8 aArr[32]; if( nArg!=1 ){ sqlite3_result_error(pCtx, "wrong number of arguments to function fts5_isalnum", -1 ); return; } + memset(aArr, 0, sizeof(aArr)); + sqlite3Fts5UnicodeCatParse("L*", aArr); + sqlite3Fts5UnicodeCatParse("N*", aArr); + sqlite3Fts5UnicodeCatParse("Co", aArr); iCode = sqlite3_value_int(apVal[0]); - sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode)); + sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]); } static void fts5ExprFold( @@ -195731,10 +205853,12 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); } - /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */ + /* Avoid warnings indicating that sqlite3Fts5ParserTrace() and + ** sqlite3Fts5ParserFallback() are unused */ #ifndef NDEBUG (void)sqlite3Fts5ParserTrace; #endif + (void)sqlite3Fts5ParserFallback; return rc; } @@ -201782,7 +211906,10 @@ static int sqlite3Fts5IndexCharlenToBytelen( for(i=0; i=nByte ) return 0; /* Input contains fewer than nChar chars */ if( (unsigned char)p[n++]>=0xc0 ){ - while( (p[n] & 0xc0)==0x80 ) n++; + while( (p[n] & 0xc0)==0x80 ){ + n++; + if( n>=nByte ) break; + } } } return n; @@ -201920,7 +212047,7 @@ static int sqlite3Fts5IndexQuery( fts5CloseReader(p); } - *ppIter = &pRet->base; + *ppIter = (Fts5IndexIter*)pRet; sqlite3Fts5BufferFree(&buf); } return fts5IndexReturn(p); @@ -203307,7 +213434,7 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ case FTS5_SAVEPOINT: assert( p->ts.eState==1 ); assert( iSavepoint>=0 ); - assert( iSavepoint>p->ts.iSavepoint ); + assert( iSavepoint>=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint; break; @@ -204232,6 +214359,13 @@ static int fts5FilterMethod( assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); + if( pTab->pSortCsr->bDesc ){ + pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid; + pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid; + }else{ + pCsr->iLastRowid = pTab->pSortCsr->iLastRowid; + pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid; + } pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); @@ -205662,12 +215796,27 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2018-04-10 17:39:29 4bb2294022060e61de7da5c227a69ccd846ba330e31626ebcd59a94efd148b3b", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2018-12-01 12:34:55 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238b4f9", -1, SQLITE_TRANSIENT); +} + +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int fts5ShadowName(const char *zName){ + static const char *azName[] = { + "config", "content", "data", "docsize", "idx" + }; + unsigned int i; + for(i=0; iaTokenChar[iCode] = (unsigned char)bTokenChars; }else{ - bToken = sqlite3Fts5UnicodeIsalnum(iCode); + bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]; assert( (bToken==0 || bToken==1) ); assert( (bTokenChars==0 || bTokenChars==1) ); if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){ @@ -207235,6 +217387,21 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){ return; } +static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){ + const char *z = zCat; + + while( *z ){ + while( *z==' ' || *z=='\t' ) z++; + if( *z && sqlite3Fts5UnicodeCatParse(z, p->aCategory) ){ + return SQLITE_ERROR; + } + while( *z!=' ' && *z!='\t' && *z!='\0' ) z++; + } + + sqlite3Fts5UnicodeAscii(p->aCategory, p->aTokenChar); + return SQLITE_OK; +} + /* ** Create a "unicode61" tokenizer. */ @@ -207253,15 +217420,28 @@ static int fts5UnicodeCreate( }else{ p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); if( p ){ + const char *zCat = "L* N* Co"; int i; memset(p, 0, sizeof(Unicode61Tokenizer)); - memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); + p->bRemoveDiacritic = 1; p->nFold = 64; p->aFold = sqlite3_malloc(p->nFold * sizeof(char)); if( p->aFold==0 ){ rc = SQLITE_NOMEM; } + + /* Search for a "categories" argument */ + for(i=0; rc==SQLITE_OK && iaCategory[sqlite3Fts5UnicodeCategory(iCode)] + ^ fts5UnicodeIsException(p, iCode) + ); } static int fts5UnicodeTokenize( @@ -208174,135 +218360,6 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ /* #include */ -/* -** Return true if the argument corresponds to a unicode codepoint -** classified as either a letter or a number. Otherwise false. -** -** The results are undefined if the value passed to this function -** is less than zero. -*/ -static int sqlite3Fts5UnicodeIsalnum(int c){ - /* Each unsigned integer in the following array corresponds to a contiguous - ** range of unicode codepoints that are not either letters or numbers (i.e. - ** codepoints for which this function should return 0). - ** - ** The most significant 22 bits in each 32-bit value contain the first - ** codepoint in the range. The least significant 10 bits are used to store - ** the size of the range (always at least 1). In other words, the value - ** ((C<<22) + N) represents a range of N codepoints starting with codepoint - ** C. It is not possible to represent a range larger than 1023 codepoints - ** using this format. - */ - static const unsigned int aEntry[] = { - 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, - 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, - 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, - 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, - 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, - 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, - 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, - 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, - 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, - 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, - 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, - 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, - 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, - 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, - 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, - 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, - 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, - 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, - 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, - 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, - 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, - 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, - 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, - 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, - 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, - 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, - 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, - 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, - 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, - 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, - 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, - 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, - 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, - 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, - 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, - 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, - 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, - 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, - 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, - 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, - 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, - 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, - 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, - 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, - 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, - 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, - 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, - 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, - 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, - 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, - 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, - 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, - 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, - 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, - 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, - 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, - 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, - 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, - 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, - 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, - 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, - 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, - 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, - 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, - 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, - 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, - 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, - 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, - 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, - 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, - 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, - 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, - 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, - 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, - 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, - 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, - 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, - 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, - 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, - 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, - 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, - 0x380400F0, - }; - static const unsigned int aAscii[4] = { - 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, - }; - - if( (unsigned int)c<128 ){ - return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); - }else if( (unsigned int)c<(1<<22) ){ - unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; - int iRes = 0; - int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; - int iLo = 0; - while( iHi>=iLo ){ - int iTest = (iHi + iLo) / 2; - if( key >= aEntry[iTest] ){ - iRes = iTest; - iLo = iTest+1; - }else{ - iHi = iTest-1; - } - } - assert( aEntry[0]=aEntry[iRes] ); - return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); - } - return 1; -} /* @@ -208515,6 +218572,539 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ return ret; } + +#if 0 +static int sqlite3Fts5UnicodeNCat(void) { + return 32; +} +#endif + +static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ + aArray[0] = 1; + switch( zCat[0] ){ + case 'C': + switch( zCat[1] ){ + case 'c': aArray[1] = 1; break; + case 'f': aArray[2] = 1; break; + case 'n': aArray[3] = 1; break; + case 's': aArray[4] = 1; break; + case 'o': aArray[31] = 1; break; + case '*': + aArray[1] = 1; + aArray[2] = 1; + aArray[3] = 1; + aArray[4] = 1; + aArray[31] = 1; + break; + default: return 1; } + break; + + case 'L': + switch( zCat[1] ){ + case 'l': aArray[5] = 1; break; + case 'm': aArray[6] = 1; break; + case 'o': aArray[7] = 1; break; + case 't': aArray[8] = 1; break; + case 'u': aArray[9] = 1; break; + case 'C': aArray[30] = 1; break; + case '*': + aArray[5] = 1; + aArray[6] = 1; + aArray[7] = 1; + aArray[8] = 1; + aArray[9] = 1; + aArray[30] = 1; + break; + default: return 1; } + break; + + case 'M': + switch( zCat[1] ){ + case 'c': aArray[10] = 1; break; + case 'e': aArray[11] = 1; break; + case 'n': aArray[12] = 1; break; + case '*': + aArray[10] = 1; + aArray[11] = 1; + aArray[12] = 1; + break; + default: return 1; } + break; + + case 'N': + switch( zCat[1] ){ + case 'd': aArray[13] = 1; break; + case 'l': aArray[14] = 1; break; + case 'o': aArray[15] = 1; break; + case '*': + aArray[13] = 1; + aArray[14] = 1; + aArray[15] = 1; + break; + default: return 1; } + break; + + case 'P': + switch( zCat[1] ){ + case 'c': aArray[16] = 1; break; + case 'd': aArray[17] = 1; break; + case 'e': aArray[18] = 1; break; + case 'f': aArray[19] = 1; break; + case 'i': aArray[20] = 1; break; + case 'o': aArray[21] = 1; break; + case 's': aArray[22] = 1; break; + case '*': + aArray[16] = 1; + aArray[17] = 1; + aArray[18] = 1; + aArray[19] = 1; + aArray[20] = 1; + aArray[21] = 1; + aArray[22] = 1; + break; + default: return 1; } + break; + + case 'S': + switch( zCat[1] ){ + case 'c': aArray[23] = 1; break; + case 'k': aArray[24] = 1; break; + case 'm': aArray[25] = 1; break; + case 'o': aArray[26] = 1; break; + case '*': + aArray[23] = 1; + aArray[24] = 1; + aArray[25] = 1; + aArray[26] = 1; + break; + default: return 1; } + break; + + case 'Z': + switch( zCat[1] ){ + case 'l': aArray[27] = 1; break; + case 'p': aArray[28] = 1; break; + case 's': aArray[29] = 1; break; + case '*': + aArray[27] = 1; + aArray[28] = 1; + aArray[29] = 1; + break; + default: return 1; } + break; + + } + return 0; +} + +static u16 aFts5UnicodeBlock[] = { + 0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760, + 1760, 1760, 1760, 1760, 1760, 1763, 1765, + }; +static u16 aFts5UnicodeMap[] = { + 0, 32, 33, 36, 37, 40, 41, 42, 43, 44, + 45, 46, 48, 58, 60, 63, 65, 91, 92, 93, + 94, 95, 96, 97, 123, 124, 125, 126, 127, 160, + 161, 162, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 180, 181, 182, 184, 185, + 186, 187, 188, 191, 192, 215, 216, 223, 247, 248, + 256, 312, 313, 329, 330, 377, 383, 385, 387, 388, + 391, 394, 396, 398, 402, 403, 405, 406, 409, 412, + 414, 415, 417, 418, 423, 427, 428, 431, 434, 436, + 437, 440, 442, 443, 444, 446, 448, 452, 453, 454, + 455, 456, 457, 458, 459, 460, 461, 477, 478, 496, + 497, 498, 499, 500, 503, 505, 506, 564, 570, 572, + 573, 575, 577, 580, 583, 584, 592, 660, 661, 688, + 706, 710, 722, 736, 741, 748, 749, 750, 751, 768, + 880, 884, 885, 886, 890, 891, 894, 900, 902, 903, + 904, 908, 910, 912, 913, 931, 940, 975, 977, 978, + 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072, + 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369, + 1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473, + 1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545, + 1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611, + 1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758, + 1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791, + 1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984, + 1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075, + 2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210, + 2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369, + 2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416, + 2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482, + 2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519, + 2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561, + 2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622, + 2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677, + 2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749, + 2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790, + 2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869, + 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902, + 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947, + 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006, + 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059, + 3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134, + 3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199, + 3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263, + 3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302, + 3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402, + 3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458, + 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544, + 3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655, + 3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737, + 3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773, + 3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860, + 3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896, + 3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967, + 3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046, + 4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153, + 4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190, + 4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229, + 4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295, + 4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704, + 4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888, + 4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743, + 5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906, + 5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068, + 6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107, + 6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160, + 6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435, + 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480, + 6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679, + 6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754, + 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824, + 6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978, + 6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043, + 7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098, + 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168, + 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288, + 7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406, + 7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616, + 7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976, + 7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033, + 8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118, + 8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141, + 8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184, + 8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219, + 8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249, + 8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275, + 8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317, + 8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413, + 8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459, + 8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484, + 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500, + 8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523, + 8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597, + 8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623, + 8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972, + 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180, + 9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665, + 9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091, + 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101, + 10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217, + 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627, + 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637, + 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647, + 10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750, + 11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365, + 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393, + 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520, + 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696, + 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780, + 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800, + 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812, + 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904, + 11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296, + 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306, + 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317, + 12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347, + 12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449, + 12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736, + 12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938, + 12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981, + 40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528, + 42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624, + 42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800, + 42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912, + 43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043, + 43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136, + 43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264, + 43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395, + 43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472, + 43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588, + 43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643, + 43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713, + 43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762, + 43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003, + 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203, + 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112, + 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320, + 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020, + 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075, + 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086, + 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097, + 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118, + 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279, + 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294, + 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343, + 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378, + 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490, + 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529, + 65532, 0, 13, 40, 60, 63, 80, 128, 256, 263, + 311, 320, 373, 377, 394, 400, 464, 509, 640, 672, + 768, 800, 816, 833, 834, 842, 896, 927, 928, 968, + 976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103, + 2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432, + 2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623, + 2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912, + 2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178, + 4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285, + 4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416, + 4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760, + 5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216, + 9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248, + 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637, + 53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298, + 54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441, + 54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541, + 54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662, + 54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922, + 54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062, + 55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178, + 55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961, + 60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003, + 61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028, + 61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099, + 61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744, + 61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368, + 62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971, + 63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488, + 1, 32, 256, 0, 65533, + }; +static u16 aFts5UnicodeData[] = { + 1025, 61, 117, 55, 117, 54, 50, 53, 57, 53, + 49, 85, 333, 85, 121, 85, 841, 54, 53, 50, + 56, 48, 56, 837, 54, 57, 50, 57, 1057, 61, + 53, 151, 58, 53, 56, 58, 39, 52, 57, 34, + 58, 56, 58, 57, 79, 56, 37, 85, 56, 47, + 39, 51, 111, 53, 745, 57, 233, 773, 57, 261, + 1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126, + 126, 73, 69, 137, 37, 73, 37, 105, 101, 73, + 37, 73, 37, 190, 158, 37, 126, 126, 73, 37, + 126, 94, 37, 39, 94, 69, 135, 41, 40, 37, + 41, 40, 37, 41, 40, 37, 542, 37, 606, 37, + 41, 40, 37, 126, 73, 37, 1886, 197, 73, 37, + 73, 69, 126, 105, 37, 286, 2181, 39, 869, 582, + 152, 390, 472, 166, 248, 38, 56, 38, 568, 3596, + 158, 38, 56, 94, 38, 101, 53, 88, 41, 53, + 105, 41, 73, 37, 553, 297, 1125, 94, 37, 105, + 101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541, + 1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38, + 213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76, + 53, 76, 53, 44, 871, 103, 85, 162, 121, 85, + 55, 85, 90, 364, 53, 85, 1031, 38, 327, 684, + 333, 149, 71, 44, 3175, 53, 39, 236, 34, 58, + 204, 70, 76, 58, 140, 71, 333, 103, 90, 39, + 469, 34, 39, 44, 967, 876, 2855, 364, 39, 333, + 1063, 300, 70, 58, 117, 38, 711, 140, 38, 300, + 38, 108, 38, 172, 501, 807, 108, 53, 39, 359, + 876, 108, 42, 1735, 44, 42, 44, 39, 106, 268, + 138, 44, 74, 39, 236, 327, 76, 85, 333, 53, + 38, 199, 231, 44, 74, 263, 71, 711, 231, 39, + 135, 44, 39, 106, 140, 74, 74, 44, 39, 42, + 71, 103, 76, 333, 71, 87, 207, 58, 55, 76, + 42, 199, 71, 711, 231, 71, 71, 71, 44, 106, + 76, 76, 108, 44, 135, 39, 333, 76, 103, 44, + 76, 42, 295, 103, 711, 231, 71, 167, 44, 39, + 106, 172, 76, 42, 74, 44, 39, 71, 76, 333, + 53, 55, 44, 74, 263, 71, 711, 231, 71, 167, + 44, 39, 42, 44, 42, 140, 74, 74, 44, 44, + 42, 71, 103, 76, 333, 58, 39, 207, 44, 39, + 199, 103, 135, 71, 39, 71, 71, 103, 391, 74, + 44, 74, 106, 106, 44, 39, 42, 333, 111, 218, + 55, 58, 106, 263, 103, 743, 327, 167, 39, 108, + 138, 108, 140, 76, 71, 71, 76, 333, 239, 58, + 74, 263, 103, 743, 327, 167, 44, 39, 42, 44, + 170, 44, 74, 74, 76, 74, 39, 71, 76, 333, + 71, 74, 263, 103, 1319, 39, 106, 140, 106, 106, + 44, 39, 42, 71, 76, 333, 207, 58, 199, 74, + 583, 775, 295, 39, 231, 44, 106, 108, 44, 266, + 74, 53, 1543, 44, 71, 236, 55, 199, 38, 268, + 53, 333, 85, 71, 39, 71, 39, 39, 135, 231, + 103, 39, 39, 71, 135, 44, 71, 204, 76, 39, + 167, 38, 204, 333, 135, 39, 122, 501, 58, 53, + 122, 76, 218, 333, 335, 58, 44, 58, 44, 58, + 44, 54, 50, 54, 50, 74, 263, 1159, 460, 42, + 172, 53, 76, 167, 364, 1164, 282, 44, 218, 90, + 181, 154, 85, 1383, 74, 140, 42, 204, 42, 76, + 74, 76, 39, 333, 213, 199, 74, 76, 135, 108, + 39, 106, 71, 234, 103, 140, 423, 44, 74, 76, + 202, 44, 39, 42, 333, 106, 44, 90, 1225, 41, + 41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319, + 135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151, + 108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551, + 61, 839, 54, 50, 2407, 117, 110, 423, 135, 108, + 583, 108, 85, 583, 76, 423, 103, 76, 1671, 76, + 42, 236, 266, 44, 74, 364, 117, 38, 117, 55, + 39, 44, 333, 335, 213, 49, 149, 108, 61, 333, + 1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138, + 76, 106, 74, 44, 202, 108, 58, 85, 333, 967, + 167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76, + 106, 85, 1703, 42, 44, 42, 236, 44, 42, 44, + 74, 268, 202, 332, 44, 333, 333, 245, 38, 213, + 140, 42, 1511, 44, 42, 172, 42, 44, 170, 44, + 74, 231, 333, 245, 346, 300, 314, 76, 42, 967, + 42, 140, 74, 76, 42, 44, 74, 71, 333, 1415, + 44, 42, 76, 106, 44, 42, 108, 74, 149, 1159, + 266, 268, 74, 76, 181, 333, 103, 333, 967, 198, + 85, 277, 108, 53, 428, 42, 236, 135, 44, 135, + 74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260, + 140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265, + 261, 265, 197, 201, 261, 41, 41, 41, 94, 229, + 265, 453, 261, 264, 261, 264, 261, 264, 165, 69, + 137, 40, 56, 37, 120, 101, 69, 137, 40, 120, + 133, 69, 137, 120, 261, 169, 120, 101, 69, 137, + 40, 88, 381, 162, 209, 85, 52, 51, 54, 84, + 51, 54, 52, 277, 59, 60, 162, 61, 309, 52, + 51, 149, 80, 117, 57, 54, 50, 373, 57, 53, + 48, 341, 61, 162, 194, 47, 38, 207, 121, 54, + 50, 38, 335, 121, 54, 50, 422, 855, 428, 139, + 44, 107, 396, 90, 41, 154, 41, 90, 37, 105, + 69, 105, 37, 58, 41, 90, 57, 169, 218, 41, + 58, 41, 58, 41, 58, 137, 58, 37, 137, 37, + 135, 37, 90, 69, 73, 185, 94, 101, 58, 57, + 90, 37, 58, 527, 1134, 94, 142, 47, 185, 186, + 89, 154, 57, 90, 57, 90, 57, 250, 57, 1018, + 89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666, + 89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217, + 602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57, + 1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50, + 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, + 975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50, + 54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54, + 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, + 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, + 50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281, + 1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69, + 254, 105, 37, 94, 37, 94, 165, 70, 105, 37, + 3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221, + 37, 37, 1799, 38, 53, 44, 743, 231, 231, 231, + 231, 231, 231, 231, 231, 1036, 85, 52, 51, 52, + 51, 117, 52, 51, 53, 52, 51, 309, 49, 85, + 49, 53, 52, 51, 85, 52, 51, 54, 50, 54, + 50, 54, 50, 54, 50, 181, 38, 341, 81, 858, + 2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54, + 50, 54, 50, 54, 50, 54, 50, 54, 50, 90, + 54, 50, 54, 50, 54, 50, 54, 50, 49, 54, + 82, 58, 302, 140, 74, 49, 166, 90, 110, 38, + 39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887, + 53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178, + 519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274, + 495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38, + 36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333, + 71, 1502, 39, 44, 107, 53, 332, 53, 38, 798, + 44, 2247, 334, 76, 213, 760, 294, 88, 478, 69, + 2014, 38, 261, 190, 350, 38, 88, 158, 158, 382, + 70, 37, 231, 44, 103, 44, 135, 44, 743, 74, + 76, 42, 154, 207, 90, 55, 58, 1671, 149, 74, + 1607, 522, 44, 85, 333, 588, 199, 117, 39, 333, + 903, 268, 85, 743, 364, 74, 53, 935, 108, 42, + 1511, 44, 74, 140, 74, 44, 138, 437, 38, 333, + 85, 1319, 204, 74, 76, 74, 76, 103, 44, 263, + 44, 42, 333, 149, 519, 38, 199, 122, 39, 42, + 1543, 44, 39, 108, 71, 76, 167, 76, 39, 44, + 39, 71, 38, 85, 359, 42, 76, 74, 85, 39, + 70, 42, 44, 199, 199, 199, 231, 231, 1127, 74, + 44, 74, 44, 74, 53, 42, 44, 333, 39, 39, + 743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399, + 229, 165, 39, 44, 327, 57, 423, 167, 39, 71, + 71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55, + 58, 524, 245, 54, 50, 53, 236, 53, 81, 80, + 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, + 54, 50, 54, 50, 54, 50, 85, 54, 50, 149, + 112, 117, 149, 49, 54, 50, 54, 50, 54, 50, + 117, 57, 49, 121, 53, 55, 85, 167, 4327, 34, + 117, 55, 117, 54, 50, 53, 57, 53, 49, 85, + 333, 85, 121, 85, 841, 54, 53, 50, 56, 48, + 56, 837, 54, 57, 50, 57, 54, 50, 53, 54, + 50, 85, 327, 38, 1447, 70, 999, 199, 199, 199, + 103, 87, 57, 56, 58, 87, 58, 153, 90, 98, + 90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455, + 314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575, + 999, 143, 551, 46, 263, 46, 967, 53, 1159, 263, + 53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71, + 39, 743, 53, 271, 711, 207, 53, 839, 53, 1799, + 71, 39, 108, 76, 140, 135, 103, 871, 108, 44, + 271, 309, 935, 79, 53, 1735, 245, 711, 271, 615, + 271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655, + 333, 76, 42, 1447, 106, 140, 74, 76, 85, 34, + 149, 807, 333, 108, 1159, 172, 42, 268, 333, 149, + 76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383, + 44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182, + 149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898, + 1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236, + 986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837, + 841, 229, 581, 841, 837, 41, 73, 41, 73, 137, + 265, 133, 37, 229, 357, 841, 837, 73, 137, 265, + 233, 837, 73, 137, 169, 41, 233, 837, 841, 837, + 841, 837, 841, 837, 841, 837, 841, 837, 841, 901, + 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, + 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, + 809, 57, 805, 57, 197, 94, 1613, 135, 871, 71, + 39, 39, 327, 135, 39, 39, 39, 39, 39, 39, + 103, 71, 39, 39, 39, 39, 39, 39, 71, 39, + 135, 231, 135, 135, 39, 327, 551, 103, 167, 551, + 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946, + 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210, + 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266, + 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351, + 34, 3074, 7692, 63, 63, + }; + +static int sqlite3Fts5UnicodeCategory(int iCode) { + int iRes = -1; + int iHi; + int iLo; + int ret; + u16 iKey; + + if( iCode>=(1<<20) ){ + return 0; + } + iLo = aFts5UnicodeBlock[(iCode>>16)]; + iHi = aFts5UnicodeBlock[1+(iCode>>16)]; + iKey = (iCode & 0xFFFF); + while( iHi>iLo ){ + int iTest = (iHi + iLo) / 2; + assert( iTest>=iLo && iTest=aFts5UnicodeMap[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest; + } + } + + if( iRes<0 ) return 0; + if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0; + ret = aFts5UnicodeData[iRes] & 0x1F; + if( ret!=30 ) return ret; + return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? 5 : 9; +} + +static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ + int i = 0; + int iTbl = 0; + while( i<128 ){ + int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; + int n = (aFts5UnicodeData[iTbl] >> 5) + i; + for(; i<128 && iiInstPos; int *po = &pCsr->iInstOff; + assert( sqlite3Fts5IterEof(pIter)==0 ); + assert( pCsr->bEof==0 ); while( eDetail==FTS5_DETAIL_NONE || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) ){ @@ -209303,7 +219895,7 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ rc = sqlite3Fts5IterNextScan(pCsr->pIter); if( rc==SQLITE_OK ){ rc = fts5VocabInstanceNewTerm(pCsr); - if( eDetail==FTS5_DETAIL_NONE ) break; + if( pCsr->bEof || eDetail==FTS5_DETAIL_NONE ) break; } if( rc ){ pCsr->bEof = 1; @@ -209618,6 +220210,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, + /* xShadowName */ 0 }; void *p = (void*)pGlobal; @@ -209625,8 +220218,6 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ } - - #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ @@ -209900,6 +220491,7 @@ static sqlite3_module stmtModule = { 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ + 0, /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -209932,9 +220524,9 @@ SQLITE_API int sqlite3_stmt_init( #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ -#if __LINE__!=209935 +#if __LINE__!=220527 #undef SQLITE_SOURCE_ID -#define SQLITE_SOURCE_ID "2018-04-10 17:39:29 4bb2294022060e61de7da5c227a69ccd846ba330e31626ebcd59a94efd14alt2" +#define SQLITE_SOURCE_ID "2018-12-01 12:34:55 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238alt2" #endif /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } diff --git a/external/sqlite/src/sqlite3.h b/external/sqlite/src/sqlite3.h index 0ba2852d..f36ae57a 100644 --- a/external/sqlite/src/sqlite3.h +++ b/external/sqlite/src/sqlite3.h @@ -123,9 +123,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.23.1" -#define SQLITE_VERSION_NUMBER 3023001 -#define SQLITE_SOURCE_ID "2018-04-10 17:39:29 4bb2294022060e61de7da5c227a69ccd846ba330e31626ebcd59a94efd148b3b" +#define SQLITE_VERSION "3.26.0" +#define SQLITE_VERSION_NUMBER 3026000 +#define SQLITE_SOURCE_ID "2018-12-01 12:34:55 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238b4f9" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -472,6 +472,7 @@ SQLITE_API int sqlite3_exec( */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) +#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) @@ -504,13 +505,16 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) +#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) +#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) @@ -884,7 +888,8 @@ struct sqlite3_io_methods { **
    • [[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary -** write ahead log and shared memory files used for transaction control +** write ahead log ([WAL file]) and shared memory +** files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not @@ -1070,6 +1075,26 @@ struct sqlite3_io_methods { ** a file lock using the xLock or xShmLock methods of the VFS to wait ** for up to M milliseconds before failing, where M is the single ** unsigned integer parameter. +** +**
    • [[SQLITE_FCNTL_DATA_VERSION]] +** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to +** a database file. The argument is a pointer to a 32-bit unsigned integer. +** The "data version" for the pager is written into the pointer. The +** "data version" changes whenever any change occurs to the corresponding +** database file, either through SQL statements on the same database +** connection or through transactions committed by separate database +** connections possibly in other processes. The [sqlite3_total_changes()] +** interface can be used to find if any database on the connection has changed, +** but that interface responds to changes on TEMP as well as MAIN and does +** not provide a mechanism to detect changes to MAIN only. Also, the +** [sqlite3_total_changes()] interface responds to internal changes only and +** omits changes made by other database connections. The +** [PRAGMA data_version] command provide a mechanism to detect changes to +** a single attached database that occur due to other database connections, +** but omits changes implemented by the database connection on which it is +** called. This file control is the only mechanism to detect changes that +** happen either internally or externally and that are associated with +** a particular attached database. **
    */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1105,6 +1130,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 +#define SQLITE_FCNTL_DATA_VERSION 35 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1930,6 +1956,22 @@ struct sqlite3_mem_methods { ** I/O required to support statement rollback. ** The default value for this setting is controlled by the ** [SQLITE_STMTJRNL_SPILL] compile-time option. +** +** [[SQLITE_CONFIG_SORTERREF_SIZE]] +**
    SQLITE_CONFIG_SORTERREF_SIZE +**
    The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter +** of type (int) - the new value of the sorter-reference size threshold. +** Usually, when SQLite uses an external sort to order records according +** to an ORDER BY clause, all fields required by the caller are present in the +** sorted records. However, if SQLite determines based on the declared type +** of a table column that its values are likely to be very large - larger +** than the configured sorter-reference size threshold - then a reference +** is stored in each sorted record and the required column values loaded +** from the database as records are returned in sorted order. The default +** value for this option is to never use this optimization. Specifying a +** negative value for this option restores the default behaviour. +** This option is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. **
    */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -1959,6 +2001,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ #define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ +#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ /* ** CAPI3REF: Database Connection Configuration Options @@ -1974,6 +2017,7 @@ struct sqlite3_mem_methods { ** is invoked. ** **
    +** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    **
    ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. @@ -1996,6 +2040,7 @@ struct sqlite3_mem_methods { ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
    ** +** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. @@ -2006,6 +2051,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]] **
    SQLITE_DBCONFIG_ENABLE_TRIGGER
    **
    ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. @@ -2016,6 +2062,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the trigger setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    **
    ^This option is used to enable or disable the two-argument ** version of the [fts3_tokenizer()] function which is part of the @@ -2029,6 +2076,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the new setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    **
    ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. @@ -2046,7 +2094,7 @@ struct sqlite3_mem_methods { ** be a NULL pointer, in which case the new setting is not reported back. **
    ** -**
    SQLITE_DBCONFIG_MAINDBNAME
    +** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database ** schema. ^The sole argument is a pointer to a constant UTF8 string ** which will become the new schema name in place of "main". ^SQLite @@ -2055,6 +2103,7 @@ struct sqlite3_mem_methods { ** until after the database connection closes. **
    ** +** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    **
    Usually, when a database in wal mode is closed or detached from a ** database handle, SQLite checks if this will mean that there are now no @@ -2068,7 +2117,7 @@ struct sqlite3_mem_methods { ** have been disabled - 0 if they are not disabled, 1 if they are. **
    ** -**
    SQLITE_DBCONFIG_ENABLE_QPSG
    +** [[SQLITE_DBCONFIG_ENABLE_QPSG]]
    SQLITE_DBCONFIG_ENABLE_QPSG
    **
    ^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates ** the [query planner stability guarantee] (QPSG). When the QPSG is active, ** a single SQL query statement will always use the same algorithm regardless @@ -2084,7 +2133,7 @@ struct sqlite3_mem_methods { ** following this call. **
    ** -**
    SQLITE_DBCONFIG_TRIGGER_EQP
    +** [[SQLITE_DBCONFIG_TRIGGER_EQP]]
    SQLITE_DBCONFIG_TRIGGER_EQP
    **
    By default, the output of EXPLAIN QUERY PLAN commands does not ** include output for any operations performed by trigger programs. This ** option is used to set or clear (the default) a flag that governs this @@ -2095,6 +2144,39 @@ struct sqlite3_mem_methods { ** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if ** it is not disabled, 1 if it is. **
    +** +** [[SQLITE_DBCONFIG_RESET_DATABASE]]
    SQLITE_DBCONFIG_RESET_DATABASE
    +**
    Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run +** [VACUUM] in order to reset a database back to an empty database +** with no schema and no content. The following process works even for +** a badly corrupted database file: +**
      +**
    1. If the database connection is newly opened, make sure it has read the +** database schema by preparing then discarding some query against the +** database, or calling sqlite3_table_column_metadata(), ignoring any +** errors. This step is only necessary if the application desires to keep +** the database in WAL mode after the reset if it was in WAL mode before +** the reset. +**
    2. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); +**
    3. [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); +**
    4. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); +**
    +** Because resetting a database is destructive and irreversible, the +** process requires the use of this obscure API and multiple steps to help +** ensure that it does not happen by accident. +** +** [[SQLITE_DBCONFIG_DEFENSIVE]]
    SQLITE_DBCONFIG_DEFENSIVE
    +**
    The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the +** "defensive" flag for a database connection. When the defensive +** flag is enabled, language features that allow ordinary SQL to +** deliberately corrupt the database file are disabled. The disabled +** features include but are not limited to the following: +**
      +**
    • The [PRAGMA writable_schema=ON] statement. +**
    • Writes to the [sqlite_dbpage] virtual table. +**
    • Direct writes to [shadow tables]. +**
    +**
    **
    */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2106,7 +2188,9 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1008 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ +#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1010 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -2234,12 +2318,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); ** program, the value returned reflects the number of rows modified by the ** previous INSERT, UPDATE or DELETE statement within the same trigger. ** -** See also the [sqlite3_total_changes()] interface, the -** [count_changes pragma], and the [changes() SQL function]. -** ** If a separate thread makes changes on the same database connection ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. +** +** See also: +**
      +**
    • the [sqlite3_total_changes()] interface +**
    • the [count_changes pragma] +**
    • the [changes() SQL function] +**
    • the [data_version pragma] +**
    */ SQLITE_API int sqlite3_changes(sqlite3*); @@ -2257,13 +2346,26 @@ SQLITE_API int sqlite3_changes(sqlite3*); ** count, but those made as part of REPLACE constraint resolution are ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. -** -** See also the [sqlite3_changes()] interface, the -** [count_changes pragma], and the [total_changes() SQL function]. ** +** This the [sqlite3_total_changes(D)] interface only reports the number +** of rows that changed due to SQL statement run against database +** connection D. Any changes by other database connections are ignored. +** To detect changes against a database file from other database +** connections use the [PRAGMA data_version] command or the +** [SQLITE_FCNTL_DATA_VERSION] [file control]. +** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. +** +** See also: +**
      +**
    • the [sqlite3_changes()] interface +**
    • the [count_changes pragma] +**
    • the [changes() SQL function] +**
    • the [data_version pragma] +**
    • the [SQLITE_FCNTL_DATA_VERSION] [file control] +**
    */ SQLITE_API int sqlite3_total_changes(sqlite3*); @@ -3319,13 +3421,24 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int ** [database connection] D failed, then the sqlite3_errcode(D) interface ** returns the numeric [result code] or [extended result code] for that ** API call. -** If the most recent API call was successful, -** then the return value from sqlite3_errcode() is undefined. ** ^The sqlite3_extended_errcode() ** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. ** +** The values returned by sqlite3_errcode() and/or +** sqlite3_extended_errcode() might change with each API call. +** Except, there are some interfaces that are guaranteed to never +** change the value of the error code. The error-code preserving +** interfaces are: +** +**
      +**
    • sqlite3_errcode() +**
    • sqlite3_extended_errcode() +**
    • sqlite3_errmsg() +**
    • sqlite3_errmsg16() +**
    +** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(Memory to hold the error message string is managed internally. @@ -3515,9 +3628,19 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** on this hint by avoiding the use of [lookaside memory] so as not to ** deplete the limited store of lookaside memory. Future versions of ** SQLite may act on this hint differently. +** +** [[SQLITE_PREPARE_NORMALIZE]] ^(
    SQLITE_PREPARE_NORMALIZE
    +**
    The SQLITE_PREPARE_NORMALIZE flag indicates that a normalized +** representation of the SQL statement should be calculated and then +** associated with the prepared statement, which can be obtained via +** the [sqlite3_normalized_sql()] interface.)^ The semantics used to +** normalize a SQL statement are unspecified and subject to change. +** At a minimum, literal values will be replaced with suitable +** placeholders. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 /* ** CAPI3REF: Compiling An SQL Statement @@ -3675,6 +3798,11 @@ SQLITE_API int sqlite3_prepare16_v3( ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. +** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 +** string containing the normalized SQL text of prepared statement P. The +** semantics used to normalize a SQL statement are unspecified and subject +** to change. At a minimum, literal values will be replaced with suitable +** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 @@ -3690,14 +3818,16 @@ SQLITE_API int sqlite3_prepare16_v3( ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** -** ^The string returned by sqlite3_sql(P) is managed by SQLite and is -** automatically freed when the prepared statement is finalized. +** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) +** are managed by SQLite and are automatically freed when the prepared +** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be free by the application ** by passing it to [sqlite3_free()]. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -4479,11 +4609,25 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** -** ^(If a memory allocation error occurs during the evaluation of any -** of these routines, a default value is returned. The default value -** is either the integer 0, the floating point number 0.0, or a NULL -** pointer. Subsequent calls to [sqlite3_errcode()] will return -** [SQLITE_NOMEM].)^ +** As long as the input parameters are correct, these routines will only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_column_blob() +**
    • sqlite3_column_text() +**
    • sqlite3_column_text16() +**
    • sqlite3_column_bytes() +**
    • sqlite3_column_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); @@ -4560,11 +4704,13 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior -** of existing SQL functions or aggregates. The only differences between -** these routines are the text encoding expected for -** the second parameter (the name of the function being created) -** and the presence or absence of a destructor callback for -** the application data pointer. +** of existing SQL functions or aggregates. The only differences between +** the three "sqlite3_create_function*" routines are the text encoding +** expected for the second parameter (the name of the function being +** created) and the presence or absence of a destructor callback for +** the application data pointer. Function sqlite3_create_window_function() +** is similar, but allows the user to supply the extra callback functions +** needed by [aggregate window functions]. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database @@ -4610,7 +4756,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** -** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are +** ^The sixth, seventh and eighth parameters passed to the three +** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal @@ -4619,15 +4766,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** -** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, -** then it is destructor for the application data pointer. -** The destructor is invoked when the function is deleted, either by being -** overloaded or when the database connection closes.)^ -** ^The destructor is also invoked if the call to -** sqlite3_create_function_v2() fails. -** ^When the destructor callback of the tenth parameter is invoked, it -** is passed a single argument which is a copy of the application data -** pointer which was the fifth parameter to sqlite3_create_function_v2(). +** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue +** and xInverse) passed to sqlite3_create_window_function are pointers to +** C-language callbacks that implement the new function. xStep and xFinal +** must both be non-NULL. xValue and xInverse may either both be NULL, in +** which case a regular aggregate function is created, or must both be +** non-NULL, in which case the new function may be used as either an aggregate +** or aggregate window function. More details regarding the implementation +** of aggregate window functions are +** [user-defined window functions|available here]. +** +** ^(If the final parameter to sqlite3_create_function_v2() or +** sqlite3_create_window_function() is not NULL, then it is destructor for +** the application data pointer. The destructor is invoked when the function +** is deleted, either by being overloaded or when the database connection +** closes.)^ ^The destructor is also invoked if the call to +** sqlite3_create_function_v2() fails. ^When the destructor callback is +** invoked, it is passed a single argument which is a copy of the application +** data pointer which was the fifth parameter to sqlite3_create_function_v2(). ** ** ^It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of @@ -4680,6 +4836,18 @@ SQLITE_API int sqlite3_create_function_v2( void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*) ); +SQLITE_API int sqlite3_create_window_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) +); /* ** CAPI3REF: Text Encodings @@ -4822,6 +4990,28 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. +** +** As long as the input parameter is correct, these routines can only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_value_blob() +**
    • sqlite3_value_text() +**
    • sqlite3_value_text16() +**
    • sqlite3_value_text16le() +**
    • sqlite3_value_text16be() +**
    • sqlite3_value_bytes() +**
    • sqlite3_value_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); @@ -5492,6 +5682,41 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory; */ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory; +/* +** CAPI3REF: Win32 Specific Interface +** +** These interfaces are available only on Windows. The +** [sqlite3_win32_set_directory] interface is used to set the value associated +** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to +** zValue, depending on the value of the type parameter. The zValue parameter +** should be NULL to cause the previous value to be freed via [sqlite3_free]; +** a non-NULL value will be copied into memory obtained from [sqlite3_malloc] +** prior to being used. The [sqlite3_win32_set_directory] interface returns +** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported, +** or [SQLITE_NOMEM] if memory could not be allocated. The value of the +** [sqlite3_data_directory] variable is intended to act as a replacement for +** the current directory on the sub-platforms of Win32 where that concept is +** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and +** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the +** sqlite3_win32_set_directory interface except the string parameter must be +** UTF-8 or UTF-16, respectively. +*/ +SQLITE_API int sqlite3_win32_set_directory( + unsigned long type, /* Identifier for directory being set or reset */ + void *zValue /* New value for directory being set or reset */ +); +SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); +SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); + +/* +** CAPI3REF: Win32 Directory Types +** +** These macros are only available on Windows. They define the allowed values +** for the type argument to the [sqlite3_win32_set_directory] interface. +*/ +#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1 +#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2 + /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} @@ -6092,6 +6317,9 @@ struct sqlite3_module { int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); }; /* @@ -6224,6 +6452,10 @@ struct sqlite3_index_info { /* ** CAPI3REF: Virtual Table Scan Flags +** +** Virtual table implementations are allowed to set the +** [sqlite3_index_info].idxFlags field to some combination of +** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ @@ -6249,6 +6481,7 @@ struct sqlite3_index_info { #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_IS 72 +#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation @@ -6925,6 +7158,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** METHOD: sqlite3 +** KEYWORDS: {file control} ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated @@ -6939,11 +7173,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** +** A few opcodes for [sqlite3_file_control()] are handled directly +** by the SQLite core and never invoke the +** sqlite3_io_methods.xFileControl method. ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into -** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER] -** case is a short-circuit path which does not actually invoke the -** underlying sqlite3_io_methods.xFileControl method. +** the space pointed to by the 4th parameter. The +** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns +** the [sqlite3_file] object associated with the journal file instead of +** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns +** a pointer to the underlying [sqlite3_vfs] object for the file. +** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter +** from the pager. ** ** ^If the second parameter (zDbName) does not match the name of any ** open database file, then SQLITE_ERROR is returned. ^This error @@ -6999,8 +7240,9 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 -#define SQLITE_TESTCTRL_ISKEYWORD 16 +#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ +#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -7013,6 +7255,189 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 #define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */ +/* +** CAPI3REF: SQL Keyword Checking +** +** These routines provide access to the set of SQL language keywords +** recognized by SQLite. Applications can uses these routines to determine +** whether or not a specific identifier needs to be escaped (for example, +** by enclosing in double-quotes) so as not to confuse the parser. +** +** The sqlite3_keyword_count() interface returns the number of distinct +** keywords understood by SQLite. +** +** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and +** makes *Z point to that keyword expressed as UTF8 and writes the number +** of bytes in the keyword into *L. The string that *Z points to is not +** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns +** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z +** or L are NULL or invalid pointers then calls to +** sqlite3_keyword_name(N,Z,L) result in undefined behavior. +** +** The sqlite3_keyword_check(Z,L) interface checks to see whether or not +** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero +** if it is and zero if not. +** +** The parser used by SQLite is forgiving. It is often possible to use +** a keyword as an identifier as long as such use does not result in a +** parsing ambiguity. For example, the statement +** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and +** creates a new table named "BEGIN" with three columns named +** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid +** using keywords as identifiers. Common techniques used to avoid keyword +** name collisions include: +**
      +**
    • Put all identifier names inside double-quotes. This is the official +** SQL way to escape identifier names. +**
    • Put identifier names inside [...]. This is not standard SQL, +** but it is what SQL Server does and so lots of programmers use this +** technique. +**
    • Begin every identifier with the letter "Z" as no SQL keywords start +** with "Z". +**
    • Include a digit somewhere in every identifier name. +**
    +** +** Note that the number of keywords understood by SQLite can depend on +** compile-time options. For example, "VACUUM" is not a keyword if +** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also, +** new keywords may be added to future releases of SQLite. +*/ +SQLITE_API int sqlite3_keyword_count(void); +SQLITE_API int sqlite3_keyword_name(int,const char**,int*); +SQLITE_API int sqlite3_keyword_check(const char*,int); + +/* +** CAPI3REF: Dynamic String Object +** KEYWORDS: {dynamic string} +** +** An instance of the sqlite3_str object contains a dynamically-sized +** string under construction. +** +** The lifecycle of an sqlite3_str object is as follows: +**
      +**
    1. ^The sqlite3_str object is created using [sqlite3_str_new()]. +**
    2. ^Text is appended to the sqlite3_str object using various +** methods, such as [sqlite3_str_appendf()]. +**
    3. ^The sqlite3_str object is destroyed and the string it created +** is returned using the [sqlite3_str_finish()] interface. +**
    +*/ +typedef struct sqlite3_str sqlite3_str; + +/* +** CAPI3REF: Create A New Dynamic String Object +** CONSTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_new(D)] interface allocates and initializes +** a new [sqlite3_str] object. To avoid memory leaks, the object returned by +** [sqlite3_str_new()] must be freed by a subsequent call to +** [sqlite3_str_finish(X)]. +** +** ^The [sqlite3_str_new(D)] interface always returns a pointer to a +** valid [sqlite3_str] object, though in the event of an out-of-memory +** error the returned object might be a special singleton that will +** silently reject new text, always return SQLITE_NOMEM from +** [sqlite3_str_errcode()], always return 0 for +** [sqlite3_str_length()], and always return NULL from +** [sqlite3_str_finish(X)]. It is always safe to use the value +** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter +** to any of the other [sqlite3_str] methods. +** +** The D parameter to [sqlite3_str_new(D)] may be NULL. If the +** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum +** length of the string contained in the [sqlite3_str] object will be +** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead +** of [SQLITE_MAX_LENGTH]. +*/ +SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); + +/* +** CAPI3REF: Finalize A Dynamic String +** DESTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X +** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()] +** that contains the constructed string. The calling application should +** pass the returned value to [sqlite3_free()] to avoid a memory leak. +** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any +** errors were encountered during construction of the string. ^The +** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** string in [sqlite3_str] object X is zero bytes long. +*/ +SQLITE_API char *sqlite3_str_finish(sqlite3_str*); + +/* +** CAPI3REF: Add Content To A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces add content to an sqlite3_str object previously obtained +** from [sqlite3_str_new()]. +** +** ^The [sqlite3_str_appendf(X,F,...)] and +** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] +** functionality of SQLite to append formatted text onto the end of +** [sqlite3_str] object X. +** +** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S +** onto the end of the [sqlite3_str] object X. N must be non-negative. +** S must contain at least N non-zero bytes of content. To append a +** zero-terminated string in its entirety, use the [sqlite3_str_appendall()] +** method instead. +** +** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of +** zero-terminated string S onto the end of [sqlite3_str] object X. +** +** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the +** single-byte character C onto the end of [sqlite3_str] object X. +** ^This method can be used, for example, to add whitespace indentation. +** +** ^The [sqlite3_str_reset(X)] method resets the string under construction +** inside [sqlite3_str] object X back to zero bytes in length. +** +** These methods do not return a result code. ^If an error occurs, that fact +** is recorded in the [sqlite3_str] object and can be recovered by a +** subsequent call to [sqlite3_str_errcode(X)]. +*/ +SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); +SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list); +SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); +SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); +SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); +SQLITE_API void sqlite3_str_reset(sqlite3_str*); + +/* +** CAPI3REF: Status Of A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces return the current status of an [sqlite3_str] object. +** +** ^If any prior errors have occurred while constructing the dynamic string +** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return +** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns +** [SQLITE_NOMEM] following any out-of-memory error, or +** [SQLITE_TOOBIG] if the size of the dynamic string exceeds +** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors. +** +** ^The [sqlite3_str_length(X)] method returns the current length, in bytes, +** of the dynamic string under construction in [sqlite3_str] object X. +** ^The length returned by [sqlite3_str_length(X)] does not include the +** zero-termination byte. +** +** ^The [sqlite3_str_value(X)] method returns a pointer to the current +** content of the dynamic string under construction in X. The value +** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X +** and might be freed or altered by any subsequent method on the same +** [sqlite3_str] object. Applications must not used the pointer returned +** [sqlite3_str_value(X)] after any subsequent method call on the same +** object. ^Applications may change the content of the string returned +** by [sqlite3_str_value(X)] as long as they do not write into any bytes +** outside the range of 0 to [sqlite3_str_length(X)] and do not read or +** write any byte after any subsequent sqlite3_str method call. +*/ +SQLITE_API int sqlite3_str_errcode(sqlite3_str*); +SQLITE_API int sqlite3_str_length(sqlite3_str*); +SQLITE_API char *sqlite3_str_value(sqlite3_str*); + /* ** CAPI3REF: SQLite Runtime Status ** @@ -8230,6 +8655,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** can use to customize and optimize their behavior. ** **
    +** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] **
    SQLITE_VTAB_CONSTRAINT_SUPPORT **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, @@ -8282,11 +8708,11 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** method of a [virtual table], then it returns true if and only if the ** column is being fetched as part of an UPDATE operation during which the ** column value will not change. Applications might use this to substitute -** a lighter-weight value to return that the corresponding [xUpdate] method -** understands as a "no-change" value. +** a return value that is less expensive to compute and that the corresponding +** [xUpdate] method understands as a "no-change" value. ** ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that -** the column is not changed by the UPDATE statement, they the xColumn +** the column is not changed by the UPDATE statement, then the xColumn ** method can optionally return without setting a result, without calling ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. ** In that case, [sqlite3_value_nochange(X)] will return true for the @@ -8579,7 +9005,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot ** KEYWORDS: {snapshot} {sqlite3_snapshot} -** EXPERIMENTAL ** ** An instance of the snapshot object records the state of a [WAL mode] ** database for some specific point in history. @@ -8596,11 +9021,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*); ** version of the database file so that it is possible to later open a new read ** transaction that sees that historical version of the database rather than ** the most recent version. -** -** The constructor for this object is [sqlite3_snapshot_get()]. The -** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer -** to an historical snapshot (if possible). The destructor for -** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. */ typedef struct sqlite3_snapshot { unsigned char hidden[48]; @@ -8608,7 +9028,7 @@ typedef struct sqlite3_snapshot { /* ** CAPI3REF: Record A Database Snapshot -** EXPERIMENTAL +** CONSTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of @@ -8624,7 +9044,7 @@ typedef struct sqlite3_snapshot { ** in this case. ** **
      -**
    • The database handle must be in [autocommit mode]. +**
    • The database handle must not be in [autocommit mode]. ** **
    • Schema S of [database connection] D must be a [WAL mode] database. ** @@ -8647,7 +9067,7 @@ typedef struct sqlite3_snapshot { ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, @@ -8657,24 +9077,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( /* ** CAPI3REF: Start a read transaction on an historical snapshot -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** -** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a -** read transaction for schema S of -** [database connection] D such that the read transaction -** refers to historical [snapshot] P, rather than the most -** recent change to the database. -** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success -** or an appropriate [error code] if it fails. +** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read +** transaction or upgrades an existing one for schema S of +** [database connection] D such that the read transaction refers to +** historical [snapshot] P, rather than the most recent change to the +** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK +** on success or an appropriate [error code] if it fails. +** +** ^In order to succeed, the database connection must not be in +** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there +** is already a read transaction open on schema S, then the database handle +** must have no active statements (SELECT statements that have been passed +** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). +** SQLITE_ERROR is returned if either of these conditions is violated, or +** if schema S does not exist, or if the snapshot object is invalid. +** +** ^A call to sqlite3_snapshot_open() will fail to open if the specified +** snapshot has been overwritten by a [checkpoint]. In this case +** SQLITE_ERROR_SNAPSHOT is returned. +** +** If there is already a read transaction open when this function is +** invoked, then the same read transaction remains open (on the same +** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT +** is returned. If another error code - for example SQLITE_PROTOCOL or an +** SQLITE_IOERR error code - is returned, then the final state of the +** read transaction is undefined. If SQLITE_OK is returned, then the +** read transaction is now open on database snapshot P. ** -** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be -** the first operation following the [BEGIN] that takes the schema S -** out of [autocommit mode]. -** ^In other words, schema S must not currently be in -** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the -** database connection D must be out of [autocommit mode]. -** ^A [snapshot] will fail to open if it has been overwritten by a -** [checkpoint]. ** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the ** database connection D does not know that the database file for ** schema S is in [WAL mode]. A database connection might not know @@ -8685,7 +9116,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( ** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, @@ -8695,20 +9126,20 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( /* ** CAPI3REF: Destroy a snapshot -** EXPERIMENTAL +** DESTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. ** The application must eventually free every [sqlite3_snapshot] object ** using this routine to avoid a memory leak. ** ** The [sqlite3_snapshot_free()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages ** of two valid snapshot handles. @@ -8727,6 +9158,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); ** Otherwise, this API returns a negative value if P1 refers to an older ** snapshot than P2, zero if the two handles refer to the same database ** snapshot, and a positive value if P1 is a newer snapshot than P2. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, @@ -8735,23 +9169,26 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( /* ** CAPI3REF: Recover snapshots from a wal file -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** -** If all connections disconnect from a database file but do not perform -** a checkpoint, the existing wal file is opened along with the database -** file the next time the database is opened. At this point it is only -** possible to successfully call sqlite3_snapshot_open() to open the most -** recent snapshot of the database (the one at the head of the wal file), -** even though the wal file may contain other valid snapshots for which -** clients have sqlite3_snapshot handles. +** If a [WAL file] remains on disk after all database connections close +** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] +** or because the last process to have the database opened exited without +** calling [sqlite3_close()]) and a new connection is subsequently opened +** on that database and [WAL file], the [sqlite3_snapshot_open()] interface +** will only be able to open the last transaction added to the WAL file +** even though the WAL file contains other valid transactions. ** -** This function attempts to scan the wal file associated with database zDb +** This function attempts to scan the WAL file associated with database zDb ** of database handle db and make all valid snapshots available to ** sqlite3_snapshot_open(). It is an error if there is already a read -** transaction open on the database, or if the database is not a wal mode +** transaction open on the database, or if the database is not a WAL mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); @@ -8781,7 +9218,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** been a prior call to [sqlite3_deserialize(D,S,...)] with the same ** values of D and S. ** The size of the database is written into *P even if the -** SQLITE_SERIALIZE_NOCOPY bit is set but no contigious copy +** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy ** of the database exists. ** ** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the @@ -8862,7 +9299,7 @@ SQLITE_API int sqlite3_deserialize( ** in the P argument is held in memory obtained from [sqlite3_malloc64()] ** and that SQLite should take ownership of this memory and automatically ** free it when it has finished using it. Without this flag, the caller -** is resposible for freeing any dynamically allocated memory. +** is responsible for freeing any dynamically allocated memory. ** ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to ** grow the size of the database using calls to [sqlite3_realloc64()]. This @@ -8988,7 +9425,7 @@ struct sqlite3_rtree_query_info { sqlite3_int64 iRowid; /* Rowid for current entry */ sqlite3_rtree_dbl rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ + int eWithin; /* OUT: Visibility */ sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ /* The following fields are only available in 3.8.11 and later */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ @@ -9484,12 +9921,38 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); ** consecutively. There is no chance that the iterator will visit a change ** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
      SQLITE_CHANGESETAPPLY_INVERT
      +** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* @@ -10144,7 +10607,7 @@ SQLITE_API int sqlite3changeset_apply_v2( ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* Combination of SESSION_APPLY_* flags */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* @@ -10162,8 +10625,14 @@ SQLITE_API int sqlite3changeset_apply_v2( ** causes the sessions module to omit this savepoint. In this case, if the ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. +** +**
      SQLITE_CHANGESETAPPLY_INVERT
      +** Invert the changeset before applying it. This is equivalent to inverting +** a changeset using sqlite3changeset_invert() before applying it. It is +** an error to specify this flag with a patchset. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 /* ** CAPI3REF: Constants Passed To The Conflict Handler @@ -10557,6 +11026,12 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); SQLITE_API int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), @@ -10583,6 +11058,45 @@ SQLITE_API int sqlite3rebaser_rebase_strm( void *pOut ); +/* +** CAPI3REF: Configure global parameters +** +** The sqlite3session_config() interface is used to make global configuration +** changes to the sessions module in order to tune it to the specific needs +** of the application. +** +** The sqlite3session_config() interface is not threadsafe. If it is invoked +** while any other thread is inside any other sessions method then the +** results are undefined. Furthermore, if it is invoked after any sessions +** related objects have been created, the results are also undefined. +** +** The first argument to the sqlite3session_config() function must be one +** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The +** interpretation of the (void*) value passed as the second parameter and +** the effect of calling this function depends on the value of the first +** parameter. +** +**
      +**
      SQLITE_SESSION_CONFIG_STRMSIZE
      +** By default, the sessions module streaming interfaces attempt to input +** and output data in approximately 1 KiB chunks. This operand may be used +** to set and query the value of this configuration setting. The pointer +** passed as the second argument must point to a value of type (int). +** If this value is greater than 0, it is used as the new streaming data +** chunk size for both input and output. Before returning, the (int) value +** pointed to by pArg is set to the final value of the streaming interface +** chunk size. +**
      +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg); + +/* +** CAPI3REF: Values for sqlite3session_config(). +*/ +#define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. @@ -11040,7 +11554,7 @@ struct Fts5ExtensionApi { ** This way, even if the tokenizer does not provide synonyms ** when tokenizing query text (it should not - to do would be ** inefficient), it doesn't matter if the user queries for -** 'first + place' or '1st + place', as there are entires in the +** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. ** ** @@ -11068,7 +11582,7 @@ struct Fts5ExtensionApi { ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the -** token "first" is subsituted for "1st" by the tokenizer, then the query: +** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** ** ... MATCH '1s*' diff --git a/linux/installer/bin/build-installpkg.sh b/linux/installer/bin/build-installpkg.sh index 90830e12..7d69f029 100755 --- a/linux/installer/bin/build-installpkg.sh +++ b/linux/installer/bin/build-installpkg.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/linux/installer/bin/install-sgx-psw.bin.tmpl b/linux/installer/bin/install-sgx-psw.bin.tmpl index 25ed31bc..3510e97c 100755 --- a/linux/installer/bin/install-sgx-psw.bin.tmpl +++ b/linux/installer/bin/install-sgx-psw.bin.tmpl @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -30,19 +30,19 @@ # # -grep intel_sgx /lib/modules/$(uname -r)/modules.builtin &> /dev/null +grep 'sgx\.ko$\|intel_sgx\.ko$' /lib/modules/$(uname -r)/modules.builtin &> /dev/null if [[ $? != "0" ]]; then - modinfo isgx &> /dev/null + /sbin/modinfo isgx &> /dev/null if [[ $? != "0" ]]; then - modinfo intel_sgx &> /dev/null + /sbin/modinfo intel_sgx &> /dev/null if [[ $? != "0" ]]; then lsmod | grep 'isgx\|intel_sgx' &> /dev/null if [[ $? = "0" ]]; then - echo "Warning: You did not follow the document to install the driver package" + echo "Warning: You did not follow the document to install the driver package." + echo + elif [[ ! -e /dev/isgx ]] && [[ ! -e /dev/sgx ]]; then + echo -e "\033[31;49;1mWarning: You may need to activate the SGX module if SGX is enabled in the kernel (e.g., sudo modprobe sgx) or download and install the SGX driver if the kernel doesn't have SGX support.\033[39;49;0m" echo - else - echo "Please install the driver package before the PSW package" - exit 4 fi fi fi diff --git a/linux/installer/bin/install-sgx-sdk.bin.tmpl b/linux/installer/bin/install-sgx-sdk.bin.tmpl index 7b2e252b..db67a9d6 100755 --- a/linux/installer/bin/install-sgx-sdk.bin.tmpl +++ b/linux/installer/bin/install-sgx-sdk.bin.tmpl @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/linux/installer/common/gen_source/gen_source.py b/linux/installer/common/gen_source/gen_source.py index 814a30a2..b3a6e82a 100755 --- a/linux/installer/common/gen_source/gen_source.py +++ b/linux/installer/common/gen_source/gen_source.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/linux/installer/common/libsgx-enclave-common-dev/Makefile b/linux/installer/common/libsgx-enclave-common-dev/Makefile index b987eeb8..94de7da2 100644 --- a/linux/installer/common/libsgx-enclave-common-dev/Makefile +++ b/linux/installer/common/libsgx-enclave-common-dev/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -35,9 +35,15 @@ SOURCE_FOLDER=package ECL_INC_PATH=$(SOURCE_FOLDER)/$(INC_DIR) USR_INC_PATH=$(addprefix $(DESTDIR)/usr/, $(INC_DIR)) +USR_LIB_PATH=$(shell readlink -m $(addsuffix /$(shell dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null), $(addprefix $(DESTDIR)/usr/, $(notdir $(shell gcc -print-multi-os-directory))))) + +ECL_VER=1.0.0 default: install: install -d $(USR_INC_PATH) install $(ECL_INC_PATH)/* $(USR_INC_PATH) + install -d $(USR_LIB_PATH) + cd $(USR_LIB_PATH) && \ + ln -fs libsgx_enclave_common.so.$(shell echo $(ECL_VER) |awk -F. '{print $$1}') libsgx_enclave_common.so diff --git a/linux/installer/common/libsgx-enclave-common-dev/createTarball.sh b/linux/installer/common/libsgx-enclave-common-dev/createTarball.sh index 1d7b8a08..007d3862 100755 --- a/linux/installer/common/libsgx-enclave-common-dev/createTarball.sh +++ b/linux/installer/common/libsgx-enclave-common-dev/createTarball.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -54,6 +54,8 @@ python ${SCRIPT_DIR}/gen_source.py --bom=BOMs/sgx-enclave-common-dev_base.txt python ${SCRIPT_DIR}/gen_source.py --bom=../licenses/BOM_license.txt --cleanup=false # Create the tarball +ECL_VER=$(awk '/ENCLAVE_COMMON_VERSION/ {print $3}' ${ROOT_DIR}/common/inc/internal/se_version.h|sed 's/^\"\(.*\)\"$/\1/') pushd ${INSTALL_PATH} &> /dev/null +sed -i "s/ECL_VER=.*/ECL_VER=${ECL_VER}/" Makefile tar -zcvf ${TARBALL_NAME} * popd &> /dev/null diff --git a/linux/installer/common/libsgx-enclave-common/BOMs/sgx-enclave-common_base.txt b/linux/installer/common/libsgx-enclave-common/BOMs/sgx-enclave-common_base.txt index 345182ee..5725600d 100644 --- a/linux/installer/common/libsgx-enclave-common/BOMs/sgx-enclave-common_base.txt +++ b/linux/installer/common/libsgx-enclave-common/BOMs/sgx-enclave-common_base.txt @@ -2,6 +2,20 @@ DeliveryName InstallName FileCheckSum FileFeature FileOwner /build/linux/aesmd.conf /package/aesm/aesmd.conf 0 main STP /build/linux/aesmd.service /package/aesm/aesmd.service 0 main STP /build/linux/aesm_service /package/aesm/aesm_service 0 main STP +/build/linux/libipc.so /package/aesm/libipc.so 0 main STP +/build/linux/liboal.so /package/aesm/liboal.so 0 main STP +/build/linux/libutils.so /package/aesm/libutils.so 0 main STP +/build/linux/libdcap_quoteprov.so /package/aesm/libdcap_quoteprov.so 0 main STP +/build/linux/libsgx_default_qcnl_wrapper.so /package/aesm/libsgx_default_qcnl_wrapper.so 0 main STP +/build/linux/liburts_internal.so /package/aesm/liburts_internal.so 0 main STP +/build/linux/libCppMicroServicesd.so.4.0.0 /package/aesm/libCppMicroServicesd.so.4.0.0 0 main STP +/build/linux/bundles/libepid_quote_service_bundle.so /package/aesm/bundles/libepid_quote_service_bundle.so 0 main STP +/build/linux/bundles/lible_launch_service_bundle.so /package/aesm/bundles/lible_launch_service_bundle.so 0 main STP +/build/linux/bundles/liblinux_network_service_bundle.so /package/aesm/bundles/liblinux_network_service_bundle.so 0 main STP +/build/linux/bundles/liblocal_pseop_service_bundle.so /package/aesm/bundles/liblocal_pseop_service_bundle.so 0 main STP +/build/linux/bundles/libpce_service_bundle.so /package/aesm/bundles/libpce_service_bundle.so 0 main STP +/build/linux/bundles/libpsepr_service_bundle.so /package/aesm/bundles/libpsepr_service_bundle.so 0 main STP +/build/linux/bundles/libecdsa_quote_service_bundle.so /package/aesm/bundles/libecdsa_quote_service_bundle.so 0 main STP /build/linux/le_prod_css.bin /package/aesm/le_prod_css.bin 0 main STP /build/linux/libsgx_le.signed.so /package/aesm/libsgx_le.signed.so 0 main STP /build/linux/libsgx_pve.signed.so /package/aesm/libsgx_pve.signed.so 0 main STP @@ -10,6 +24,7 @@ DeliveryName InstallName FileCheckSum FileFeature FileOwner /build/linux/libsgx_pse_pr.signed.so /package/aesm/libsgx_pse_pr.signed.so 0 main STP /build/linux/libsgx_pse_pr_2.signed.so /package/aesm/libsgx_pse_pr_2.signed.so 0 main STP /build/linux/libsgx_pse_op.signed.so /package/aesm/libsgx_pse_op.signed.so 0 main STP +/build/linux/libsgx_qe3.signed.so /package/aesm/libsgx_qe3.signed.so 0 main STP /build/linux/PSDA.dalp /package/aesm/PSDA.dalp 0 main STP /linux/installer/common/libsgx-enclave-common/install.sh /scripts/install.sh 0 main STP /linux/installer/common/libsgx-enclave-common/Makefile /Makefile 0 main STP diff --git a/linux/installer/common/libsgx-enclave-common/Makefile b/linux/installer/common/libsgx-enclave-common/Makefile index eaa0ad10..49f50ad5 100644 --- a/linux/installer/common/libsgx-enclave-common/Makefile +++ b/linux/installer/common/libsgx-enclave-common/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -38,7 +38,7 @@ INSTALL_PATH=$(shell readlink -m $(DESTDIR)/$(ECL_PACKAGES_PATH)/$(ECL_PKG_NAME) SOURCE_INSTALL_PATH=$(INSTALL_PATH) SCRIPTS_INSTALL_PATH=$(INSTALL_PATH)/$(SCRIPTS_FOLDER) ECL_LIB_PATH=$(SOURCE_INSTALL_PATH)/$(LIB_DIR) -USR_LIB_PATH=$(addsuffix /$(shell dpkg-architecture -qDEB_HOST_MULTIARCH), $(addprefix $(DESTDIR)/usr/, $(notdir $(shell gcc -print-multi-os-directory)))) +USR_LIB_PATH=$(addsuffix /$(shell dpkg-architecture -qDEB_HOST_MULTIARCH 2> /dev/null), $(addprefix $(DESTDIR)/usr/, $(notdir $(shell gcc -print-multi-os-directory)))) UAE_VER=1.0.0 URTS_VER=1.0.0 diff --git a/linux/installer/common/libsgx-enclave-common/createTarball.sh b/linux/installer/common/libsgx-enclave-common/createTarball.sh index 713c4469..e9555055 100755 --- a/linux/installer/common/libsgx-enclave-common/createTarball.sh +++ b/linux/installer/common/libsgx-enclave-common/createTarball.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/linux/installer/common/libsgx-enclave-common/install.sh b/linux/installer/common/libsgx-enclave-common/install.sh index d32f9533..296879af 100755 --- a/linux/installer/common/libsgx-enclave-common/install.sh +++ b/linux/installer/common/libsgx-enclave-common/install.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -33,6 +33,11 @@ set -e +if test $(id -u) -ne 0; then + echo "Root privilege is required." + exit 1 +fi + SCRIPT_DIR=$(dirname "$0") source ${SCRIPT_DIR}/installConfig @@ -41,15 +46,13 @@ AESM_PATH=$ECL_DST_PATH/aesm # Install the AESM service -cut -d: -f1 /etc/passwd | grep -q -w aesmd || \ +id -u aesmd &> /dev/null || \ /usr/sbin/useradd -r -U -c "User for aesmd" \ -d /var/opt/aesmd -s /sbin/nologin aesmd mkdir -p /var/opt/aesmd cp -rf $AESM_PATH/data /var/opt/aesmd/ -rm -rf $AESM_PATH/data cp -rf $AESM_PATH/conf/aesmd.conf /etc/aesmd.conf -rm -rf $AESM_PATH/conf chmod 0644 /etc/aesmd.conf chown -R aesmd:aesmd /var/opt/aesmd chmod 0750 /var/opt/aesmd @@ -63,10 +66,8 @@ mkdir -p /var/run/aesmd chown -R aesmd:aesmd /var/run/aesmd chmod 0755 /var/run/aesmd -# Stop aesmd first. -/usr/sbin/service aesmd stop &> /dev/null || echo - if [ -d /run/systemd/system ]; then + systemctl stop aesmd &> /dev/null || echo AESMD_NAME=aesmd.service AESMD_TEMP=$AESM_PATH/$AESMD_NAME if [ -d /lib/systemd/system ]; then @@ -78,12 +79,10 @@ if [ -d /run/systemd/system ]; then sed -e "s:@aesm_folder@:$AESM_PATH:" \ $AESMD_TEMP > $AESMD_DEST chmod 0644 $AESMD_DEST - rm -f $AESMD_TEMP - rm -f $AESM_PATH/aesmd.conf - DISABLE_AESMD="systemctl disable aesmd" systemctl enable aesmd retval=$? elif [ -d /etc/init/ ]; then + /sbin/initctl stop aesmd &> /dev/null || echo AESMD_NAME=aesmd.conf AESMD_TEMP=$AESM_PATH/$AESMD_NAME AESMD_DEST=/etc/init/$AESMD_NAME @@ -91,8 +90,6 @@ elif [ -d /etc/init/ ]; then sed -e "s:@aesm_folder@:$AESM_PATH:" \ $AESMD_TEMP > $AESMD_DEST chmod 0644 $AESMD_DEST - rm -f $AESMD_TEMP - rm -f $AESM_PATH/aesmd.service /sbin/initctl reload-configuration retval=$? else @@ -112,7 +109,7 @@ echo " done." cat > $ECL_DST_PATH/cleanup.sh < /dev/null +elif [ -d /etc/init/ ]; then + /sbin/initctl reload-configuration + /sbin/initctl stop aesmd +fi + # Removing AESM configuration files rm -f $AESMD_DEST rm -f /etc/aesmd.conf @@ -175,12 +174,11 @@ EOF chmod +x $ECL_DST_PATH/cleanup.sh $AESM_PATH/cse_provision_tool || true -rm $AESM_PATH/cse_provision_tool cat > $AESM_PATH/linksgx.sh </build/linux/aesmd.conf /package/aesm/aesmd.conf 0 main STP /build/linux/aesmd.service /package/aesm/aesmd.service 0 main STP /build/linux/aesm_service /package/aesm/aesm_service 0 main STP +/build/linux/libipc.so /package/aesm/libipc.so 0 main STP +/build/linux/liboal.so /package/aesm/liboal.so 0 main STP +/build/linux/libutils.so /package/aesm/libutils.so 0 main STP +/build/linux/libdcap_quoteprov.so /package/aesm/libdcap_quoteprov.so 0 main STP +/build/linux/libsgx_default_qcnl_wrapper.so /package/aesm/libsgx_default_qcnl_wrapper.so 0 main STP +/build/linux/liburts_internal.so /package/aesm/liburts_internal.so 0 main STP +/build/linux/libCppMicroServicesd.so.4.0.0 /package/aesm/libCppMicroServicesd.so.4.0.0 0 main STP +/build/linux/bundles/libepid_quote_service_bundle.so /package/aesm/bundles/libepid_quote_service_bundle.so 0 main STP +/build/linux/bundles/lible_launch_service_bundle.so /package/aesm/bundles/lible_launch_service_bundle.so 0 main STP +/build/linux/bundles/liblinux_network_service_bundle.so /package/aesm/bundles/liblinux_network_service_bundle.so 0 main STP +/build/linux/bundles/liblocal_pseop_service_bundle.so /package/aesm/bundles/liblocal_pseop_service_bundle.so 0 main STP +/build/linux/bundles/libpce_service_bundle.so /package/aesm/bundles/libpce_service_bundle.so 0 main STP +/build/linux/bundles/libpsepr_service_bundle.so /package/aesm/bundles/libpsepr_service_bundle.so 0 main STP +/build/linux/bundles/libepid_quote_service_bundle.so /package/aesm/bundles/libepid_quote_service_bundle.so 0 main STP +/build/linux/bundles/libecdsa_quote_service_bundle.so /package/aesm/bundles/libecdsa_quote_service_bundle.so 0 main STP /build/linux/le_prod_css.bin /package/aesm/le_prod_css.bin 0 main STP /build/linux/libsgx_le.signed.so /package/aesm/libsgx_le.signed.so 0 main STP /build/linux/libsgx_pve.signed.so /package/aesm/libsgx_pve.signed.so 0 main STP @@ -10,6 +25,7 @@ DeliveryName InstallName FileCheckSum FileFeature FileOwner /build/linux/libsgx_pse_pr.signed.so /package/aesm/libsgx_pse_pr.signed.so 0 main STP /build/linux/libsgx_pse_pr_2.signed.so /package/aesm/libsgx_pse_pr_2.signed.so 0 main STP /build/linux/libsgx_pse_op.signed.so /package/aesm/libsgx_pse_op.signed.so 0 main STP +/build/linux/libsgx_qe3.signed.so /package/aesm/libsgx_qe3.signed.so 0 main STP /build/linux/PSDA.dalp /package/aesm/PSDA.dalp 0 main STP /linux/installer/common/psw/install.sh /scripts/install.sh 0 main STP /linux/installer/common/psw/Makefile /Makefile 0 main STP diff --git a/linux/installer/common/psw/Makefile b/linux/installer/common/psw/Makefile index a70f7ca0..e46cf53d 100644 --- a/linux/installer/common/psw/Makefile +++ b/linux/installer/common/psw/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -38,7 +38,7 @@ INSTALL_PATH=$(shell readlink -m $(DESTDIR)/$(SGX_PACKAGES_PATH)/$(PSW_PKG_NAME) SOURCE_INSTALL_PATH=$(INSTALL_PATH) SCRIPTS_INSTALL_PATH=$(INSTALL_PATH)/$(SCRIPTS_FOLDER) PSW_LIB_PATH=$(SOURCE_INSTALL_PATH)/$(LIB_DIR) -USR_LIB_PATH=$(addprefix $(DESTDIR)/usr/, $(notdir $(shell gcc -print-multi-os-directory))) +USR_LIB_PATH=$(addprefix $(DESTDIR)/usr/, $(or $(notdir $(shell gcc -print-multi-os-directory 2> /dev/null)),$(if $(wildcard /usr/lib64/.*),lib64),lib)) ECL_VER=1.0.0 diff --git a/linux/installer/common/psw/createTarball.sh b/linux/installer/common/psw/createTarball.sh index 3ff94b43..f01684ec 100755 --- a/linux/installer/common/psw/createTarball.sh +++ b/linux/installer/common/psw/createTarball.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/linux/installer/common/psw/install.sh b/linux/installer/common/psw/install.sh index c0d3a00d..59f3ed61 100755 --- a/linux/installer/common/psw/install.sh +++ b/linux/installer/common/psw/install.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -41,7 +41,7 @@ AESM_PATH=$PSW_DST_PATH/aesm # Install the AESM service -cut -d: -f1 /etc/passwd | grep -q -w aesmd || \ +id -u aesmd &> /dev/null || \ /usr/sbin/useradd -r -U -c "User for aesmd" \ -d /var/opt/aesmd -s /sbin/nologin aesmd @@ -64,6 +64,7 @@ chown -R aesmd:aesmd /var/run/aesmd chmod 0755 /var/run/aesmd if [ -d /run/systemd/system ]; then + systemctl stop aesmd &> /dev/null || echo AESMD_NAME=aesmd.service AESMD_TEMP=$AESM_PATH/$AESMD_NAME if [ -d /lib/systemd/system ]; then @@ -77,10 +78,10 @@ if [ -d /run/systemd/system ]; then chmod 0644 $AESMD_DEST rm -f $AESMD_TEMP rm -f $AESM_PATH/aesmd.conf - DISABLE_AESMD="systemctl disable aesmd" systemctl enable aesmd retval=$? elif [ -d /etc/init/ ]; then + /sbin/initctl stop aesmd &> /dev/null || echo AESMD_NAME=aesmd.conf AESMD_TEMP=$AESM_PATH/$AESMD_NAME AESMD_DEST=/etc/init/$AESMD_NAME @@ -109,7 +110,7 @@ echo " done." cat > $PSW_DST_PATH/uninstall.sh < /dev/null +elif [ -d /etc/init/ ]; then + /sbin/initctl reload-configuration + /sbin/initctl stop aesmd +fi + # Removing AESM configuration files rm -f $AESMD_DEST rm -f /etc/aesmd.conf @@ -162,9 +165,9 @@ rm -f /etc/aesmd.conf rm -fr /var/run/aesmd # Removing runtime libraries -rm -f /usr/\$(get_lib)/libsgx_uae_service.so -rm -f /usr/\$(get_lib)/libsgx_urts.so -rm -f /usr/\$(get_lib)/libsgx_enclave_common.so* +rm -f /usr/{lib,lib64}/libsgx_uae_service.so +rm -f /usr/{lib,lib64}/libsgx_urts.so +rm -f /usr/{lib,lib64}/libsgx_enclave_common.so* rm -f /usr/lib/i386-linux-gnu/libsgx_uae_service.so rm -f /usr/lib/i386-linux-gnu/libsgx_urts.so rm -f /usr/lib/i386-linux-gnu/libsgx_enclave_common.so* @@ -187,7 +190,7 @@ rm $AESM_PATH/cse_provision_tool cat > $AESM_PATH/linksgx.sh < $GDB_SCRIPT < $SDK_DST_PATH/uninstall.sh < $SDK_DST_PATH/uninstall.sh <= 2.5), ${shlibs:Depends}, ${misc:Depends} Description: SGX uRTS diff --git a/psw/Makefile b/psw/Makefile index 28a068d7..ed9ee0fa 100644 --- a/psw/Makefile +++ b/psw/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/Makefile b/psw/ae/Makefile index ce5e03c9..5e128f14 100644 --- a/psw/ae/Makefile +++ b/psw/ae/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -31,22 +31,22 @@ include ../../buildenv.mk -CHECK_CURL := $(shell which curl-config) +CHECK_CMAKE := $(shell which cmake) -ifeq ($(CHECK_CURL), ) - CURL_RESULT := check_fail +ifeq ($(CHECK_CMAKE), ) + CMAKE_RESULT := cmake_check_fail else - CURL_RESULT := + CMAKE_RESULT := endif .PHONY: all ifeq ($(BUILD_REF_LE), 1) -all: $(CURL_RESULT) AESM REF_LE COPY_AES CSE| $(BUILD_DIR) +all: $(CMAKE_RESULT) AESM REF_LE COPY_AES CSE| $(BUILD_DIR) else -all: $(CURL_RESULT) AESM COPY_AES CSE| $(BUILD_DIR) +all: $(CMAKE_RESULT) AESM COPY_AES CSE| $(BUILD_DIR) endif #($(BUILD_REF_LE), 1) -# COPY_AES: currently copy le, qe, pve, pce, pse_op, pse_pr, pse_pr_2 +# COPY_AES: currently copy le, qe, pve, pce, pse_op, pse_pr, pse_pr_2, qe3 .PHONY: COPY_AES COPY_AES: | $(BUILD_DIR) $(CP) data/prebuilt/* $(BUILD_DIR) @@ -80,11 +80,12 @@ rebuild: $(MAKE) clean $(MAKE) all -.PHONY: check_fail -check_fail: - @echo ERROR: Please install libcurl by command such as - @echo apt-get install libcurl4-openssl-dev + +.PHONY: cmake_check_fail +cmake_check_fail: + @echo ERROR: Please install cmake by command such as + @echo apt-get install cmake @echo or - @echo yum install libcurl-devel + @echo yum install cmake @echo with root account @exit 2 diff --git a/psw/ae/aesm_service/Makefile b/psw/ae/aesm_service/Makefile index ce0da3ef..d45b6231 100644 --- a/psw/ae/aesm_service/Makefile +++ b/psw/ae/aesm_service/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -32,75 +32,19 @@ TOP_DIR = ../../.. include $(TOP_DIR)/buildenv.mk -IPC_COMMON_DIR := ../common -IPC_COMMON_SRC_DIR := $(IPC_COMMON_DIR)/src -IPC_COMMON_INC_DIR := $(IPC_COMMON_DIR)/inc -IPC_COMMON_PROTO_DIR := source/protobuf -AESM_WRAPPER_DIR := $(LINUX_PSW_DIR)/ae/aesm_service/source/aesm_wrapper -AESM_SRC_DIR := $(AESM_WRAPPER_DIR)/src -AESM_INC_DIR := $(AESM_WRAPPER_DIR)/inc -AESM_APPLICATION := $(LINUX_PSW_DIR)/ae/aesm_service/source/aesm/application -AESM_EXTENSION := $(LINUX_PSW_DIR)/ae/aesm_service/source/aesm/extension - -INCLUDE += -I$(COMMON_DIR)/inc \ - -I$(COMMON_DIR)/inc/internal \ - -I./include \ - -I./include/oal \ - -I./source/ \ - -I./source/ssl_wrapper/ \ - -I./source/aesm_wrapper/inc - -INCLUDE += -I$(LINUX_SDK_DIR)/tseal - -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/aesm/application/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/aesm/extension/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/epid_provision/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/le/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/network/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/oal/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/protobuf/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/pse_op/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/pse_pr/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/pve/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/qe/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/pce/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/storage/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/upse/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/aesm_service/source/upse/BackendInterface/ -INCLUDE += -I$(LINUX_PSW_DIR)/ae/data/constants/linux - -INCLUDE += -I$(LINUX_PSW_DIR)/ae/inc \ - -I$(LINUX_PSW_DIR)/ae/inc/internal \ - -I$(LINUX_PSW_DIR)/ae/common - -INCLUDE += -I$(LINUX_PSW_DIR)/ae/pve \ - -I$(LINUX_PSW_DIR)/ae/pse/pse_op - -INCLUDE += -I$(LINUX_EXTERNAL_DIR)/epid-sdk \ - -I$(LINUX_EXTERNAL_DIR)/sqlite/src \ - -I$(LINUX_EXTERNAL_DIR)/DALSdk/JHI/linux - -INCLUDE += -I$(LINUX_EXTERNAL_DIR)/ \ - -I$(LINUX_EXTERNAL_DIR)/rdrand \ - -I$(IPC_COMMON_INC_DIR) \ - -I$(AESM_INC_DIR) \ - -I$(IPC_COMMON_PROTO_DIR) - -EDGER8R := $(LINUX_SDK_DIR)/edger8r/linux/_build/Edger8r.native - - -SQLITECFLAGS := -fpie -Wall -Werror -Wno-maybe-uninitialized $(call cc-disable-warning,unused-const-variable) -ifeq ($(CC_BELOW_4_9), 1) - SQLITECFLAGS += -fstack-protector -else - SQLITECFLAGS += -fstack-protector-strong -endif - +CPPMICROSERVICES_DIR := $(LINUX_EXTERNAL_DIR)/CppMicroServices +CPPMICROSERVICES_INSTALL := $(CPPMICROSERVICES_DIR)/local-install +AESM_CONFIG := -DBUILD_SHARED_LIBS=ON -DUS_BUILD_SHARED_LIBS=ON -DMODE=$(MODE) ifdef DEBUG - SQLITECFLAGS += -ggdb -DDEBUG -UNDEBUG + AESM_CONFIG += -DCMAKE_BUILD_TYPE=Debug else - SQLITECFLAGS += -O2 -UDEBUG -DNDEBUG -D_FORTIFY_SOURCE=2 + AESM_CONFIG += -DCMAKE_BUILD_TYPE=Release endif + +ifeq ($(BUILD_REF_LE), 1) + AESM_CONFIG += -DREF_LE=ON +endif + ifeq ($(ARCH), x86) SQLITECFLAGS += -m32 else @@ -108,238 +52,56 @@ else endif ifdef PROFILE - CXXFLAGS += -D_PROFILE_ - CFLAGS += -D_PROFILE_ + CXXFLAGS += -D_PROFILE_ + CFLAGS += -D_PROFILE_ endif CXXFLAGS += -fpie CFLAGS += -fpie CFLAGS := $(filter-out -Werror, $(CFLAGS)) -LINUX_SE_WRAPPER = $(COMMON_DIR)/se_wrapper -ifdef DEBUG -CXXFLAGS += -DDBG_LOG -CFLAGS += -DDBG_LOG -endif - -URTSLIB := -lurts_internal -TRTSLIB := -lsgx_trts WHITE_LIST_FILE := $(LINUX_PSW_DIR)/ae/data/prebuilt/white_list_cert_to_be_verify.bin - -VTUNE_LIBDIR := $(LINUX_EXTERNAL_DIR)/vtune/linux/sdk/src/ittnotify +APPNAME := source/build/bin/aesm_service +CPPMICROSERVICES:= $(CPPMICROSERVICES_DIR)/build/lib/libCppMicroServicesd.so.4.0.0 RDRAND_LIBDIR :=$(LINUX_EXTERNAL_DIR)/rdrand/src RDRAND_MAKEFILE := $(RDRAND_LIBDIR)/Makefile -ifeq ($(ARCH), x86) - VTUNE_LIBDIR = $(LINUX_EXTERNAL_DIR)/vtune/linux/lib32 -endif - - -EXTERNAL_LIB += -lprotobuf -lrt -EXTERNAL_LIB += -lcrypto -EXTERNAL_LIB += $(shell curl-config --libs) -EXTERNAL_LIB += -L$(LINUX_SE_WRAPPER) -lwrapper -lrt -EXTERNAL_LIB += -L$(RDRAND_LIBDIR) -lrdrand -EXTERNAL_LIB += -L$(VTUNE_LIBDIR) -littnotify - -vpath %.cpp $(COMMON_DIR)/src ./source/epid_provision source/ssl_wrapper ./source/upse ./source/pve ./source/upse/BackendInterface $(LINUX_PSW_DIR)/ae/common $(AESM_APPLICATION) $(AESM_EXTENSION) $(AESM_SRC_DIR) $(IPC_COMMON_PROTO_DIR) $(TOP_DIR)/sdk/tseal $(IPC_COMMON_SRC_DIR) -vpath %.cc $(IPC_COMMON_PROTO_DIR) -vpath %.c $(LINUX_EXTERNAL_DIR)/sqlite/src -vpath %.c $(TOP_DIR)/sdk/tlibc/string - -COMMON_SRC := ./source/le/LEClass.cpp \ - ./source/oal/aesm_util.cpp \ - ./source/storage/persistent_storage_table.cpp \ - aesm_logic.cpp \ - ./source/oal/oal_power.cpp \ - aesm_rand.cpp \ - ./source/oal/error_report.cpp \ - ./source/oal/internal_log.cpp \ - sgx_memset_s.cpp \ - sgx_read_rand.cpp \ - sgx_profile.cpp \ - tSeal_util.cpp \ - ./source/oal/aesm_thread.cpp \ - event_strings.cpp - -COMMON_SRC += ./source/qe/QEClass.cpp \ - ./source/pse_op/PSEClass.cpp \ - ./source/pse_pr/PSEPRClass.cpp \ - ./source/pse_op/PSDAService.cpp \ - ./source/pve/PVEClass.cpp \ - ./source/pce/PCEClass.cpp \ - aesm_encode.cpp \ - aesm_epid_blob.cpp \ - aesm_xegd_blob.cpp \ - epid_provision_msg1.cpp \ - epid_provision_msg2.cpp \ - epid_provision_msg4.cpp \ - epid_endpoint_selection.cpp \ - epid_utility.cpp \ - type_length_value.cpp \ - ./source/qe/qe_logic.cpp \ - ./source/pve/pve_logic.cpp \ - ./source/pse_op/pse_op_logic.cpp \ - ./source/pse_op/aesm_pse_status.cpp \ - platform_info_logic.cpp \ - platform_info_facility.cpp \ - pve_pub_key.cpp \ - pek_pub_key.cpp \ - ./source/network/network_encoding_wrapper.cpp \ - endpoint_select_info.cpp \ - aesm_ecdsa.cpp \ - ./source/pse_op/pse_op_psda_ocall.cpp \ - ./source/pse_op/pse_op_vmc_sqlite_ocall.cpp \ - upse.cpp \ - helper.cpp \ - sigma_helper.cpp \ - interface_ocsp.cpp \ - u_certificate_provisioning.cpp \ - uecall_bridge.cpp \ - u_long_term_pairing.cpp \ - CertificateProvisioningProtocol.cpp \ - pse_crypto_helper.cpp \ - pse_provisioning_msg1.cpp \ - pse_provisioning_msg2.cpp \ - pse_provisioning_msg3.cpp \ - pse_provisioning_msg4.cpp \ - interface_psda.cpp \ - pse_pr_common.cpp \ - se_sig_rl.cpp \ - aesm_long_lived_thread.cpp - -COMMON_SRC += crypto_ecc.cpp crypto_rsa.cpp crypto_sha256_msg.cpp crypto_aes_gcm.cpp crypto_cmac128.cpp ssl_compat_wrapper.cpp - -COMMON_OBJ := $(COMMON_SRC:.cpp=.o) - -IPC_SRC := AECloseSessionRequest.cpp \ - AEGetQuoteResponse.cpp \ - AECloseSessionResponse.cpp \ - AEInitQuoteRequest.cpp \ - AECreateSessionRequest.cpp \ - AEInitQuoteResponse.cpp \ - AECreateSessionResponse.cpp \ - AEInvokeServiceRequest.cpp \ - AEExchangeReportRequest.cpp \ - AEInvokeServiceResponse.cpp \ - AEExchangeReportResponse.cpp \ - ProtobufSerializer.cpp \ - AEGetLaunchTokenRequest.cpp \ - AEGetPsCapRequest.cpp \ - AEGetPsCapResponse.cpp \ - AEGetWhiteListSizeRequest.cpp \ - AEGetWhiteListSizeResponse.cpp \ - AEGetWhiteListRequest.cpp \ - AEGetWhiteListResponse.cpp \ - AESGXGetExtendedEpidGroupIdRequest.cpp \ - AESGXGetExtendedEpidGroupIdResponse.cpp \ - AESGXSwitchExtendedEpidGroupRequest.cpp \ - AESGXSwitchExtendedEpidGroupResponse.cpp \ - AEReportAttestationRequest.cpp \ - AEReportAttestationResponse.cpp \ - AESGXRegisterRequest.cpp \ - AESGXRegisterResponse.cpp \ - SocketTransporter.cpp \ - AEGetLaunchTokenResponse.cpp \ - UnixCommunicationSocket.cpp \ - NonBlockingUnixCommunicationSocket.cpp \ - AEGetQuoteRequest.cpp \ - UnixSocketFactory.cpp \ - NonBlockingUnixSocketFactory.cpp - -PROTOBUF_SRC := messages.pb.cc - -AESM_SRC := AESMLogicWrapper.cpp \ - CAESMServer.cpp \ - main.cpp \ - Thread.cpp \ - AESMWorkerThread.cpp \ - AESMQueueManager.cpp \ - CSelector.cpp \ - UnixServerSocket.cpp \ - ./source/oal/aesm_util.cpp \ - aesm_config.cpp - -AESM_SRC += aesm_http_msg.cpp -AESM_SRC += source/pse_op/jhi_proxy.cpp - -CSRC := $(sort $(wildcard *.c)) - -MEMCMPSRC := consttime_memequal.c - -SQLITESRC := sqlite3.c - -OBJ := $(IPC_SRC:.cpp=.o) \ - $(CSRC:.c=.o) \ - $(MEMCMPSRC:.c=.o) \ - $(AESM_SRC:.cpp=.o) \ - $(PROTOBUF_SRC:.cc=.o) - -OBJ += $(SQLITESRC:.c=.o) - -LDUFLAGS := -pthread -L$(BUILD_DIR) $(URTSLIB) -LDUFLAGS += -pie $(COMMON_LDFLAGS) - -APPNAME := aesm_service -APPNAME_DEBUG := aesm_service.debug -LIBNAME := libaesm_service_common.a - .PHONY: all all: $(APPNAME) $(APPNAME_DEBUG) copy_data_file | $(BUILD_DIR) - @$(CP) $(APPNAME) $| -ifndef DEBUG - @$(CP) $(APPNAME_DEBUG) $| -endif + $(CP) -r source/build/bin/* $| copy_data_file: @$(MKDIR) -p data @$(CP) $(LINUX_PSW_DIR)/ae/pse/pse_op/vmc_db_generator/prebuild_pse_vmc.db data @$(CP) $(WHITE_LIST_FILE) data/white_list_cert_to_be_verify.bin +$(APPNAME): $(CPPMICROSERVICES) source/build/CMakeCache.txt urts RDRAND + $(MAKE) -C source/build + $(CP) $(CPPMICROSERVICES) source/build/bin/ -$(LIBNAME): $(COMMON_OBJ) - $(AR) rcs $@ $^ +CMAKE_VERSION_MAJOR=$(shell cmake --version | head -n 1 | cut -d \ -f 3 | cut -d . -f 1) +CMAKE_VERSION_MINOR=$(shell cmake --version | head -n 1 | cut -d \ -f 3 | cut -d . -f 2) +CMAKE_VERSION=$(CMAKE_VERSION_MAJOR)$(CMAKE_VERSION_MINOR) +CMAKE := $(HOME)/cache/bin/cmake -$(IPC_SRC:.cpp=.o) : $(IPC_COMMON_PROTO_DIR)/messages.pb.cc -CAESMServer.o : $(IPC_COMMON_PROTO_DIR)/messages.pb.cc -%.o :%.cpp - $(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -o $@ - -messages.pb.o : $(IPC_COMMON_PROTO_DIR)/messages.pb.cc - $(CXX) $(filter-out -Wshadow, $(CXXFLAGS)) $(INCLUDE) -c $< -o $@ - -consttime_memequal.o :consttime_memequal.c - $(CC) $(filter-out -O2,$(CFLAGS)) -O1 $(INCLUDE) -c $< -o $@ - -sqlite3.o :sqlite3.c - $(CC) $(SQLITECFLAGS) $(INCLUDE) -c $< -o $@ - -$(APPNAME): $(OBJ) $(LIBNAME) -lrdrand urts - $(CXX) $(CXXFLAGS) $(OBJ) $(LIBNAME) $(LDUFLAGS) $(EXTERNAL_LIB) -o $@ -ldl - -$(APPNAME_DEBUG): $(APPNAME) -ifndef DEBUG - $(CP) $(APPNAME) $(APPNAME).orig - $(OBJCOPY) --only-keep-debug $(APPNAME) $(APPNAME_DEBUG) - $(STRIP) -g $(APPNAME) - $(OBJCOPY) --add-gnu-debuglink=$(APPNAME_DEBUG) $(APPNAME) -endif - -ifeq ($(BUILD_REF_LE), 1) -LE_DEP := ${AESM_EXTENSION}/ref_le_u.c -LE_EDL := ${LINUX_PSW_DIR}/ae/ref_le/ref_le.edl +.PHONY: CPPMICROSERVICES +$(CPPMICROSERVICES): + mkdir -p $(CPPMICROSERVICES_DIR)/build +ifeq ($(shell test $(CMAKE_VERSION) -lt 32 && echo 1), 1) + $(CPPMICROSERVICES_DIR)/install_cmake.sh + cd $(CPPMICROSERVICES_DIR)/build && $(CMAKE) -DCMAKE_COMMAND=$(CMAKE) -DCMAKE_INSTALL_PREFIX=$(CPPMICROSERVICES_INSTALL) ../ && $(MAKE) && $(MAKE) install else -LE_DEP := ${AESM_EXTENSION}/launch_enclave_u.c -LE_EDL := ${LINUX_PSW_DIR}/ae/le/launch_enclave.edl + cd $(CPPMICROSERVICES_DIR)/build && cmake -DCMAKE_INSTALL_PREFIX=$(CPPMICROSERVICES_INSTALL) ../ && $(MAKE) && $(MAKE) install endif -./source/le/LEClass.o: $(LE_DEP) -./source/pve/PVEClass.o: ${AESM_EXTENSION}/provision_enclave_u.c -./source/qe/QEClass.o: ${AESM_EXTENSION}/quoting_enclave_u.c -./source/pse_op/PSEClass.o: ${AESM_EXTENSION}/pse_op_u.c -./source/pce/PCEClass.o: ${AESM_EXTENSION}/pce_u.c -uecall_bridge.o: ${AESM_EXTENSION}/pse_pr_u.c --lrdrand: $(RDRAND_MAKEFILE) +source/build/CMakeCache.txt: $(CPPMICROSERVICES) +ifeq ($(shell test $(CMAKE_VERSION) -lt 30 && echo 1), 1) + mkdir -p source/build && cd source/build && $(CMAKE) -DCMAKE_COMMAND=$(CMAKE) $(AESM_CONFIG) ../ +else + mkdir -p source/build && cd source/build && cmake $(AESM_CONFIG) ../ +endif + +RDRAND: $(RDRAND_MAKEFILE) $(MAKE) -C $(RDRAND_LIBDIR) $(RDRAND_MAKEFILE): @@ -349,27 +111,6 @@ else @cd $(RDRAND_LIBDIR);./configure CFLAGS=-fPIC endif -$(LE_DEP): $(LE_EDL) - @$(EDGER8R) --untrusted --untrusted-dir ${AESM_EXTENSION} $< --search-path $(TOP_DIR)/common/inc - -${AESM_EXTENSION}/provision_enclave_u.c: ${LINUX_PSW_DIR}/ae/pve/provision_enclave.edl - @$(EDGER8R) --untrusted --untrusted-dir ${AESM_EXTENSION} $< --search-path $(TOP_DIR)/common/inc - -${AESM_EXTENSION}/quoting_enclave_u.c: ${LINUX_PSW_DIR}/ae/qe/quoting_enclave.edl - @$(EDGER8R) --untrusted --untrusted-dir ${AESM_EXTENSION} $< --search-path $(TOP_DIR)/common/inc - -${AESM_EXTENSION}/pse_op_u.c: ${LINUX_PSW_DIR}/ae/pse/pse_op/pse_op.edl - @$(EDGER8R) --untrusted --untrusted-dir ${AESM_EXTENSION} $< --search-path $(TOP_DIR)/common/inc - -${AESM_EXTENSION}/pse_pr_u.c: ${LINUX_PSW_DIR}/ae/pse/pse_pr/pse_pr.edl - @$(EDGER8R) --untrusted --untrusted-dir ${AESM_EXTENSION} $< --search-path $(TOP_DIR)/common/inc - -${AESM_EXTENSION}/pce_u.c: ${LINUX_PSW_DIR}/ae/pce/pce.edl - @$(EDGER8R) --untrusted --untrusted-dir ${AESM_EXTENSION} $< --search-path $(TOP_DIR)/common/inc - -$(IPC_COMMON_PROTO_DIR)/messages.pb.cc: - $(MAKE) -C $(IPC_COMMON_PROTO_DIR) - .PHONY: urts urts: $(MAKE) -C $(LINUX_PSW_DIR)/urts/linux @@ -379,25 +120,9 @@ $(BUILD_DIR): .PHONY: clean clean: - @$(RM) *.o $(IPC_COMMON_SRC_DIR)/*.o - @$(RM) -r data - @$(RM) $(APPNAME) $(APPNAME).orig $(APPNAME_DEBUG) - @$(RM) $(BUILD_DIR)/$(APPNAME) $(BUILD_DIR)/$(APPNAME_DEBUG) - @$(RM) $(LIBNAME) - $(MAKE) -C $(IPC_COMMON_PROTO_DIR) clean - @$(RM) source/le/*.o - @$(RM) source/pse_op/*.o - @$(RM) source/pve/*.o - @$(RM) source/pce/*.o - @$(RM) source/network/*.o - @$(RM) source/oal/*.o - @$(RM) source/qe/*.o - @$(RM) source/pse_pr/*.o - @$(RM) source/storage/*.o - @$(RM) $(AESM_EXTENSION)/*_u.c $(AESM_EXTENSION)/*_u.h -ifeq ($(RDRAND_MAKEFILE), $(wildcard $(RDRAND_MAKEFILE))) - @$(MAKE) distclean -C $(RDRAND_LIBDIR) -endif + @$(RM) -r source/build + @$(RM) -r $(CPPMICROSERVICES_DIR)/build + @$(RM) -r $(CPPMICROSERVICES_INSTALL) .PHONY: rebuild rebuild: diff --git a/psw/ae/aesm_service/config/aesmd_service/aesmd.conf b/psw/ae/aesm_service/config/aesmd_service/aesmd.conf index ed529c09..76723a0e 100644 --- a/psw/ae/aesm_service/config/aesmd_service/aesmd.conf +++ b/psw/ae/aesm_service/config/aesmd_service/aesmd.conf @@ -26,4 +26,5 @@ pre-start script end script +env LD_LIBRARY_PATH=$AESM_PATH exec $AESM_PATH/$NAME diff --git a/psw/ae/aesm_service/config/aesmd_service/aesmd.service b/psw/ae/aesm_service/config/aesmd_service/aesmd.service index 837418c7..7f109ba1 100644 --- a/psw/ae/aesm_service/config/aesmd_service/aesmd.service +++ b/psw/ae/aesm_service/config/aesmd_service/aesmd.service @@ -8,6 +8,8 @@ User=aesmd Type=forking Environment=NAME=aesm_service Environment=AESM_PATH=@aesm_folder@ +Environment=LD_LIBRARY_PATH=@aesm_folder@ +WorkingDirectory=@aesm_folder@ PermissionsStartOnly=true ExecStartPre=@aesm_folder@/linksgx.sh ExecStartPre=/bin/mkdir -p /var/run/aesmd/ diff --git a/psw/ae/aesm_service/source/CMakeLists.txt b/psw/ae/aesm_service/source/CMakeLists.txt new file mode 100644 index 00000000..133e8bbf --- /dev/null +++ b/psw/ae/aesm_service/source/CMakeLists.txt @@ -0,0 +1,104 @@ +# [proj-begin] +cmake_minimum_required(VERSION 3.0.0) +project(ModularAESM VERSION 0.1.0) + + +#set(CMAKE_MODULE_PATH "path to CppMicroServicesConfig.cmake" ${CMAKE_MODULE_PATH}) + + +# check if protobuf was found +find_package(Protobuf REQUIRED) +if(PROTOBUF_FOUND) + message ("protobuf found") +else() + message (FATAL_ERROR "Cannot find Protobuf") +endif() + +# check if CppMicroServices was found +set(CppMicroServices_DIR ../../../../external/CppMicroServices/local-install/share/cppmicroservices4/cmake) +find_package(CppMicroServices NO_MODULE REQUIRED) +cmake_minimum_required(VERSION ${US_CMAKE_MINIMUM_REQUIRED_VERSION}) +cmake_policy(VERSION ${US_CMAKE_MINIMUM_REQUIRED_VERSION}) +if(CppMicroServices_FOUND) + message ("CppMicroServices found") +else() + message (FATAL_ERROR "Cannot find CppMicroServices") +endif() + +if(REF_LE) + add_definitions("-DREF_LE") +endif() + +set(CMAKE_CXX_STANDARD_REQUIRED 1) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_SKIP_BUILD_RPATH true) + +set(ModularAESM_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +set(ModularAESM_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") +set(ModularAESM_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") + +foreach(_type ARCHIVE LIBRARY RUNTIME) + if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) + set(CMAKE_${_type}_OUTPUT_DIRECTORY ${ModularAESM_${_type}_OUTPUT_DIRECTORY}) + endif() +endforeach() +#[proj-end] + +MACRO(BUNDLELIST result curdir) + FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) + SET(dirlist "") + FOREACH(child ${children}) + IF(IS_DIRECTORY ${curdir}/${child}) + LIST(APPEND dirlist ${child}) + ENDIF() + ENDFOREACH() + SET(${result} ${dirlist}) +ENDMACRO() + +function(CreateBundle _name) + set(_srcs ${ARGN}) + + usFunctionGetResourceSource(TARGET ${_name} OUT _srcs) + usFunctionGenerateBundleInit(TARGET ${_name} OUT _srcs) + + add_library(${_name} ${_srcs}) + target_include_directories(${_name} PRIVATE + ${PROJECT_SOURCE_DIR}/interfaces + ${CMAKE_CURRENT_BINARY_DIR} + ${PROJECT_SOURCE_DIR}/../../data/constants/linux + ) + + set(_bundle_name ${_name}_name) + target_compile_definitions(${_name} PRIVATE + $<$:DBG_LOG> + US_BUNDLE_NAME=${_bundle_name} + ) + target_link_libraries(${_name} ${CppMicroServices_LIBRARIES}) + + set_target_properties(${_name} PROPERTIES + US_BUNDLE_NAME ${_bundle_name} + ) + if(BUILD_SHARED_LIBS) + set_target_properties(${_name} PROPERTIES + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN 1 + ) + set_target_properties(${_name} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/bundles" + ) + endif() + + usFunctionEmbedResources(TARGET ${_name} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + FILES + manifest.json + ) +endfunction() + +ADD_SUBDIRECTORY(oal) +ADD_SUBDIRECTORY(utils) +ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(bundles) +ADD_SUBDIRECTORY(qcnl) +ADD_SUBDIRECTORY(qpl) diff --git a/psw/ae/aesm_service/source/aesm/application/aesm_logic.cpp b/psw/ae/aesm_service/source/aesm/application/aesm_logic.cpp deleted file mode 100644 index 6ef4781d..00000000 --- a/psw/ae/aesm_service/source/aesm/application/aesm_logic.cpp +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#include "QEClass.h" -#include "LEClass.h" -#include "PSEClass.h" -#include "PVEClass.h" -#include "PCEClass.h" -#include "PSEPRClass.h" - -#include "arch.h" -#include "sgx_report.h" -#include "sgx_tseal.h" -#include "epid_pve_type.h" -#include "util.h" -#include -#include -#include "oal/oal.h" -#include "oal/aesm_thread.h" -#include "aesm_encode.h" -#include "pairing_blob.h" -#include "aesm_epid_blob.h" -#include "aesm_xegd_blob.h" -#include "aesm_logic.h" -#include "pve_logic.h" -#include "qe_logic.h" -#include "pse_op_logic.h" -#include "platform_info_logic.h" -#include "prov_msg_size.h" -#include "se_sig_rl.h" -#include "se_quote_internal.h" -#include "endpoint_select_info.h" -#include "se_wrapper.h" -#include "PSDAService.h" -#include -#include -#include "prof_fun.h" -#include "upse/helper.h" -#include "aesm_long_lived_thread.h" -#include "sgx_profile.h" -#include "service_enclave_mrsigner.hh" -#include "ssl_compat_wrapper.h" -#define __STDC_FORMAT_MACROS -#include - -#define CHECK_SERVICE_STATUS if (!is_service_running()) return AESM_SERVICE_STOPPED; -#define CHECK_SGX_STATUS if (g_sgx_device_status != SGX_ENABLED) return AESM_SGX_DEVICE_NOT_AVAILABLE; - -AESMLogicMutex AESMLogic::_qe_pve_mutex; -AESMLogicMutex AESMLogic::_pse_mutex; -AESMLogicMutex AESMLogic::_le_mutex; - -bool AESMLogic::_is_qe_psvn_set; -bool AESMLogic::_is_pse_psvn_set; -bool AESMLogic::_is_pce_psvn_set; -psvn_t AESMLogic::_qe_psvn; -psvn_t AESMLogic::_pce_psvn; -psvn_t AESMLogic::_pse_psvn; -aesm_thread_t AESMLogic::qe_thread = NULL; -aesm_thread_t AESMLogic::pse_thread = NULL; - -uint32_t AESMLogic::active_extended_epid_group_id; - -extern "C" bool is_in_kernel_driver(); - -static ae_error_t read_global_extended_epid_group_id(uint32_t *xeg_id) -{ - char path_name[MAX_PATH]; - ae_error_t ae_ret = aesm_get_pathname(FT_PERSISTENT_STORAGE, EXTENDED_EPID_GROUP_ID_FID, path_name, MAX_PATH); - if(AE_SUCCESS != ae_ret){ - return ae_ret; - } - FILE * f = fopen(path_name, "r"); - if( f == NULL){ - return OAL_CONFIG_FILE_ERROR; - } - ae_ret = OAL_CONFIG_FILE_ERROR; - if(fscanf(f, "%" SCNu32, xeg_id)==1){ - ae_ret = AE_SUCCESS; - } - fclose(f); - return ae_ret; -} -static ae_error_t set_global_extended_epid_group_id(uint32_t xeg_id) -{ - char path_name[MAX_PATH]; - ae_error_t ae_ret = aesm_get_pathname(FT_PERSISTENT_STORAGE, EXTENDED_EPID_GROUP_ID_FID, path_name, MAX_PATH); - if(AE_SUCCESS != ae_ret){ - return ae_ret; - } - FILE *f = fopen(path_name, "w"); - if(f == NULL){ - return OAL_CONFIG_FILE_ERROR; - } - ae_ret = OAL_CONFIG_FILE_ERROR; - if(fprintf(f, "%" PRIu32, xeg_id)>0){ - ae_ret = AE_SUCCESS; - } - fclose(f); - return ae_ret; -} - -uint32_t AESMLogic::get_active_extended_epid_group_id() -{ - return active_extended_epid_group_id; -} - -static ae_error_t thread_to_load_qe(aesm_thread_arg_type_t arg) -{ - epid_blob_with_cur_psvn_t epid_data; - ae_error_t ae_ret = AE_FAILURE; - UNUSED(arg); - AESM_DBG_TRACE("start to load qe"); - memset(&epid_data, 0, sizeof(epid_data)); - AESMLogicLock lock(AESMLogic::_qe_pve_mutex); - if((ae_ret = EPIDBlob::instance().read(epid_data)) == AE_SUCCESS) - { - AESM_DBG_TRACE("EPID blob is read successfully, loading QE ..."); - ae_ret = CQEClass::instance().load_enclave(); - if(AE_SUCCESS != ae_ret) - { - AESM_DBG_WARN("fail to load QE: %d", ae_ret); - }else{ - AESM_DBG_TRACE("QE loaded successfully"); - bool resealed = false; - se_static_assert(SGX_TRUSTED_EPID_BLOB_SIZE_SDK>=SGX_TRUSTED_EPID_BLOB_SIZE_SIK); - // Just take this chance to reseal EPID blob in case TCB is - // upgraded, return value is ignored and no provisioning is - // triggered. - ae_ret = static_cast(CQEClass::instance().verify_blob( - epid_data.trusted_epid_blob, - SGX_TRUSTED_EPID_BLOB_SIZE_SDK, - &resealed)); - if(AE_SUCCESS != ae_ret) - { - AESM_DBG_WARN("Failed to verify EPID blob: %d", ae_ret); - EPIDBlob::instance().remove(); - }else{ - uint32_t epid_xeid; - // Check whether EPID blob XEGDID is aligned with active extended group id if it exists. - if ((EPIDBlob::instance().get_extended_epid_group_id(&epid_xeid) == AE_SUCCESS) && (epid_xeid == AESMLogic::get_active_extended_epid_group_id())) { - AESM_DBG_TRACE("EPID blob Verified"); - // XEGDID is aligned - if (true == resealed) - { - AESM_DBG_TRACE("EPID blob is resealed"); - if ((ae_ret = EPIDBlob::instance().write(epid_data)) - != AE_SUCCESS) - { - AESM_DBG_WARN("Failed to update epid blob: %d", ae_ret); - } - } - } - else { // XEGDID is NOT aligned - AESM_DBG_TRACE("XEGDID mismatch in EPIDBlob, remove it..."); - EPIDBlob::instance().remove(); - } - } - } - }else{ - AESM_DBG_TRACE("Fail to read EPID Blob"); - } - AESM_DBG_TRACE("QE Thread finished succ"); - return AE_SUCCESS; -} - -static ae_error_t thread_to_init_pse(aesm_thread_arg_type_t arg) -{ - UNUSED(arg); - AESM_DBG_INFO("start to init_ps"); - AESMLogicLock lock(AESMLogic::_pse_mutex); - ae_error_t psError = CPSEClass::instance().init_ps(); - UNUSED(psError);// To ignore the error that the symbol not used in release mode - AESM_DBG_INFO("init_ps return ( ae %d)", psError); - return AE_SUCCESS; -} - -// Must be called when AESM starts -ae_error_t AESMLogic::service_start() -{ - AESM_PROFILE_INIT; - ae_error_t ae_ret = AE_SUCCESS; - // Initialize crypto library - crypto_initialize(); - - AESM_LOG_INIT(); - - AESM_DBG_INFO("aesm service is starting"); - // Try to read active extended epid group id from data file - ae_ret = read_global_extended_epid_group_id(&AESMLogic::active_extended_epid_group_id); - if (AE_SUCCESS != ae_ret){ - AESM_DBG_INFO("Fail to read extended epid group id, default extended epid group used"); - AESMLogic::active_extended_epid_group_id = DEFAULT_EGID; // Use default extended epid group id 0 if it is not available from data file - } - else{ - AESM_DBG_INFO("active extended group id %d used", AESMLogic::active_extended_epid_group_id); - } - if (AE_SUCCESS != (XEGDBlob::verify_xegd_by_xgid(active_extended_epid_group_id)) || - AE_SUCCESS != (EndpointSelectionInfo::verify_file_by_xgid(active_extended_epid_group_id))){// Try to load XEGD and URL file to make sure it is valid - AESM_LOG_WARN_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PCD_NOT_AVAILABLE]); - AESM_LOG_WARN("%s: original extended epid group id = %d", g_event_string_table[SGX_EVENT_PCD_NOT_AVAILABLE], AESMLogic::active_extended_epid_group_id); - AESMLogic::active_extended_epid_group_id = DEFAULT_EGID;// If the active extended epid group id read from data file is not valid, switch to default extended epid group id - } - - ae_ret = CLEClass::instance().load_enclave(); - if(AE_SUCCESS != ae_ret) - { - AESM_DBG_INFO("fail to load LE: %d", ae_ret); - AESM_LOG_FATAL("%s", g_event_string_table[SGX_EVENT_SERVICE_UNAVAILABLE]); - return ae_ret; - } - - ae_error_t aesm_ret1 = aesm_create_thread(thread_to_load_qe, 0,&qe_thread); - ae_error_t aesm_ret2 = aesm_create_thread(thread_to_init_pse, 0, &pse_thread); - if(AE_SUCCESS != aesm_ret1 ){ - AESM_DBG_WARN("Fail to create thread to preload QE:(ae %d)",aesm_ret1); - } - if(AE_SUCCESS != aesm_ret2 ){ - AESM_DBG_WARN("Fail to create thread to init PSE:( ae %d)",aesm_ret2); - } - start_white_list_thread(); - AESM_DBG_TRACE("aesm service is started"); - - return AE_SUCCESS; -} - -void AESMLogic::service_stop() -{ - ae_error_t ae_ret, thread_ret; - // Waiting for QE and PSE thread - ae_ret = aesm_wait_thread(qe_thread, &thread_ret, AESM_STOP_TIMEOUT); - if (ae_ret != AE_SUCCESS || thread_ret != AE_SUCCESS) - { - AESM_DBG_INFO("aesm_wait_thread failed(qe_thread):(ae %d) (%d)", ae_ret, thread_ret); - } - (void)aesm_free_thread(qe_thread);//release thread handle to free memory - ae_ret = aesm_wait_thread(pse_thread, &thread_ret, AESM_STOP_TIMEOUT); - if (ae_ret != AE_SUCCESS || thread_ret != AE_SUCCESS) - { - AESM_DBG_INFO("aesm_wait_thread failed(pse_thread):(ae %d) (%d)", ae_ret, thread_ret); - } - (void)aesm_free_thread(pse_thread);//release thread handle to free memory - - //waiting for pending threads util timeout - stop_all_long_lived_threads(0);//waiting for pending threads util timeout - CPVEClass::instance().unload_enclave(); - CPCEClass::instance().unload_enclave(); - CPSEClass::instance().unload_enclave(); - CQEClass::instance().unload_enclave(); - CLEClass::instance().unload_enclave(); - CPSEPRClass::instance().unload_enclave(); - AESM_DBG_INFO("start to stop psda service"); - PSDAService::instance().stop_service(); - // Crypto library cleanup - crypto_cleanup(); - AESM_DBG_INFO("aesm service down"); - AESM_LOG_FINI(); - - AESM_PROFILE_OUTPUT; -} - -bool AESMLogic::is_service_running() -{ - return true; -} - -ae_error_t AESMLogic::save_unverified_white_list(const uint8_t *white_list_cert, uint32_t white_list_cert_size) -{ - wl_cert_chain_t old_cert; - const wl_cert_chain_t *p_new_cert = reinterpret_cast(white_list_cert); - uint32_t old_cert_size = sizeof(old_cert); - memset(&old_cert, 0, sizeof(old_cert)); - if((aesm_read_data(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_TO_BE_VERIFY_FID, reinterpret_cast(&old_cert), &old_cert_size) == AE_SUCCESS) - && (old_cert_size == sizeof(old_cert)) && (white_list_cert_size >= sizeof(wl_cert_chain_t))) - { - if(_ntohl(p_new_cert->wl_cert.wl_version) <= _ntohl(old_cert.wl_cert.wl_version)) - { - AESM_DBG_WARN("White list version downgraded! current version is %d, new version is %d", - _ntohl(old_cert.wl_cert.wl_version), _ntohl(p_new_cert->wl_cert.wl_version)); - return OAL_PARAMETER_ERROR; // OAL_PARAMETER_ERROR used here is to indicate the white list is incorrect - } - } - return aesm_write_data(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_TO_BE_VERIFY_FID, white_list_cert, white_list_cert_size); -} - -aesm_error_t AESMLogic::white_list_register( - const uint8_t *white_list_cert, uint32_t white_list_cert_size) -{ - AESM_DBG_INFO("enter function"); - AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_START]); - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_le_mutex); - CHECK_SERVICE_STATUS; - ae_error_t ret_le = AE_SUCCESS; - aesm_error_t ret = AESM_UNEXPECTED_ERROR; - if (NULL == white_list_cert||0==white_list_cert_size){ - AESM_DBG_TRACE("Invalid parameter"); - AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_FAIL]); - return AESM_PARAMETER_ERROR; - } - if (is_in_kernel_driver()) - { - AESM_DBG_INFO("InKernel LE loaded"); - return AESM_SERVICE_UNAVAILABLE; - } - - ae_error_t ae_ret = CLEClass::instance().load_enclave(); - if (AE_FAILED(ae_ret)) - { - switch (ae_ret) - { - case AE_SERVER_NOT_AVAILABLE: - AESM_DBG_WARN("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); - ret_le = save_unverified_white_list(white_list_cert, white_list_cert_size); - break; - case AESM_AE_OUT_OF_EPC: - AESM_DBG_WARN("LE not loaded due to out of EPC"); - ret = AESM_OUT_OF_EPC; - goto exit; - default: - AESM_DBG_ERROR("LE not loaded:(ae%d)", ae_ret); - ret = AESM_UNEXPECTED_ERROR; - goto exit; - } - } - else - { - ret_le = static_cast(CLEClass::instance().white_list_register( - white_list_cert, white_list_cert_size)); - } - - switch (ret_le) - { - case AE_SUCCESS: - ret = AESM_SUCCESS; - break; - case LE_INVALID_PARAMETER: - AESM_DBG_TRACE("Invalid parameter"); - ret = AESM_PARAMETER_ERROR; - break; - default: - AESM_DBG_WARN("unexpeted error (ae %d)", ret_le); - ret = AESM_UNEXPECTED_ERROR; - break; - } - -exit: - // Always log success or failure to the Admin log before returning - if (AE_FAILED(ae_ret) || AE_FAILED(ret_le)) { - AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_FAIL]); - } else { - const wl_cert_chain_t* wl = reinterpret_cast(white_list_cert); - AESM_LOG_INFO_ADMIN("%s for Version: %d", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_SUCCESS], - _ntohl(wl->wl_cert.wl_version)); - } - - return ret; -} - -aesm_error_t AESMLogic::get_launch_token( - const uint8_t * mrenclave, uint32_t mrenclave_size, - const uint8_t *public_key, uint32_t public_key_size, - const uint8_t *se_attributes, uint32_t se_attributes_size, - uint8_t * lictoken, uint32_t lictoken_size) -{ - AESM_DBG_INFO("enter function"); - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_le_mutex); - CHECK_SERVICE_STATUS; - - ae_error_t ret_le = AE_SUCCESS; - if (NULL == mrenclave || - NULL == public_key || - NULL == se_attributes || - NULL == lictoken) - { - // Sizes are checked in CLEClass::get_launch_token() - AESM_DBG_TRACE("Invalid parameter"); - return AESM_PARAMETER_ERROR; - } - if (is_in_kernel_driver()) - { - //Should not be called - AESM_LOG_ERROR("InKernel LE loaded"); - return AESM_SERVICE_UNAVAILABLE; - } - ae_error_t ae_ret = CLEClass::instance().load_enclave(); - if(ae_ret == AE_SERVER_NOT_AVAILABLE) - { - AESM_LOG_ERROR("%s", g_event_string_table[SGX_EVENT_SERVICE_UNAVAILABLE]); - AESM_DBG_FATAL("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); - return AESM_NO_DEVICE_ERROR; - } - else if(ae_ret == AESM_AE_OUT_OF_EPC) - { - AESM_DBG_ERROR("LE not loaded due to out of EPC"); - return AESM_OUT_OF_EPC; - } - else if(AE_FAILED(ae_ret)) - { - AESM_DBG_ERROR("LE not loaded:%d", ae_ret); - return AESM_SERVICE_UNAVAILABLE; - } - ret_le = static_cast(CLEClass::instance().get_launch_token( - const_cast(mrenclave), mrenclave_size, - const_cast(public_key), public_key_size, - const_cast(se_attributes), se_attributes_size, - lictoken, lictoken_size)); - - switch (ret_le) - { - case AE_SUCCESS: - return AESM_SUCCESS; - case LE_INVALID_PARAMETER: - AESM_DBG_TRACE("Invalid parameter"); - return AESM_PARAMETER_ERROR; - case LE_INVALID_ATTRIBUTE: - case LE_INVALID_PRIVILEGE_ERROR: - AESM_DBG_TRACE("Launch token error"); - return AESM_GET_LICENSETOKEN_ERROR; - case LE_WHITELIST_UNINITIALIZED_ERROR: - AESM_DBG_TRACE("LE whitelist uninitialized error"); - return AESM_UNEXPECTED_ERROR; - default: - AESM_DBG_WARN("unexpeted error (ae %d)", ret_le); - return AESM_UNEXPECTED_ERROR; - } -} - -/* This function will be called outside aesm(from urts_internal) */ -extern "C" sgx_status_t get_launch_token(const enclave_css_t* signature, - const sgx_attributes_t* attribute, - sgx_launch_token_t* launch_token) -{ - AESM_DBG_INFO("enter function"); - return AESMLogic::get_launch_token(signature, attribute, launch_token); -} - -ae_error_t AESMLogic::get_qe_isv_svn(uint16_t& isv_svn) -{ - if(!_is_qe_psvn_set){ - ae_error_t ae_err = CQEClass::instance().load_enclave(); - if(AE_SUCCESS != ae_err){ - AESM_DBG_ERROR("Fail to load QE Enclave:(ae %d)",ae_err); - return ae_err; - } - } - assert(_is_qe_psvn_set); - if(0!=memcpy_s(&isv_svn, sizeof(isv_svn), &_qe_psvn.isv_svn, sizeof(_qe_psvn.isv_svn))){ - AESM_DBG_ERROR("memcpy failed"); - return AE_FAILURE; - } - return AE_SUCCESS; -} - -ae_error_t AESMLogic::get_pce_isv_svn(uint16_t& isv_svn) -{ - if(!_is_pce_psvn_set){ - ae_error_t ae_err = CPCEClass::instance().load_enclave(); - if(AE_SUCCESS != ae_err){ - AESM_DBG_ERROR("Fail to load PCE Enclave:(ae %d)",ae_err); - return ae_err; - } - } - assert(_is_pce_psvn_set); - if(0!=memcpy_s(&isv_svn, sizeof(isv_svn), &_pce_psvn.isv_svn, sizeof(_pce_psvn.isv_svn))){ - AESM_DBG_ERROR("memcpy failed"); - return AE_FAILURE; - } - return AE_SUCCESS; -} - -ae_error_t AESMLogic::get_pse_isv_svn(uint16_t& isv_svn) -{ - ae_error_t retVal = AE_SUCCESS; - if(!_is_pse_psvn_set){ - ae_error_t ae_err = CPSEClass::instance().load_enclave(); - if(AE_SUCCESS != ae_err){ - AESM_DBG_ERROR("Fail to load PSEOP Enclave:(ae %d)",ae_err); - retVal = ae_err; - } - } - if (AE_SUCCESS == retVal) { - assert(_is_pse_psvn_set); - if(0!=memcpy_s(&isv_svn, sizeof(isv_svn), &_pse_psvn.isv_svn, sizeof(_pse_psvn.isv_svn))){ - AESM_DBG_ERROR("memcpy failed"); - retVal = AE_FAILURE; - } - } - SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" returning ", retVal, isv_svn); - - return retVal; -} - -ae_error_t AESMLogic::get_qe_cpu_svn(sgx_cpu_svn_t& cpu_svn) -{ - if(!_is_qe_psvn_set){ - ae_error_t ae_err = CQEClass::instance().load_enclave(); - if(AE_SUCCESS != ae_err){ - AESM_DBG_ERROR("Fail to load QE Enclave:( ae %d)",ae_err); - return ae_err; - } - } - assert(_is_qe_psvn_set); - if(0!=memcpy_s(&cpu_svn, sizeof(sgx_cpu_svn_t), &_qe_psvn.cpu_svn, sizeof(_qe_psvn.cpu_svn))){ - AESM_DBG_ERROR("memcpy failed"); - return AE_FAILURE; - } - return AE_SUCCESS; -} - - - -ae_error_t AESMLogic::set_psvn(uint16_t prod_id, uint16_t isv_svn, sgx_cpu_svn_t cpu_svn, uint32_t mrsigner_index) -{ - if(prod_id == QE_PROD_ID){ - if(mrsigner_index == AE_MR_SIGNER){ - if(_is_qe_psvn_set){ - if(0!=memcmp(&_qe_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| - 0!=memcmp(&_qe_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ - AESM_DBG_ERROR("PSVN unmatched for QE/PVE"); - return AE_PSVN_UNMATCHED_ERROR; - } - }else{ - if(0!=memcpy_s(&_qe_psvn.isv_svn, sizeof(_qe_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| - 0!=memcpy_s(&_qe_psvn.cpu_svn, sizeof(_qe_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ - AESM_DBG_ERROR("memcpy failed"); - return AE_FAILURE; - } - AESM_DBG_TRACE("get QE or PvE isv_svn=%d",(int)isv_svn); - _is_qe_psvn_set = true; - return AE_SUCCESS; - } - }else if(mrsigner_index==PCE_MR_SIGNER){ - if(_is_pce_psvn_set){ - if(0!=memcmp(&_pce_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| - 0!=memcmp(&_pce_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ - AESM_DBG_ERROR("PSVN unmatched for PCE"); - return AE_PSVN_UNMATCHED_ERROR; - } - }else{ - if(0!=memcpy_s(&_pce_psvn.isv_svn, sizeof(_pce_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| - 0!=memcpy_s(&_pce_psvn.cpu_svn, sizeof(_pce_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ - AESM_DBG_ERROR("memcpy failed"); - return AE_FAILURE; - } - AESM_DBG_TRACE("get PCE isv_svn=%d", (int)isv_svn); - _is_pce_psvn_set = true; - return AE_SUCCESS; - } - } - }else if(prod_id == PSE_PROD_ID){ - if(mrsigner_index == AE_MR_SIGNER){ - if(_is_pse_psvn_set){ - if(0!=memcmp(&_pse_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| - 0!=memcmp(&_pse_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ - AESM_DBG_ERROR("PSVN unmatched for PSE"); - return AE_PSVN_UNMATCHED_ERROR; - } - }else{ - if(0!=memcpy_s(&_pse_psvn.isv_svn, sizeof(_pse_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| - 0!=memcpy_s(&_pse_psvn.cpu_svn, sizeof(_pse_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ - AESM_DBG_ERROR("memcpy failed"); - return AE_FAILURE; - } - AESM_DBG_TRACE("get PSE isv_svn=%d", (int)isv_svn); - _is_pse_psvn_set = true; - return AE_SUCCESS; - } - } - } - return AE_SUCCESS; -} - -sgx_status_t AESMLogic::get_launch_token(const enclave_css_t* signature, - const sgx_attributes_t* attribute, - sgx_launch_token_t* launch_token) -{ - AESM_DBG_INFO("enter function"); - AESMLogicLock lock(_le_mutex); - - ae_error_t ret_le = AE_SUCCESS; - uint32_t mrsigner_index = UINT32_MAX; - - if (is_in_kernel_driver()) - { - //Should not be called - AESM_LOG_ERROR("InKernel LE loaded"); - return SGX_ERROR_SERVICE_UNAVAILABLE; - } - // load LE to get launch token - if((ret_le=CLEClass::instance().load_enclave()) != AE_SUCCESS) - { - if(ret_le == AESM_AE_NO_DEVICE) - { - AESM_DBG_FATAL("LE not loaded due to no SGX device available, possible SGX Env Not Ready"); - return SGX_ERROR_NO_DEVICE; - } - else if(ret_le == AESM_AE_OUT_OF_EPC) - { - AESM_DBG_FATAL("LE not loaded due to out of EPC"); - return SGX_ERROR_OUT_OF_EPC; - } - else - { - AESM_DBG_FATAL("fail to load LE:%d",ret_le); - return SGX_ERROR_SERVICE_UNAVAILABLE; - } - } - - - ret_le = static_cast(CLEClass::instance().get_launch_token( - const_cast(reinterpret_cast(&signature->body.enclave_hash)), - sizeof(sgx_measurement_t), - const_cast(reinterpret_cast(&signature->key.modulus)), - sizeof(signature->key.modulus), - const_cast(reinterpret_cast(attribute)), - sizeof(sgx_attributes_t), - reinterpret_cast(launch_token), - sizeof(token_t), - &mrsigner_index)); - switch (ret_le) - { - case AE_SUCCESS: - break; - case LE_INVALID_PARAMETER: - AESM_DBG_TRACE("Invalid parameter"); - return SGX_ERROR_INVALID_PARAMETER; - case LE_INVALID_ATTRIBUTE: - case LE_INVALID_PRIVILEGE_ERROR: - AESM_DBG_TRACE("Launch token error"); - return SGX_ERROR_SERVICE_INVALID_PRIVILEGE; - case LE_WHITELIST_UNINITIALIZED_ERROR: - AESM_DBG_TRACE("LE whitelist uninitialized error"); - return SGX_ERROR_UNEXPECTED; - default: - AESM_DBG_WARN("unexpected error (ae%d)", ret_le); - return SGX_ERROR_UNEXPECTED; - } - - token_t *lt = reinterpret_cast(launch_token); - ret_le = set_psvn(signature->body.isv_prod_id, signature->body.isv_svn, lt->cpu_svn_le, mrsigner_index); - if(AE_PSVN_UNMATCHED_ERROR == ret_le) - { - //QE or PSE has been changed, but AESM doesn't restart. Will not provide service. - return SGX_ERROR_SERVICE_UNAVAILABLE; - }else if(AE_SUCCESS != ret_le) { - AESM_DBG_ERROR("fail to save psvn:(ae%d)", ret_le); - return SGX_ERROR_UNEXPECTED; - } - - return SGX_SUCCESS; -} - -#define CHECK_LONG_TERM_PAIRING_STATUS \ - if(!query_pse_thread_status()){\ - return AESM_BUSY; \ - } - -aesm_error_t AESMLogic::create_session( - uint32_t* session_id, - uint8_t* se_dh_msg1, uint32_t se_dh_msg1_size) -{ - - AESM_DBG_INFO("AESMLogic::create_session"); - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_pse_mutex); - CHECK_SERVICE_STATUS; - CHECK_LONG_TERM_PAIRING_STATUS; - ae_error_t psStatus; - // If PSDA not loaded or CSE not provisioned - if (CPSEClass::instance().get_status() == PSE_STATUS_INIT || - CPSEClass::instance().get_status() == PSE_STATUS_UNAVAILABLE ) - { - AESM_DBG_ERROR("unexpected status PSE_STATUS_INIT : PSDA not loaded or CSE not provisioned."); - return AESM_PSDA_UNAVAILABLE; - } - else - psStatus = PlatformInfoLogic::create_session_pre_internal(); - if (AE_SUCCESS != psStatus) { - AESM_DBG_ERROR("psStatus = 0x%X in create_session", psStatus); - } - if (OAL_THREAD_TIMEOUT_ERROR == psStatus){ - AESM_DBG_INFO("AESM is busy in intializing for pse"); - return AESM_BUSY; - } - if (PVE_PROV_ATTEST_KEY_NOT_FOUND == psStatus) { - AESM_DBG_INFO("Key not found reported by Provisioning backend"); - return AESM_UNRECOGNIZED_PLATFORM; - } - if(OAL_PROXY_SETTING_ASSIST == psStatus){ - AESM_DBG_INFO("Proxy assist required in initializing for pse"); - return AESM_PROXY_SETTING_ASSIST; - } - if(PSW_UPDATE_REQUIRED == psStatus){ - AESM_DBG_INFO("PSW software update required"); - return AESM_UPDATE_AVAILABLE; - } - if (AESM_AE_OUT_OF_EPC == psStatus){ - AESM_DBG_INFO("AE out of EPC"); - return AESM_OUT_OF_EPC; - } - if (OAL_NETWORK_UNAVAILABLE_ERROR == psStatus){ - AESM_DBG_INFO("Network is unavailable"); - return AESM_NETWORK_ERROR; - } - if (AESM_PSDA_PLATFORM_KEYS_REVOKED == psStatus) { - AESM_DBG_INFO("This platform was revoked"); - return AESM_EPID_REVOKED_ERROR; - } - - if (PVE_PROV_ATTEST_KEY_TCB_OUT_OF_DATE == psStatus) { - AESM_DBG_INFO("TCB out of date reported by Provisioning backend"); - return AESM_UPDATE_AVAILABLE; - } - - if (AE_SUCCESS != psStatus) { - AESM_DBG_ERROR("psStatus = 0x%X in create_session", psStatus); - } - - return PSEOPAESMLogic::create_session(session_id, se_dh_msg1, se_dh_msg1_size); -} - -aesm_error_t AESMLogic::exchange_report( - uint32_t session_id, - const uint8_t* se_dh_msg2, uint32_t se_dh_msg2_size, - uint8_t* se_dh_msg3, uint32_t se_dh_msg3_size) -{ - - AESM_DBG_INFO("AESMLogic::exchange_report"); - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_pse_mutex); - CHECK_SERVICE_STATUS; - CHECK_LONG_TERM_PAIRING_STATUS; - - return PSEOPAESMLogic::exchange_report(session_id, - se_dh_msg2, - se_dh_msg2_size, - se_dh_msg3, - se_dh_msg3_size); -} - -aesm_error_t AESMLogic::close_session( - uint32_t session_id) -{ - - AESM_DBG_INFO("AESMLogic::close_session"); - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_pse_mutex); - CHECK_SERVICE_STATUS; - - return PSEOPAESMLogic::close_session(session_id); -} - -aesm_error_t AESMLogic::invoke_service( - const uint8_t* pse_message_req, uint32_t pse_message_req_size, - uint8_t* pse_message_resp, uint32_t pse_message_resp_size) -{ - - AESM_DBG_INFO("AESMLogic::invoke_service"); - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_pse_mutex); - CHECK_SERVICE_STATUS; - CHECK_LONG_TERM_PAIRING_STATUS; - return PSEOPAESMLogic::invoke_service(pse_message_req, - pse_message_req_size, - pse_message_resp, - pse_message_resp_size); -} - -aesm_error_t AESMLogic::get_ps_cap( - uint64_t* ps_cap) -{ - AESM_DBG_INFO("AESMLogic::get_ps_cap"); - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_pse_mutex); - CHECK_SERVICE_STATUS; - - return PSEOPAESMLogic::get_ps_cap(ps_cap); -} - -#define CHECK_EPID_PROVISIONG_STATUS \ - if(!query_pve_thread_status()){\ - return AESM_BUSY;\ - } - -aesm_error_t AESMLogic::init_quote( - uint8_t *target_info, uint32_t target_info_size, - uint8_t *gid, uint32_t gid_size) -{ - ae_error_t ret = AE_SUCCESS; - uint16_t qe_isv_svn = 0xFFFF; - uint16_t pce_isv_svn = 0xFFFF; - sgx_cpu_svn_t qe_cpu_svn; - memset(&qe_cpu_svn, 0, sizeof(qe_cpu_svn)); - AESM_DBG_INFO("init_quote"); - if(sizeof(sgx_target_info_t) != target_info_size || - sizeof(sgx_epid_group_id_t) != gid_size) - { - return AESM_PARAMETER_ERROR; - } - AESMLogicLock lock(_qe_pve_mutex); - CHECK_EPID_PROVISIONG_STATUS; - ret = get_pce_isv_svn(pce_isv_svn); - if(AE_SUCCESS != ret) - { - if(AESM_AE_OUT_OF_EPC == ret) - return AESM_OUT_OF_EPC; - else if(AESM_AE_NO_DEVICE == ret) - return AESM_NO_DEVICE_ERROR; - else if(AE_SERVER_NOT_AVAILABLE == ret) - return AESM_SERVICE_UNAVAILABLE; - return AESM_UNEXPECTED_ERROR; - } - ret = get_qe_cpu_svn(qe_cpu_svn); - if(AE_SUCCESS != ret) - { - if(AESM_AE_OUT_OF_EPC == ret) - return AESM_OUT_OF_EPC; - else if(AESM_AE_NO_DEVICE == ret) - return AESM_NO_DEVICE_ERROR; - else if(AE_SERVER_NOT_AVAILABLE == ret) - return AESM_SERVICE_UNAVAILABLE; - return AESM_UNEXPECTED_ERROR; - } - ret = get_qe_isv_svn(qe_isv_svn); - if(AE_SUCCESS != ret) - { - if(AESM_AE_OUT_OF_EPC == ret) - return AESM_OUT_OF_EPC; - else if(AESM_AE_NO_DEVICE == ret) - return AESM_NO_DEVICE_ERROR; - else if(AE_SERVER_NOT_AVAILABLE == ret) - return AESM_SERVICE_UNAVAILABLE; - return AESM_UNEXPECTED_ERROR; - } - return QEAESMLogic::init_quote( - reinterpret_cast(target_info), - gid, gid_size, pce_isv_svn, qe_isv_svn, qe_cpu_svn); -} - -aesm_error_t AESMLogic::get_quote(const uint8_t *report, uint32_t report_size, - uint32_t quote_type, - const uint8_t *spid, uint32_t spid_size, - const uint8_t *nonce, uint32_t nonce_size, - const uint8_t *sigrl, uint32_t sigrl_size, - uint8_t *qe_report, uint32_t qe_report_size, - uint8_t *quote, uint32_t buf_size) -{ - ae_error_t ret = AE_SUCCESS; - uint16_t pce_isv_svn = 0xFFFF; - AESM_DBG_INFO("get_quote"); - if(sizeof(sgx_report_t) != report_size || - sizeof(sgx_spid_t) != spid_size) - { - return AESM_PARAMETER_ERROR; - } - if((nonce && sizeof(sgx_quote_nonce_t) != nonce_size) - || (qe_report && sizeof(sgx_report_t) != qe_report_size)) - - { - return AESM_PARAMETER_ERROR; - } - AESMLogicLock lock(_qe_pve_mutex); - CHECK_EPID_PROVISIONG_STATUS; - ret = get_pce_isv_svn(pce_isv_svn); - if(AE_SUCCESS != ret) - { - if(AESM_AE_OUT_OF_EPC == ret) - return AESM_OUT_OF_EPC; - else if(AESM_AE_NO_DEVICE == ret) - return AESM_NO_DEVICE_ERROR; - else if(AE_SERVER_NOT_AVAILABLE == ret) - return AESM_SERVICE_UNAVAILABLE; - return AESM_UNEXPECTED_ERROR; - } - return QEAESMLogic::get_quote(report, quote_type, spid, nonce, sigrl, - sigrl_size, qe_report, quote, buf_size, pce_isv_svn); -} - -uint32_t AESMLogic::endpoint_selection(endpoint_selection_infos_t& es_info) -{ - AESMLogicLock lock(_qe_pve_mutex); - SGX_DBGPRINT_ONE_STRING_TWO_INTS_ENDPOINT_SELECTION(__FUNCTION__" (line, 0)", __LINE__, 0); - return EndpointSelectionInfo::instance().start_protocol(es_info); -} - - -uint32_t AESMLogic::is_gid_matching_result_in_epid_blob(const GroupId& gid) -{ - AESMLogicLock lock(_qe_pve_mutex); - EPIDBlob& epid_blob = EPIDBlob::instance(); - uint32_t le_gid; - if(epid_blob.get_sgx_gid(&le_gid)!=AE_SUCCESS){//get littlen endian gid - return GIDMT_UNEXPECTED_ERROR; - } - le_gid=_htonl(le_gid);//use bigendian gid - se_static_assert(sizeof(le_gid)==sizeof(gid)); - if(memcmp(&le_gid,&gid,sizeof(gid))!=0){ - return GIDMT_UNMATCHED; - } - return GIDMT_MATCHED; -} - -aesm_error_t AESMLogic::report_attestation_status( - uint8_t* platform_info, uint32_t platform_info_size, - uint32_t attestation_status, - uint8_t* update_info, uint32_t update_info_size) -{ - - AESM_DBG_INFO("report_attestation_status"); - AESMLogicLock lock(_pse_mutex); - CHECK_LONG_TERM_PAIRING_STATUS; - return PlatformInfoLogic::report_attestation_status(platform_info, platform_info_size, attestation_status, update_info, update_info_size); -} - -ae_error_t AESMLogic::get_white_list_size_without_lock(uint32_t *white_list_cert_size) -{ - uint32_t white_cert_size = 0; - ae_error_t ae_ret = aesm_query_data_size(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_FID, &white_cert_size); - if (AE_SUCCESS == ae_ret) - { - if (white_cert_size != 0){//file existing and not 0 size - *white_list_cert_size = white_cert_size; - return AE_SUCCESS; - } - else - return AE_FAILURE; - } - else - { - return ae_ret; - } -} - -aesm_error_t AESMLogic::get_white_list_size( - uint32_t* white_list_cert_size) -{ - if (NULL == white_list_cert_size){ - return AESM_PARAMETER_ERROR; - } - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_le_mutex); - CHECK_SERVICE_STATUS; - if (is_in_kernel_driver()) - { - AESM_LOG_INFO("InKernel LE loaded"); - return AESM_SERVICE_UNAVAILABLE; - } - ae_error_t ae_ret = get_white_list_size_without_lock(white_list_cert_size); - if (AE_SUCCESS == ae_ret) - return AESM_SUCCESS; - else - return AESM_UNEXPECTED_ERROR; -} - - -aesm_error_t AESMLogic::get_white_list( - uint8_t *white_list_cert, uint32_t buf_size) -{ - uint32_t white_cert_size=0; - if (NULL == white_list_cert){ - return AESM_PARAMETER_ERROR; - } - CHECK_SERVICE_STATUS; - AESMLogicLock lock(_le_mutex); - CHECK_SERVICE_STATUS; - if (is_in_kernel_driver()) - { - AESM_LOG_INFO("InKernel LE loaded"); - return AESM_SERVICE_UNAVAILABLE; - } - ae_error_t ae_ret = get_white_list_size_without_lock(&white_cert_size); - if (AE_SUCCESS != ae_ret) - return AESM_UNEXPECTED_ERROR; - if (white_cert_size != buf_size) - { - return AESM_PARAMETER_ERROR; - } - - ae_ret = aesm_read_data(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_FID, white_list_cert, &white_cert_size); - if (AE_SUCCESS != ae_ret){ - AESM_DBG_WARN("Fail to read white cert list file"); - return AESM_UNEXPECTED_ERROR; - } - return AESM_SUCCESS; -} - -ae_error_t sgx_error_to_ae_error(sgx_status_t status) -{ - if(SGX_ERROR_OUT_OF_MEMORY == status) - return AE_OUT_OF_MEMORY_ERROR; - if(SGX_SUCCESS == status) - return AE_SUCCESS; - return AE_FAILURE; -} - -aesm_error_t AESMLogic::switch_extended_epid_group( - uint32_t extended_epid_group_id - ) -{ - AESM_DBG_INFO("AESMLogic::switch_extended_epid_group"); - ae_error_t ae_ret; - if ((ae_ret = XEGDBlob::verify_xegd_by_xgid(extended_epid_group_id)) != AE_SUCCESS || - (ae_ret = EndpointSelectionInfo::verify_file_by_xgid(extended_epid_group_id)) != AE_SUCCESS){ - AESM_DBG_INFO("Fail to switch to extended epid group to %d due to XEGD blob for URL blob not available", extended_epid_group_id); - return AESM_PARAMETER_ERROR; - } - ae_ret = set_global_extended_epid_group_id(extended_epid_group_id); - if (ae_ret != AE_SUCCESS){ - AESM_DBG_INFO("Fail to switch to extended epid group %d", extended_epid_group_id); - return AESM_UNEXPECTED_ERROR; - } - - AESM_DBG_INFO("Succ to switch to extended epid group %d in data file, restart aesm required to use it", extended_epid_group_id); - return AESM_SUCCESS; -} -aesm_error_t AESMLogic::get_extended_epid_group_id( - uint32_t* extended_epid_group_id) -{ - AESM_DBG_INFO("AESMLogic::get_extended_epid_group"); - if (NULL == extended_epid_group_id) - { - return AESM_PARAMETER_ERROR; - } - *extended_epid_group_id = get_active_extended_epid_group_id(); - return AESM_SUCCESS; -} - diff --git a/psw/ae/aesm_service/source/aesm/application/aesm_logic.h b/psw/ae/aesm_service/source/aesm/application/aesm_logic.h deleted file mode 100644 index 19d7a649..00000000 --- a/psw/ae/aesm_service/source/aesm/application/aesm_logic.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -#ifndef _AESM_LOGIC_H_ -#define _AESM_LOGIC_H_ -#include "sgx_urts.h" -#include "aesm_error.h" -#include "arch.h" -#include "aeerror.h" -#include "tlv_common.h" -#include "se_thread.h" -#include "internal/se_stdio.h" -#include "internal/se_memcpy.h" -#include "internal/uncopyable.h" -#include "oal/oal.h" -#include -#include -#include "se_wrapper.h" -#include "upse/platform_info_blob.h" - -#include "default_url_info.hh" - -/*File to declare AESMLogic Class and facility class(Mutex/Lock) for it*/ - -const uint32_t THREAD_TIMEOUT = 5000; - -class AESMLogicMutex{ - CLASS_UNCOPYABLE(AESMLogicMutex) -public: - AESMLogicMutex() {se_mutex_init(&mutex);} - ~AESMLogicMutex() { se_mutex_destroy(&mutex);} - void lock() { se_mutex_lock(&mutex); } - void unlock() { se_mutex_unlock(&mutex); } -private: - se_mutex_t mutex; -}; - -class AESMLogicLock { - CLASS_UNCOPYABLE(AESMLogicLock) -public: - explicit AESMLogicLock(AESMLogicMutex& cs) :_cs(cs) { _cs.lock(); } - ~AESMLogicLock() { _cs.unlock(); } -private: - AESMLogicMutex& _cs; -}; - -#define QE_PROD_ID 1 -#define PSE_PROD_ID 2 - - -typedef struct _endpoint_selection_infos_t endpoint_selection_infos_t; -class AESMLogic{ -public: - static AESMLogicMutex _qe_pve_mutex, _pse_mutex, _le_mutex; /*mutex to lock external interface*/ -private: - static aesm_thread_t qe_thread, pse_thread; - static psvn_t _qe_psvn, _pse_psvn, _pce_psvn; /*different cpu svn used although they're same. We should only access _qe_psvn/_pce_svn when qe_pve_mutex is acquired and only access _pse_psvn when pse_mutext is acquired*/ - static bool _is_qe_psvn_set, _is_pse_psvn_set, _is_pce_psvn_set; - static uint32_t active_extended_epid_group_id; - static ae_error_t set_psvn(uint16_t prod_id, uint16_t isv_svn, sgx_cpu_svn_t cpu_svn, uint32_t mrsigner_index); - static ae_error_t save_unverified_white_list(const uint8_t *white_list_cert, uint32_t white_list_cert_size); - static ae_error_t get_white_list_size_without_lock(uint32_t *white_list_cert_size); -public: - static ae_error_t get_qe_isv_svn(uint16_t& isv_svn); /*This function should only be called when _qe_pve_mutex is acquired*/ - static ae_error_t get_qe_cpu_svn(sgx_cpu_svn_t& cpu_svn);/*This function should only be called when _qe_pve_mutex is acquired*/ - static ae_error_t get_pse_isv_svn(uint16_t& isv_svn); /*This function should only be called when _pse_mutex is acquired*/ - static ae_error_t get_pse_cpu_svn(sgx_cpu_svn_t& cpu_svn);/*This function should only be called when _pse_mutex is acquired*/ - static ae_error_t get_pce_isv_svn(uint16_t& isv_svn); - static uint32_t get_active_extended_epid_group_id(void); - - static ae_error_t service_start(); - static void service_stop(); - - static bool is_service_running(); - - static sgx_status_t get_launch_token(const enclave_css_t* signature, - const sgx_attributes_t* attribute, - sgx_launch_token_t* launch_token); - - static aesm_error_t get_launch_token( - const uint8_t *mrenclave, uint32_t mrenclave_size, - const uint8_t *public_key, uint32_t public_key_size, - const uint8_t *se_attributes, uint32_t se_attributes_size, - uint8_t * lictoken, uint32_t lictoken_size); - - static aesm_error_t init_quote(uint8_t *target_info, uint32_t target_info_size, - uint8_t *gid, uint32_t gid_size); - - static aesm_error_t get_quote(const uint8_t *report, uint32_t report_size, - uint32_t quote_type, - const uint8_t *spid, uint32_t spid_size, - const uint8_t *nonce, uint32_t nonce_size, - const uint8_t *sigrl, uint32_t sigrl_size, - uint8_t *qe_report, uint32_t qe_report_size, - uint8_t *quote, uint32_t buf_size); - - static aesm_error_t create_session( - uint32_t* session_id, - uint8_t* se_dh_msg1, uint32_t se_dh_msg1_size); - - static aesm_error_t exchange_report( - uint32_t session_id, - const uint8_t* se_dh_msg2, uint32_t se_dh_msg2_size, - uint8_t* se_dh_msg3, uint32_t se_dh_msg3_size); - - static aesm_error_t close_session( - uint32_t session_id); - - static aesm_error_t invoke_service( - const uint8_t* pse_message_req, uint32_t pse_message_req_size, - uint8_t* pse_message_resp, uint32_t pse_message_resp_size); - - static aesm_error_t get_ps_cap( - uint64_t* ps_cap); - - static uint32_t endpoint_selection(endpoint_selection_infos_t& es_info); - enum {GIDMT_UNMATCHED, GIDMT_NOT_AVAILABLE, GIDMT_MATCHED,GIDMT_UNEXPECTED_ERROR}; - static uint32_t is_gid_matching_result_in_epid_blob(const GroupId& gid); - - static aesm_error_t report_attestation_status( - uint8_t* platform_info, uint32_t platform_info_size, - uint32_t attestation_status, - uint8_t* update_info, uint32_t update_info_size); - - static aesm_error_t white_list_register( - const uint8_t *white_list_cert, uint32_t white_list_cert_size); - - static aesm_error_t get_white_list_size( - uint32_t* white_list_cert_size); - - static aesm_error_t get_white_list( - uint8_t *white_list_cert, uint32_t buf_size); - - static aesm_error_t get_extended_epid_group_id( - uint32_t* extended_epid_group_id); - - static aesm_error_t switch_extended_epid_group( - uint32_t extended_epid_group_id ); -}; -#endif - diff --git a/psw/ae/aesm_service/source/aesm_wrapper/src/AESMLogicWrapper.cpp b/psw/ae/aesm_service/source/aesm_wrapper/src/AESMLogicWrapper.cpp deleted file mode 100644 index f8e1be96..00000000 --- a/psw/ae/aesm_service/source/aesm_wrapper/src/AESMLogicWrapper.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#include "AESMLogicWrapper.h" -#include -#include - -#include "LEClass.h" -#include "sgx_quote.h" - -aesm_error_t AESMLogicWrapper::initQuote(uint8_t** target_info, - uint32_t* target_info_length, - uint8_t** gid, - uint32_t* gid_length) -{ - uint8_t *output_target_info = new uint8_t[sizeof(sgx_target_info_t)](); - uint8_t *output_gid = new uint8_t[sizeof(sgx_epid_group_id_t)](); - uint32_t output_target_info_length=sizeof(sgx_target_info_t); - uint32_t output_gid_length=sizeof(sgx_epid_group_id_t); - aesm_error_t result = AESMLogic::init_quote(output_target_info, output_target_info_length, - output_gid, output_gid_length); - if(result == AESM_SUCCESS) - { - *target_info = output_target_info; - *target_info_length = output_target_info_length; - - *gid = output_gid; - *gid_length = output_gid_length; - } - else - { - delete [] output_target_info; - delete [] output_gid; - } - return result; -} - -aesm_error_t AESMLogicWrapper::getQuote(uint32_t reportLength, const uint8_t* report, - uint32_t quoteType, - uint32_t spidLength, const uint8_t* spid, - uint32_t nonceLength, const uint8_t* nonce, - uint32_t sig_rlLength, const uint8_t* sig_rl, - uint32_t bufferSize, uint8_t** quote, - bool b_qe_report, uint32_t* qe_reportSize, uint8_t** qe_report) -{ - uint8_t *output_quote = new uint8_t[bufferSize](); - uint8_t *output_qe_report = NULL; - uint32_t output_qe_reportSize = 0; - if (b_qe_report) - { - output_qe_report = new uint8_t[sizeof(sgx_report_t)](); - output_qe_reportSize = sizeof(sgx_report_t); - - } - aesm_error_t result = AESMLogic::get_quote(report, reportLength, - quoteType, - spid, spidLength, - nonce, nonceLength, - sig_rl, sig_rlLength, - output_qe_report, output_qe_reportSize, - output_quote, bufferSize); - if(result == AESM_SUCCESS) - { - *quote = output_quote; - - *qe_report = output_qe_report; - *qe_reportSize = output_qe_reportSize; - } - else - { - delete [] output_quote; - if (output_qe_report) - delete [] output_qe_report; - } - return result; -} - -aesm_error_t AESMLogicWrapper::closeSession(uint32_t sessionId) -{ - return AESMLogic::close_session(sessionId); -} - -aesm_error_t AESMLogicWrapper::createSession(uint32_t *session_id, - uint8_t **se_dh_msg1, - uint32_t se_dh_msg1_size) -{ - uint8_t *output_se_dh_msg1 = new uint8_t[se_dh_msg1_size](); - aesm_error_t result = AESMLogic::create_session(session_id, output_se_dh_msg1, se_dh_msg1_size); - if(result == AESM_SUCCESS) - { - *se_dh_msg1 = output_se_dh_msg1; - } - else - { - delete [] output_se_dh_msg1; - } - return result; -} - -aesm_error_t AESMLogicWrapper::exchangeReport(uint32_t session_id, - const uint8_t* se_dh_msg2, - uint32_t se_dh_msg2_size, - uint8_t** se_dh_msg3, - uint32_t se_dh_msg3_size ) -{ - uint8_t *output_se_dh_msg3 = new uint8_t[se_dh_msg3_size](); - aesm_error_t result = AESMLogic::exchange_report(session_id, - se_dh_msg2, - se_dh_msg2_size, - output_se_dh_msg3, - se_dh_msg3_size); - if(result == AESM_SUCCESS) - { - *se_dh_msg3 = output_se_dh_msg3; - } - else - { - delete [] output_se_dh_msg3; - } - return result; -} - -aesm_error_t AESMLogicWrapper::getLaunchToken(const uint8_t *measurement, - uint32_t measurement_size, - const uint8_t *mrsigner, - uint32_t mrsigner_size, - const uint8_t *se_attributes, - uint32_t se_attributes_size, - uint8_t **launch_token, - uint32_t *launch_token_size) -{ - uint32_t output_launch_token_size = sizeof(token_t); - uint8_t *output_launch_token = new uint8_t[sizeof(token_t)](); - - aesm_error_t result = AESMLogic::get_launch_token(measurement, - measurement_size, - mrsigner, - mrsigner_size, - se_attributes, - se_attributes_size, - output_launch_token, - output_launch_token_size); - if(result == AESM_SUCCESS) - { - *launch_token = output_launch_token; - *launch_token_size = output_launch_token_size; - } - else - { - delete [] output_launch_token; - } - return result; -} - -aesm_error_t AESMLogicWrapper::invokeService(const uint8_t *pse_message_req, - uint32_t pse_message_req_size, - uint8_t **pse_message_resp, - uint32_t pse_message_resp_size) -{ - uint8_t* output_pse_message_resp = new uint8_t[pse_message_resp_size](); - aesm_error_t result = AESMLogic::invoke_service(pse_message_req, - pse_message_req_size, - output_pse_message_resp, - pse_message_resp_size); - if (result == AESM_SUCCESS) - { - *pse_message_resp = output_pse_message_resp; - } - else - { - delete[] output_pse_message_resp; - } - return result; -} - -aesm_error_t AESMLogicWrapper::getPsCap(uint64_t* ps_cap) -{ - return AESMLogic::get_ps_cap(ps_cap); -} - -aesm_error_t AESMLogicWrapper::reportAttestationStatus(uint8_t* platform_info, uint32_t platform_info_size, - uint32_t attestation_error_code, - uint8_t** update_info, uint32_t update_info_size) - -{ - uint8_t* output_update_info = new uint8_t[update_info_size](); - aesm_error_t result = AESMLogic::report_attestation_status(platform_info,platform_info_size, - attestation_error_code, - output_update_info, update_info_size); - - //update_info is valid when result is AESM_UPDATE_AVAILABLE - if (result == AESM_SUCCESS || result == AESM_UPDATE_AVAILABLE) - { - *update_info = output_update_info; - } - else - { - delete[] output_update_info; - } - return result; -} - -aesm_error_t AESMLogicWrapper::getWhiteListSize(uint32_t* white_list_size) -{ - return AESMLogic::get_white_list_size(white_list_size); -} - -aesm_error_t AESMLogicWrapper::getWhiteList(uint8_t **white_list, - uint32_t white_list_size) -{ - uint8_t* output_white_list = new uint8_t[white_list_size](); - aesm_error_t result = AESMLogic::get_white_list(output_white_list, white_list_size); - if (result == AESM_SUCCESS) - { - *white_list = output_white_list; - } - else - { - delete[] output_white_list; - } - return result; -} - -aesm_error_t AESMLogicWrapper::sgxGetExtendedEpidGroupId(uint32_t* x_group_id) -{ - return AESMLogic::get_extended_epid_group_id(x_group_id); -} - -aesm_error_t AESMLogicWrapper::sgxSwitchExtendedEpidGroup(uint32_t x_group_id) -{ - return AESMLogic::switch_extended_epid_group(x_group_id); -} - -aesm_error_t AESMLogicWrapper::sgxRegister(uint8_t* buf, uint32_t buf_size, uint32_t data_type) -{ - if(data_type == SGX_REGISTER_WHITE_LIST_CERT){ - return AESMLogic::white_list_register(buf, buf_size); - }else{ - return AESM_PARAMETER_ERROR; - } -} - -void AESMLogicWrapper::service_stop() -{ - AESMLogic::service_stop(); -} diff --git a/psw/ae/aesm_service/source/bundles/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/CMakeLists.txt new file mode 100644 index 00000000..18e188c8 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/CMakeLists.txt @@ -0,0 +1,5 @@ +BUNDLELIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}) + +FOREACH(subdir ${SUBDIRS}) + ADD_SUBDIRECTORY(${subdir}) +ENDFOREACH() \ No newline at end of file diff --git a/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/CMakeLists.txt new file mode 100644 index 00000000..b6d895c3 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/CMakeLists.txt @@ -0,0 +1,33 @@ +set(Edger8rOutputQE3 "${CMAKE_CURRENT_BINARY_DIR}/qe3_u.c") +get_filename_component(bundle ${CMAKE_CURRENT_SOURCE_DIR} NAME) +aux_source_directory(. _srcs) +set(all_src ${_srcs} + ${CMAKE_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/qe_logic.cpp + ${CMAKE_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/sgx_ql_core_wrapper.cpp) +link_directories(${CMAKE_SOURCE_DIR}/../../../../build/linux) +CreateBundle(${bundle} ${all_src} ${Edger8rOutputQE3}) + +target_include_directories(${bundle} PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk + ${PROJECT_SOURCE_DIR}/../../../../external/ippcp_internal/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/common/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/enclave + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/pce_wrapper/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/common/inc/internal/linux +) + +target_compile_definitions(${bundle} PRIVATE AESM_ECDSA_BUNDLE) +add_custom_command( + OUTPUT ${Edger8rOutputQE3} + COMMAND ${PROJECT_SOURCE_DIR}/../../../../build/linux/sgx_edger8r --untrusted --untrusted-dir ${CMAKE_CURRENT_BINARY_DIR} qe3.edl --search-path ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/enclave + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) +target_link_libraries(${bundle} oal utils urts_internal) +set_property(TARGET ${bundle} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/ecdsa_quote_service_bundle.cpp b/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/ecdsa_quote_service_bundle.cpp new file mode 100644 index 00000000..3fcd7c21 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/ecdsa_quote_service_bundle.cpp @@ -0,0 +1,339 @@ +#include +#include + +#include +#include "cppmicroservices/BundleContext.h" +#include + +#include +#include "aesm_logic.h" +#include "sgx_quote_3.h" +#include "sgx_ql_quote.h" +#include "sgx_ql_core_wrapper.h" + +#include "cppmicroservices_util.h" + +using namespace cppmicroservices; +std::shared_ptr g_pce_service; +static AESMLogicMutex ecdsa_quote_mutex; + + +static sgx_pce_error_t ae_error_to_pce_error(uint32_t input) +{ + sgx_pce_error_t ret = SGX_PCE_SUCCESS; + switch(input) + { + case AE_SUCCESS: + ret = SGX_PCE_SUCCESS; + break; + case AE_INVALID_PARAMETER: + case AE_INSUFFICIENT_DATA_IN_BUFFER: + ret = SGX_PCE_INVALID_PARAMETER; + break; + case PCE_INVALID_REPORT: + ret = SGX_PCE_INVALID_REPORT; + break; + case PCE_CRYPTO_ERROR: + ret = SGX_PCE_CRYPTO_ERROR; + break; + case PCE_INVALID_PRIVILEGE: + ret = SGX_PCE_INVALID_PRIVILEGE; + break; + case AE_OUT_OF_MEMORY_ERROR: + ret = SGX_PCE_OUT_OF_EPC; + break; + default: + ret = SGX_PCE_UNEXPECTED; + break; + } + return ret; +} + +static aesm_error_t quote3_error_to_aesm_error(quote3_error_t input) +{ + aesm_error_t ret = AESM_SUCCESS; + switch(input) + { + case SGX_QL_SUCCESS: + ret = AESM_SUCCESS; + break; + + case SGX_QL_ERROR_UNEXPECTED: + ret = AESM_UNEXPECTED_ERROR; + break; + + case SGX_QL_ERROR_INVALID_PARAMETER: + ret = AESM_PARAMETER_ERROR; + break; + + case SGX_QL_ERROR_OUT_OF_MEMORY: + ret = AESM_OUT_OF_MEMORY_ERROR; + break; + + case SGX_QL_ERROR_ECDSA_ID_MISMATCH: + ret = AESM_ECDSA_ID_MISMATCH; + break; + + case SGX_QL_PATHNAME_BUFFER_OVERFLOW_ERROR: + ret = AESM_PATHNAME_BUFFER_OVERFLOW_ERROR; + break; + + case SGX_QL_FILE_ACCESS_ERROR: + ret = AESM_FILE_ACCESS_ERROR; + break; + + case SGX_QL_ERROR_STORED_KEY: + ret = AESM_ERROR_STORED_KEY; + break; + + case SGX_QL_ERROR_PUB_KEY_ID_MISMATCH: + ret = AESM_PUB_KEY_ID_MISMATCH; + break; + + case SGX_QL_ERROR_INVALID_PCE_SIG_SCHEME: + ret = AESM_INVALID_PCE_SIG_SCHEME; + break; + + case SGX_QL_ATT_KEY_BLOB_ERROR: + ret = AESM_ATT_KEY_BLOB_ERROR; + break; + + case SGX_QL_UNSUPPORTED_ATT_KEY_ID: + ret = AESM_UNSUPPORTED_ATT_KEY_ID; + break; + + case SGX_QL_UNSUPPORTED_LOADING_POLICY: + ret = AESM_UNSUPPORTED_LOADING_POLICY; + break; + + case SGX_QL_INTERFACE_UNAVAILABLE: + ret = AESM_INTERFACE_UNAVAILABLE; + break; + + case SGX_QL_PLATFORM_LIB_UNAVAILABLE: + ret = AESM_PLATFORM_LIB_UNAVAILABLE; + break; + + case SGX_QL_ATT_KEY_NOT_INITIALIZED: + ret = AESM_ATT_KEY_NOT_INITIALIZED; + break; + + case SGX_QL_ATT_KEY_CERT_DATA_INVALID: + ret = AESM_ATT_KEY_CERT_DATA_INVALID; + break; + + case SGX_QL_NO_PLATFORM_CERT_DATA: + ret = AESM_NO_PLATFORM_CERT_DATA; + break; + + case SGX_QL_OUT_OF_EPC: + ret = AESM_OUT_OF_EPC; + break; + + case SGX_QL_ERROR_REPORT: + ret = AESM_ERROR_REPORT; + break; + + case SGX_QL_ENCLAVE_LOST: + ret = AESM_ENCLAVE_LOST; + break; + + case SGX_QL_INVALID_REPORT: + ret = AESM_INVALID_REPORT; + break; + + case SGX_QL_ENCLAVE_LOAD_ERROR: + ret = AESM_ENCLAVE_LOAD_ERROR; + break; + + case SGX_QL_UNABLE_TO_GENERATE_QE_REPORT: + ret = AESM_UNABLE_TO_GENERATE_QE_REPORT; + break; + + case SGX_QL_KEY_CERTIFCATION_ERROR: + ret = AESM_KEY_CERTIFICATION_ERROR; + break; + + default: + ret = AESM_UNEXPECTED_ERROR; + break; + } + return ret; +} + +sgx_pce_error_t sgx_set_pce_enclave_load_policy( + sgx_ql_request_policy_t policy) +{ + + return SGX_PCE_SUCCESS; +} + +sgx_pce_error_t sgx_pce_get_target(sgx_target_info_t *p_target, + sgx_isv_svn_t *p_isvsvn) +{ + return ae_error_to_pce_error(g_pce_service->pce_get_target(p_target, p_isvsvn)); +} + +sgx_pce_error_t sgx_get_pce_info(const sgx_report_t *p_report, + const uint8_t *p_pek, + uint32_t pek_size, + uint8_t crypto_suite, + uint8_t *p_encrypted_ppid, + uint32_t encrypted_ppid_size, + uint32_t *p_encrypted_ppid_out_size, + sgx_isv_svn_t* p_pce_isvsvn, + uint16_t* p_pce_id, + uint8_t *p_signature_scheme) +{ + return ae_error_to_pce_error(g_pce_service->get_pce_info(p_report, + p_pek, pek_size, crypto_suite, p_encrypted_ppid, + encrypted_ppid_size, p_encrypted_ppid_out_size, + p_pce_isvsvn, p_pce_id, p_signature_scheme)); +} + +sgx_pce_error_t sgx_pce_sign_report(const sgx_isv_svn_t *p_isv_svn, + const sgx_cpu_svn_t *p_cpu_svn, + const sgx_report_t *p_report, + uint8_t *p_sig, + uint32_t sig_size, + uint32_t *p_sig_out_size) +{ + return ae_error_to_pce_error(g_pce_service->pce_sign_report(p_isv_svn, + p_cpu_svn, p_report, p_sig, sig_size, p_sig_out_size)); +} + +extern void unload_qe(); + +class EcdsaQuoteServiceImp : public IQuoteExService +{ +private: + + bool initialized; +public: + EcdsaQuoteServiceImp():initialized(false) {} + + ae_error_t start() + { + if (initialized == true) + { + AESM_DBG_INFO("ecdsa bundle has been started"); + return AE_SUCCESS; + } + + AESM_DBG_INFO("Starting ecdsa bundle"); + get_service_wrapper(g_pce_service); + + if (!g_pce_service) + { + AESM_DBG_ERROR("Starting ecdsa bundle failed because pce service is not available"); + return AE_FAILURE; + } + + if (g_pce_service->start() != AE_SUCCESS) + { + AESM_DBG_ERROR("Starting ecdsa bundle failed because pce service failed to start"); + return AE_FAILURE; + } + + if (SGX_QL_SUCCESS != sgx_ql_set_enclave_load_policy(SGX_QL_PERSISTENT)) + { + AESM_DBG_ERROR("Starting ecdsa bundle failed because pce service failed to start"); + return AE_FAILURE; + } + + initialized = true; + AESM_DBG_INFO("ecdsa bundle started"); + return AE_SUCCESS; + } + void stop() + { + sgx_ql_set_enclave_load_policy(SGX_QL_EPHEMERAL); + unload_qe(); + AESM_DBG_INFO("ecdsa bundle stopped"); + } + + aesm_error_t init_quote_ex( + const uint8_t *att_key_id, uint32_t att_key_id_size, + uint32_t certification_key_type, + uint8_t *target_info, uint32_t target_info_size, + bool refresh_att_key, + uint8_t *pub_key_id, size_t *pub_key_id_size) + { + AESM_DBG_INFO("init_quote_ex"); + if(NULL != att_key_id && sizeof(sgx_ql_att_key_id_t) != att_key_id_size + || NULL != target_info && sizeof(sgx_target_info_t) != target_info_size) + { + return AESM_PARAMETER_ERROR; + } + AESMLogicLock lock(ecdsa_quote_mutex); + return quote3_error_to_aesm_error(sgx_ql_init_quote( + //TODO: need to update sgx_ql_get_quote_size to add "const" for att_key_id + const_cast(reinterpret_cast(att_key_id)), + reinterpret_cast(target_info), + refresh_att_key, + pub_key_id_size, + pub_key_id)); + } + + aesm_error_t get_quote_size_ex( + const uint8_t *att_key_id, uint32_t att_key_id_size, + uint32_t certification_key_type, + uint32_t *quote_size) + { + AESM_DBG_INFO("get_quote_size_ex"); + if(NULL != att_key_id && sizeof(sgx_ql_att_key_id_t) != att_key_id_size) + { + return AESM_PARAMETER_ERROR; + } + AESMLogicLock lock(ecdsa_quote_mutex); + return quote3_error_to_aesm_error(sgx_ql_get_quote_size( + //TODO: need to update sgx_ql_get_quote_size to add "const" for att_key_id + const_cast(reinterpret_cast(att_key_id)), + quote_size)); + } + + aesm_error_t get_quote_ex( + const uint8_t *app_report, uint32_t app_report_size, + const uint8_t *att_key_id, uint32_t att_key_id_size, + uint8_t *qe_report_info, uint32_t qe_report_info_size, + uint8_t *quote, uint32_t quote_size) + { + AESM_DBG_INFO("get_quote_ex"); + if(NULL != app_report && sizeof(sgx_report_t) != app_report_size + || NULL != att_key_id && sizeof(sgx_ql_att_key_id_t) != att_key_id_size + || NULL != qe_report_info && sizeof(sgx_ql_qe_report_info_t) != qe_report_info_size) + { + return AESM_PARAMETER_ERROR; + } + AESMLogicLock lock(ecdsa_quote_mutex); + return quote3_error_to_aesm_error(sgx_ql_get_quote( + reinterpret_cast(app_report), + //TODO: need to update sgx_ql_get_quote_size to add "const" for att_key_id + const_cast(reinterpret_cast(att_key_id)), + reinterpret_cast(qe_report_info), + quote, quote_size)); + } +}; + +class Activator : public BundleActivator +{ + void Start(BundleContext ctx) + { + auto service = std::make_shared(); + ctx.RegisterService(service); + } + + void Stop(BundleContext) + { + // Nothing to do + } +}; + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator) + +// [no-cmake] +// The code below is required if the CMake +// helper functions are not used. +#ifdef NO_CMAKE +CPPMICROSERVICES_INITIALIZE_BUNDLE(ecdsa_quote_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/manifest.json b/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/manifest.json new file mode 100644 index 00000000..c1d245f8 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/ecdsa_quote_service_bundle/manifest.json @@ -0,0 +1,7 @@ +{ + "bundle.symbolic_name" : "ecdsa_quote_service_symbolic_name", + "bundle.activator" : true, + "bundle.name" : "ECDSA Quote Service", + "bundle.description" : "This bundle provide ECDSA Quote Service", + "bundle.version" : "1.0.0" +} diff --git a/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/CMakeLists.txt new file mode 100644 index 00000000..0983b478 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/CMakeLists.txt @@ -0,0 +1,33 @@ +set(Edger8rOutputPVE "${CMAKE_CURRENT_BINARY_DIR}/provision_enclave_u.c") +set(Edger8rOutputQE "${CMAKE_CURRENT_BINARY_DIR}/quoting_enclave_u.c") +get_filename_component(bundle ${CMAKE_CURRENT_SOURCE_DIR} NAME) +aux_source_directory(. _srcs) +set(all_src ${_srcs} ${CMAKE_SOURCE_DIR}/../../common/pek_pub_key.cpp) +link_directories(${CMAKE_SOURCE_DIR}/../../../../build/linux) +CreateBundle(${bundle} ${all_src} ${Edger8rOutputQE} ${Edger8rOutputPVE}) + +target_include_directories(${bundle} PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../pve + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk + ${PROJECT_SOURCE_DIR}/../../../../external/ippcp_internal/inc +) + +add_custom_command( + OUTPUT ${Edger8rOutputPVE} + COMMAND ${PROJECT_SOURCE_DIR}/../../../../build/linux/sgx_edger8r --untrusted --untrusted-dir ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/../../pve/provision_enclave.edl --search-path ${PROJECT_SOURCE_DIR}/../../../../common/inc + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +add_custom_command( + OUTPUT ${Edger8rOutputQE} + COMMAND ${PROJECT_SOURCE_DIR}/../../../../build/linux/sgx_edger8r --untrusted --untrusted-dir ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/../../qe/quoting_enclave.edl --search-path ${PROJECT_SOURCE_DIR}/../../../../common/inc + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries(${bundle} oal utils urts_internal) +set_property(TARGET ${bundle} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/pve/PVEClass.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/PVEClass.cpp similarity index 96% rename from psw/ae/aesm_service/source/pve/PVEClass.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/PVEClass.cpp index f9514522..89026db2 100644 --- a/psw/ae/aesm_service/source/pve/PVEClass.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/PVEClass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,7 +33,7 @@ #include #include "PVEClass.h" #include "QEClass.h" -#include "PCEClass.h" +#include "pce_service.h" #include "util.h" #include "prof_fun.h" #include "sgx_report.h" @@ -41,12 +41,15 @@ #include "epid_pve_type.h" #include "aesm_xegd_blob.h" #include "provision_enclave_u.h" -#include "provision_enclave_u.c" + +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_pce_service; void CPVEClass::before_enclave_load() { // always unload qe enclave before loading pve enclave CQEClass::instance().unload_enclave(); - CPCEClass::instance().unload_enclave(); } uint32_t CPVEClass::gen_prov_msg1_data( diff --git a/psw/ae/aesm_service/source/pve/PVEClass.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/PVEClass.h similarity index 98% rename from psw/ae/aesm_service/source/pve/PVEClass.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/PVEClass.h index b48e51da..962acbe3 100644 --- a/psw/ae/aesm_service/source/pve/PVEClass.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/PVEClass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/qe/QEClass.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/QEClass.cpp similarity index 77% rename from psw/ae/aesm_service/source/qe/QEClass.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/QEClass.cpp index 4075c6a2..0243816b 100644 --- a/psw/ae/aesm_service/source/qe/QEClass.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/QEClass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,42 +34,67 @@ #include "arch.h" #include "QEClass.h" #include "PVEClass.h" -#include "PCEClass.h" +#include "pce_service.h" #include "se_memcpy.h" #include "prof_fun.h" #include "quoting_enclave_u.h" -#include "quoting_enclave_u.c" +#include "metadata.h" + +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_pce_service; void CQEClass::before_enclave_load() { // always unload qe enclave before loading pve enclave CPVEClass::instance().unload_enclave(); - CPCEClass::instance().unload_enclave(); } +extern "C" bool get_metadata(const char* enclave_file, metadata_t *metadata); + uint32_t CQEClass::get_qe_target( - sgx_target_info_t *p_qe_target) + sgx_target_info_t *p_target, + sgx_isv_svn_t *p_isvsvn) { + ae_error_t ae_err; + metadata_t metadata; + char enclave_path[MAX_PATH]= {0}; + if ((NULL == p_target) || (NULL == p_isvsvn)) + return AE_INVALID_PARAMETER; + /* We need to make sure the QE is successfully loaded */ assert(m_enclave_id); - memset(p_qe_target, 0, sizeof(sgx_target_info_t)); - if (SGX_SUCCESS != sgx_get_target_info(m_enclave_id, p_qe_target)) + memset(p_target, 0, sizeof(sgx_target_info_t)); + if(SGX_SUCCESS != sgx_get_target_info(m_enclave_id, p_target)) return AE_FAILURE; - return AE_SUCCESS; + + if((ae_err = aesm_get_pathname(FT_ENCLAVE_NAME, get_enclave_fid(), enclave_path, MAX_PATH)) != AE_SUCCESS){ + AESM_DBG_ERROR("fail to get QE pathname"); + return AE_FAILURE; + } + if (!get_metadata(enclave_path, &metadata)) + return AE_FAILURE; + *p_isvsvn = metadata.enclave_css.body.isv_svn; + return AE_SUCCESS; } + uint32_t CQEClass::verify_blob( uint8_t *p_epid_blob, uint32_t blob_size, - bool *p_is_resealed) + bool *p_is_resealed, + sgx_cpu_svn_t *p_cpusvn) { uint32_t ret = AE_SUCCESS; sgx_status_t status = SGX_SUCCESS; uint8_t is_resealed = 0; int retry = 0; + sgx_cpu_svn_t cpusvn; + memset(&cpusvn, 0, sizeof(cpusvn)); AESM_PROFILE_FUN; assert(m_enclave_id); status = ::verify_blob(m_enclave_id, &ret, p_epid_blob, blob_size, - &is_resealed); + &is_resealed, &cpusvn); for(; status == SGX_ERROR_ENCLAVE_LOST && retry < AESM_RETRY_COUNT; retry++) { unload_enclave(); @@ -77,13 +102,15 @@ uint32_t CQEClass::verify_blob( if(AE_SUCCESS != load_enclave()) return AE_FAILURE; status = ::verify_blob(m_enclave_id, &ret, p_epid_blob, blob_size, - &is_resealed); + &is_resealed, &cpusvn); } if(status != SGX_SUCCESS) return AE_FAILURE; if(ret == AE_SUCCESS) { *p_is_resealed = is_resealed != 0; + if (memcpy_s(p_cpusvn, sizeof(*p_cpusvn), &cpusvn, sizeof(cpusvn))) + return AE_FAILURE; } if(ret == QE_EPIDBLOB_ERROR) { diff --git a/psw/ae/aesm_service/source/qe/QEClass.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/QEClass.h similarity index 92% rename from psw/ae/aesm_service/source/qe/QEClass.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/QEClass.h index adafa692..755bedaa 100644 --- a/psw/ae/aesm_service/source/qe/QEClass.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/QEClass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -50,11 +50,13 @@ protected: public: uint32_t get_qe_target( - sgx_target_info_t *p_qe_target); + sgx_target_info_t *p_qe_target, + sgx_isv_svn_t *p_isvsvn); uint32_t verify_blob( uint8_t *p_epid_blob, uint32_t blob_size, - bool *p_is_resealed); + bool *p_is_resealed, + sgx_cpu_svn_t *p_cpusvn); uint32_t get_quote( uint8_t *p_epid_blob, uint32_t blob_size, diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_ecdsa.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_ecdsa.cpp similarity index 98% rename from psw/ae/aesm_service/source/aesm/extension/aesm_ecdsa.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_ecdsa.cpp index e23e26d2..d121958a 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_ecdsa.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_ecdsa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_epid_blob.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_epid_blob.cpp similarity index 99% rename from psw/ae/aesm_service/source/aesm/extension/aesm_epid_blob.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_epid_blob.cpp index 16890720..a12a9869 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_epid_blob.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_epid_blob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_epid_blob.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_epid_blob.h similarity index 97% rename from psw/ae/aesm_service/source/aesm/extension/aesm_epid_blob.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_epid_blob.h index 256d7535..539c06e9 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_epid_blob.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_epid_blob.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_xegd_blob.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_xegd_blob.cpp similarity index 93% rename from psw/ae/aesm_service/source/aesm/extension/aesm_xegd_blob.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_xegd_blob.cpp index 5a775450..743eb963 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_xegd_blob.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_xegd_blob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -54,12 +54,14 @@ ae_error_t XEGDBlob::verify_xegd_by_xgid(uint32_t xgid) return ae_ret; } +extern uint32_t get_active_extended_epid_group_id_internal(); + ae_error_t XEGDBlob::read(extended_epid_group_blob_t& blob) { ae_error_t ae_ret = AE_FAILURE; if(status == not_initialized){ uint32_t data_size = sizeof(blob_cache); - if ((ae_ret = aesm_read_data(FT_PERSISTENT_STORAGE, EXTENDED_EPID_GROUP_BLOB_INFO_FID, reinterpret_cast(&blob_cache), &data_size, AESMLogic::get_active_extended_epid_group_id())) != AE_SUCCESS){ + if ((ae_ret = aesm_read_data(FT_PERSISTENT_STORAGE, EXTENDED_EPID_GROUP_BLOB_INFO_FID, reinterpret_cast(&blob_cache), &data_size, get_active_extended_epid_group_id_internal())) != AE_SUCCESS){ goto CLEANUP_READ_FILE; } if (data_size != sizeof(blob_cache)){ @@ -74,7 +76,7 @@ ae_error_t XEGDBlob::read(extended_epid_group_blob_t& blob) status = update_to_date; CLEANUP_READ_FILE: if (status != update_to_date){ - if (AESMLogic::get_active_extended_epid_group_id() == DEFAULT_EGID){ + if (get_active_extended_epid_group_id_internal() == DEFAULT_EGID){ memset(&blob_cache, 0, sizeof(blob_cache));//indicate other part to use default data status = update_to_date; } diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_xegd_blob.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_xegd_blob.h similarity index 97% rename from psw/ae/aesm_service/source/aesm/extension/aesm_xegd_blob.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_xegd_blob.h index 774a2852..305f80ea 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_xegd_blob.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/aesm_xegd_blob.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/extension/endpoint_select_info.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/endpoint_select_info.cpp similarity index 91% rename from psw/ae/aesm_service/source/aesm/extension/endpoint_select_info.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/endpoint_select_info.cpp index af5ca911..a3c40d7f 100644 --- a/psw/ae/aesm_service/source/aesm/extension/endpoint_select_info.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/endpoint_select_info.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,13 +33,19 @@ #include "endpoint_select_info.h" #include "PVEClass.h" #include "prov_msg_size.h" -#include "network_encoding_wrapper.h" +#include "network_service.h" #include "aesm_xegd_blob.h" #include "peksk_pub.hh" #include "sgx_read_rand.h" #include "ssl_crypto.h" #include +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; + +extern std::shared_ptr g_network_service; + //Function to do basic checking of the endpoint selection blob. Esp to avoid no zero-ending in the input string url static bool is_valid_endpoint_selection_info(const endpoint_selection_infos_t& es_info) @@ -110,15 +116,17 @@ ae_error_t EndpointSelectionInfo::verify_file_by_xgid(uint32_t xgid) return AE_SUCCESS; } +extern uint32_t get_active_extended_epid_group_id_internal(); + //Function to read urls from configure files ae_error_t EndpointSelectionInfo::get_url_info() { ae_error_t ae_err=AE_SUCCESS; uint32_t server_urls_size = sizeof(_server_urls); - ae_err = aesm_read_data(FT_PERSISTENT_STORAGE, AESM_SERVER_URL_FID, reinterpret_cast(&_server_urls), &server_urls_size, AESMLogic::get_active_extended_epid_group_id()); + ae_err = aesm_read_data(FT_PERSISTENT_STORAGE, AESM_SERVER_URL_FID, reinterpret_cast(&_server_urls), &server_urls_size, get_active_extended_epid_group_id_internal()); - if(AE_SUCCESS != ae_err || + if(AE_SUCCESS != ae_err || server_urls_size != sizeof(_server_urls)|| !is_valid_server_url_infos(_server_urls)){ //If fail to read or data format error, use default value _is_server_url_valid = false; @@ -130,7 +138,7 @@ ae_error_t EndpointSelectionInfo::get_url_info() }else{ AESM_DBG_INFO("server url blob file not available in persistent storage"); } - if (AESMLogic::get_active_extended_epid_group_id() == DEFAULT_EGID){ + if (get_active_extended_epid_group_id_internal() == DEFAULT_EGID){ if (strcpy_s(_server_urls.endpoint_url, MAX_PATH, DEFAULT_URL) != 0) return AE_FAILURE; if (strcpy_s(_server_urls.pse_rl_url, MAX_PATH, DEFAULT_PSE_RL_URL) != 0) @@ -149,26 +157,6 @@ ae_error_t EndpointSelectionInfo::get_url_info() return AE_SUCCESS; } -ae_error_t EndpointSelectionInfo::get_url_info(aesm_server_url_infos_t& server_url) -{ - AESMLogicLock lock(_es_lock); - if (!_is_server_url_valid){ - (void)get_url_info(); - } - if (_is_server_url_valid) - { - if (memcpy_s(&server_url, sizeof(server_url), &_server_urls, sizeof(_server_urls)) != 0){ - return AE_FAILURE; - } - } - else - { - return AE_FAILURE; - } - return AE_SUCCESS; - -} - ae_error_t aesm_check_pek_signature(const signed_pek_t& signed_pek, const extended_epid_group_blob_t& xegb); sgx_status_t get_provision_server_rsa_pub_key(const signed_pek_t& pek, void **rsa_pub_key); //The function is to verify the PEK ECDSA Signature and RSA Signature for ES Msg2 @@ -212,6 +200,8 @@ ae_error_t EndpointSelectionInfo::verify_signature(const endpoint_selection_info goto ret_point; } + // Take care that the n and e in pek are BIG-ENDIAN, while LITTLE-ENDIAN is used to + // generate RSA public key. The conversion is done inside get_provision_server_rsa_pub_key() sgx_status = get_provision_server_rsa_pub_key(es_info.pek, &rsa_pub_key); if(SGX_SUCCESS != sgx_status){ AESM_DBG_ERROR("Fail to load rsa public key from PEK:%d", sgx_status); @@ -225,22 +215,21 @@ ae_error_t EndpointSelectionInfo::verify_signature(const endpoint_selection_info { AESM_DBG_ERROR("Fail to verify rsa signature:%d", sgx_status); ae_err = sgx_error_to_ae_error(sgx_status); - goto ret_point; + goto ret_point; } - if(vr == 0){ - AESM_DBG_TRACE("rsa signature verification failed"); - ae_err = PVE_MSG_ERROR; - goto ret_point; - }else{ + if(vr == SGX_RSA_VALID){ AESM_DBG_TRACE("rsa signature verification passed"); ae_err = AE_SUCCESS; + }else{ + AESM_DBG_TRACE("rsa signature verification failed"); + ae_err = PVE_MSG_ERROR; } ret_point: if(NULL != rsa_pub_key){ sgx_free_rsa_key(rsa_pub_key, SGX_RSA_PUBLIC_KEY, RSA_3072_KEY_BYTES, sizeof(es_info.pek.e)); } - + return ae_err; } @@ -312,8 +301,12 @@ ae_error_t EndpointSelectionInfo::start_protocol(endpoint_selection_infos_t& es_ } AESM_DBG_TRACE("ES msg1 generated"); - ae_ret = AESMNetworkEncoding::aesm_send_recv_msg_encoding(_server_urls.endpoint_url, msg, msg_size, resp, resp_size);//Encoding/send/receive/Decoding - + if(!g_network_service){ + AESM_DBG_ERROR("failed to get network service"); + ae_ret = AE_FAILURE; + goto final_point; + } + ae_ret = g_network_service->aesm_send_recv_msg_encoding(_server_urls.endpoint_url, msg, msg_size, resp, resp_size);//Encoding/send/receive/Decoding if(ae_ret != AE_SUCCESS){ AESM_DBG_ERROR("fail to send ES msg1 to backend server:%d",ae_ret); if(OAL_PROXY_SETTING_ASSIST == ae_ret){//when proxy setting assistant required, return directly @@ -347,7 +340,7 @@ ae_error_t EndpointSelectionInfo::start_protocol(endpoint_selection_infos_t& es_ final_point: if(msg!=NULL)free(msg); if(resp!=NULL){ - AESMNetworkEncoding::aesm_free_response_msg(resp); + g_network_service->aesm_free_response_msg(resp); } return ae_ret; @@ -382,16 +375,6 @@ const char *EndpointSelectionInfo::get_server_url(aesm_network_server_enum_type_ } } -void EndpointSelectionInfo::get_proxy(uint32_t& proxy_type, char proxy_url[MAX_PATH]) -{ - AESMLogicLock lock(_es_lock); - if(!_is_white_list_url_valid){ - (void)read_aesm_config(_config_urls); - _is_white_list_url_valid=true; - } - proxy_type = _config_urls.proxy_type; - strcpy_s(proxy_url, MAX_PATH, _config_urls.aesm_proxy); -} const char *EndpointSelectionInfo::get_pse_provisioning_url(const endpoint_selection_infos_t& es_info) { return es_info.provision_url; diff --git a/psw/ae/aesm_service/source/aesm/extension/endpoint_select_info.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/endpoint_select_info.h similarity index 78% rename from psw/ae/aesm_service/source/aesm/extension/endpoint_select_info.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/endpoint_select_info.h index 198f9e4b..b011b314 100644 --- a/psw/ae/aesm_service/source/aesm/extension/endpoint_select_info.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/endpoint_select_info.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,35 +40,12 @@ #include "se_wrapper.h" #include #include -#include "epid_pve_type.h" -#include "default_url_info.hh" +#include "es_info.h" #include "AEClass.h" #include "aesm_logic.h" -#define AESM_DATA_SERVER_URL_INFOS 'A' -#define AESM_DATA_ENDPOINT_SELECTION_INFOS 'B' -#define AESM_DATA_SERVER_URL_VERSION_1 1 -#define AESM_DATA_SERVER_URL_VERSION 2 -#define AESM_DATA_ENDPOINT_SELECTION_VERSION 1 #pragma pack(1) #include "aesm_config.h" - -/*Struct for PCE based url information which will be installed by PSW Installer*/ -typedef struct _aesm_server_url_infos_t{ - uint8_t aesm_data_type; - uint8_t aesm_data_version; - char endpoint_url[MAX_PATH]; /*URL for endpoint selection protocol server*/ - char pse_rl_url[MAX_PATH]; /*URL to retrieve PSE rovocation List*/ - char pse_ocsp_url[MAX_PATH]; -}aesm_server_url_infos_t; - -/*Struct for data to save endpoint selection protocol result into persistent data storage*/ -typedef struct _endpoint_selection_infos_t{ - uint8_t aesm_data_type; - uint8_t aesm_data_version; - signed_pek_t pek; - char provision_url[MAX_PATH]; -}endpoint_selection_infos_t; #pragma pack() /*An interface to provide the endpoint selection protocol and also provide some URLs (result of ES protocol or some static url) @@ -100,9 +77,7 @@ public: static ae_error_t verify_file_by_xgid(uint32_t xgid); const char* get_dal_emulator_url(){return NULL;}/*dal emulator not supported. The interface is kept to keep PSE untrusted code compilable*/ ae_error_t get_url_info(); - ae_error_t get_url_info(aesm_server_url_infos_t& server_url); const char *get_server_url(aesm_network_server_enum_type_t type); - void get_proxy(uint32_t& proxy_type, char proxy_url[MAX_PATH]); /*Function to get result of Endpoint Selection Protocol from Backend Server*/ ae_error_t start_protocol(endpoint_selection_infos_t& es_info); }; diff --git a/psw/ae/aesm_service/source/epid_provision/epid_endpoint_selection.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_endpoint_selection.cpp similarity index 99% rename from psw/ae/aesm_service/source/epid_provision/epid_endpoint_selection.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_endpoint_selection.cpp index a32a7887..0825ddef 100644 --- a/psw/ae/aesm_service/source/epid_provision/epid_endpoint_selection.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_endpoint_selection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/epid_provision/epid_provision_msg1.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg1.cpp similarity index 92% rename from psw/ae/aesm_service/source/epid_provision/epid_provision_msg1.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg1.cpp index a6b7a451..7c44526d 100644 --- a/psw/ae/aesm_service/source/epid_provision/epid_provision_msg1.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,11 +35,16 @@ #include "oal/oal.h" #include "aeerror.h" #include "PVEClass.h" -#include "PCEClass.h" +#include "pce_service.h" #include "aesm_rand.h" #include "epid_pve_type.h" #include "crypto_wrapper.h" +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; + +extern std::shared_ptr g_pce_service; /** * File: epid_provision_msg1.cpp * Description: Provide the untrusted implementation of code to generate ProvMsg1 @@ -116,7 +121,7 @@ static ae_error_t aesm_rsa_oaep_encrypt(const uint8_t *src, uint32_t src_len, co { size_t dst_len = RSA_3072_KEY_BYTES; // Check the encrypt output length - + sgx_status_t res = sgx_rsa_pub_encrypt_sha256(const_cast(rsa), NULL, &dst_len, src, src_len); if(res != SGX_SUCCESS || dst_len != RSA_3072_KEY_BYTES) { @@ -153,6 +158,8 @@ static ae_error_t aesm_rsa_oaep_encrypt(const uint8_t *src, uint32_t src_len, co uint8_t field2_iv[IV_SIZE]; uint8_t field2_mac[MAC_SIZE]; uint8_t encrypted_ppid[RSA_3072_KEY_BYTES]; + uint32_t encrypted_ppid_output_size = 0; + uint8_t signature_scheme = 0; //msg1 header will be in the beginning part of the output msg provision_request_header_t *msg1_header = reinterpret_cast(msg1); memset(&pek_report, 0, sizeof(pek_report)); @@ -160,12 +167,13 @@ static ae_error_t aesm_rsa_oaep_encrypt(const uint8_t *src, uint32_t src_len, co sgx_status_t sgx_status; //Load PCE Enclave required - ret = CPCEClass::instance().load_enclave(); + if(!g_pce_service) return AE_FAILURE; + ret = g_pce_service->load_enclave(); if(ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PCE enclave:( ae%d)\n",ret); return ret; } - ret = CPCEClass::instance().get_pce_target(&pce_target_info); + ret = g_pce_service->pce_get_target(&pce_target_info, &pce_isv_svn); if(ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to get PCE target info:( ae %d)\n",ret); return ret; @@ -185,13 +193,14 @@ static ae_error_t aesm_rsa_oaep_encrypt(const uint8_t *src, uint32_t src_len, co } se_static_assert(sizeof(encrypted_ppid)==PEK_MOD_SIZE); //Load PCE Enclave required - ret = CPCEClass::instance().load_enclave(); + ret = g_pce_service->load_enclave(); if(ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PCE enclave:( ae %d)\n",ret); return ret; } - ret = CPCEClass::instance().get_pce_info(pek_report, pve_data.pek, pce_id, - pce_isv_svn, encrypted_ppid); + ret = g_pce_service->get_pce_info(&pek_report, (uint8_t *)&pve_data.pek, + PEK_MOD_SIZE + sizeof(pve_data.pek.e), ALG_RSA_OAEP_3072, encrypted_ppid, sizeof(encrypted_ppid), + &encrypted_ppid_output_size, &pce_isv_svn, &pce_id, &signature_scheme); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("Fail to generate pc_info:(ae%d)",ret); return ret; @@ -209,7 +218,6 @@ static ae_error_t aesm_rsa_oaep_encrypt(const uint8_t *src, uint32_t src_len, co AESM_DBG_ERROR("Fail to generate random SK (ae%d)",ret); return ret; } - CPCEClass::instance().unload_enclave(); ret = prov_msg1_gen_header(msg1_header, pve_data.is_performance_rekey, pve_data.xid, msg1_size); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("fail to generate ProvMsg1 Header:(ae %d)",ret); @@ -243,26 +251,17 @@ static ae_error_t aesm_rsa_oaep_encrypt(const uint8_t *src, uint32_t src_len, co } //transform rsa format PEK public key of Provision Server void *rsa_pub_key = NULL; - signed_pek_t le_pek{}; - // Change the endian for the PEK public key - for(uint32_t i = 0; i< sizeof(le_pek.n); i++) - { - le_pek.n[i] = pve_data.pek.n[sizeof(le_pek.n) - i - 1]; - } - for(uint32_t i= 0; i < sizeof(le_pek.e); i++) - { - le_pek.e[i] = pve_data.pek.e[sizeof(le_pek.e) - i - 1]; - } - - sgx_status = get_provision_server_rsa_pub_key(le_pek, &rsa_pub_key); + // Take care that the n and e in pek are BIG-ENDIAN, while LITTLE-ENDIAN is used to + // generate RSA public key. The conversion is done inside get_provision_server_rsa_pub_key() + sgx_status = get_provision_server_rsa_pub_key(pve_data.pek, &rsa_pub_key); if( SGX_SUCCESS != sgx_status){ AESM_DBG_ERROR("Fail to decode PEK:%d",sgx_status); return AE_FAILURE; } uint8_t field0[RSA_3072_KEY_BYTES]; ret = aesm_rsa_oaep_encrypt(tlvs_msg1_sub.get_tlv_msg(), tlvs_msg1_sub.get_tlv_msg_size(), rsa_pub_key, field0); - sgx_free_rsa_key(rsa_pub_key, SGX_RSA_PUBLIC_KEY, RSA_3072_KEY_BYTES, sizeof(le_pek.e)); + sgx_free_rsa_key(rsa_pub_key, SGX_RSA_PUBLIC_KEY, RSA_3072_KEY_BYTES, sizeof(pve_data.pek.e)); if(AE_SUCCESS!=ret){ AESM_DBG_ERROR("Fail to in RSA_OAEP for ProvMsg1:(ae%d)",ret); return ret; diff --git a/psw/ae/aesm_service/source/epid_provision/epid_provision_msg2.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg2.cpp similarity index 96% rename from psw/ae/aesm_service/source/epid_provision/epid_provision_msg2.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg2.cpp index b3bc0052..8aa1f59a 100644 --- a/psw/ae/aesm_service/source/epid_provision/epid_provision_msg2.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,7 +34,7 @@ #include "aesm_xegd_blob.h" #include "aeerror.h" #include "PVEClass.h" -#include "PCEClass.h" +#include "pce_service.h" #include "aesm_rand.h" /** @@ -59,6 +59,10 @@ #define MSG2_FIELD1_PREV_GID tlvs_field1[PREV_GID_INDEX] #define MSG2_FIELD1_PLAT_INFO tlvs_field1[alt_index+3] +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_pce_service; //Function to verify that EPID SigRl type and version is correct for sigrl static ae_error_t verify_sigrl_cert_type_version(const se_sig_rl_t *sigrl_cert) @@ -268,6 +272,11 @@ uint32_t CPVEClass::proc_prov_msg2( size_t aad_size = PROVISION_RESPONSE_HEADER_SIZE; const provision_response_header_t *msg2_header = reinterpret_cast(msg2); provision_request_header_t *msg3_header = reinterpret_cast(msg3); + if (!g_pce_service){ + AESM_DBG_FATAL("failed to load pce service"); + return PVE_UNEXPECTED_ERROR; + } + if(msg2_size < PROVISION_RESPONSE_HEADER_SIZE){ AESM_DBG_ERROR("ProvMsg2 size too small"); return PVE_MSG_ERROR; @@ -304,6 +313,7 @@ uint32_t CPVEClass::proc_prov_msg2( do{ TLVsMsg tlvs_msg2; tlv_status_t tlv_status; + uint16_t pce_isv_svn = 0; //decode TLV structure of message body tlv_status= tlvs_msg2.init_from_buffer(msg2+static_cast(PROVISION_RESPONSE_HEADER_SIZE), msg2_size - static_cast(PROVISION_RESPONSE_HEADER_SIZE)); ret = tlv_error_2_pve_error(tlv_status); @@ -384,12 +394,12 @@ uint32_t CPVEClass::proc_prov_msg2( } proc_prov_msg2_blob_input_t msg2_blob_input; memset(&msg2_blob_input, 0, sizeof(msg2_blob_input)); - ret = CPCEClass::instance().load_enclave();//Load PCE enclave now + ret = g_pce_service->load_enclave();//Load PCE enclave now if( ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PCE enclave:(ae%d)\n",ret); break; } - ret = (ae_error_t)CPCEClass::instance().get_pce_target(&msg2_blob_input.pce_target_info); + ret = (ae_error_t)g_pce_service->pce_get_target(&msg2_blob_input.pce_target_info, &pce_isv_svn); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("fail to get PCE target info:(ae%d)\n",ret); break; @@ -461,24 +471,18 @@ uint32_t CPVEClass::proc_prov_msg2( break; } uint8_t ecdsa_sign[64]; - psvn_t psvn; - memset(&psvn, 0, sizeof(psvn)); - if(0!=memcpy_s(&psvn.cpu_svn,sizeof(psvn.cpu_svn), &msg2_blob_input.equiv_pi.cpu_svn, sizeof(msg2_blob_input.equiv_pi.cpu_svn))|| - 0!=memcpy_s(&psvn.isv_svn, sizeof(psvn.isv_svn), &msg2_blob_input.equiv_pi.pce_svn, sizeof(msg2_blob_input.equiv_pi.pce_svn))){ - ret = PVE_UNEXPECTED_ERROR; - break; - } - ret = CPCEClass::instance().load_enclave();//Load PCE enclave now + uint32_t ecdsa_sign_output_size = 0; + ret = g_pce_service->load_enclave();//Load PCE enclave now if( ret != AE_SUCCESS){ AESM_DBG_ERROR("Fail to load PCE enclave:(ae%d)\n",ret); break; } - ret = (ae_error_t)CPCEClass::instance().sign_report(psvn, msg3_fixed_output.pwk2_report, ecdsa_sign); + ret = (ae_error_t)g_pce_service->pce_sign_report(&msg2_blob_input.equiv_pi.pce_svn, &msg2_blob_input.equiv_pi.cpu_svn, + &msg3_fixed_output.pwk2_report, ecdsa_sign, sizeof(ecdsa_sign), &ecdsa_sign_output_size); if(AE_SUCCESS != ret){ AESM_DBG_ERROR("PCE report error (ae%d) in sign report",ret); break; } - CPCEClass::instance().unload_enclave(); uint8_t iv[IV_SIZE]; uint8_t mac[MAC_SIZE]; uint8_t *payload_data=NULL; diff --git a/psw/ae/aesm_service/source/epid_provision/epid_provision_msg4.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg4.cpp similarity index 99% rename from psw/ae/aesm_service/source/epid_provision/epid_provision_msg4.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg4.cpp index 0ede901f..df947cba 100644 --- a/psw/ae/aesm_service/source/epid_provision/epid_provision_msg4.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_provision_msg4.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_quote_service_bundle.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_quote_service_bundle.cpp new file mode 100644 index 00000000..62f3d94d --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_quote_service_bundle.cpp @@ -0,0 +1,401 @@ +#include +#include +#include + +#include +#include "cppmicroservices/BundleContext.h" +#include + +#include +#include +#include "aesm_xegd_blob.h" +#include "aesm_logic.h" +#include "pve_logic.h" +#include "qe_logic.h" +#include "aesm_epid_blob.h" +#include "aesm_long_lived_thread.h" +#include "QEClass.h" +#include "PVEClass.h" +#include "util.h" +#include "launch_service.h" +#include "pce_service.h" +#include "es_info.h" +#include "endpoint_select_info.h" +#include "cppmicroservices_util.h" + +using namespace cppmicroservices; +std::shared_ptr g_network_service; +std::shared_ptr g_pce_service; +std::shared_ptr g_launch_service; + + +extern ThreadStatus epid_thread; +static uint32_t active_extended_epid_group_id = 0; +static AESMLogicMutex _qe_pve_mutex; + +#define CHECK_EPID_PROVISIONG_STATUS \ + if(!query_pve_thread_status()){\ + return AESM_BUSY;\ + } + +bool query_pve_thread_status(void) +{ + return epid_thread.query_status_and_reset_clock(); +} + + +uint32_t get_active_extended_epid_group_id_internal() +{ + return active_extended_epid_group_id; +} + +static ae_error_t thread_to_load_qe(aesm_thread_arg_type_t arg) +{ + epid_blob_with_cur_psvn_t epid_data; + ae_error_t ae_ret = AE_FAILURE; + UNUSED(arg); + AESM_DBG_TRACE("start to load qe"); + memset(&epid_data, 0, sizeof(epid_data)); + AESMLogicLock lock(_qe_pve_mutex); + if((ae_ret = EPIDBlob::instance().read(epid_data)) == AE_SUCCESS) + { + AESM_DBG_TRACE("EPID blob is read successfully, loading QE ..."); + ae_ret = CQEClass::instance().load_enclave(); + if(AE_SUCCESS != ae_ret) + { + AESM_DBG_WARN("fail to load QE: %d", ae_ret); + }else{ + AESM_DBG_TRACE("QE loaded successfully"); + bool resealed = false; + sgx_cpu_svn_t cpusvn; + memset(&cpusvn, 0, sizeof(cpusvn)); + se_static_assert(SGX_TRUSTED_EPID_BLOB_SIZE_SDK>=SGX_TRUSTED_EPID_BLOB_SIZE_SIK); + // Just take this chance to reseal EPID blob in case TCB is + // upgraded, return value is ignored and no provisioning is + // triggered. + ae_ret = static_cast(CQEClass::instance().verify_blob( + epid_data.trusted_epid_blob, + SGX_TRUSTED_EPID_BLOB_SIZE_SDK, + &resealed, &cpusvn)); + if(AE_SUCCESS != ae_ret) + { + AESM_DBG_WARN("Failed to verify EPID blob: %d", ae_ret); + EPIDBlob::instance().remove(); + }else{ + uint32_t epid_xeid; + // Check whether EPID blob XEGDID is aligned with active extended group id if it exists. + if ((EPIDBlob::instance().get_extended_epid_group_id(&epid_xeid) == AE_SUCCESS) && (epid_xeid == get_active_extended_epid_group_id_internal())) { + AESM_DBG_TRACE("EPID blob Verified"); + // XEGDID is aligned + if (true == resealed) + { + AESM_DBG_TRACE("EPID blob is resealed"); + if ((ae_ret = EPIDBlob::instance().write(epid_data)) + != AE_SUCCESS) + { + AESM_DBG_WARN("Failed to update epid blob: %d", ae_ret); + } + } + } + else { // XEGDID is NOT aligned + AESM_DBG_TRACE("XEGDID mismatch in EPIDBlob, remove it..."); + EPIDBlob::instance().remove(); + } + } + } + }else{ + AESM_DBG_TRACE("Fail to read EPID Blob"); + } + AESM_DBG_TRACE("QE Thread finished succ"); + return AE_SUCCESS; +} + +static ae_error_t read_global_extended_epid_group_id(uint32_t *xeg_id) +{ + char path_name[MAX_PATH]; + ae_error_t ae_ret = aesm_get_pathname(FT_PERSISTENT_STORAGE, EXTENDED_EPID_GROUP_ID_FID, path_name, MAX_PATH); + if(AE_SUCCESS != ae_ret){ + return ae_ret; + } + FILE * f = fopen(path_name, "r"); + if( f == NULL){ + return OAL_CONFIG_FILE_ERROR; + } + ae_ret = OAL_CONFIG_FILE_ERROR; + if(fscanf(f, "%" SCNu32, xeg_id)==1){ + ae_ret = AE_SUCCESS; + } + fclose(f); + return ae_ret; +} +static ae_error_t set_global_extended_epid_group_id(uint32_t xeg_id) +{ + char path_name[MAX_PATH]; + ae_error_t ae_ret = aesm_get_pathname(FT_PERSISTENT_STORAGE, EXTENDED_EPID_GROUP_ID_FID, path_name, MAX_PATH); + if(AE_SUCCESS != ae_ret){ + return ae_ret; + } + FILE *f = fopen(path_name, "w"); + if(f == NULL){ + return OAL_CONFIG_FILE_ERROR; + } + ae_ret = OAL_CONFIG_FILE_ERROR; + if(fprintf(f, "%" PRIu32, xeg_id)>0){ + ae_ret = AE_SUCCESS; + } + fclose(f); + return ae_ret; +} + + +class EpidQuoteServiceImp : public IEpidQuoteService +{ +private: + bool initialized; + aesm_thread_t qe_thread; +public: + EpidQuoteServiceImp():initialized(false), qe_thread(NULL){} + + + ae_error_t start() + { + ae_error_t ae_ret = AE_SUCCESS; + if (initialized == true) + { + AESM_DBG_INFO("epid bundle has been started"); + return AE_SUCCESS; + } + + AESM_DBG_INFO("Starting epid bundle"); + get_service_wrapper(g_network_service); + get_service_wrapper(g_launch_service); + get_service_wrapper(g_pce_service); + + if (g_launch_service) + g_launch_service->start(); + + ae_ret = read_global_extended_epid_group_id(&active_extended_epid_group_id); + if (AE_SUCCESS != ae_ret){ + AESM_DBG_INFO("Fail to read extended epid group id, default extended epid group used"); + active_extended_epid_group_id = DEFAULT_EGID; // Use default extended epid group id 0 if it is not available from data file + } + else{ + AESM_DBG_INFO("active extended group id %d used", active_extended_epid_group_id); + } + if (AE_SUCCESS != (XEGDBlob::verify_xegd_by_xgid(active_extended_epid_group_id)) || + AE_SUCCESS != (EndpointSelectionInfo::verify_file_by_xgid(active_extended_epid_group_id))){// Try to load XEGD and URL file to make sure it is valid + AESM_LOG_WARN_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PCD_NOT_AVAILABLE]); + AESM_LOG_WARN("%s: original extended epid group id = %d", g_event_string_table[SGX_EVENT_PCD_NOT_AVAILABLE], active_extended_epid_group_id); + active_extended_epid_group_id = DEFAULT_EGID;// If the active extended epid group id read from data file is not valid, switch to default extended epid group id + } + + ae_error_t aesm_ret = aesm_create_thread(thread_to_load_qe, 0,&qe_thread); + if(AE_SUCCESS != aesm_ret){ + AESM_DBG_WARN("Fail to create thread to preload QE:(ae %d)",aesm_ret); + return AE_FAILURE; + } + initialized = true; + AESM_DBG_INFO("epid bundle started"); + return AE_SUCCESS; + } + void stop() + { + ae_error_t ae_ret, thread_ret; + + ae_ret = aesm_wait_thread(qe_thread, &thread_ret, AESM_STOP_TIMEOUT); + if (ae_ret != AE_SUCCESS || thread_ret != AE_SUCCESS) + { + AESM_DBG_INFO("aesm_wait_thread failed(qe_thread):(ae %d) (%d)", ae_ret, thread_ret); + } + (void)aesm_free_thread(qe_thread);//release thread handle to free memory + + uint64_t stop_tick_count = se_get_tick_count()+500/1000; + epid_thread.stop_thread(stop_tick_count); + + CPVEClass::instance().unload_enclave(); + CQEClass::instance().unload_enclave(); + AESM_DBG_INFO("epid bundle stopped"); + } + + aesm_error_t init_quote( + uint8_t *target_info, + uint32_t target_info_size, + uint8_t *gid, + uint32_t gid_size) + { + ae_error_t ret = AE_SUCCESS; + sgx_target_info_t pce_target_info; + uint16_t pce_isv_svn = 0xFFFF; + memset(&pce_target_info, 0, sizeof(pce_target_info)); + AESM_DBG_INFO("init_quote"); + if(sizeof(sgx_target_info_t) != target_info_size || + sizeof(sgx_epid_group_id_t) != gid_size) + { + return AESM_PARAMETER_ERROR; + } + AESMLogicLock lock(_qe_pve_mutex); + CHECK_EPID_PROVISIONG_STATUS; + if(!g_pce_service) + return AESM_SERVICE_UNAVAILABLE; + ret = g_pce_service->load_enclave(); + if(AE_SUCCESS == ret) + ret = static_cast(g_pce_service->pce_get_target(&pce_target_info, &pce_isv_svn)); + if(AE_SUCCESS != ret) + { + if(AESM_AE_OUT_OF_EPC == ret) + return AESM_OUT_OF_EPC; + else if(AESM_AE_NO_DEVICE == ret) + return AESM_NO_DEVICE_ERROR; + else if(AE_SERVER_NOT_AVAILABLE == ret) + return AESM_SERVICE_UNAVAILABLE; + return AESM_UNEXPECTED_ERROR; + } + return QEAESMLogic::init_quote( + reinterpret_cast(target_info), + gid, gid_size, pce_isv_svn); + } + + aesm_error_t get_quote( + const uint8_t *report, uint32_t report_size, + uint32_t quote_type, + const uint8_t *spid, uint32_t spid_size, + const uint8_t *nonce, uint32_t nonce_size, + const uint8_t *sigrl, uint32_t sigrl_size, + uint8_t *qe_report, uint32_t qe_report_size, + uint8_t *quote, uint32_t buf_size) + { + ae_error_t ret = AE_SUCCESS; + sgx_target_info_t pce_target_info; + uint16_t pce_isv_svn = 0xFFFF; + memset(&pce_target_info, 0, sizeof(pce_target_info)); + AESM_DBG_INFO("get_quote"); + if(sizeof(sgx_report_t) != report_size || + sizeof(sgx_spid_t) != spid_size) + { + return AESM_PARAMETER_ERROR; + } + if((nonce && sizeof(sgx_quote_nonce_t) != nonce_size) + || (qe_report && sizeof(sgx_report_t) != qe_report_size)) + + { + return AESM_PARAMETER_ERROR; + } + AESMLogicLock lock(_qe_pve_mutex); + CHECK_EPID_PROVISIONG_STATUS; + if(!g_pce_service) + return AESM_SERVICE_UNAVAILABLE; + + ret = g_pce_service->load_enclave(); + if(AE_SUCCESS == ret) + ret = static_cast(g_pce_service->pce_get_target(&pce_target_info, &pce_isv_svn)); + if(AE_SUCCESS != ret) + { + if(AESM_AE_OUT_OF_EPC == ret) + return AESM_OUT_OF_EPC; + else if(AESM_AE_NO_DEVICE == ret) + return AESM_NO_DEVICE_ERROR; + else if(AE_SERVER_NOT_AVAILABLE == ret) + return AESM_SERVICE_UNAVAILABLE; + return AESM_UNEXPECTED_ERROR; + } + return QEAESMLogic::get_quote(report, quote_type, spid, nonce, sigrl, + sigrl_size, qe_report, quote, buf_size, pce_isv_svn); + } + + aesm_error_t get_extended_epid_group_id( + uint32_t* extended_epid_group_id) + { + AESM_DBG_INFO("get_extended_epid_group"); + if (NULL == extended_epid_group_id) + { + return AESM_PARAMETER_ERROR; + } + *extended_epid_group_id = get_active_extended_epid_group_id_internal(); + return AESM_SUCCESS; + } + + aesm_error_t switch_extended_epid_group( + uint32_t extended_epid_group_id) + { + AESM_DBG_INFO("switch_extended_epid_group"); + ae_error_t ae_ret; + if ((ae_ret = XEGDBlob::verify_xegd_by_xgid(extended_epid_group_id)) != AE_SUCCESS || + (ae_ret = EndpointSelectionInfo::verify_file_by_xgid(extended_epid_group_id)) != AE_SUCCESS){ + AESM_DBG_INFO("Fail to switch to extended epid group to %d due to XEGD blob for URL blob not available", extended_epid_group_id); + return AESM_PARAMETER_ERROR; + } + ae_ret = set_global_extended_epid_group_id(extended_epid_group_id); + if (ae_ret != AE_SUCCESS){ + AESM_DBG_INFO("Fail to switch to extended epid group %d", extended_epid_group_id); + return AESM_UNEXPECTED_ERROR; + } + + AESM_DBG_INFO("Succ to switch to extended epid group %d in data file, restart aesm required to use it", extended_epid_group_id); + return AESM_SUCCESS; + } + + uint32_t endpoint_selection( + endpoint_selection_infos_t& es_info) + { + AESMLogicLock lock(_qe_pve_mutex); + SGX_DBGPRINT_ONE_STRING_TWO_INTS_ENDPOINT_SELECTION(__FUNCTION__" (line, 0)", __LINE__, 0); + return EndpointSelectionInfo::instance().start_protocol(es_info); + } + aesm_error_t provision( + bool performance_rekey_used, + uint32_t timeout_usec) + { + AESMLogicLock lock(_qe_pve_mutex); + CHECK_EPID_PROVISIONG_STATUS; + return PvEAESMLogic::provision(performance_rekey_used, timeout_usec); + } + const char *get_server_url( + aesm_network_server_enum_type_t type) + { + return EndpointSelectionInfo::instance().get_server_url(type); + } + const char *get_pse_provisioning_url( + const endpoint_selection_infos_t& es_info) + { + return EndpointSelectionInfo::instance().get_pse_provisioning_url(es_info); + } + uint32_t is_gid_matching_result_in_epid_blob( + const GroupId& gid) + { + AESMLogicLock lock(_qe_pve_mutex); + EPIDBlob& epid_blob = EPIDBlob::instance(); + uint32_t le_gid; + if(epid_blob.get_sgx_gid(&le_gid)!=AE_SUCCESS){//get littlen endian gid + return GIDMT_UNEXPECTED_ERROR; + } + le_gid=_htonl(le_gid);//use bigendian gid + se_static_assert(sizeof(le_gid)==sizeof(gid)); + if(memcmp(&le_gid,&gid,sizeof(gid))!=0){ + return GIDMT_UNMATCHED; + } + return GIDMT_MATCHED; + } +}; + +class Activator : public BundleActivator +{ + void Start(BundleContext ctx) + { + auto service = std::make_shared(); + ctx.RegisterService(service); + } + + void Stop(BundleContext) + { + // Nothing to do + } +}; + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator) + +// [no-cmake] +// The code below is required if the CMake +// helper functions are not used. +#ifdef NO_CMAKE +CPPMICROSERVICES_INITIALIZE_BUNDLE(epid_quote_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/epid_provision/epid_utility.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_utility.cpp similarity index 86% rename from psw/ae/aesm_service/source/epid_provision/epid_utility.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_utility.cpp index 21fa339b..5ff402a5 100644 --- a/psw/ae/aesm_service/source/epid_provision/epid_utility.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_utility.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,28 +31,6 @@ #include "epid_utility.h" -ae_error_t tlv_error_2_pve_error(tlv_status_t tlv_status) -{ - switch(tlv_status){ - case TLV_SUCCESS: - return AE_SUCCESS; - case TLV_INVALID_PARAMETER_ERROR: - return PVE_PARAMETER_ERROR; - case TLV_INVALID_MSG_ERROR: - case TLV_INVALID_FORMAT: - return PVE_MSG_ERROR; - case TLV_INSUFFICIENT_MEMORY: - return PVE_INSUFFICIENT_MEMORY_ERROR; - case TLV_OUT_OF_MEMORY_ERROR: - return AE_OUT_OF_MEMORY_ERROR; - case TLV_UNKNOWN_ERROR: - case TLV_MORE_TLVS: - case TLV_UNSUPPORTED: - return PVE_UNEXPECTED_ERROR; - } - return PVE_UNEXPECTED_ERROR; -} - ae_error_t check_endpoint_pg_stauts(const provision_response_header_t *msg_header) { uint16_t gstatus; diff --git a/psw/ae/aesm_service/source/epid_provision/epid_utility.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_utility.h similarity index 94% rename from psw/ae/aesm_service/source/epid_provision/epid_utility.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_utility.h index 620d76b3..e13e0888 100644 --- a/psw/ae/aesm_service/source/epid_provision/epid_utility.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/epid_utility.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +37,6 @@ #include "arch.h" #include "type_length_value.h" -ae_error_t tlv_error_2_pve_error(tlv_status_t tlv_status); ae_error_t check_endpoint_pg_stauts(const provision_response_header_t *msg_header); ae_error_t check_epid_pve_pg_status_before_mac_verification(const provision_response_header_t *msg_header); ae_error_t check_epid_pve_pg_status_after_mac_verification(const provision_response_header_t *msg_header); diff --git a/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/manifest.json b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/manifest.json new file mode 100644 index 00000000..873c75ac --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/manifest.json @@ -0,0 +1,7 @@ +{ + "bundle.symbolic_name" : "epid_quote_service_symbolic_name", + "bundle.activator" : true, + "bundle.name" : "EPID Quote Service", + "bundle.description" : "This bundle provide EPID Quote Service", + "bundle.version" : "1.0.0" +} diff --git a/psw/ae/aesm_service/source/pve/prov_msg_size.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/prov_msg_size.h similarity index 98% rename from psw/ae/aesm_service/source/pve/prov_msg_size.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/prov_msg_size.h index 0009abdf..7a09a277 100644 --- a/psw/ae/aesm_service/source/pve/prov_msg_size.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/prov_msg_size.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pve/pve_logic.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_logic.cpp similarity index 88% rename from psw/ae/aesm_service/source/pve/pve_logic.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_logic.cpp index 26fce708..fd425abb 100644 --- a/psw/ae/aesm_service/source/pve/pve_logic.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_logic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,19 +34,59 @@ #include "aesm_logic.h" #include "PVEClass.h" #include "QEClass.h" -#include "PCEClass.h" #include "oal/oal.h" #include "aesm_epid_blob.h" #include "se_wrapper.h" #include "prov_msg_size.h" -#include "network_encoding_wrapper.h" +#include "network_service.h" #include "prof_fun.h" #include "aesm_long_lived_thread.h" #include "endpoint_select_info.h" #include +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_network_service; + #define SAFE_FREE(ptr) {if (NULL != (ptr)) {free(ptr); (ptr)=NULL;}} +class EpidProvIOCache:public BaseThreadIOCache{ + bool performance_rekey;//input +protected: + EpidProvIOCache(bool perf_rekey){ + this->performance_rekey = perf_rekey; + } + virtual ae_error_t entry(void); + virtual ThreadStatus& get_thread(); + friend ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout); +public: + virtual bool operator==(const BaseThreadIOCache& oc)const{ + const EpidProvIOCache *p=dynamic_cast(&oc); + if(p==NULL)return false; + return performance_rekey==p->performance_rekey;//only compare input + } +}; +ThreadStatus epid_thread; + +ThreadStatus& EpidProvIOCache::get_thread() +{ + return epid_thread; +} + +ae_error_t EpidProvIOCache::entry() +{ + return ae_ret = PvEAESMLogic::epid_provision_thread_func(performance_rekey); +} + +ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout) +{ + INIT_THREAD(EpidProvIOCache, timeout, (performance_rekey)) + FINI_THREAD() +} + + + //Function to continue process Provisioning logic when the response of ProvMsg1 is ProvMsg2 ae_error_t PvEAESMLogic::process_pve_msg2(pve_data_t& data, const uint8_t* msg2, uint32_t msg2_size, const endpoint_selection_infos_t& es_info) { @@ -57,6 +97,11 @@ ae_error_t PvEAESMLogic::process_pve_msg2(pve_data_t& data, const uint8_t* msg2, epid_blob_with_cur_psvn_t epid_data; ae_error_t ret = AE_SUCCESS; AESM_PROFILE_FUN; + if(!g_network_service){ + AESM_DBG_ERROR("failed to load network service"); + ret = AE_FAILURE; + goto CLEANUP; + } AESM_DBG_DEBUG("enter fun"); AESM_DBG_TRACE("processing msg2 whose length is %d",msg2_size); @@ -95,7 +140,7 @@ ae_error_t PvEAESMLogic::process_pve_msg2(pve_data_t& data, const uint8_t* msg2, } AESM_DBG_TRACE("Start send msg3 and recv msg4"); msg_size = static_cast(GET_SIZE_FROM_PROVISION_REQUEST(msg));//get the real size of ProvMsg3 - ret = AESMNetworkEncoding::aesm_send_recv_msg_encoding(es_info.provision_url, + ret = g_network_service->aesm_send_recv_msg_encoding(es_info.provision_url, msg, msg_size, resp_msg, resp_size); //Encoding ProvMsg3, send to server, receive ProvMsg4 and decode if(ret != AE_SUCCESS){ AESM_LOG_ERROR("%s",g_event_string_table[SGX_EVENT_EPID_PROV_FAILURE]); @@ -117,7 +162,7 @@ ae_error_t PvEAESMLogic::process_pve_msg2(pve_data_t& data, const uint8_t* msg2, CLEANUP: SAFE_FREE(msg); if(resp_msg!=NULL) - AESMNetworkEncoding::aesm_free_response_msg(resp_msg); + g_network_service->aesm_free_response_msg(resp_msg); return ret; } @@ -172,6 +217,11 @@ ae_error_t PvEAESMLogic::update_old_blob(pve_data_t& data, const endpoint_select msg_size = estimate_msg1_size(false); assert(msg_size > 0); + if(!g_network_service){ + AESM_DBG_ERROR("failed to load network service"); + ae_ret = AE_FAILURE; + goto ret_point; + } msg = static_cast(malloc(msg_size)); if(msg == NULL){ @@ -193,7 +243,7 @@ ae_error_t PvEAESMLogic::update_old_blob(pve_data_t& data, const endpoint_select msg_size = static_cast(GET_SIZE_FROM_PROVISION_REQUEST(msg)); AESM_DBG_TRACE("start to send msg1 to server and recv msg4"); - ae_ret = AESMNetworkEncoding::aesm_send_recv_msg_encoding(es_info.provision_url, + ae_ret = g_network_service->aesm_send_recv_msg_encoding(es_info.provision_url, msg, msg_size, resp_msg,resp_size);//encoding/send/receive/decoding if(ae_ret != AE_SUCCESS){ AESM_LOG_ERROR("%s",g_event_string_table[SGX_EVENT_EPID_PROV_FAILURE]); @@ -219,7 +269,7 @@ ae_error_t PvEAESMLogic::update_old_blob(pve_data_t& data, const endpoint_select ret_point: if(msg)free(msg); if(resp_msg!=NULL){ - AESMNetworkEncoding::aesm_free_response_msg(resp_msg); + g_network_service->aesm_free_response_msg(resp_msg); } return (ae_error_t)ae_ret; } @@ -331,7 +381,13 @@ ae_error_t PvEAESMLogic::epid_provision_thread_func(bool performance_rekey_used) uint32_t repeat = 0; endpoint_selection_infos_t es_info; pve_data_t pve_data; - + if(!g_network_service){ + ae_ret = OAL_NETWORK_UNAVAILABLE_ERROR; + AESM_DBG_ERROR("failed to load network service"); + log_provision_result(ae_ret); + return ae_ret; + } + AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_EPID_PROV_START]); memset(&pve_data, 0, sizeof(pve_data)); if(AE_SUCCESS!=(ae_ret=aesm_start_request_wake_execution())){ @@ -382,11 +438,11 @@ ae_error_t PvEAESMLogic::epid_provision_thread_func(bool performance_rekey_used) AESM_DBG_TRACE("msg1 generated with size %d",msg_size); if(resp_msg!=NULL){ - AESMNetworkEncoding::aesm_free_response_msg(resp_msg); + g_network_service->aesm_free_response_msg(resp_msg); resp_msg=NULL; } AESM_DBG_TRACE("start to send prov msg1 and recv response"); - ae_ret = AESMNetworkEncoding::aesm_send_recv_msg_encoding(es_info.provision_url, + ae_ret = g_network_service->aesm_send_recv_msg_encoding(es_info.provision_url, msg,msg_size, resp_msg, resp_size);//encoding/send ProvMsg1, receiving and decoding resp message if(ae_ret != AE_SUCCESS){ AESM_DBG_WARN("send msg1 via network fail:(ae%d)",ae_ret); @@ -433,7 +489,7 @@ ae_error_t PvEAESMLogic::epid_provision_thread_func(bool performance_rekey_used) SAFE_FREE(msg); if(resp_msg!=NULL){ - AESMNetworkEncoding::aesm_free_response_msg(resp_msg); + g_network_service->aesm_free_response_msg(resp_msg); } (void)aesm_stop_request_wake_execution(); diff --git a/psw/ae/aesm_service/source/pve/pve_logic.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_logic.h similarity index 97% rename from psw/ae/aesm_service/source/pve/pve_logic.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_logic.h index 569f6c14..d391bd46 100644 --- a/psw/ae/aesm_service/source/pve/pve_logic.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_logic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pve/pve_pub_key.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_pub_key.cpp similarity index 72% rename from psw/ae/aesm_service/source/pve/pve_pub_key.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_pub_key.cpp index 5f42a734..5072f6f2 100644 --- a/psw/ae/aesm_service/source/pve/pve_pub_key.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/pve_pub_key.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,19 +29,30 @@ * */ -#include "byte_order.h" #include "epid_pve_type.h" #include "ssl_crypto.h" #include "sgx_error.h" +static void get_provision_server_rsa_key_little_endian_order(const signed_pek_t& pek, signed_pek_t& little_endian_key) +{ + uint32_t i; + for(i=0;i(pek.n), - reinterpret_cast(pek.e), + sizeof(little_endian_key.e), + reinterpret_cast(little_endian_key.n), + reinterpret_cast(little_endian_key.e), rsa_pub_key); } diff --git a/psw/ae/aesm_service/source/qe/qe_logic.cpp b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/qe_logic.cpp similarity index 94% rename from psw/ae/aesm_service/source/qe/qe_logic.cpp rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/qe_logic.cpp index d455a08a..b579558b 100644 --- a/psw/ae/aesm_service/source/qe/qe_logic.cpp +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/qe_logic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,7 +43,7 @@ #include "prof_fun.h" #include "util.h" -static ae_error_t get_qe_target(sgx_target_info_t *p_qe_target) +static ae_error_t get_qe_target(sgx_target_info_t *p_qe_target, sgx_isv_svn_t *p_isvsvn) { ae_error_t ae_ret = AE_SUCCESS; @@ -52,14 +52,14 @@ static ae_error_t get_qe_target(sgx_target_info_t *p_qe_target) AESM_DBG_ERROR("Fail to load QE:(ae%d)",ae_ret); return ae_ret; } - ae_ret = static_cast(CQEClass::instance().get_qe_target(p_qe_target)); + ae_ret = static_cast(CQEClass::instance().get_qe_target(p_qe_target, p_isvsvn)); if(ae_ret != AE_SUCCESS) return ae_ret; return AE_SUCCESS; } //Function to do reprovision if flag updated is false and set it to true if updated successfully -//The flag updated is used to simpilify logic in caller's code so that provision will not be invoked again +//The flag updated is used to simpilify logic in caller's code so that provision will not be invoked again //if a previous provision has been successfully run //After reprovision, the output epid_blob will be copied into output parameter epid_data static aesm_error_t try_reprovision_if_not(bool& updated, epid_blob_with_cur_psvn_t& epid_data) @@ -88,13 +88,13 @@ static aesm_error_t try_reprovision_if_not(bool& updated, epid_blob_with_cur_psv return AESM_SUCCESS; } +extern uint32_t get_active_extended_epid_group_id_internal(); //Function to fetch gid from Epid Data Blob and also return target info //EPID Provisioning will be redone if Epid Data Blob is not existing/invalid or // the qe_isv_svn or cpu_svn don't match that in Epid Data Blob aesm_error_t QEAESMLogic::init_quote( sgx_target_info_t *target, - uint8_t *gid, uint32_t gid_size, uint16_t pce_isv_svn, - uint16_t qe_isv_svn, const sgx_cpu_svn_t qe_cpu_svn) + uint8_t *gid, uint32_t gid_size, uint16_t pce_isv_svn) { ae_error_t ae_ret = AE_SUCCESS; EPIDBlob& epid_blob = EPIDBlob::instance(); @@ -106,9 +106,12 @@ aesm_error_t QEAESMLogic::init_quote( epid_blob_with_cur_psvn_t epid_data; bool resealed = false; bool updated = false; + uint16_t qe_isv_svn = 0xFFFF; + sgx_cpu_svn_t qe_cpu_svn; + memset(&qe_cpu_svn, 0, sizeof(qe_cpu_svn)); memset(&epid_data,0,sizeof(epid_data)); - uint32_t xegd_xeid = AESMLogic::get_active_extended_epid_group_id(); + uint32_t xegd_xeid = get_active_extended_epid_group_id_internal(); AESM_DBG_TRACE("start read and verify old epid blob"); uint32_t epid_xeid = 0; //EPID BLOB not exist @@ -148,7 +151,7 @@ aesm_error_t QEAESMLogic::init_quote( } } - ae_ret = get_qe_target(target); + ae_ret = get_qe_target(target, &qe_isv_svn); if(ae_ret!=AE_SUCCESS){ AESM_DBG_ERROR("get qe target failed (ae%d)",ae_ret); if(ae_ret==AESM_AE_OUT_OF_EPC) @@ -163,7 +166,7 @@ aesm_error_t QEAESMLogic::init_quote( se_static_assert(SGX_TRUSTED_EPID_BLOB_SIZE_SDK>=SGX_TRUSTED_EPID_BLOB_SIZE_SIK); ae_ret = static_cast(CQEClass::instance().verify_blob(epid_data.trusted_epid_blob, SGX_TRUSTED_EPID_BLOB_SIZE_SDK, - &resealed)); + &resealed, &qe_cpu_svn)); if(ae_ret == QE_EPIDBLOB_ERROR){ (void)epid_blob.remove(); if(AESM_SUCCESS!=(aesm_result = try_reprovision_if_not(updated, epid_data))){ @@ -175,7 +178,7 @@ aesm_error_t QEAESMLogic::init_quote( aesm_result = AESM_OUT_OF_EPC; goto ret_point; } - else if(ae_ret != AE_SUCCESS) + else if(ae_ret != AE_SUCCESS) { aesm_result = AESM_UNEXPECTED_ERROR; goto ret_point; diff --git a/psw/ae/aesm_service/source/qe/qe_logic.h b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/qe_logic.h similarity index 91% rename from psw/ae/aesm_service/source/qe/qe_logic.h rename to psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/qe_logic.h index ab86384f..7cd42ac2 100644 --- a/psw/ae/aesm_service/source/qe/qe_logic.h +++ b/psw/ae/aesm_service/source/bundles/epid_quote_service_bundle/qe_logic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,8 +45,7 @@ class QEAESMLogic{ public: static aesm_error_t init_quote(sgx_target_info_t *target_info, - uint8_t *gid, uint32_t gid_size, uint16_t pce_isv_svn, - uint16_t qe_isv_svn, const sgx_cpu_svn_t qe_cpu_svn); + uint8_t *gid, uint32_t gid_size, uint16_t pce_isv_svn); static aesm_error_t get_quote(const uint8_t *report, uint32_t quote_type, diff --git a/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/CMakeLists.txt new file mode 100644 index 00000000..99e946bc --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/CMakeLists.txt @@ -0,0 +1,31 @@ +if(REF_LE) + set(Edger8rOutputLE "${CMAKE_CURRENT_BINARY_DIR}/ref_le_u.c") + set(Edger8rEDLLE "${PROJECT_SOURCE_DIR}/../../ref_le/ref_le.edl") +else() + set(Edger8rOutputLE "${CMAKE_CURRENT_BINARY_DIR}/launch_enclave_u.c") + set(Edger8rEDLLE "${PROJECT_SOURCE_DIR}/../../le/launch_enclave.edl") +endif() + +get_filename_component(bundle ${CMAKE_CURRENT_SOURCE_DIR} NAME) +aux_source_directory(. _srcs) +link_directories(${CMAKE_SOURCE_DIR}/../../../../build/linux) +CreateBundle(${bundle} ${_srcs} ${Edger8rOutputLE}) + +target_include_directories(${bundle} PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk + ${PROJECT_SOURCE_DIR}/../../../../external/ippcp_internal/inc +) + +add_custom_command( + OUTPUT ${Edger8rOutputLE} + COMMAND ${PROJECT_SOURCE_DIR}/../../../../build/linux/sgx_edger8r --untrusted --untrusted-dir ${CMAKE_CURRENT_BINARY_DIR} ${Edger8rEDLLE} --search-path ${PROJECT_SOURCE_DIR}/../../../../common/inc + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries(${bundle} oal utils urts_internal) +set_property(TARGET ${bundle} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/le/LEClass.cpp b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/LEClass.cpp similarity index 90% rename from psw/ae/aesm_service/source/le/LEClass.cpp rename to psw/ae/aesm_service/source/bundles/le_launch_service_bundle/LEClass.cpp index 99888a0e..9c19bb64 100644 --- a/psw/ae/aesm_service/source/le/LEClass.cpp +++ b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/LEClass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,22 +37,60 @@ #include "util.h" #include "service_enclave_mrsigner.hh" #include "aesm_long_lived_thread.h" +#include "aesm_config.h" #ifdef REF_LE #include "ref_le_u.h" -#include "ref_le_u.c" #else #include "launch_enclave_u.h" -#include "launch_enclave_u.c" extern "C" sgx_status_t sgx_create_le(const char *file_name, const char *prd_css_file_name, const int debug, sgx_launch_token_t *launch_token, int *launch_token_updated, sgx_enclave_id_t *enclave_id, sgx_misc_attribute_t *misc_attr, int *production_loaded); extern "C" bool is_in_kernel_driver(); #endif +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; + +extern AESMLogicMutex _le_mutex; +extern std::shared_ptr g_network_service; + +ThreadStatus white_list_thread; +class WhiteListIOCache :public BaseThreadIOCache{ +//no input to be cached for white list pulling +protected: + WhiteListIOCache(void){ + } + virtual ae_error_t entry(void); + virtual ThreadStatus& get_thread(); + friend ae_error_t start_white_list_thread(unsigned long timeout); +public: + virtual bool operator==(const BaseThreadIOCache& oc)const{ + const WhiteListIOCache *p = dynamic_cast(&oc); + if (p == NULL) return false; + return true; + } +}; +ThreadStatus& WhiteListIOCache::get_thread() +{ + return white_list_thread; +} + +ae_error_t WhiteListIOCache::entry() +{ + return ae_ret = CLEClass::update_white_list_by_url(); +} + + +ae_error_t start_white_list_thread(unsigned long timeout) +{ + INIT_THREAD(WhiteListIOCache, timeout, ()) + FINI_THREAD() +} int CLEClass::white_list_register( const uint8_t *white_list_cert, @@ -62,7 +100,7 @@ int CLEClass::white_list_register( sgx_status_t ret = SGX_SUCCESS; int retry = 0; uint32_t status = 0; - AESMLogicLock locker(AESMLogic::_le_mutex); + AESMLogicLock locker(_le_mutex); assert(m_enclave_id); #ifdef REF_LE @@ -72,7 +110,7 @@ int CLEClass::white_list_register( AESM_DBG_WARN("white list size is smaller than the expected minimum"); return AE_INVALID_PARAMETER; } - + ref_le_white_list_t *p_white_list = (ref_le_white_list_t*)white_list_cert; uint32_t entries_count = _ntohs(p_white_list->entries_count); uint32_t white_list_size = REF_LE_WL_SIZE(entries_count); @@ -90,7 +128,7 @@ int CLEClass::white_list_register( if (white_list_cert_size < sizeof(wl_cert_chain_t)) { return LE_INVALID_PARAMETER; } - + ret = le_init_white_list_wrapper(m_enclave_id, &status, const_cast(white_list_cert), white_list_cert_size); @@ -130,7 +168,6 @@ void CLEClass::load_white_cert_list() load_white_cert_list_to_be_verify();//If this version is older than previous one, it will not be loaded } #include -#include "endpoint_select_info.h" #include "stdint.h" #define UPDATE_DURATION (24*3600) @@ -154,12 +191,16 @@ ae_error_t CLEClass::update_white_list_by_url() for (i = 0; i < 2; i++){//at most retry once if network error uint8_t *resp_buf = NULL; uint32_t resp_size = 0; - const char *url = EndpointSelectionInfo::instance().get_server_url(SGX_WHITE_LIST_FILE); - if (NULL == url){ + aesm_config_infos_t urls = {0}; + if(false == read_aesm_config(urls)){ return OAL_CONFIG_FILE_ERROR; } - ret = aesm_network_send_receive(url, - NULL, 0, &resp_buf, &resp_size,GET, false); + if(!g_network_service){ + AESM_DBG_WARN("Network failure in getting white list..."); + continue; + } + ret = g_network_service->aesm_send_recv_msg(urls.white_list_url, + NULL, 0, resp_buf, resp_size, GET, false); if (ret == OAL_NETWORK_UNAVAILABLE_ERROR){ AESM_DBG_WARN("Network failure in getting white list..."); continue; @@ -179,7 +220,7 @@ ae_error_t CLEClass::update_white_list_by_url() } } last_updated_time = cur_time; - aesm_free_network_response_buffer(resp_buf); + if(g_network_service) g_network_service->aesm_free_response_msg(resp_buf); } break; } @@ -288,7 +329,7 @@ ae_error_t CLEClass::load_enclave_only() UNUSED(production_le_loaded); ret = sgx_create_enclave(enclave_path, get_debug_flag(), &m_launch_token, &launch_token_update, &m_enclave_id, - &m_attributes);//simulation or ref_le mode has no sgx_create_le function. Use sgx_create_enclave + &m_attributes);//simulation or ref_le mode has no sgx_create_le function. Use sgx_create_enclave if(ret != SGX_SUCCESS){ AESM_DBG_ERROR("Fail to load LE"); return AE_FAILURE; @@ -344,7 +385,7 @@ ae_error_t CLEClass::load_enclave() return ae_err; } -int CLEClass::get_launch_token( +int CLEClass::get_launch_token_internal( uint8_t * mrenclave, uint32_t mrenclave_size, uint8_t *public_key, uint32_t public_key_size, uint8_t *se_attributes, uint32_t se_attributes_size, diff --git a/psw/ae/aesm_service/source/le/LEClass.h b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/LEClass.h similarity index 95% rename from psw/ae/aesm_service/source/le/LEClass.h rename to psw/ae/aesm_service/source/bundles/le_launch_service_bundle/LEClass.h index 8fd0dce2..13fd7e98 100644 --- a/psw/ae/aesm_service/source/le/LEClass.h +++ b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/LEClass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,7 @@ #include "arch.h" #include "AEClass.h" #include "ae_debug_flag.hh" +#include "network_service.h" class CLEClass: public SingletonEnclave { @@ -51,7 +52,7 @@ protected: bool m_ufd; // if LEClass considers the platform ufd public: virtual ae_error_t load_enclave();/*overload LE load enclave function since i) we have two different LE SigStruct now, ii) we need load white list*/ - int get_launch_token( + int get_launch_token_internal( uint8_t * mrenclave, uint32_t mrenclave_size, uint8_t *mrsigner, uint32_t mrsigner_size, uint8_t *se_attributes, uint32_t se_attributes_size, diff --git a/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/le_launch_service_bundle.cpp b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/le_launch_service_bundle.cpp new file mode 100644 index 00000000..2f2b6ea8 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/le_launch_service_bundle.cpp @@ -0,0 +1,472 @@ +#include + + +#include "aesm_logic.h" +#include "service_enclave_mrsigner.hh" +#include "LEClass.h" +#include "aesm_long_lived_thread.h" + +#include +#include "cppmicroservices/BundleContext.h" +#include +#include "cppmicroservices_util.h" +using namespace cppmicroservices; + +AESMLogicMutex _le_mutex; +std::shared_ptr g_network_service; + + +extern "C" bool is_in_kernel_driver(); +extern ae_error_t start_white_list_thread(unsigned long timeout=THREAD_TIMEOUT); +extern ThreadStatus white_list_thread; + +class LeLaunchServiceImp : public ILaunchService +{ +private: + bool _is_qe_psvn_set; + bool _is_pse_psvn_set; + bool _is_pce_psvn_set; + psvn_t _qe_psvn; + psvn_t _pce_psvn; + psvn_t _pse_psvn; + bool initialized; + + ae_error_t save_unverified_white_list(const uint8_t *white_list_cert, uint32_t white_list_cert_size) + { + wl_cert_chain_t old_cert; + const wl_cert_chain_t *p_new_cert = reinterpret_cast(white_list_cert); + uint32_t old_cert_size = sizeof(old_cert); + memset(&old_cert, 0, sizeof(old_cert)); + if((aesm_read_data(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_TO_BE_VERIFY_FID, reinterpret_cast(&old_cert), &old_cert_size) == AE_SUCCESS) + && (old_cert_size == sizeof(old_cert)) && (white_list_cert_size >= sizeof(wl_cert_chain_t))) + { + if(_ntohl(p_new_cert->wl_cert.wl_version) <= _ntohl(old_cert.wl_cert.wl_version)) + { + AESM_DBG_WARN("White list version downgraded! current version is %d, new version is %d", + _ntohl(old_cert.wl_cert.wl_version), _ntohl(p_new_cert->wl_cert.wl_version)); + return OAL_PARAMETER_ERROR; // OAL_PARAMETER_ERROR used here is to indicate the white list is incorrect + } + } + return aesm_write_data(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_TO_BE_VERIFY_FID, white_list_cert, white_list_cert_size); + } + ae_error_t set_psvn(uint16_t prod_id, uint16_t isv_svn, sgx_cpu_svn_t cpu_svn, uint32_t mrsigner_index) + { + if(prod_id == QE_PROD_ID){ + if(mrsigner_index == AE_MR_SIGNER){ + if(_is_qe_psvn_set){ + if(0!=memcmp(&_qe_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| + 0!=memcmp(&_qe_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ + AESM_DBG_ERROR("PSVN unmatched for QE/PVE"); + return AE_PSVN_UNMATCHED_ERROR; + } + }else{ + if(0!=memcpy_s(&_qe_psvn.isv_svn, sizeof(_qe_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| + 0!=memcpy_s(&_qe_psvn.cpu_svn, sizeof(_qe_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ + AESM_DBG_ERROR("memcpy failed"); + return AE_FAILURE; + } + AESM_DBG_TRACE("get QE or PvE isv_svn=%d",(int)isv_svn); + _is_qe_psvn_set = true; + return AE_SUCCESS; + } + }else if(mrsigner_index==PCE_MR_SIGNER){ + if(_is_pce_psvn_set){ + if(0!=memcmp(&_pce_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| + 0!=memcmp(&_pce_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ + AESM_DBG_ERROR("PSVN unmatched for PCE"); + return AE_PSVN_UNMATCHED_ERROR; + } + }else{ + if(0!=memcpy_s(&_pce_psvn.isv_svn, sizeof(_pce_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| + 0!=memcpy_s(&_pce_psvn.cpu_svn, sizeof(_pce_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ + AESM_DBG_ERROR("memcpy failed"); + return AE_FAILURE; + } + AESM_DBG_TRACE("get PCE isv_svn=%d", (int)isv_svn); + _is_pce_psvn_set = true; + return AE_SUCCESS; + } + } + }else if(prod_id == PSE_PROD_ID){ + if(mrsigner_index == AE_MR_SIGNER){ + if(_is_pse_psvn_set){ + if(0!=memcmp(&_pse_psvn.isv_svn, &isv_svn, sizeof(isv_svn))|| + 0!=memcmp(&_pse_psvn.cpu_svn, &cpu_svn, sizeof(sgx_cpu_svn_t))){ + AESM_DBG_ERROR("PSVN unmatched for PSE"); + return AE_PSVN_UNMATCHED_ERROR; + } + }else{ + if(0!=memcpy_s(&_pse_psvn.isv_svn, sizeof(_pse_psvn.isv_svn), &isv_svn, sizeof(isv_svn))|| + 0!=memcpy_s(&_pse_psvn.cpu_svn, sizeof(_pse_psvn.cpu_svn), &cpu_svn, sizeof(sgx_cpu_svn_t))){ + AESM_DBG_ERROR("memcpy failed"); + return AE_FAILURE; + } + AESM_DBG_TRACE("get PSE isv_svn=%d", (int)isv_svn); + _is_pse_psvn_set = true; + return AE_SUCCESS; + } + } + } + return AE_SUCCESS; + } + + ae_error_t get_white_list_size_without_lock(uint32_t *white_list_cert_size) + { + uint32_t white_cert_size = 0; + ae_error_t ae_ret = aesm_query_data_size(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_FID, &white_cert_size); + if (AE_SUCCESS == ae_ret) + { + if (white_cert_size != 0) + { //file existing and not 0 size + *white_list_cert_size = white_cert_size; + return AE_SUCCESS; + } + else + return AE_FAILURE; + } + else + { + return ae_ret; + } + } + + public: + LeLaunchServiceImp() + : _is_qe_psvn_set(false), + _is_pse_psvn_set(false), + _is_pce_psvn_set(false), + _qe_psvn({0}), + _pce_psvn({0}), + _pse_psvn({0}), + initialized(false) + { + } + + ae_error_t start() + { + ae_error_t ae_ret = AE_SUCCESS; + if (initialized == true) + { + AESM_DBG_INFO("le bundle has been started"); + return AE_SUCCESS; + } + + AESM_DBG_INFO("Starting le bundle"); + ae_ret = CLEClass::instance().load_enclave(); + if(AE_SUCCESS != ae_ret) + { + AESM_DBG_INFO("fail to load LE: %d", ae_ret); + //AESM_LOG_FATAL("%s", g_event_string_table[SGX_EVENT_SERVICE_UNAVAILABLE]); + return ae_ret; + } + + get_service_wrapper(g_network_service); + start_white_list_thread(); + initialized = true; + AESM_DBG_INFO("le bundle started"); + return AE_SUCCESS; + } + void stop() + { + uint64_t stop_tick_count = se_get_tick_count()+500/1000; + white_list_thread.stop_thread(stop_tick_count); + CLEClass::instance().unload_enclave(); + AESM_DBG_INFO("le bundle stopped"); + } + + aesm_error_t get_launch_token( + const uint8_t *mrenclave, uint32_t mrenclave_size, + const uint8_t *public_key, uint32_t public_key_size, + const uint8_t *se_attributes, uint32_t se_attributes_size, + uint8_t *lictoken, uint32_t lictoken_size) + { + AESM_DBG_INFO("enter function"); + AESMLogicLock lock(_le_mutex); + + ae_error_t ret_le = AE_SUCCESS; + if (NULL == mrenclave || + NULL == public_key || + NULL == se_attributes || + NULL == lictoken) + { + // Sizes are checked in get_launch_token_internal() + AESM_DBG_TRACE("Invalid parameter"); + return AESM_PARAMETER_ERROR; + } + if (is_in_kernel_driver()) + { + //Should not be called + AESM_LOG_ERROR("InKernel LE loaded"); + return AESM_SERVICE_UNAVAILABLE; + } + ae_error_t ae_ret = CLEClass::instance().load_enclave(); + if(ae_ret == AE_SERVER_NOT_AVAILABLE) + { + AESM_LOG_ERROR("%s", g_event_string_table[SGX_EVENT_SERVICE_UNAVAILABLE]); + AESM_DBG_FATAL("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); + return AESM_NO_DEVICE_ERROR; + } + else if(ae_ret == AESM_AE_OUT_OF_EPC) + { + AESM_DBG_ERROR("LE not loaded due to out of EPC"); + return AESM_OUT_OF_EPC; + } + else if(AE_FAILED(ae_ret)) + { + AESM_DBG_ERROR("LE not loaded:%d", ae_ret); + return AESM_SERVICE_UNAVAILABLE; + } + ret_le = static_cast(CLEClass::instance().get_launch_token_internal( + const_cast(mrenclave), mrenclave_size, + const_cast(public_key), public_key_size, + const_cast(se_attributes), se_attributes_size, + lictoken, lictoken_size)); + + switch (ret_le) + { + case AE_SUCCESS: + return AESM_SUCCESS; + case LE_INVALID_PARAMETER: + AESM_DBG_TRACE("Invalid parameter"); + return AESM_PARAMETER_ERROR; + case LE_INVALID_ATTRIBUTE: + case LE_INVALID_PRIVILEGE_ERROR: + AESM_DBG_TRACE("Launch token error"); + return AESM_GET_LICENSETOKEN_ERROR; + case LE_WHITELIST_UNINITIALIZED_ERROR: + AESM_DBG_TRACE("LE whitelist uninitialized error"); + return AESM_UNEXPECTED_ERROR; + default: + AESM_DBG_WARN("unexpeted error (ae %d)", ret_le); + return AESM_UNEXPECTED_ERROR; + } + } + + sgx_status_t get_launch_token(const enclave_css_t* signature, + const sgx_attributes_t* attribute, + sgx_launch_token_t* launch_token) + { + AESM_DBG_INFO("enter function"); + AESMLogicLock lock(_le_mutex); + + ae_error_t ret_le = AE_SUCCESS; + uint32_t mrsigner_index = UINT32_MAX; + + if (is_in_kernel_driver()) + { + //Should not be called + AESM_LOG_ERROR("InKernel LE loaded"); + return SGX_ERROR_SERVICE_UNAVAILABLE; + } + // load LE to get launch token + if((ret_le=CLEClass::instance().load_enclave()) != AE_SUCCESS) + { + if(ret_le == AESM_AE_NO_DEVICE) + { + AESM_DBG_FATAL("LE not loaded due to no SGX device available, possible SGX Env Not Ready"); + return SGX_ERROR_NO_DEVICE; + } + else if(ret_le == AESM_AE_OUT_OF_EPC) + { + AESM_DBG_FATAL("LE not loaded due to out of EPC"); + return SGX_ERROR_OUT_OF_EPC; + } + else + { + AESM_DBG_FATAL("fail to load LE:%d",ret_le); + return SGX_ERROR_SERVICE_UNAVAILABLE; + } + } + + ret_le = static_cast(CLEClass::instance().get_launch_token_internal( + const_cast(reinterpret_cast(&signature->body.enclave_hash)), + sizeof(sgx_measurement_t), + const_cast(reinterpret_cast(&signature->key.modulus)), + sizeof(signature->key.modulus), + const_cast(reinterpret_cast(attribute)), + sizeof(sgx_attributes_t), + reinterpret_cast(launch_token), + sizeof(token_t), + &mrsigner_index)); + switch (ret_le) + { + case AE_SUCCESS: + break; + case LE_INVALID_PARAMETER: + AESM_DBG_TRACE("Invalid parameter"); + return SGX_ERROR_INVALID_PARAMETER; + case LE_INVALID_ATTRIBUTE: + case LE_INVALID_PRIVILEGE_ERROR: + AESM_DBG_TRACE("Launch token error"); + return SGX_ERROR_SERVICE_INVALID_PRIVILEGE; + case LE_WHITELIST_UNINITIALIZED_ERROR: + AESM_DBG_TRACE("LE whitelist uninitialized error"); + return SGX_ERROR_UNEXPECTED; + default: + AESM_DBG_WARN("unexpected error (ae%d)", ret_le); + return SGX_ERROR_UNEXPECTED; + } + + token_t *lt = reinterpret_cast(launch_token); + ret_le = set_psvn(signature->body.isv_prod_id, signature->body.isv_svn, lt->cpu_svn_le, mrsigner_index); + if(AE_PSVN_UNMATCHED_ERROR == ret_le) + { + //QE or PSE has been changed, but AESM doesn't restart. Will not provide service. + return SGX_ERROR_SERVICE_UNAVAILABLE; + }else if(AE_SUCCESS != ret_le) { + AESM_DBG_ERROR("fail to save psvn:(ae%d)", ret_le); + return SGX_ERROR_UNEXPECTED; + } + + return SGX_SUCCESS; + } + + aesm_error_t get_white_list( + uint8_t *white_list_cert, uint32_t buf_size) + { + uint32_t white_cert_size = 0; + if (NULL == white_list_cert) + { + return AESM_PARAMETER_ERROR; + } + AESMLogicLock lock(_le_mutex); + if (is_in_kernel_driver()) + { + AESM_LOG_INFO("InKernel LE loaded"); + return AESM_SERVICE_UNAVAILABLE; + } + ae_error_t ae_ret = get_white_list_size_without_lock(&white_cert_size); + if (AE_SUCCESS != ae_ret) + return AESM_UNEXPECTED_ERROR; + if (white_cert_size != buf_size) + { + return AESM_PARAMETER_ERROR; + } + + ae_ret = aesm_read_data(FT_PERSISTENT_STORAGE, AESM_WHITE_LIST_CERT_FID, white_list_cert, &white_cert_size); + if (AE_SUCCESS != ae_ret) + { + AESM_DBG_WARN("Fail to read white cert list file"); + return AESM_UNEXPECTED_ERROR; + } + return AESM_SUCCESS; + } + + aesm_error_t get_white_list_size( + uint32_t *white_list_cert_size) + { + if (NULL == white_list_cert_size) + { + return AESM_PARAMETER_ERROR; + } + AESMLogicLock lock(_le_mutex); + if (is_in_kernel_driver()) + { + AESM_LOG_INFO("InKernel LE loaded"); + return AESM_SERVICE_UNAVAILABLE; + } + ae_error_t ae_ret = get_white_list_size_without_lock(white_list_cert_size); + if (AE_SUCCESS == ae_ret) + return AESM_SUCCESS; + else + return AESM_UNEXPECTED_ERROR; + } + + aesm_error_t white_list_register( + const uint8_t *white_list_cert, + uint32_t white_list_cert_size) + { + AESM_DBG_INFO("enter function"); + AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_START]); + AESMLogicLock lock(_le_mutex); + ae_error_t ret_le = AE_SUCCESS; + aesm_error_t ret = AESM_UNEXPECTED_ERROR; + if (NULL == white_list_cert || 0 == white_list_cert_size) + { + AESM_DBG_TRACE("Invalid parameter"); + AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_FAIL]); + return AESM_PARAMETER_ERROR; + } + if (is_in_kernel_driver()) + { + AESM_DBG_INFO("InKernel LE loaded"); + return AESM_SERVICE_UNAVAILABLE; + } + + ae_error_t ae_ret = CLEClass::instance().load_enclave(); + if (AE_FAILED(ae_ret)) + { + switch (ae_ret) + { + case AE_SERVER_NOT_AVAILABLE: + AESM_DBG_WARN("LE not loaded due to AE_SERVER_NOT_AVAILABLE, possible SGX Env Not Ready"); + ret_le = save_unverified_white_list(white_list_cert, white_list_cert_size); + break; + case AESM_AE_OUT_OF_EPC: + AESM_DBG_WARN("LE not loaded due to out of EPC"); + ret = AESM_OUT_OF_EPC; + goto exit; + default: + AESM_DBG_ERROR("LE not loaded:(ae%d)", ae_ret); + ret = AESM_UNEXPECTED_ERROR; + goto exit; + } + } + else + { + ret_le = static_cast(CLEClass::instance().white_list_register( + white_list_cert, white_list_cert_size, true)); + } + + switch (ret_le) + { + case AE_SUCCESS: + ret = AESM_SUCCESS; + break; + case LE_INVALID_PARAMETER: + AESM_DBG_TRACE("Invalid parameter"); + ret = AESM_PARAMETER_ERROR; + break; + default: + AESM_DBG_WARN("unexpeted error (ae %d)", ret_le); + ret = AESM_UNEXPECTED_ERROR; + break; + } + + exit: + // Always log success or failure to the Admin log before returning + if (AE_FAILED(ae_ret) || AE_FAILED(ret_le)) + { + AESM_LOG_ERROR_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_FAIL]); + } else { + const wl_cert_chain_t* wl = reinterpret_cast(white_list_cert); + AESM_LOG_INFO_ADMIN("%s for Version: %d", g_admin_event_string_table[SGX_ADMIN_EVENT_WL_UPDATE_SUCCESS], + _ntohl(wl->wl_cert.wl_version)); + } + + return ret; + } +}; + +class Activator : public BundleActivator +{ + void Start(BundleContext ctx) + { + auto service = std::make_shared(); + ctx.RegisterService(service); + } + + void Stop(BundleContext) + { + // Nothing to do + } +}; + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator) + +// [no-cmake] +// The code below is required if the CMake +// helper functions are not used. +#ifdef NO_CMAKE +CPPMICROSERVICES_INITIALIZE_BUNDLE(le_launch_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/manifest.json b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/manifest.json new file mode 100644 index 00000000..8104a27d --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/le_launch_service_bundle/manifest.json @@ -0,0 +1,7 @@ +{ + "bundle.symbolic_name" : "le_launch_service_symbolic_name", + "bundle.activator" : true, + "bundle.name" : "LE Launch Service", + "bundle.description" : "This bundle provide LE launch Service", + "bundle.version" : "1.0.0" +} diff --git a/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/CMakeLists.txt new file mode 100644 index 00000000..bb41b179 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/CMakeLists.txt @@ -0,0 +1,22 @@ +find_package(CURL REQUIRED) +if(CURL_FOUND) + message ("CURL found") +else() + message (FATAL_ERROR "Cannot find CURL") +endif() +get_filename_component(bundle ${CMAKE_CURRENT_SOURCE_DIR} NAME) +aux_source_directory(. _srcs) +CreateBundle(${bundle} ${_srcs}) + +target_include_directories(${bundle} PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/common/oal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk +) + +target_link_libraries(${bundle} ${CURL_LIBRARIES} oal utils) +set_property(TARGET ${bundle} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_encode.cpp b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_encode.cpp similarity index 98% rename from psw/ae/aesm_service/source/aesm/extension/aesm_encode.cpp rename to psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_encode.cpp index ffddcdbd..57e3d16c 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_encode.cpp +++ b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_encode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,15 +33,15 @@ #include "aesm_encode.h" #include "se_memcpy.h" #include "AEClass.h" -#include "PVEClass.h" +//#include "PVEClass.h" #include "tlv_common.h" #include #include #include #include #include -#include "upse/helper.h" -#include "upse/Buffer.h" +#include "helper.h" +#include "Buffer.h" /** * Method converts byte containing value from 0x00-0x0F into its corresponding ASCII code, * e.g. converts 0x00 to '0', 0x0A to 'A'. diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_http_msg.cpp b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_http_msg.cpp similarity index 92% rename from psw/ae/aesm_service/source/aesm/extension/aesm_http_msg.cpp rename to psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_http_msg.cpp index 030757f7..6c1821d3 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_http_msg.cpp +++ b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_http_msg.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,7 +36,8 @@ #include "se_wrapper.h" #include "prof_fun.h" #include "aesm_proxy_type.h" -#include "endpoint_select_info.h" +#include "aesm_network.h" +#include "aesm_config.h" #include "util.h" #include @@ -47,7 +48,6 @@ #define AESM_DEFAULT_CONN_TIME_OUT 1000 #define AESM_DEFAULT_TIME_OUT 10000 -bool is_curl_initialized_succ(void);//network is available only when curl library is successfully initialized typedef struct _network_malloc_info_t{ char *base; @@ -97,18 +97,16 @@ static ae_error_t http_network_init(CURL **curl, const char *url, bool is_ocsp) CURLcode cc = CURLE_OK; UNUSED(is_ocsp); AESM_DBG_TRACE("http init for url %s",url); - if(!is_curl_initialized_succ()){ - AESM_DBG_ERROR("libcurl not initialized"); - return AE_FAILURE;//fatal error that libcurl could not be initialized - } + if(NULL == url){ AESM_DBG_ERROR("NULL url"); return AE_FAILURE; } std::string url_path = url; - uint32_t proxy_type; - char proxy_url[MAX_PATH]; - EndpointSelectionInfo::instance().get_proxy(proxy_type, proxy_url); + aesm_config_infos_t urls = {0}; + if(false == read_aesm_config(urls)){ + return AE_FAILURE; + } *curl = curl_easy_init(); if(!*curl){ @@ -122,12 +120,12 @@ static ae_error_t http_network_init(CURL **curl, const char *url, bool is_ocsp) } (void)curl_easy_setopt(*curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); //setting proxy now - if(proxy_type == AESM_PROXY_TYPE_DIRECT_ACCESS){ + if(urls.proxy_type == AESM_PROXY_TYPE_DIRECT_ACCESS){ AESM_DBG_TRACE("use no proxy"); (void)curl_easy_setopt(*curl, CURLOPT_NOPROXY , "*"); - }else if(proxy_type == AESM_PROXY_TYPE_MANUAL_PROXY){ - AESM_DBG_TRACE("use manual proxy %s",proxy_url); - (void)curl_easy_setopt(*curl, CURLOPT_PROXY, proxy_url); + }else if(urls.proxy_type == AESM_PROXY_TYPE_MANUAL_PROXY){ + AESM_DBG_TRACE("use manual proxy %s",urls.aesm_proxy); + (void)curl_easy_setopt(*curl, CURLOPT_PROXY, urls.aesm_proxy); } return AE_SUCCESS; } diff --git a/psw/ae/aesm_service/include/oal/aesm_network.h b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_network.h similarity index 92% rename from psw/ae/aesm_service/include/oal/aesm_network.h rename to psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_network.h index 78f3347c..ccac63ee 100644 --- a/psw/ae/aesm_service/include/oal/aesm_network.h +++ b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/aesm_network.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,23 +33,13 @@ #define _AESM_NETWORK_H_ #include "aeerror.h" #include "se_types.h" +#include "network_service.h" /** * File: aesm_network.h * Description: Definition for interface of HTTP/HTTPS network communication used in AESM */ -typedef enum _network_protocol_type_t -{ - HTTP = 0, - HTTPS, -} network_protocol_type_t; - -typedef enum _http_methods_t -{ - GET = 0, - POST, -} http_methods_t; /*Function to send data to a server and receive the response *@server_url: provide the url of the server diff --git a/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/linux_network_service_bundle.cpp b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/linux_network_service_bundle.cpp new file mode 100644 index 00000000..8d2d9ef0 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/linux_network_service_bundle.cpp @@ -0,0 +1,170 @@ +#include + +#include + +#include +#include + +#include "oal/oal.h" +#include "aesm_encode.h" +#include "aesm_network.h" + +using namespace cppmicroservices; + +class LinuxNetworkServiceImp : public INetworkService +{ +private: + ae_error_t aesm_send_recv_msg_encoding_internal( + const char *url, + const uint8_t * msg, + uint32_t msg_size, + uint8_t* &resp, + uint32_t& resp_size) + { + resp = NULL; + resp_size = 0; + + ae_error_t ae_ret = AE_SUCCESS; + uint8_t *encode_msg = NULL; + uint32_t encoding_size = get_request_encoding_length(msg); + uint8_t *recv_msg = NULL; + uint32_t decode_buffer_size = 0; + uint32_t recv_size = 0; + if(encoding_size == 0){ + AESM_DBG_WARN("invalid msg_size 0 to send to url:%s", url); + ae_ret = AE_FAILURE; + goto ret_point; + } + encode_msg = reinterpret_cast(malloc(encoding_size)); + if(encode_msg == NULL){ + AESM_DBG_ERROR("malloc failed"); + ae_ret = AE_OUT_OF_MEMORY_ERROR; + goto ret_point; + } + #ifdef DBG_LOG + char dbg_hex_string[256]; + aesm_dbg_format_hex(msg, msg_size, dbg_hex_string, 256); + AESM_DBG_TRACE("send msg \"%s\" to server:%s",dbg_hex_string, url); + #endif + memset(encode_msg, 0, encoding_size); + if(!encode_request(msg, msg_size, encode_msg, &encoding_size)){ + AESM_DBG_ERROR("message encoding error, msg size %d",msg_size); + ae_ret = AE_FAILURE; + goto ret_point; + } + AESM_DBG_TRACE("encoded msg %.*s",encoding_size, encode_msg); + ae_ret = aesm_network_send_receive(url, encode_msg, encoding_size, + &recv_msg, &recv_size, POST, false); + if(ae_ret != AE_SUCCESS ){ + AESM_DBG_ERROR("fail to send encoded msg (size=%d) to url:%s",encoding_size, url); + goto ret_point; + } + if(recv_msg == NULL){ + AESM_DBG_ERROR("recv NULL message from backend server"); + ae_ret = AE_FAILURE; + goto ret_point; + } + AESM_DBG_TRACE("response msg %.*s", recv_size, recv_msg); + decode_buffer_size= get_response_decoding_length(recv_size); + + if(decode_buffer_size == 0){ + AESM_DBG_ERROR("response 0 length message from backend server:%s",url); + ae_ret = AE_FAILURE; + goto ret_point; + } + AESM_DBG_TRACE("Succ recv msg:%.*s", recv_size, recv_msg); + + resp = reinterpret_cast(malloc(decode_buffer_size)); + if(resp == NULL){ + AESM_DBG_ERROR("malloc error"); + ae_ret = AE_OUT_OF_MEMORY_ERROR; + goto ret_point; + } + memset(resp, 0, decode_buffer_size); + if(!decode_response(recv_msg,recv_size, resp, &decode_buffer_size)){ + AESM_DBG_WARN("fail to decode message from server"); + ae_ret = AE_FAILURE; + goto ret_point; + } + #ifdef DBG_LOG + aesm_dbg_format_hex(resp, decode_buffer_size, dbg_hex_string, 256); + AESM_DBG_TRACE("succ decode msg \"%s\" ",dbg_hex_string); + #endif + resp_size = decode_buffer_size; + ret_point: + aesm_free_network_response_buffer(recv_msg); + if(ae_ret != AE_SUCCESS){ + if(resp!=NULL)free(resp); + resp = NULL; + } + if(encode_msg!=NULL)free(encode_msg); + return ae_ret; + } + +public: + ae_error_t start() + { + return AE_SUCCESS; + } + + void stop() + { + } + + ae_error_t aesm_send_recv_msg( + const char *url, + const uint8_t * msg, + uint32_t msg_size, + uint8_t* &resp_msg, + uint32_t& resp_size, + http_methods_t type, + bool is_ocsp) + { + return ::aesm_network_send_receive(url, msg, msg_size, &resp_msg, &resp_size, type, is_ocsp); + } + + void aesm_free_response_msg(uint8_t *resp) + { + if(resp!=NULL){ + free(resp); + } + } + + ae_error_t aesm_send_recv_msg_encoding( + const char *url, + const uint8_t * msg, + uint32_t msg_size, + uint8_t* &resp, + uint32_t& resp_size) + { + resp = NULL; + resp_size = 0; + AESM_DBG_TRACE("send msg to url %s",url); + //call global function to encoding message, send/receive message via HTTP POST and decode response message + return aesm_send_recv_msg_encoding_internal(url, msg, msg_size, resp, resp_size); + } +}; + +class Activator : public BundleActivator +{ + void Start(BundleContext ctx) + { + CURLcode curl_code = curl_global_init(CURL_GLOBAL_DEFAULT); + auto service = std::make_shared(); + ctx.RegisterService(service); + } + + void Stop(BundleContext) + { + // Nothing to do + } +}; + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator) + +// [no-cmake] +// The code below is required if the CMake +// helper functions are not used. +#ifdef NO_CMAKE +CPPMICROSERVICES_INITIALIZE_BUNDLE(linux_network_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/manifest.json b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/manifest.json new file mode 100644 index 00000000..0d34a9ee --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/linux_network_service_bundle/manifest.json @@ -0,0 +1,7 @@ +{ + "bundle.symbolic_name" : "linux_network_service_symbolic_name", + "bundle.activator" : true, + "bundle.name" : "Linux Network Service", + "bundle.description" : "This bundle provide Linux Network Service", + "bundle.version" : "1.0.0" +} diff --git a/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/CMakeLists.txt new file mode 100644 index 00000000..a04cab7a --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/CMakeLists.txt @@ -0,0 +1,31 @@ +set(Edger8rOutputOP "${CMAKE_CURRENT_BINARY_DIR}/pse_op_u.h") +set(sqlite_src "${PROJECT_SOURCE_DIR}/../../../../external/sqlite/src/sqlite3.c") +get_filename_component(bundle ${CMAKE_CURRENT_SOURCE_DIR} NAME) +aux_source_directory(. _srcs) +link_directories(${CMAKE_SOURCE_DIR}/../../../../build/linux) +CreateBundle(${bundle} ${_srcs} ${sqlite_src} ${Edger8rOutputOP}) + +target_include_directories(${bundle} PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../pse/pse_op + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk + ${PROJECT_SOURCE_DIR}/../../data/constants/linux + ${PROJECT_SOURCE_DIR}/../../../../external/DALSdk/JHI/linux + ${PROJECT_SOURCE_DIR}/../../../../external/sqlite/src + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/common/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/pce_wrapper/inc +) + +add_custom_command( + OUTPUT ${Edger8rOutputOP} + COMMAND ${PROJECT_SOURCE_DIR}/../../../../build/linux/sgx_edger8r --untrusted --untrusted-dir ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/../../pse/pse_op/pse_op.edl --search-path ${PROJECT_SOURCE_DIR}/../../../../common/inc + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries(${bundle} oal utils urts_internal) +set_property(TARGET ${bundle} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/pse_op/PSDAService.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSDAService.cpp similarity index 99% rename from psw/ae/aesm_service/source/pse_op/PSDAService.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSDAService.cpp index 1500a59b..3e779e08 100644 --- a/psw/ae/aesm_service/source/pse_op/PSDAService.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSDAService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pse_op/PSDAService.h b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSDAService.h similarity index 98% rename from psw/ae/aesm_service/source/pse_op/PSDAService.h rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSDAService.h index bde98ecd..42347313 100644 --- a/psw/ae/aesm_service/source/pse_op/PSDAService.h +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSDAService.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pse_op/PSEClass.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSEClass.cpp similarity index 95% rename from psw/ae/aesm_service/source/pse_op/PSEClass.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSEClass.cpp index f577b225..c4fa6089 100644 --- a/psw/ae/aesm_service/source/pse_op/PSEClass.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSEClass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,15 +42,19 @@ #include "oal/oal.h" #include "byte_order.h" -#include "LEClass.h" +#include "psepr_service.h" #include "PSDAService.h" #include "se_wrapper.h" -#include "PSEPRClass.h" +#include "interface_psda.h" #include "sgx_profile.h" #include "sgx_uae_service.h" #include "aesm_pse_status.h" -#include "interface_psda.h" + +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_psepr_service; #define PSDA_CAP_PRTC 0x1 #define PSDA_CAP_RPDATA 0x8 @@ -86,7 +90,7 @@ ae_error_t CPSEClass::init_ps(void) if (PSDAService::instance().is_sigma20_supported()) { AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_SIGMA_20_SESSION]); - AESM_LOG_INFO("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_SIGMA_20_SESSION]); + AESM_LOG_INFO("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_SIGMA_20_SESSION]); } else { @@ -97,14 +101,14 @@ ae_error_t CPSEClass::init_ps(void) //provisioning is attempted using iclsclient and the return code is not verified //In case of emulator the emulator provisioning tool is used to provision for epid 1.1 and if not long term pairing will return not provisioned error. pse_pr_interface_psda* pPSDA = new(std::nothrow) pse_pr_interface_psda(PSDAService::instance().is_sigma20_supported()); - if (pPSDA == NULL) + if (pPSDA == NULL) { return AE_OUT_OF_MEMORY_ERROR; } // Will fail if CSME is not provisioned ae_error_t ret = pPSDA->get_csme_gid(&PSDAService::instance().csme_gid); - if (ret != AE_SUCCESS) + if (ret != AE_SUCCESS) { // Failed to get CSME GID AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_START]); @@ -127,12 +131,16 @@ ae_error_t CPSEClass::init_ps(void) if(ret != AE_SUCCESS) { AESM_DBG_ERROR("creatfe_ephemeral_session_pse_cse failed:%d", ret); - if (ret == PSE_OP_LTPB_SEALING_OUT_OF_DATE) + if (ret == PSE_OP_LTPB_SEALING_OUT_OF_DATE) { + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to load psepr service"); + return AE_FAILURE; + } AESM_DBG_ERROR("TCB update casued ephemeral session failure, reseal LTP blob now"); // Try to reseal LTP blob bool is_new_pairing = false; - ae_error_t ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + ae_error_t ltpStatus = g_psepr_service->long_term_pairing(&is_new_pairing); if (ltpStatus == AE_SUCCESS) { AESM_DBG_INFO("Reseal LTP blob succeeded. Try ephermeal session again."); @@ -145,7 +153,7 @@ ae_error_t CPSEClass::init_ps(void) } else { // If this succeeds we should log PS Init start/success, simply because it won't be repeated and - // logged later. We don't log the error flows here, because we don't consider this the "real" + // logged later. We don't log the error flows here, because we don't consider this the "real" // PS Init. That will happen the first time create_session(), etc is invoked. AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_START]); AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_SUCCESS]); @@ -156,7 +164,13 @@ ae_error_t CPSEClass::init_ps(void) void CPSEClass::before_enclave_load() { // always unload pse_pr enclave before loading pse_op enclave - CPSEPRClass::instance().unload_enclave(); + + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to load psepr service"); + return; + } + else + g_psepr_service->unload_enclave(); } ae_error_t CPSEClass::create_session( @@ -373,7 +387,13 @@ ae_error_t CPSEClass::create_ephemeral_session_pse_cse(bool is_new_pairing, bool unload_enclave(); // load pse_pr enclave - CPSEPRClass::instance().load_enclave(); + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to load psepr service"); + ret = AE_FAILURE; + break; + } + else + g_psepr_service->stop(); break; } @@ -408,7 +428,7 @@ ae_error_t CPSEClass::create_ephemeral_session_pse_cse(bool is_new_pairing, bool PROFILE_START("psda_start_ephemeral_session"); ret = psda_start_ephemeral_session(((pairing_blob_t*)p_sealed_buffer)->plaintext.pse_instance_id, &msg2); PROFILE_END("psda_start_ephemeral_session"); - if (ret != AE_SUCCESS) + if (ret != AE_SUCCESS) break; AESM_DBG_INFO("Ephemral Session M2/M3"); @@ -445,7 +465,7 @@ ae_error_t CPSEClass::create_ephemeral_session_pse_cse(bool is_new_pairing, bool ae_error_t ret2; stat_initdb = initialize_sqlite_database_file_wrapper(m_enclave_id, &ret2, is_new_pairing); PROFILE_END("initialize_sqlite_database_file_wrapper"); - if (stat_initdb == SGX_ERROR_ENCLAVE_LOST) + if (stat_initdb == SGX_ERROR_ENCLAVE_LOST) { retry++; continue; @@ -475,7 +495,7 @@ ae_error_t CPSEClass::create_ephemeral_session_pse_cse(bool is_new_pairing, bool return ret; } -ae_error_t CPSEClass::psda_start_ephemeral_session(const uint8_t* pse_instance_id, +ae_error_t CPSEClass::psda_start_ephemeral_session(const uint8_t* pse_instance_id, pse_cse_msg2_t* cse_msg2) { assert(cse_msg2 != NULL); @@ -524,8 +544,8 @@ ae_error_t CPSEClass::psda_start_ephemeral_session(const uint8_t* pse_instance_i return AE_SUCCESS; } -ae_error_t CPSEClass::psda_finalize_session(const uint8_t* pse_instance_id, - const pse_cse_msg3_t* cse_msg3, +ae_error_t CPSEClass::psda_finalize_session(const uint8_t* pse_instance_id, + const pse_cse_msg3_t* cse_msg3, pse_cse_msg4_t* cse_msg4) { assert(cse_msg3 != NULL && cse_msg4 != NULL); diff --git a/psw/ae/aesm_service/source/pse_op/PSEClass.h b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSEClass.h similarity index 98% rename from psw/ae/aesm_service/source/pse_op/PSEClass.h rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSEClass.h index 7c1e800c..299b3068 100644 --- a/psw/ae/aesm_service/source/pse_op/PSEClass.h +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/PSEClass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pse_op/aesm_pse_status.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/aesm_pse_status.cpp similarity index 96% rename from psw/ae/aesm_service/source/pse_op/aesm_pse_status.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/aesm_pse_status.cpp index 537f8fe0..34a4b822 100644 --- a/psw/ae/aesm_service/source/pse_op/aesm_pse_status.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/aesm_pse_status.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pse_op/aesm_pse_status.h b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/aesm_pse_status.h similarity index 97% rename from psw/ae/aesm_service/source/pse_op/aesm_pse_status.h rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/aesm_pse_status.h index 5ebd32f5..36bcbc6c 100644 --- a/psw/ae/aesm_service/source/pse_op/aesm_pse_status.h +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/aesm_pse_status.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/interface_psda.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/interface_psda.cpp similarity index 98% rename from psw/ae/aesm_service/source/upse/interface_psda.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/interface_psda.cpp index 1a287be5..27668d05 100644 --- a/psw/ae/aesm_service/source/upse/interface_psda.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/interface_psda.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,6 +44,8 @@ #define BREAK_IF_TRUE(x, Sts, ErrCode) if (x) { Sts = ErrCode; break; } #define BREAK_IF_FALSE(x, Sts, ErrCode) if (!(x)) { Sts = ErrCode; break; } + + static JVM_COMM_BUFFER commBuf_s1, commBuf_s3; static INT32 responseCode; @@ -108,6 +110,7 @@ ae_error_t pse_pr_interface_psda::GetS1(/*in*/const uint8_t* pse_instance_id, /* do { + // endian-ness doesn't matter for these two; they're 0 memcpy_s(lt_session_m1.msg_hdr.pse_instance_id, SW_INSTANCE_ID_SIZE, pse_instance_id, SW_INSTANCE_ID_SIZE); lt_session_m1.msg_hdr.msg_type = _htonl(m_is_sigma20 ? PSDA_MSG_TYPE_LT_M1_20 : PSDA_MSG_TYPE_LT_M1_11); lt_session_m1.msg_hdr.msg_len = 0; diff --git a/psw/ae/aesm_service/source/upse/interface_psda.h b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/interface_psda.h similarity index 97% rename from psw/ae/aesm_service/source/upse/interface_psda.h rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/interface_psda.h index 24dc76ce..1166b6a3 100644 --- a/psw/ae/aesm_service/source/upse/interface_psda.h +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/interface_psda.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pse_op/jhi_proxy.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/jhi_proxy.cpp similarity index 99% rename from psw/ae/aesm_service/source/pse_op/jhi_proxy.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/jhi_proxy.cpp index 22d97945..79cb1c94 100644 --- a/psw/ae/aesm_service/source/pse_op/jhi_proxy.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/jhi_proxy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pse_op/jhi_proxy.h b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/jhi_proxy.h similarity index 96% rename from psw/ae/aesm_service/source/pse_op/jhi_proxy.h rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/jhi_proxy.h index 8b6b8f05..27594271 100644 --- a/psw/ae/aesm_service/source/pse_op/jhi_proxy.h +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/jhi_proxy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/local_pseop_service_bundle.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/local_pseop_service_bundle.cpp new file mode 100644 index 00000000..2c588f8e --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/local_pseop_service_bundle.cpp @@ -0,0 +1,299 @@ +#include +#include +#include + +#include +#include "cppmicroservices/BundleContext.h" +#include +#include "cppmicroservices_util.h" + +#include +#include "util.h" +#include "aesm_logic.h" +#include "aesm_long_lived_thread.h" +#include "pse_op_logic.h" +#include "PSEClass.h" +#include "PSDAService.h" +#include "platform_info_logic.h" +#include "interface_psda.h" + + +using namespace cppmicroservices; +std::shared_ptr g_epid_service; +std::shared_ptr g_psepr_service; + + +extern ThreadStatus long_term_paring_thread; +static AESMLogicMutex _pse_mutex; + +bool query_pse_thread_status(void) +{ + return long_term_paring_thread.query_status_and_reset_clock(); +} + +#define CHECK_LONG_TERM_PAIRING_STATUS \ + if(!query_pse_thread_status()){\ + return AESM_BUSY; \ + } + +static ae_error_t thread_to_init_pse(aesm_thread_arg_type_t arg) +{ + UNUSED(arg); + AESM_DBG_INFO("start to init_ps"); + AESMLogicLock lock(_pse_mutex); + ae_error_t psError = CPSEClass::instance().init_ps(); + UNUSED(psError);// To ignore the error that the symbol not used in release mode + AESM_DBG_INFO("init_ps return ( ae %d)", psError); + return AE_SUCCESS; +} + +class LocalPseopServiceImp : public IPseopService +{ +private: + aesm_thread_t pse_thread; +public: + LocalPseopServiceImp():pse_thread(NULL){} + + aesm_error_t create_session( + uint32_t* session_id, + uint8_t* se_dh_msg1, + uint32_t se_dh_msg1_size) + { + AESM_DBG_INFO("LocalPseopServiceImp::create_session"); + AESMLogicLock lock(_pse_mutex); + CHECK_LONG_TERM_PAIRING_STATUS; + ae_error_t psStatus; + // If PSDA not loaded or CSE not provisioned + if (CPSEClass::instance().get_status() == PSE_STATUS_INIT || + CPSEClass::instance().get_status() == PSE_STATUS_UNAVAILABLE ) + { + AESM_DBG_ERROR("unexpected status PSE_STATUS_INIT : PSDA not loaded or CSE not provisioned."); + return AESM_PSDA_UNAVAILABLE; + } + else + psStatus = PlatformInfoLogic::create_session_pre_internal(); + if (AE_SUCCESS != psStatus) { + AESM_DBG_ERROR("psStatus = 0x%X in create_session", psStatus); + } + if (OAL_THREAD_TIMEOUT_ERROR == psStatus){ + AESM_DBG_INFO("AESM is busy in intializing for pse"); + return AESM_BUSY; + } + if (PVE_PROV_ATTEST_KEY_NOT_FOUND == psStatus) { + AESM_DBG_INFO("Key not found reported by Provisioning backend"); + return AESM_UNRECOGNIZED_PLATFORM; + } + if(OAL_PROXY_SETTING_ASSIST == psStatus){ + AESM_DBG_INFO("Proxy assist required in initializing for pse"); + return AESM_PROXY_SETTING_ASSIST; + } + if(PSW_UPDATE_REQUIRED == psStatus){ + AESM_DBG_INFO("PSW software update required"); + return AESM_UPDATE_AVAILABLE; + } + if (AESM_AE_OUT_OF_EPC == psStatus){ + AESM_DBG_INFO("AE out of EPC"); + return AESM_OUT_OF_EPC; + } + if (OAL_NETWORK_UNAVAILABLE_ERROR == psStatus){ + AESM_DBG_INFO("Network is unavailable"); + return AESM_NETWORK_ERROR; + } + if (AESM_PSDA_PLATFORM_KEYS_REVOKED == psStatus) { + AESM_DBG_INFO("This platform was revoked"); + return AESM_EPID_REVOKED_ERROR; + } + + if (PVE_PROV_ATTEST_KEY_TCB_OUT_OF_DATE == psStatus) { + AESM_DBG_INFO("TCB out of date reported by Provisioning backend"); + return AESM_UPDATE_AVAILABLE; + } + + if (AE_SUCCESS != psStatus) { + AESM_DBG_ERROR("psStatus = 0x%X in create_session", psStatus); + } + + return PSEOPAESMLogic::create_session(session_id, se_dh_msg1, se_dh_msg1_size); + } + + aesm_error_t exchange_report( + uint32_t session_id, + const uint8_t* se_dh_msg2, + uint32_t se_dh_msg2_size, + uint8_t* se_dh_msg3, + uint32_t se_dh_msg3_size) + { + AESM_DBG_INFO("LocalPseopServiceImp::exchange_report"); + AESMLogicLock lock(_pse_mutex); + CHECK_LONG_TERM_PAIRING_STATUS; + + return PSEOPAESMLogic::exchange_report(session_id, + se_dh_msg2, + se_dh_msg2_size, + se_dh_msg3, + se_dh_msg3_size); + } + + aesm_error_t invoke_service( + const uint8_t* pse_message_req, + uint32_t pse_message_req_size, + uint8_t* pse_message_resp, + uint32_t pse_message_resp_size) + { + AESM_DBG_INFO("LocalPseopServiceImp::invoke_service"); + AESMLogicLock lock(_pse_mutex); + CHECK_LONG_TERM_PAIRING_STATUS; + return PSEOPAESMLogic::invoke_service(pse_message_req, + pse_message_req_size, + pse_message_resp, + pse_message_resp_size); + } + + aesm_error_t get_ps_cap( + uint64_t* ps_cap) + { + AESM_DBG_INFO("LocalPseopServiceImp::get_ps_cap"); + AESMLogicLock lock(_pse_mutex); + + return PSEOPAESMLogic::get_ps_cap(ps_cap); + } + + aesm_error_t close_session( + uint32_t session_id) + { + AESM_DBG_INFO("LocalPseopServiceImp::close_session"); + AESMLogicLock lock(_pse_mutex); + + return PSEOPAESMLogic::close_session(session_id); + } + + + aesm_error_t report_attestation_status( + uint8_t* platform_info, uint32_t platform_info_size, + uint32_t attestation_status, + uint8_t* update_info, uint32_t update_info_size) + { + AESM_DBG_INFO("LocalPseopServiceImp::report_attestation_status"); + AESMLogicLock lock(_pse_mutex); + CHECK_LONG_TERM_PAIRING_STATUS; + return PlatformInfoLogic::report_attestation_status(platform_info,platform_info_size, + attestation_status, + update_info, update_info_size); + } + + ae_error_t save_psda_capability() + { + return PSDAService::instance().save_psda_capability(); + } + + ae_error_t PSDA_send_and_recv( + int32_t nCommandId, + void* pComm, + int32_t* responseCode, + uint32_t flag) + { + return PSDAService::instance().send_and_recv(nCommandId, + (JVM_COMM_BUFFER*)pComm, + responseCode, + (session_loss_retry_flag_t)flag); + } + bool PSDA_is_sigma20_supported() + { + return PSDAService::instance().is_sigma20_supported(); + } + + ae_error_t start() + { + AESM_DBG_INFO("Starting pseop bundle"); + get_service_wrapper(g_epid_service); + get_service_wrapper(g_psepr_service); + if (g_epid_service == nullptr || g_epid_service->start()) + return AE_FAILURE; + if (g_psepr_service == nullptr || g_psepr_service->start()) + return AE_FAILURE; + + ae_error_t aesm_ret2 = aesm_create_thread(thread_to_init_pse, 0, &pse_thread); + if(AE_SUCCESS != aesm_ret2 ){ + AESM_DBG_WARN("Fail to create thread to init PSE:( ae %d)",aesm_ret2); + return AE_FAILURE; + } + AESM_DBG_INFO("pseop bundle started"); + return AE_SUCCESS; + } + + void stop() + { + ae_error_t ae_ret, thread_ret; + + ae_ret = aesm_wait_thread(pse_thread, &thread_ret, AESM_STOP_TIMEOUT); + if (ae_ret != AE_SUCCESS || thread_ret != AE_SUCCESS) + { + AESM_DBG_INFO("aesm_wait_thread failed(pse_thread):(ae %d) (%d)", ae_ret, thread_ret); + } + (void)aesm_free_thread(pse_thread);//release thread handle to free memory + + uint64_t stop_tick_count = se_get_tick_count()+500/1000; + long_term_paring_thread.stop_thread(stop_tick_count); + + CPSEClass::instance().unload_enclave(); + AESM_DBG_INFO("pseop bundle stopped"); + } + + ae_error_t load_enclave() + { + return CPSEClass::instance().load_enclave(); + } + + void unload_enclave() + { + CPSEClass::instance().unload_enclave(); + } + ae_error_t GetS1 + ( /*in*/ const uint8_t* pse_instance_id, + /*out*/ upse::Buffer& s1 + ) + { + return pse_pr_interface_psda(PSDAService::instance().is_sigma20_supported()).GetS1(pse_instance_id, s1); + } + + ae_error_t ExchangeS2AndS3 + ( /*in*/ const uint8_t* pse_instance_id, + /*in */ const upse::Buffer& s2, + /*out*/ upse::Buffer& s3 + ) + { + return pse_pr_interface_psda(PSDAService::instance().is_sigma20_supported()).ExchangeS2AndS3(pse_instance_id, s2, s3); + } + + ae_error_t get_csme_gid( + /*out*/ uint32_t* p_cse_gid + ) + { + return pse_pr_interface_psda(PSDAService::instance().is_sigma20_supported()).get_csme_gid(p_cse_gid); + } + + +}; + +class Activator : public BundleActivator +{ + void Start(BundleContext ctx) + { + auto service = std::make_shared(); + ctx.RegisterService(service); + } + + void Stop(BundleContext) + { + // Nothing to do + } +}; + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator) + +// [no-cmake] +// The code below is required if the CMake +// helper functions are not used. +#ifdef NO_CMAKE +CPPMICROSERVICES_INITIALIZE_BUNDLE(local_pseop_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/manifest.json b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/manifest.json new file mode 100644 index 00000000..38243925 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/manifest.json @@ -0,0 +1,7 @@ +{ + "bundle.symbolic_name" : "local_pseop_service_symbolic_name", + "bundle.activator" : true, + "bundle.name" : "Local PSEOP Service", + "bundle.description" : "This bundle provide Local PSEOP Service", + "bundle.version" : "1.0.0" +} diff --git a/psw/ae/aesm_service/source/aesm/extension/platform_info_facility.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_facility.cpp similarity index 95% rename from psw/ae/aesm_service/source/aesm/extension/platform_info_facility.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_facility.cpp index dfe27e6d..37d53164 100644 --- a/psw/ae/aesm_service/source/aesm/extension/platform_info_facility.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_facility.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,12 +30,19 @@ */ #include "platform_info_logic.h" -#include "PSEPRClass.h" +#include "psepr_service.h" #include "byte_order.h" #include "PSDAService.h" -#include "upse/helper.h" +#include "helper.h" #include #include "sgx_profile.h" + + +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_psepr_service; + #include "interface_psda.h" static bool newer_psda_svn(uint32_t psdasvn1, uint32_t psdasvn2) @@ -84,21 +91,6 @@ ae_error_t PlatformInfoLogic::get_pse_evaluation_flags(const platform_info_blob_ } return retval; } - -bool PlatformInfoLogic::sgx_epid_group_revoked(const platform_info_blob_wrapper_t* p_platform_info_blob) -{ - uint8_t flags = 0; - bool retVal = false; - ae_error_t getflagsError = get_sgx_epid_group_flags(p_platform_info_blob, &flags); - if (AE_SUCCESS == getflagsError) { - retVal = (0 != (QE_EPID_GROUP_REVOKED & flags)); - } - SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" returning ", retVal, retVal); - - return retVal; -} - - bool PlatformInfoLogic::sgx_gid_out_of_date(const platform_info_blob_wrapper_t* p_platform_info_blob) { uint8_t flags = 0; @@ -268,7 +260,7 @@ bool PlatformInfoLogic::psda_svn_out_of_date(const platform_info_blob_wrapper_t* ae_error_t PlatformInfoLogic::need_epid_provisioning(const platform_info_blob_wrapper_t* p_platform_info_blob) { ae_error_t status = AESM_NEP_DONT_NEED_EPID_PROVISIONING; - if ((sgx_gid_out_of_date(p_platform_info_blob) || sgx_epid_group_revoked(p_platform_info_blob)) && + if (sgx_gid_out_of_date(p_platform_info_blob) && !qe_svn_out_of_date(p_platform_info_blob) && !cpu_svn_out_of_date(p_platform_info_blob) && !pce_svn_out_of_date(p_platform_info_blob)) @@ -331,6 +323,7 @@ ae_error_t PlatformInfoLogic::need_long_term_pairing(const platform_info_blob_wr uint32_t current_psda_svn = PSDAService::instance().psda_svn; pse_pr_interface_psda* pPSDA = NULL; + pPSDA = new(std::nothrow) pse_pr_interface_psda(PSDAService::instance().is_sigma20_supported()); if (pPSDA == NULL) { return AE_OUT_OF_MEMORY_ERROR; @@ -444,8 +437,14 @@ ae_error_t PlatformInfoLogic::pse_cert_provisioning_helper(const platform_info_b { platform_info_blob_wrapper_t new_platform_info_blob; new_platform_info_blob.valid_info_blob = 0; + + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to get IPseprService service"); + status = AE_FAILURE; + break; + } AESM_DBG_INFO("helper; redo certificate provisioning"); - ae_error_t cpStatus = CPSEPRClass::instance().certificate_provisioning(&new_platform_info_blob); + ae_error_t cpStatus = g_psepr_service->certificate_provisioning(&new_platform_info_blob); SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION("cpStatus = ", cpStatus, cpStatus); switch (cpStatus) diff --git a/psw/ae/aesm_service/source/aesm/extension/platform_info_logic.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_logic.cpp similarity index 79% rename from psw/ae/aesm_service/source/aesm/extension/platform_info_logic.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_logic.cpp index d372fb51..864e76a0 100644 --- a/psw/ae/aesm_service/source/aesm/extension/platform_info_logic.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_logic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,18 +33,102 @@ #include "platform_info_logic.h" #include "sgx_quote.h" #include "aesm_encode.h" -#include "pve_logic.h" -#include "aesm_logic.h" +//#include "pve_logic.h" +#include "epid_quote_service.h" #include "PSEClass.h" -#include "PSEPRClass.h" +#include "psepr_service.h" #include "PSDAService.h" -#include "upse/helper.h" +#include "pse_op_logic.h" +#include "helper.h" #include "interface_psda.h" #include "aesm_pse_status.h" +#include "le2be_macros.h" +#include "pibsk_pub.hh" +#include "sgx_sha256_128.h" #include #include "sgx_profile.h" #include "aesm_long_lived_thread.h" +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_epid_service; +extern std::shared_ptr g_psepr_service; + +ThreadStatus long_term_paring_thread; +class CheckLtpIOCache:public BaseThreadIOCache{ + bool is_new_pairing;//extra output +protected: + CheckLtpIOCache(){ + is_new_pairing=false; + } + virtual ae_error_t entry(); + virtual ThreadStatus& get_thread(); + friend ae_error_t start_check_ltp_thread(bool& is_new_pairing, unsigned long timeout); +public: + virtual bool operator==(const BaseThreadIOCache& oc)const{ + const CheckLtpIOCache *p=dynamic_cast(&oc); + if(p==NULL)return false; + return true;//no input, always equal + } +}; + +class UpdatePseIOCache:public BaseThreadIOCache{ + platform_info_blob_wrapper_t pib;//input + uint32_t attestation_status;//input +protected: + UpdatePseIOCache(const platform_info_blob_wrapper_t& pib_info, uint32_t attst_status){ + (void)memcpy_s(&this->pib, sizeof(this->pib), &pib_info, sizeof(pib_info)); + attestation_status=attst_status; + } + virtual ae_error_t entry(); + virtual ThreadStatus& get_thread(); + friend ae_error_t start_update_pse_thread(const platform_info_blob_wrapper_t* update_blob, uint32_t attestation_status, unsigned long timeout); +public: + virtual bool operator==(const BaseThreadIOCache& oc)const{ + const UpdatePseIOCache *p=dynamic_cast(&oc); + if(p==NULL)return false; + return attestation_status==p->attestation_status&&memcmp(&pib, &p->pib, sizeof(pib))==0; + } +}; + +ThreadStatus& CheckLtpIOCache::get_thread() +{ + return long_term_paring_thread; +} + +ThreadStatus& UpdatePseIOCache::get_thread() +{ + return long_term_paring_thread; +} + +ae_error_t CheckLtpIOCache::entry() +{ + return ae_ret = PlatformInfoLogic::check_ltp_thread_func(is_new_pairing); +} + +ae_error_t UpdatePseIOCache::entry() +{ + return ae_ret = PlatformInfoLogic::update_pse_thread_func(&pib, attestation_status); +} + + +ae_error_t start_check_ltp_thread(bool& is_new_pairing, unsigned long timeout) +{ + INIT_THREAD(CheckLtpIOCache, timeout, ()) + COPY_OUTPUT(is_new_pairing); + FINI_THREAD() +} + +ae_error_t start_update_pse_thread(const platform_info_blob_wrapper_t* update_blob, uint32_t attestation_status, unsigned long timeout=THREAD_TIMEOUT) +{ + INIT_THREAD(UpdatePseIOCache, timeout, (*update_blob, attestation_status)) + FINI_THREAD() +} + + + + ae_error_t PlatformInfoLogic::check_ltp_thread_func(bool& is_new_pairing) { @@ -128,7 +212,13 @@ ae_error_t PlatformInfoLogic::check_ltp_thread_func(bool& is_new_pairing) case AESM_NLTP_MAY_NEED_UPDATE_LTP: //case AESM_NLTP_OLD_EPID11_RLS: // not possible since no info blob { - ae_error_t ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to get IPseprService service"); + return AE_FAILURE; + } + + ae_error_t ltpStatus = g_psepr_service->long_term_pairing(&is_new_pairing); // // what do we do if new pairing? // @@ -179,7 +269,14 @@ ae_error_t PlatformInfoLogic::check_ltp_thread_func(bool& is_new_pairing) // // retry one time // - ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to get IPseprService service"); + psStatus = AE_FAILURE; + break; + } + + ltpStatus = g_psepr_service->long_term_pairing(&is_new_pairing); SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" ltpStatus = ", ltpStatus, __LINE__); switch (ltpStatus) { @@ -321,6 +418,66 @@ ae_error_t PlatformInfoLogic::create_session_pre_internal(void) return psStatus; } +ae_error_t pib_verify_signature(platform_info_blob_wrapper_t& piBlobWrapper) +{ + ae_error_t ae_err = AE_FAILURE; + sgx_ecc_state_handle_t ecc_handle = NULL; + + uint8_t result = SGX_EC_INVALID_SIGNATURE; + + const uint32_t data_size = static_cast(sizeof(piBlobWrapper.platform_info_blob) - sizeof(piBlobWrapper.platform_info_blob.signature)); + + + piBlobWrapper.valid_info_blob = false; + do + { + sgx_ec256_public_t publicKey; + sgx_ec256_signature_t signature; + sgx_status_t sgx_status; + + //BREAK_IF_TRUE((sizeof(publicKey) != sizeof(s_pib_pub_key_big_endian)), ae_err, AE_FAILURE); + //BREAK_IF_TRUE((sizeof(signature) != sizeof(piBlobWrapper.platform_info_blob.signature)), ae_err, AE_FAILURE); + + // convert the public key to little endian + if(0!=memcpy_s(&publicKey, sizeof(publicKey), s_pib_pub_key_big_endian, sizeof(s_pib_pub_key_big_endian))){ + ae_err = AE_FAILURE; + break; + } + SwapEndian_32B(((uint8_t*)&publicKey) + 0); + SwapEndian_32B(((uint8_t*)&publicKey) + 32); + + // convert the signature to little endian + if(0!=memcpy_s(&signature, sizeof(signature), &piBlobWrapper.platform_info_blob.signature, sizeof(piBlobWrapper.platform_info_blob.signature))){ + ae_err = AE_FAILURE; + break; + } + SwapEndian_32B(((uint8_t*)&signature) + 0); + SwapEndian_32B(((uint8_t*)&signature) + 32); + + sgx_status = sgx_ecc256_open_context(&ecc_handle); + BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), ae_err, AE_FAILURE); + + sgx_status = sgx_ecdsa_verify((uint8_t*)&piBlobWrapper.platform_info_blob, data_size, &publicKey, &signature, &result, ecc_handle); + BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), ae_err, AE_FAILURE); + + if (SGX_EC_VALID != result) + { + AESM_LOG_WARN(g_event_string_table[SGX_EVENT_PID_SIGNATURE_FAILURE]); + break; + } + + piBlobWrapper.valid_info_blob = true; + + ae_err = AE_SUCCESS; + + } while (0); + if (ecc_handle != NULL) { + sgx_ecc256_close_context(ecc_handle); + } + + return ae_err; +} + ae_error_t PlatformInfoLogic::update_pse_thread_func(const platform_info_blob_wrapper_t* p_platform_info, uint32_t attestation_status) { AESM_DBG_TRACE("enter fun"); @@ -341,7 +498,11 @@ ae_error_t PlatformInfoLogic::update_pse_thread_func(const platform_info_blob_wr AESM_DBG_TRACE("pse_cert_provisioning_helper Return: (ae%d)", pcphStatus); if (AE_SUCCESS == pcphStatus) { - pcphStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to get IPseprService service"); + return AE_FAILURE; + } + pcphStatus = g_psepr_service->long_term_pairing(&is_new_pairing); AESM_DBG_TRACE("long_term_pairing Return: (ae%d)", pcphStatus); if(OAL_PROXY_SETTING_ASSIST == pcphStatus){ return OAL_PROXY_SETTING_ASSIST; @@ -376,7 +537,12 @@ ae_error_t PlatformInfoLogic::update_pse_thread_func(const platform_info_blob_wr // if (attestation_status || ((AESM_NLTP_NO_LTP_BLOB == nltpStatus) || (AESM_NLTP_DONT_NEED_UPDATE_PAIR_LTP == nltpStatus))) { - ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to get IPseprService service"); + retVal = AE_FAILURE; + break; + } + ltpStatus = g_psepr_service->long_term_pairing(&is_new_pairing); switch(ltpStatus) { case AE_SUCCESS: @@ -425,7 +591,13 @@ ae_error_t PlatformInfoLogic::update_pse_thread_func(const platform_info_blob_wr // // retry one time // - ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to get IPseprService service"); + retVal = AE_FAILURE; + break; + } + ltpStatus = g_psepr_service->long_term_pairing(&is_new_pairing); switch (ltpStatus) { case AE_SUCCESS: @@ -476,6 +648,7 @@ ae_error_t PlatformInfoLogic::update_pse_thread_func(const platform_info_blob_wr return retVal; } + aesm_error_t PlatformInfoLogic::report_attestation_status( uint8_t* platform_info, uint32_t platform_info_size, uint32_t attestation_status, @@ -492,7 +665,6 @@ aesm_error_t PlatformInfoLogic::report_attestation_status( platform_info_blob_wrapper_t pibw; - // // presence of platform info is conditional, on whether we're up to date // if we're up to date, no platform info and no need for update info @@ -527,7 +699,7 @@ aesm_error_t PlatformInfoLogic::report_attestation_status( AESM_DBG_ERROR("read_ltp_blob Return: (ae%d)", readLtpBlobStatus); } } - // check ltp bolb version + // check ltp bolb version // if sigma 2.0 is supported and version is 1.1, trigger re-pairing if (AE_SUCCESS == readLtpBlobStatus) { @@ -562,15 +734,26 @@ aesm_error_t PlatformInfoLogic::report_attestation_status( AESM_DBG_ERROR("pib verify signature failed"); return AESM_PLATFORM_INFO_BLOB_INVALID_SIG; } - if(pibw.platform_info_blob.xeid != AESMLogic::get_active_extended_epid_group_id()){ + + if(!g_epid_service){ + AESM_DBG_ERROR("failed to get IEpidquoteService service"); + return AESM_SERVICE_UNAVAILABLE; + } + uint32_t x_group_id; + + if(AESM_SUCCESS != g_epid_service->get_extended_epid_group_id(&x_group_id)){ + AESM_DBG_ERROR("get_extended_epid_group_id failed"); return AESM_UNEXPECTED_ERROR; } - uint32_t gid_mt_result = AESMLogic::is_gid_matching_result_in_epid_blob( pibw.platform_info_blob.gid); - if(AESMLogic::GIDMT_UNMATCHED == gid_mt_result|| - AESMLogic::GIDMT_UNEXPECTED_ERROR == gid_mt_result){ + if(pibw.platform_info_blob.xeid != x_group_id){ + return AESM_UNEXPECTED_ERROR; + } + uint32_t gid_mt_result = g_epid_service->is_gid_matching_result_in_epid_blob( pibw.platform_info_blob.gid); + if(IEpidQuoteService::GIDMT_UNMATCHED == gid_mt_result|| + IEpidQuoteService::GIDMT_UNEXPECTED_ERROR == gid_mt_result){ return AESM_UNEXPECTED_ERROR; } - else if (AESMLogic::GIDMT_NOT_AVAILABLE == gid_mt_result) { + else if (IEpidQuoteService::GIDMT_NOT_AVAILABLE == gid_mt_result) { return AESM_EPIDBLOB_ERROR; } @@ -584,13 +767,13 @@ aesm_error_t PlatformInfoLogic::report_attestation_status( } case AESM_NEP_DONT_NEED_UPDATE_PVEQE: // sure thing { - AESMLogicLock lock(AESMLogic::_qe_pve_mutex); - if(!query_pve_thread_status()){//If another thread is busy on Epid Provisioning - status = AESM_SUCCESS; + if(!g_epid_service){ + AESM_DBG_ERROR("failed to get IEpidquoteService service"); + status = AESM_SERVICE_UNAVAILABLE; break; } bool perfRekey = false; - status = PvEAESMLogic::provision(perfRekey, THREAD_TIMEOUT); + status = g_epid_service->provision(perfRekey, THREAD_TIMEOUT); if (AESM_BUSY == status || //thread timeout AESM_PROXY_SETTING_ASSIST == status || //uae service need to set up proxy info and retry AESM_UPDATE_AVAILABLE == status || //PSW need be updated @@ -614,12 +797,12 @@ aesm_error_t PlatformInfoLogic::report_attestation_status( if (0 == attestation_status) // pr only if we succeeded (also we'll never get pr unless gid up-to-date) { bool perfRekey = true; - AESMLogicLock lock(AESMLogic::_qe_pve_mutex); - if(!query_pve_thread_status()){//If another thread is busy on Epid Provisioning - status = AESM_SUCCESS; + if(!g_epid_service){ + AESM_DBG_ERROR("failed to get IEpidquoteService service"); + status = AESM_SERVICE_UNAVAILABLE; break; } - status = PvEAESMLogic::provision(perfRekey, THREAD_TIMEOUT); + status = g_epid_service->provision(perfRekey, THREAD_TIMEOUT); if (AESM_BUSY == status ||//thread timeout AESM_PROXY_SETTING_ASSIST == status ||//uae service need to set up proxy info and retry AESM_UPDATE_AVAILABLE == status || @@ -646,8 +829,9 @@ aesm_error_t PlatformInfoLogic::report_attestation_status( } } + // don't worry about pairing unless indication that PS being used - if (ps_collectively_not_uptodate(&pibw) && pibw.platform_info_blob.xeid == AESMLogic::get_active_extended_epid_group_id()) + if (ps_collectively_not_uptodate(&pibw) && pibw.platform_info_blob.xeid == x_group_id) { ae_error_t ae_ret = start_update_pse_thread(&pibw, attestation_status); switch (ae_ret) @@ -788,7 +972,13 @@ ae_error_t PlatformInfoLogic::attestation_failure_in_pse_cert_provisioning(const case AESM_NEP_DONT_NEED_UPDATE_PVEQE: case AESM_NEP_PERFORMANCE_REKEY: { - aesm_error_t pvStatus = PvEAESMLogic::provision(nepStatus == AESM_NEP_PERFORMANCE_REKEY, AESM_THREAD_INFINITE); + + if(!g_epid_service){ + AESM_DBG_ERROR("failed to load IEpidQuoteService service"); + status = AE_FAILURE; + break; + } + aesm_error_t pvStatus = g_epid_service->provision(nepStatus == AESM_NEP_PERFORMANCE_REKEY, AESM_THREAD_INFINITE); SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION("pvStatus = ", pvStatus, pvStatus); switch (pvStatus) @@ -821,10 +1011,16 @@ ae_error_t PlatformInfoLogic::attestation_failure_in_pse_cert_provisioning(const // retry one time // AESM_DBG_INFO("attestation; redo certificate provisioning"); + + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to load IPseprService service"); + status = AE_FAILURE; + break; + } platform_info_blob_wrapper_t new_platform_info_blob; new_platform_info_blob.valid_info_blob = false; - ae_error_t cpStatus = CPSEPRClass::instance().certificate_provisioning(&new_platform_info_blob); + ae_error_t cpStatus = g_psepr_service->certificate_provisioning(&new_platform_info_blob); SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION("cpStatus = ", cpStatus, cpStatus); switch (cpStatus) { diff --git a/psw/ae/aesm_service/source/aesm/extension/platform_info_logic.h b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_logic.h similarity index 97% rename from psw/ae/aesm_service/source/aesm/extension/platform_info_logic.h rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_logic.h index 86b47322..683b4895 100644 --- a/psw/ae/aesm_service/source/aesm/extension/platform_info_logic.h +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/platform_info_logic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,7 @@ #include "aesm_error.h" #include "aeerror.h" #include "oal/oal.h" -#include "upse/platform_info_blob.h" +#include "platform_info_blob.h" struct update_pse_thread_func_arg; diff --git a/psw/ae/aesm_service/source/pse_op/pse_op_logic.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_logic.cpp similarity index 90% rename from psw/ae/aesm_service/source/pse_op/pse_op_logic.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_logic.cpp index 8f8fd1aa..5142c952 100644 --- a/psw/ae/aesm_service/source/pse_op/pse_op_logic.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_logic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,11 +33,58 @@ #include "pse_op_logic.h" #include "aesm_logic.h" #include "PSEClass.h" -#include "PSEPRClass.h" +//#include "epid_quote_service.h" +#include "psepr_service.h" #include "aesm_long_lived_thread.h" #include "platform_info_logic.h" #include +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_psepr_service; + +class CertProvLtpIOCache:public BaseThreadIOCache{ + bool is_new_pairing;//extra output +protected: + CertProvLtpIOCache(){ + is_new_pairing = false; + } + virtual ae_error_t entry(); + virtual ThreadStatus& get_thread(); + friend ae_error_t start_long_term_pairing_thread(bool& is_new_paring, unsigned long timeout); +public: + virtual bool operator==(const BaseThreadIOCache& oc)const{ + const CertProvLtpIOCache *p=dynamic_cast(&oc); + if(p==NULL)return false; + return true; + } +}; + +extern ThreadStatus long_term_paring_thread; +ThreadStatus& CertProvLtpIOCache::get_thread() +{ + return long_term_paring_thread; +} + +ae_error_t start_long_term_pairing_thread(bool& is_new_pairing, unsigned long timeout) +{ + INIT_THREAD(CertProvLtpIOCache, timeout, ()) + COPY_OUTPUT(is_new_pairing); + FINI_THREAD() +} + +ae_error_t CertProvLtpIOCache::entry() +{ + return ae_ret = PSEOPAESMLogic::certificate_provisioning_and_long_term_pairing_func(is_new_pairing); +} + + + + + + + static aesm_error_t pse_ret_to_aesm_ret(ae_error_t ret_pse) { switch(ret_pse) @@ -156,7 +203,7 @@ aesm_error_t PSEOPAESMLogic::create_session( ret_pse = CPSEClass::instance().create_session( session_id, se_dh_msg1, - se_dh_msg1_size); + se_dh_msg1_size); } log_admin_ps_ae(ret_pse); @@ -170,8 +217,13 @@ ae_error_t PSEOPAESMLogic::certificate_provisioning_and_long_term_pairing_func(b AESM_DBG_INFO("certificate_provisioning_and_long_term_pairing_func()"); + if(!g_psepr_service){ + AESM_DBG_ERROR("failed to load IPseprService service"); + return AE_FAILURE; + } + is_new_pairing = false; - ae_error_t ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + ae_error_t ltpStatus = g_psepr_service->long_term_pairing(&is_new_pairing); SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" ltpStatus = ", ltpStatus, __LINE__); switch (ltpStatus) @@ -206,7 +258,7 @@ ae_error_t PSEOPAESMLogic::certificate_provisioning_and_long_term_pairing_func(b // // retry one time // - ltpStatus = CPSEPRClass::instance().long_term_pairing(&is_new_pairing); + ltpStatus = g_psepr_service->long_term_pairing(&is_new_pairing); SGX_DBGPRINT_ONE_STRING_TWO_INTS_CREATE_SESSION(__FUNCTION__" ltpStatus = ", ltpStatus, __LINE__); switch (ltpStatus) { @@ -289,7 +341,7 @@ aesm_error_t PSEOPAESMLogic::establish_ephemeral_session(bool force_redo) ae_error_t ret = AE_SUCCESS; // If session already exists and force_redo is false, session is already ready - if (force_redo == false && CPSEClass::instance().get_status() == PSE_STATUS_SERVICE_READY) + if (force_redo == false && CPSEClass::instance().get_status() == PSE_STATUS_SERVICE_READY) return AESM_SUCCESS; AESM_LOG_INFO_ADMIN("%s", g_admin_event_string_table[SGX_ADMIN_EVENT_PS_INIT_START]); @@ -299,7 +351,7 @@ aesm_error_t PSEOPAESMLogic::establish_ephemeral_session(bool force_redo) ret = CPSEClass::instance().create_ephemeral_session_pse_cse(false, force_redo); // Attempt retry/recovery, where appropriate - switch (ret) + switch (ret) { case PSE_PAIRING_BLOB_UNSEALING_ERROR: case PSE_PAIRING_BLOB_INVALID_ERROR: @@ -412,7 +464,7 @@ aesm_error_t PSEOPAESMLogic::exchange_report( } AESM_DBG_INFO("Exchange report again"); - // If CPSECLass:exchange_report() returned PSE_OP_EPHMERAL_SESSIOn_INVALID because PSE-Op loss, + // If CPSECLass:exchange_report() returned PSE_OP_EPHMERAL_SESSIOn_INVALID because PSE-Op loss, // the retry here will fail too, as the session is also lost when enclave is lost. ret_pse = CPSEClass::instance().exchange_report( session_id, @@ -450,7 +502,7 @@ aesm_error_t PSEOPAESMLogic::invoke_service( } AESM_DBG_INFO("Invoke service again"); - // If CPSECLass:invoke_service() returned PSE_OP_EPHEMERAL_SESSION_INVALID because PSE-Op loss, + // If CPSECLass:invoke_service() returned PSE_OP_EPHEMERAL_SESSION_INVALID because PSE-Op loss, // the retry here will fail too, as the session is also lost when enclave is lost. ret_pse = CPSEClass::instance().invoke_service( const_cast(pse_message_req),pse_message_req_size, diff --git a/psw/ae/aesm_service/source/pse_op/pse_op_logic.h b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_logic.h similarity index 93% rename from psw/ae/aesm_service/source/pse_op/pse_op_logic.h rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_logic.h index d9c914f0..382fc3d6 100644 --- a/psw/ae/aesm_service/source/pse_op/pse_op_logic.h +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_logic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -64,5 +64,7 @@ public: static ae_error_t certificate_provisioning_and_long_term_pairing_func(bool& is_new_pairing); }; + +ae_error_t start_long_term_pairing_thread(bool& is_new_pairing, unsigned long timeout=THREAD_TIMEOUT); #endif diff --git a/psw/ae/aesm_service/source/pse_op/pse_op_psda_ocall.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_psda_ocall.cpp similarity index 96% rename from psw/ae/aesm_service/source/pse_op/pse_op_psda_ocall.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_psda_ocall.cpp index 30594bfa..26b11f46 100644 --- a/psw/ae/aesm_service/source/pse_op/pse_op_psda_ocall.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_psda_ocall.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/pse_op/pse_op_vmc_sqlite_ocall.cpp b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_vmc_sqlite_ocall.cpp similarity index 99% rename from psw/ae/aesm_service/source/pse_op/pse_op_vmc_sqlite_ocall.cpp rename to psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_vmc_sqlite_ocall.cpp index af47afb8..b271b985 100644 --- a/psw/ae/aesm_service/source/pse_op/pse_op_vmc_sqlite_ocall.cpp +++ b/psw/ae/aesm_service/source/bundles/local_pseop_service_bundle/pse_op_vmc_sqlite_ocall.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/bundles/pce_service_bundle/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/pce_service_bundle/CMakeLists.txt new file mode 100644 index 00000000..2ce47500 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/pce_service_bundle/CMakeLists.txt @@ -0,0 +1,24 @@ +set(Edger8rOutputPCE "${CMAKE_CURRENT_BINARY_DIR}/pce_u.c") +get_filename_component(bundle ${CMAKE_CURRENT_SOURCE_DIR} NAME) +aux_source_directory(. _srcs) +link_directories(${CMAKE_SOURCE_DIR}/../../../../build/linux) +CreateBundle(${bundle} ${_srcs} ${Edger8rOutputPCE}) + +target_include_directories(${bundle} PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../pve + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk +) + +add_custom_command( + OUTPUT ${Edger8rOutputPCE} + COMMAND ${PROJECT_SOURCE_DIR}/../../../../build/linux/sgx_edger8r --untrusted --untrusted-dir ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/../../pce/pce.edl --search-path ${PROJECT_SOURCE_DIR}/../../../../common/inc + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries(${bundle} oal urts_internal) +set_property(TARGET ${bundle} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/pce/PCEClass.cpp b/psw/ae/aesm_service/source/bundles/pce_service_bundle/PCEClass.cpp similarity index 52% rename from psw/ae/aesm_service/source/pce/PCEClass.cpp rename to psw/ae/aesm_service/source/bundles/pce_service_bundle/PCEClass.cpp index bc359e9d..10f82849 100644 --- a/psw/ae/aesm_service/source/pce/PCEClass.cpp +++ b/psw/ae/aesm_service/source/bundles/pce_service_bundle/PCEClass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,96 +35,129 @@ #endif #include #include "PCEClass.h" -#include "QEClass.h" -#include "PVEClass.h" +//#include "QEClass.h" +//#include "PVEClass.h" #include "util.h" #include "prof_fun.h" #include "sgx_report.h" #include "sgx_tseal.h" #include "epid_pve_type.h" #include "pce_u.h" -#include "pce_u.c" +#include "metadata.h" + +extern "C" bool get_metadata(const char* enclave_file, metadata_t *metadata); void CPCEClass::before_enclave_load() { // always unload qe/pve enclave before loading pce enclave - CQEClass::instance().unload_enclave(); - CPVEClass::instance().unload_enclave(); + //CQEClass::instance().unload_enclave(); + //CPVEClass::instance().unload_enclave(); } -uint32_t CPCEClass::get_pce_target( - sgx_target_info_t *p_pce_target) +uint32_t CPCEClass::pce_get_target(sgx_target_info_t *p_target, + sgx_isv_svn_t *p_isvsvn) { + ae_error_t ae_err; + metadata_t metadata; + char enclave_path[MAX_PATH]= {0}; + if ((NULL == p_target) || (NULL == p_isvsvn)) + return AE_INVALID_PARAMETER; + /* We need to make sure the PCE is successfully loaded */ assert(m_enclave_id); - memset(p_pce_target, 0, sizeof(sgx_target_info_t)); - if(SGX_SUCCESS != sgx_get_target_info(m_enclave_id, p_pce_target)) + memset(p_target, 0, sizeof(sgx_target_info_t)); + if(SGX_SUCCESS != sgx_get_target_info(m_enclave_id, p_target)) return AE_FAILURE; + + if((ae_err = aesm_get_pathname(FT_ENCLAVE_NAME, get_enclave_fid(), enclave_path, MAX_PATH)) != AE_SUCCESS){ + AESM_DBG_ERROR("fail to get PCE pathname"); + return AE_FAILURE; + } + if (!get_metadata(enclave_path, &metadata)) + return AE_FAILURE; + *p_isvsvn = metadata.enclave_css.body.isv_svn; return AE_SUCCESS; } -uint32_t CPCEClass::get_pce_info(const sgx_report_t& report, const signed_pek_t& pek, uint16_t& pce_id, uint16_t& isv_svn, uint8_t encrypted_ppid[PEK_MOD_SIZE]) +uint32_t CPCEClass::get_pce_info(const sgx_report_t *p_report, + const uint8_t *p_pek, + uint32_t pek_size, + uint8_t crypto_suite, + uint8_t *p_encrypted_ppid, + uint32_t encrypted_ppid_size, + uint32_t *p_encrypted_ppid_out_size, + sgx_isv_svn_t *p_isv_svn, + uint16_t *p_pce_id, + uint8_t *p_signature_scheme) { sgx_status_t status = SGX_SUCCESS; uint32_t ret_val = 0; - uint32_t ret_size = PEK_MOD_SIZE; int retry = 0; pce_info_t pce_info; - uint8_t signature_scheme; AESM_PROFILE_FUN; if (m_enclave_id == 0){ AESM_DBG_ERROR("call get_pc_info without loading PCE"); return AE_FAILURE; } + + if ((NULL == p_report) || (NULL == p_pek) || (NULL == p_encrypted_ppid) || + (NULL == p_encrypted_ppid_out_size) || (NULL == p_isv_svn) || + (NULL == p_pce_id) || (NULL == p_signature_scheme)) + return AE_INVALID_PARAMETER; - status = ::get_pc_info(m_enclave_id, &ret_val, &report, (uint8_t*)&pek, static_cast(PEK_MOD_SIZE + sizeof(pek.e)), ALG_RSA_OAEP_3072, encrypted_ppid, PEK_MOD_SIZE, &ret_size, &pce_info, &signature_scheme); + status = ::get_pc_info(m_enclave_id, &ret_val, p_report, p_pek, pek_size, crypto_suite, p_encrypted_ppid, + encrypted_ppid_size, p_encrypted_ppid_out_size, &pce_info, p_signature_scheme); for(; status == SGX_ERROR_ENCLAVE_LOST && retry < AESM_RETRY_COUNT; retry++) { unload_enclave(); if(AE_SUCCESS != load_enclave()) return AE_FAILURE; - status = ::get_pc_info(m_enclave_id, &ret_val, &report, (uint8_t*)&pek, static_cast(PEK_MOD_SIZE + sizeof(pek.e)), ALG_RSA_OAEP_3072, encrypted_ppid, PEK_MOD_SIZE, &ret_size, &pce_info, &signature_scheme); + status = ::get_pc_info(m_enclave_id, &ret_val, p_report, p_pek, pek_size, crypto_suite, p_encrypted_ppid, + encrypted_ppid_size, p_encrypted_ppid_out_size, &pce_info, p_signature_scheme); } if(status != SGX_SUCCESS) return AE_FAILURE; if (ret_val != AE_SUCCESS) return ret_val; - if(signature_scheme != NIST_P256_ECDSA_SHA256){ - return AE_FAILURE; - } - if(ret_size != PEK_MOD_SIZE){ - return AE_FAILURE; - } - pce_id = pce_info.pce_id; - isv_svn = pce_info.pce_isvn; + *p_pce_id = pce_info.pce_id; + *p_isv_svn = pce_info.pce_isvn; return AE_SUCCESS; } -uint32_t CPCEClass::sign_report(const psvn_t& cert_psvn, const sgx_report_t& report, uint8_t signed_sign[2*SE_ECDSA_SIGN_SIZE]) +uint32_t CPCEClass::pce_sign_report(const sgx_isv_svn_t *p_isv_svn, + const sgx_cpu_svn_t *p_cpu_svn, + const sgx_report_t *p_report, + uint8_t *p_sig, + uint32_t sig_size, + uint32_t *p_sig_out_size) { sgx_status_t status = SGX_SUCCESS; uint32_t ret_val = 0; - uint32_t ret_size = 2*SE_ECDSA_SIGN_SIZE; int retry = 0; + psvn_t psvn; AESM_PROFILE_FUN; if (m_enclave_id == 0){ AESM_DBG_ERROR("call certify_enclave without loading PCE"); return AE_FAILURE; } - - status = ::certify_enclave(m_enclave_id, &ret_val, &cert_psvn, &report, signed_sign, 2*SE_ECDSA_SIGN_SIZE, &ret_size); + if ((NULL == p_cpu_svn) || (NULL == p_isv_svn) || (NULL == p_report) || + (NULL == p_sig) || (NULL == p_sig_out_size)) + return AE_INVALID_PARAMETER; + + psvn.cpu_svn = *p_cpu_svn; + psvn.isv_svn = *p_isv_svn; + + status = ::certify_enclave(m_enclave_id, &ret_val, &psvn, p_report, (uint8_t*)p_sig, sig_size, p_sig_out_size); for(; status == SGX_ERROR_ENCLAVE_LOST && retry < AESM_RETRY_COUNT; retry++) { unload_enclave(); if(AE_SUCCESS != load_enclave()) return AE_FAILURE; - status = ::certify_enclave(m_enclave_id, &ret_val, &cert_psvn, &report, signed_sign, 2*SE_ECDSA_SIGN_SIZE, &ret_size); + status = ::certify_enclave(m_enclave_id, &ret_val, &psvn, p_report, (uint8_t*)p_sig, sig_size, p_sig_out_size); } if(status != SGX_SUCCESS) return AE_FAILURE; if(ret_val != AE_SUCCESS){ return ret_val; } - if(ret_size != 2*SE_ECDSA_SIGN_SIZE) - return AE_FAILURE; return AE_SUCCESS; } diff --git a/psw/ae/aesm_service/source/pce/PCEClass.h b/psw/ae/aesm_service/source/bundles/pce_service_bundle/PCEClass.h similarity index 67% rename from psw/ae/aesm_service/source/pce/PCEClass.h rename to psw/ae/aesm_service/source/bundles/pce_service_bundle/PCEClass.h index 751b428c..fd56aa96 100644 --- a/psw/ae/aesm_service/source/pce/PCEClass.h +++ b/psw/ae/aesm_service/source/bundles/pce_service_bundle/PCEClass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -50,14 +50,23 @@ protected: virtual int get_debug_flag() { return 0;} public: - uint32_t get_pce_target(sgx_target_info_t *p_pce_target); - uint32_t get_pce_info(const sgx_report_t& report, - const signed_pek_t& pek, - uint16_t& pce_id, - uint16_t& isv_svn, - uint8_t encrypted_ppid[PEK_MOD_SIZE]); - uint32_t sign_report(const psvn_t& cert_psvn, - const sgx_report_t& report, - uint8_t signed_sign[2*SE_ECDSA_SIGN_SIZE]); + uint32_t pce_get_target(sgx_target_info_t *p_target, + sgx_isv_svn_t *p_isvsvn); + uint32_t get_pce_info(const sgx_report_t *p_report, + const uint8_t *p_pek, + uint32_t pek_size, + uint8_t crypto_suite, + uint8_t *p_encrypted_ppid, + uint32_t encrypted_ppid_size, + uint32_t *p_encrypted_ppid_out_size, + sgx_isv_svn_t* p_pce_isvsvn, + uint16_t* p_pce_id, + uint8_t *p_signature_scheme); + uint32_t pce_sign_report(const sgx_isv_svn_t *p_isv_svn, + const sgx_cpu_svn_t *p_cpu_svn, + const sgx_report_t *p_report, + uint8_t *p_sig, + uint32_t sig_size, + uint32_t *p_sig_out_size); }; diff --git a/psw/ae/aesm_service/source/bundles/pce_service_bundle/manifest.json b/psw/ae/aesm_service/source/bundles/pce_service_bundle/manifest.json new file mode 100644 index 00000000..5b7a46de --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/pce_service_bundle/manifest.json @@ -0,0 +1,7 @@ +{ + "bundle.symbolic_name" : "pce_service_symbolic_name", + "bundle.activator" : true, + "bundle.name" : "PCE Service", + "bundle.description" : "This bundle provide PCE Service", + "bundle.version" : "1.0.0" +} diff --git a/psw/ae/aesm_service/source/bundles/pce_service_bundle/pce_service_bundle.cpp b/psw/ae/aesm_service/source/bundles/pce_service_bundle/pce_service_bundle.cpp new file mode 100644 index 00000000..c919cf7a --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/pce_service_bundle/pce_service_bundle.cpp @@ -0,0 +1,119 @@ +#include +#include + +#include +#include +#include +#include "cppmicroservices_util.h" + +#include +#include "PCEClass.h" + +using namespace cppmicroservices; +std::shared_ptr g_launch_service; + +class PceServiceImp : public IPceService +{ +private: + bool initialized; +public: + PceServiceImp():initialized(false){} + + ae_error_t start() + { + if (initialized == true) + { + AESM_DBG_INFO("pce bundle has been started"); + return AE_SUCCESS; + } + AESM_DBG_INFO("Starting pce bundle"); + get_service_wrapper(g_launch_service); + + if (g_launch_service) + g_launch_service->start(); + if (AE_SUCCESS != load_enclave()) + { + AESM_DBG_INFO("failed to load pce"); + return AE_FAILURE; + } + initialized = true; + AESM_DBG_INFO("pce bundle started"); + return AE_SUCCESS; + } + void stop() + { + unload_enclave(); + AESM_DBG_INFO("pce bundle stopped"); + } + + ae_error_t load_enclave() + { + return CPCEClass::instance().load_enclave(); + } + + void unload_enclave() + { + CPCEClass::instance().unload_enclave(); + } + + uint32_t pce_get_target( + sgx_target_info_t *p_target, + sgx_isv_svn_t *p_isvsvn) + { + return CPCEClass::instance().pce_get_target(p_target, p_isvsvn); + } + + uint32_t get_pce_info( + const sgx_report_t *p_report, + const uint8_t *p_pek, + uint32_t pek_size, + uint8_t crypto_suite, + uint8_t *p_encrypted_ppid, + uint32_t encrypted_ppid_size, + uint32_t *p_encrypted_ppid_out_size, + sgx_isv_svn_t* p_pce_isvsvn, + uint16_t* p_pce_id, + uint8_t *p_signature_scheme) + { + return CPCEClass::instance().get_pce_info(p_report, + p_pek, pek_size, crypto_suite, p_encrypted_ppid, + encrypted_ppid_size, p_encrypted_ppid_out_size, + p_pce_isvsvn, p_pce_id, p_signature_scheme); + } + + uint32_t pce_sign_report( + const sgx_isv_svn_t *p_isv_svn, + const sgx_cpu_svn_t *p_cpu_svn, + const sgx_report_t *p_report, + uint8_t *p_sig, + uint32_t sig_size, + uint32_t *p_sig_out_size) + { + return CPCEClass::instance().pce_sign_report(p_isv_svn, + p_cpu_svn, p_report, p_sig, sig_size, p_sig_out_size); + } + +}; + +class Activator : public BundleActivator +{ + void Start(BundleContext ctx) + { + auto service = std::make_shared(); + ctx.RegisterService(service); + } + + void Stop(BundleContext) + { + // Nothing to do + } +}; + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator) + +// [no-cmake] +// The code below is required if the CMake +// helper functions are not used. +#ifdef NO_CMAKE +CPPMICROSERVICES_INITIALIZE_BUNDLE(pce_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/upse/BackendInterface/CertificateProvisioningProtocol.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/CertificateProvisioningProtocol.cpp similarity index 93% rename from psw/ae/aesm_service/source/upse/BackendInterface/CertificateProvisioningProtocol.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/CertificateProvisioningProtocol.cpp index 8cf6e856..ec0cbb89 100644 --- a/psw/ae/aesm_service/source/upse/BackendInterface/CertificateProvisioningProtocol.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/CertificateProvisioningProtocol.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,12 @@ #include "CertificateProvisioningProtocol.h" #include #include "oal/oal.h" -#include "network_encoding_wrapper.h" +#include "network_service.h" + +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_network_service; CertificateProvisioningProtocol::CertificateProvisioningProtocol() : m_is_initialized(false), @@ -211,10 +216,12 @@ ae_error_t CertificateProvisioningProtocol::sendReceive(const upse::Buffer& send uint8_t* recv = NULL; uint32_t recv_size = 0; + if (!g_network_service) + return AE_FAILURE; do - { + { AESM_DBG_INFO("start send msg"); - status = AESMNetworkEncoding::aesm_send_recv_msg_encoding(m_url.c_str(), const_cast(sendSerialized.getData()), sendSerialized.getSize(), recv, recv_size); + status = g_network_service->aesm_send_recv_msg_encoding(m_url.c_str(), const_cast(sendSerialized.getData()), sendSerialized.getSize(), recv, recv_size); if (AE_FAILED(status)) break; AESM_DBG_INFO("msg received with size %u", recv_size); @@ -232,7 +239,7 @@ ae_error_t CertificateProvisioningProtocol::sendReceive(const upse::Buffer& send } while (0); if (NULL != recv) - AESMNetworkEncoding::aesm_free_response_msg(recv); + g_network_service->aesm_free_response_msg(recv); return status; } diff --git a/psw/ae/aesm_service/source/upse/BackendInterface/CertificateProvisioningProtocol.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/CertificateProvisioningProtocol.h similarity index 99% rename from psw/ae/aesm_service/source/upse/BackendInterface/CertificateProvisioningProtocol.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/CertificateProvisioningProtocol.h index 028dd88b..b1aa003f 100644 --- a/psw/ae/aesm_service/source/upse/BackendInterface/CertificateProvisioningProtocol.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/CertificateProvisioningProtocol.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/BackendInterface/pse_crypto_helper.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_crypto_helper.cpp similarity index 98% rename from psw/ae/aesm_service/source/upse/BackendInterface/pse_crypto_helper.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_crypto_helper.cpp index 231a7cee..5c70728f 100644 --- a/psw/ae/aesm_service/source/upse/BackendInterface/pse_crypto_helper.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_crypto_helper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,7 +34,7 @@ #include "arch.h" #include "crypto_wrapper.h" -#include "../../aesm_service/source/aesm/application/aesm_rand.h" +#include "aesm_rand.h" #include "sgx_memset_s.h" #include "se_wrapper.h" diff --git a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg1.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg1.cpp similarity index 99% rename from psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg1.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg1.cpp index 36901122..d0b8e081 100644 --- a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg1.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,8 +29,9 @@ * */ +#include #include "CertificateProvisioningProtocol.h" -#include "epid_utility.h" +//#include "epid_utility.h" #include "tlv_common.h" #include "type_length_value.h" diff --git a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg2.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg2.cpp similarity index 99% rename from psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg2.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg2.cpp index c2ce169e..21b6aca3 100644 --- a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg2.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +31,7 @@ #include "CertificateProvisioningProtocol.h" #include -#include "epid_utility.h" +//#include "epid_utility.h" #include "tlv_common.h" #include "type_length_value.h" diff --git a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg3.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg3.cpp similarity index 99% rename from psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg3.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg3.cpp index 57cba9e1..64eabbdf 100644 --- a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg3.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg3.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +31,8 @@ #include "CertificateProvisioningProtocol.h" #include -#include "epid_utility.h" +//#include "epid_utility.h" +#include #include "sgx_quote.h" #include "tlv_common.h" diff --git a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg4.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg4.cpp similarity index 99% rename from psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg4.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg4.cpp index e8382edd..f1f6f28e 100644 --- a/psw/ae/aesm_service/source/upse/BackendInterface/pse_provisioning_msg4.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/BackendInterface/pse_provisioning_msg4.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,7 @@ */ #include "CertificateProvisioningProtocol.h" -#include "epid_utility.h" +//#include "epid_utility.h" #include "tlv_common.h" #include "type_length_value.h" diff --git a/psw/ae/aesm_service/source/bundles/psepr_service_bundle/CMakeLists.txt b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/CMakeLists.txt new file mode 100644 index 00000000..4cc3b242 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/CMakeLists.txt @@ -0,0 +1,28 @@ +set(Edger8rOutputPR "${CMAKE_CURRENT_BINARY_DIR}/pse_pr_u.h") +set(PSEPRCommon "${CMAKE_SOURCE_DIR}/../../common/pse_pr_common.cpp") +set(SIGRLCommon "${CMAKE_SOURCE_DIR}/../../common/se_sig_rl.cpp") +set(TSealCommon "${CMAKE_SOURCE_DIR}/../../../../sdk/tseal/tSeal_util.cpp") +get_filename_component(bundle ${CMAKE_CURRENT_SOURCE_DIR} NAME) +aux_source_directory(. _srcs) +aux_source_directory(BackendInterface BackendInterface_srcs) +link_directories(${CMAKE_SOURCE_DIR}/../../../../build/linux) +CreateBundle(${bundle} ${_srcs} ${BackendInterface_srcs} ${PSEPRCommon} ${SIGRLCommon} ${TSealCommon} ${Edger8rOutputPR}) + +target_include_directories(${bundle} PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../pve + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk +) + +add_custom_command( + OUTPUT ${Edger8rOutputPR} + COMMAND ${PROJECT_SOURCE_DIR}/../../../../build/linux/sgx_edger8r --untrusted --untrusted-dir ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/../../pse/pse_pr/pse_pr.edl --search-path ${PROJECT_SOURCE_DIR}/../../../../common/inc + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries(${bundle} oal utils urts_internal) +set_property(TARGET ${bundle} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/pse_pr/PSEPRClass.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/PSEPRClass.cpp similarity index 74% rename from psw/ae/aesm_service/source/pse_pr/PSEPRClass.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/PSEPRClass.cpp index a45ca016..eb1f8c7d 100644 --- a/psw/ae/aesm_service/source/pse_pr/PSEPRClass.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/PSEPRClass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,15 +31,35 @@ #include "PSEPRClass.h" -#include "PSEClass.h" -#include "PSDAService.h" +#include "pseop_service.h" #include -#include "../upse/upse.h" +#include "upse.h" #include "oal/oal.h" +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_pseop_service; + +CPSEPRClass::CPSEPRClass():m_is_sigma20_supported(false) { + + if(!g_pseop_service){ + AESM_DBG_ERROR("failed to load pseop service"); + return; + } + else + m_is_sigma20_supported = g_pseop_service->PSDA_is_sigma20_supported(); +} + + void CPSEPRClass::before_enclave_load() { - CPSEClass::instance().unload_enclave(); + if(!g_pseop_service){ + AESM_DBG_ERROR("failed to load pseop service"); + return; + } + else + g_pseop_service->unload_enclave(); } ae_error_t CPSEPRClass::certificate_provisioning(platform_info_blob_wrapper_t* pib_wrapper) @@ -51,9 +71,9 @@ ae_error_t CPSEPRClass::certificate_provisioning(platform_info_blob_wrapper_t* p { if ((status = CPSEPRClass::instance().load_enclave()) != AE_SUCCESS) break; - + status = upse_certificate_provisioning(m_enclave_id, pib_wrapper); - + } while (0); CPSEPRClass::instance().unload_enclave(); @@ -71,13 +91,18 @@ ae_error_t CPSEPRClass::long_term_pairing(bool* p_new_pairing) { if ((status = CPSEPRClass::instance().load_enclave()) != AE_SUCCESS) break; - + status = upse_long_term_pairing(m_enclave_id, p_new_pairing); - + } while (0); CPSEPRClass::instance().unload_enclave(); - PSDAService::instance().save_psda_capability(); + + if(!g_pseop_service){ + AESM_DBG_ERROR("failed to load pseop service"); + } + else + g_pseop_service->save_psda_capability(); return status; } diff --git a/psw/ae/aesm_service/source/pse_pr/PSEPRClass.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/PSEPRClass.h similarity index 90% rename from psw/ae/aesm_service/source/pse_pr/PSEPRClass.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/PSEPRClass.h index 9365c05f..7f823765 100644 --- a/psw/ae/aesm_service/source/pse_pr/PSEPRClass.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/PSEPRClass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,8 +33,7 @@ #define _PSE_PR_CLASS_H_ #include "AEClass.h" #include "aeerror.h" -#include "PSDAService.h" -#include "./upse/platform_info_blob.h" +#include "platform_info_blob.h" #include "ae_debug_flag.hh" #include @@ -45,21 +44,22 @@ class CPSEPRClass: public SingletonEnclave friend class SingletonEnclave; static aesm_enclave_id_t get_enclave_fid() { - if (PSDAService::instance().is_sigma20_supported()) + if (instance().m_is_sigma20_supported) return PSE_PR_2_ENCLAVE_FID; else return PSE_PR_ENCLAVE_FID; } protected: - CPSEPRClass(){}; + CPSEPRClass(); ~CPSEPRClass(){}; + bool m_is_sigma20_supported; virtual void before_enclave_load(); virtual int get_debug_flag() { return AE_DEBUG_FLAG;} public: - + bool is_sigma20_supported(){return m_is_sigma20_supported;} ae_error_t certificate_provisioning(platform_info_blob_wrapper_t* pib_wrapper); ae_error_t long_term_pairing(bool* new_pairing); diff --git a/psw/ae/aesm_service/source/upse/interface_ocsp.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/interface_ocsp.cpp similarity index 92% rename from psw/ae/aesm_service/source/upse/interface_ocsp.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/interface_ocsp.cpp index 802d1865..2f801604 100644 --- a/psw/ae/aesm_service/source/upse/interface_ocsp.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/interface_ocsp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,16 +36,22 @@ #include "openssl/ocsp.h" -#pragma GCC diagnostic pop +#pragma GCC diagnostic pop #include "interface_ocsp.h" #include "oal/oal.h" #include "pse_pr_sigma_common_defs.h" #include "Buffer.h" -#include "network_encoding_wrapper.h" +#include "network_service.h" #include "helper.h" + +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_network_service; + #undef OCSP_CLEAN #undef _OPENSSL_FULL_INIT #undef USE_CERTID_STACK @@ -133,7 +139,7 @@ ae_error_t Get_OCSPResponse // Convert verifier to internal X509 data x509CertNextDER = verifierCertificateDER.getData(); - if (NULL == d2i_X509(&verifierX509Cert, &x509CertNextDER, verifierCertificateDER.getSize())) + if (NULL == d2i_X509(&verifierX509Cert, &x509CertNextDER, verifierCertificateDER.getSize())) { Helper::RemoveCertificateChain(); break; @@ -143,7 +149,7 @@ ae_error_t Get_OCSPResponse // Convert issuer to internal X509 data x509CertNextDER = issuerCertificateDER.getData(); - if (NULL == d2i_X509(&issuerX509Cert, &x509CertNextDER, issuerCertificateDER.getSize())) + if (NULL == d2i_X509(&issuerX509Cert, &x509CertNextDER, issuerCertificateDER.getSize())) { Helper::RemoveCertificateChain(); break; @@ -179,7 +185,7 @@ ae_error_t Get_OCSPResponse #endif pOneReq = OCSP_request_add0_id(pOcspReq, pCertID); - if (NULL == pOneReq) + if (NULL == pOneReq) { Helper::RemoveCertificateChain(); break; @@ -189,7 +195,7 @@ ae_error_t Get_OCSPResponse // Add nonce int retVal = OCSP_request_add1_nonce(pOcspReq, (uint8_t*)const_cast(ocspNonce), NONCE_LENGTH); - if (retVal <= 0) + if (retVal <= 0) { Helper::RemoveCertificateChain(); break; @@ -206,7 +212,7 @@ ae_error_t Get_OCSPResponse // to mem bio to binary // retVal = get_ocsp_req_size(reqbio, pOcspReq); - if (retVal <= 0) + if (retVal <= 0) { Helper::RemoveCertificateChain(); break; @@ -220,7 +226,7 @@ ae_error_t Get_OCSPResponse memset(ocsp_request, 0x0, reqbio_num_write); retVal = BIO_read(reqbio, ocsp_request, static_cast(reqbio_num_write)); - if (retVal <= 0) + if (retVal <= 0) { Helper::RemoveCertificateChain(); break; @@ -228,12 +234,17 @@ ae_error_t Get_OCSPResponse SGX_DBGPRINT_ONE_STRING_ONE_INT_OCSP("convertd to binary", 0); - ae_error_t netStatus = aesm_network_send_receive( urlOcspResponder, - (const uint8_t *) ocsp_request, + if(!g_network_service){ + AESM_DBG_ERROR("failed to load INetworkService service"); + status = AE_FAILURE; + break; ; + } + ae_error_t netStatus = g_network_service->aesm_send_recv_msg( urlOcspResponder, + (const uint8_t *) ocsp_request, static_cast(reqbio_num_write), - (uint8_t **) &ocsp_response, - &ocsp_response_size, - POST, + (uint8_t*&)ocsp_response, + ocsp_response_size, + POST, true); if (AE_SUCCESS != netStatus) { status = netStatus; @@ -266,7 +277,7 @@ ae_error_t Get_OCSPResponse SGX_DBGPRINT_ONE_STRING_ONE_INT_OCSP("converted ocsp response to internal format", 0); - // + // // even though cse verifies/checks the ocsp response, // we can save time by doing the easy checks here // we'll check: @@ -382,26 +393,26 @@ ae_error_t Get_OCSPResponse } while (0); - if (ocsp_response) + if (ocsp_response) { - aesm_free_network_response_buffer((uint8_t*)ocsp_response); + g_network_service->aesm_free_response_msg((uint8_t*)ocsp_response); SGX_DBGPRINT_ONE_STRING_ONE_INT_OCSP("freed network response buffer", 0); } - if (verifierX509Cert) + if (verifierX509Cert) { X509_free(verifierX509Cert); SGX_DBGPRINT_ONE_STRING_ONE_INT_OCSP("freed verifier cert", 0); } - if (issuerX509Cert) + if (issuerX509Cert) { X509_free(issuerX509Cert); SGX_DBGPRINT_ONE_STRING_ONE_INT_OCSP("freed issuer cert", 0); } if (pOcspReq) - { + { OCSP_REQUEST_free(pOcspReq); SGX_DBGPRINT_ONE_STRING_ONE_INT_OCSP("freed ocsp request", 0); } diff --git a/psw/ae/aesm_service/source/upse/interface_ocsp.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/interface_ocsp.h similarity index 96% rename from psw/ae/aesm_service/source/upse/interface_ocsp.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/interface_ocsp.h index 73d5b9bf..4bfa6741 100644 --- a/psw/ae/aesm_service/source/upse/interface_ocsp.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/interface_ocsp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/bundles/psepr_service_bundle/manifest.json b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/manifest.json new file mode 100644 index 00000000..f1b0ac9c --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/manifest.json @@ -0,0 +1,7 @@ +{ + "bundle.symbolic_name" : "psepr_service_symbolic_name", + "bundle.activator" : true, + "bundle.name" : "PSEPR Service", + "bundle.description" : "This bundle provide PSEPR Service", + "bundle.version" : "1.0.0" +} diff --git a/psw/ae/aesm_service/source/upse/pse_pr_inc.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/pse_pr_inc.h similarity index 96% rename from psw/ae/aesm_service/source/upse/pse_pr_inc.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/pse_pr_inc.h index a20cf9df..4473ee48 100644 --- a/psw/ae/aesm_service/source/upse/pse_pr_inc.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/pse_pr_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/bundles/psepr_service_bundle/psepr_service_bundle.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/psepr_service_bundle.cpp new file mode 100644 index 00000000..033427a6 --- /dev/null +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/psepr_service_bundle.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +#include +#include "cppmicroservices/BundleContext.h" +#include +#include "cppmicroservices_util.h" + +#include +#include "PSEPRClass.h" +#include "oal/oal.h" + + +using namespace cppmicroservices; +std::shared_ptr g_epid_service; +std::shared_ptr g_pseop_service; +std::shared_ptr g_network_service; + +class PseprServiceImp : public IPseprService +{ + ae_error_t certificate_provisioning( + platform_info_blob_wrapper_t* pib_wrapper) const + { + std::cout << "PseprServiceImp::certificate_provisioning called" << std::endl; + return CPSEPRClass::instance().certificate_provisioning(pib_wrapper); + } + + + ae_error_t long_term_pairing( + bool* p_new_pairing) const + { + std::cout << "PseprServiceImp::long_term_pairing called" << std::endl; + return CPSEPRClass::instance().long_term_pairing(p_new_pairing); + } + + ae_error_t start() + { + AESM_DBG_INFO("Starting psepr bundle"); + get_service_wrapper(g_network_service); + get_service_wrapper(g_epid_service); + get_service_wrapper(g_pseop_service); + + if (g_epid_service == nullptr || g_epid_service->start()) + return AE_FAILURE; + AESM_DBG_INFO("psepr bundle started"); + return AE_SUCCESS;//CPSEPRClass::instance().load_enclave(); + } + + void unload_enclave() + { + CPSEPRClass::instance().unload_enclave(); + } + + void stop() + { + CPSEPRClass::instance().unload_enclave(); + AESM_DBG_INFO("psepr bundle stopped"); + } +}; + +class Activator : public BundleActivator +{ + void Start(BundleContext ctx) + { + auto service = std::make_shared(); + ctx.RegisterService(service); + } + + void Stop(BundleContext) + { + // Nothing to do + } +}; + +CPPMICROSERVICES_EXPORT_BUNDLE_ACTIVATOR(Activator) + +// [no-cmake] +// The code below is required if the CMake +// helper functions are not used. +#ifdef NO_CMAKE +CPPMICROSERVICES_INITIALIZE_BUNDLE(psepr_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/upse/sigma_helper.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/sigma_helper.cpp similarity index 88% rename from psw/ae/aesm_service/source/upse/sigma_helper.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/sigma_helper.cpp index 0c963d5b..9b05f18f 100644 --- a/psw/ae/aesm_service/source/upse/sigma_helper.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/sigma_helper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,7 @@ #include #include "pse_pr_sigma_common_defs.h" #include "se_time.h" -#include "endpoint_select_info.h" +//#include "endpoint_select_info.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wredundant-decls" @@ -43,7 +43,7 @@ #include "openssl/ocsp.h" #include "openssl/ssl.h" -#pragma GCC diagnostic pop +#pragma GCC diagnostic pop #include "interface_ocsp.h" @@ -57,7 +57,15 @@ #include "provision_msg.h" #include "aesm_logic.h" #include "oal/oal.h" -#include "network_encoding_wrapper.h" + +#include "epid_quote_service.h" +#include "network_service.h" + +#include +#include +using namespace cppmicroservices; +extern std::shared_ptr g_epid_service; +extern std::shared_ptr g_network_service; #ifndef UINT16_MAX #define UINT16_MAX 0xFFFF @@ -92,7 +100,17 @@ ae_error_t SigmaHelper::GetRLsFromServer ae_error_t sigRetValue = AE_FAILURE; ae_error_t privRetValue = AE_FAILURE; - const char *url = EndpointSelectionInfo::instance().get_server_url(REVOCATION_LIST_RETRIEVAL); + if(!g_epid_service){ + AESM_DBG_ERROR("failed to load IEpidQuoteService service"); + return AE_FAILURE; + } + + if(!g_network_service){ + AESM_DBG_ERROR("failed to load network service"); + return AE_FAILURE; + } + + const char *url = g_epid_service->get_server_url(REVOCATION_LIST_RETRIEVAL); if (url == NULL) { return OAL_CONFIG_FILE_ERROR; @@ -106,7 +124,7 @@ ae_error_t SigmaHelper::GetRLsFromServer char msg[9]; for (unsigned i = 0; i < m_gid.getSize(); i++) { - + sprintf_s((char*) msg+2*i, 3, "%02X", *(p1+m_gid.getSize()-1-i)); } std::string gidString(msg); @@ -126,7 +144,7 @@ ae_error_t SigmaHelper::GetRLsFromServer uint8_t *recv=NULL; uint32_t recv_size = 0; - sigRetValue = AESMNetworkEncoding::aesm_send_recv_msg(stringUrl.c_str(), NULL, 0, recv, recv_size, GET, false); + sigRetValue = g_network_service->aesm_send_recv_msg(stringUrl.c_str(), NULL, 0, recv, recv_size, GET, false); if (AE_SUCCESS != sigRetValue) { @@ -137,13 +155,13 @@ ae_error_t SigmaHelper::GetRLsFromServer sigRlOut.Alloc(recv_size); upse::BufferWriter bw(sigRlOut); bw.writeRaw(recv, recv_size); - AESMNetworkEncoding::aesm_free_response_msg(recv); + g_network_service->aesm_free_response_msg(recv); } stringUrl = s_url + "Product_" + gidString + ".crl"; recv=NULL; recv_size = 0; - privRetValue = AESMNetworkEncoding::aesm_send_recv_msg(stringUrl.c_str(), NULL, 0, recv, recv_size, GET, false); + privRetValue = g_network_service->aesm_send_recv_msg(stringUrl.c_str(), NULL, 0, recv, recv_size, GET, false); if (AE_SUCCESS != privRetValue) { @@ -154,7 +172,7 @@ ae_error_t SigmaHelper::GetRLsFromServer privRlOut.Alloc(recv_size); upse::BufferWriter bw(privRlOut); bw.writeRaw(recv, recv_size); - aesm_free_network_response_buffer(recv); + g_network_service->aesm_free_response_msg(recv); } } while (0); @@ -206,7 +224,12 @@ ae_error_t SigmaHelper::GetOcspResponseFromServer break; } - const char *url = EndpointSelectionInfo::instance().get_server_url( PSE_OCSP); + if(!g_epid_service){ + AESM_DBG_ERROR("failed to load IEpidQuoteService service"); + return AE_FAILURE; + } + + const char *url = g_epid_service->get_server_url( PSE_OCSP); if (url == NULL){ return OAL_CONFIG_FILE_ERROR; } diff --git a/psw/ae/aesm_service/source/upse/sigma_helper.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/sigma_helper.h similarity index 97% rename from psw/ae/aesm_service/source/upse/sigma_helper.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/sigma_helper.h index 2a178ee2..f1eac797 100644 --- a/psw/ae/aesm_service/source/upse/sigma_helper.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/sigma_helper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/u_certificate_provisioning.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_certificate_provisioning.cpp similarity index 90% rename from psw/ae/aesm_service/source/upse/u_certificate_provisioning.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_certificate_provisioning.cpp index 8eeddac9..461e2a39 100644 --- a/psw/ae/aesm_service/source/upse/u_certificate_provisioning.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_certificate_provisioning.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,7 @@ #include "u_certificate_provisioning.h" #include "helper.h" -#include "CertificateProvisioningProtocol.h" +#include "BackendInterface/CertificateProvisioningProtocol.h" #include "sgx_quote.h" @@ -48,10 +48,12 @@ #include "epid/common/types.h" #include "provision_msg.h" -#include "qe_logic.h" +//#include "qe_logic.h" #include "aesm_logic.h" -#include "endpoint_select_info.h" -#include "pve_logic.h" +//#include "endpoint_select_info.h" +#include "quote_service.h" +#include "epid_quote_service.h" +//#include "pve_logic.h" #include "sgx_tseal.h" #include "pairing_blob.h" @@ -67,6 +69,11 @@ #include "aesm_long_lived_thread.h" #include "sgx_sha256_128.h" +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_epid_service; + #define PSEPR_LOST_ENCLAVE_RETRY_COUNT 3 //#define FAKE_QUOTE @@ -81,7 +88,7 @@ uint8_t GID_TO_USE[4] = { 0x00, 0x00, 0x00, 0x06 }; /* hardcoded "Public" PSE Certificate */ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -363,7 +370,13 @@ static ae_error_t do_certificate_chain_provisioning upse::Buffer pairing_blob; // Received from PSE_pr upse::Buffer ocsp_req; // Created here from cert chain - const char *szURL = EndpointSelectionInfo::instance().get_pse_provisioning_url(es_info); + if(!g_epid_service){ + AESM_DBG_ERROR("failed to load IEpidQuoteService service"); + status = AE_FAILURE; + return status; + } + + const char *szURL = g_epid_service->get_pse_provisioning_url(es_info); memset(pib_wrapper, 0, sizeof(platform_info_blob_wrapper_t)); // Receive from Server in M4 @@ -506,16 +519,22 @@ static ae_error_t do_quote_initialization aesm_error_t result; SGX_DBGPRINT_PRINT_ANSI_STRING("aesmLogic.init_quote?"); - result = AESMLogic::init_quote( + if(!g_epid_service){ + AESM_DBG_ERROR("failed to load IQuoteService service"); + status = AE_FAILURE; + break; + } + + result = g_epid_service->init_quote( (uint8_t*)pTargetInfo, sizeof(sgx_target_info_t), (uint8_t*)pGID, sizeof(*pGID)); if (result == AESM_BUSY) { //EPID_PROVISION triggered, make sure previous EPID provision has finished - ae_error_t temp_ret = wait_pve_thread(); - BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR); +// ae_error_t temp_ret = wait_pve_thread(); +// BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR); //redo init_quote - result = AESMLogic::init_quote( + result = g_epid_service->init_quote( (uint8_t*)pTargetInfo, sizeof(sgx_target_info_t), (uint8_t*)pGID, sizeof(*pGID)); } @@ -608,7 +627,13 @@ static ae_error_t do_get_quote memcpy_s(&enclaveReport, reportBuffer.getSize(), reportBuffer.getData(), reportBuffer.getSize()); aesm_error_t result; - result = AESMLogic::get_quote( + + if(!g_epid_service){ + AESM_DBG_ERROR("failed to load IQuoteService service"); + status = AE_FAILURE; + break; + } + result = g_epid_service->get_quote( (uint8_t*)&enclaveReport, sizeof(enclaveReport), quote_type, (uint8_t*)&spid, sizeof(spid), @@ -619,10 +644,10 @@ static ae_error_t do_get_quote if (result == AESM_BUSY) { //EPID_PROVISION triggered, make sure previous EPID provision has finished - ae_error_t temp_ret = wait_pve_thread(); - BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR); +// ae_error_t temp_ret = wait_pve_thread(); +// BREAK_IF_TRUE(AE_SUCCESS != temp_ret , status, PSE_PR_PCH_EPID_UNKNOWN_ERROR); //redo get_quote - result = AESMLogic::get_quote( + result = g_epid_service->get_quote( (uint8_t*)&enclaveReport, sizeof(enclaveReport), quote_type, (uint8_t*)&spid, sizeof(spid), @@ -673,73 +698,6 @@ static ae_error_t do_get_quote return status; } - -// -// fwiw -// hex-encoded private part -// -//std::string prvPibSK = "942BCC166737FCF62CBF39668C6980F42A69A6828BEAB912362FEC0E21A2A61D"; - -ae_error_t pib_verify_signature(platform_info_blob_wrapper_t& piBlobWrapper) -{ - ae_error_t ae_err = AE_FAILURE; - sgx_ecc_state_handle_t ecc_handle = NULL; - - uint8_t result = SGX_EC_INVALID_SIGNATURE; - - const uint32_t data_size = static_cast(sizeof(piBlobWrapper.platform_info_blob) - sizeof(piBlobWrapper.platform_info_blob.signature)); - - - piBlobWrapper.valid_info_blob = false; - do - { - sgx_ec256_public_t publicKey; - sgx_ec256_signature_t signature; - sgx_status_t sgx_status; - - //BREAK_IF_TRUE((sizeof(publicKey) != sizeof(s_pib_pub_key_big_endian)), ae_err, AE_FAILURE); - //BREAK_IF_TRUE((sizeof(signature) != sizeof(piBlobWrapper.platform_info_blob.signature)), ae_err, AE_FAILURE); - - // convert the public key to little endian - if(0!=memcpy_s(&publicKey, sizeof(publicKey), s_pib_pub_key_big_endian, sizeof(s_pib_pub_key_big_endian))){ - ae_err = AE_FAILURE; - break; - } - SwapEndian_32B(((uint8_t*)&publicKey) + 0); - SwapEndian_32B(((uint8_t*)&publicKey) + 32); - - // convert the signature to little endian - if(0!=memcpy_s(&signature, sizeof(signature), &piBlobWrapper.platform_info_blob.signature, sizeof(piBlobWrapper.platform_info_blob.signature))){ - ae_err = AE_FAILURE; - break; - } - SwapEndian_32B(((uint8_t*)&signature) + 0); - SwapEndian_32B(((uint8_t*)&signature) + 32); - - sgx_status = sgx_ecc256_open_context(&ecc_handle); - BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), ae_err, AE_FAILURE); - - sgx_status = sgx_ecdsa_verify((uint8_t*)&piBlobWrapper.platform_info_blob, data_size, &publicKey, &signature, &result, ecc_handle); - BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), ae_err, AE_FAILURE); - - if (SGX_EC_VALID != result) - { - AESM_LOG_WARN(g_event_string_table[SGX_EVENT_PID_SIGNATURE_FAILURE]); - break; - } - - piBlobWrapper.valid_info_blob = true; - - ae_err = AE_SUCCESS; - - } while (0); - if (ecc_handle != NULL) { - sgx_ecc256_close_context(ecc_handle); - } - - return ae_err; -} - ae_error_t generate_pse_instance_id(uint8_t* instance_id) { memset(instance_id, 0, 16); diff --git a/psw/ae/aesm_service/source/upse/u_certificate_provisioning.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_certificate_provisioning.h similarity index 96% rename from psw/ae/aesm_service/source/upse/u_certificate_provisioning.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_certificate_provisioning.h index b6236859..a0ae99f0 100644 --- a/psw/ae/aesm_service/source/upse/u_certificate_provisioning.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_certificate_provisioning.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/u_long_term_pairing.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_long_term_pairing.cpp similarity index 95% rename from psw/ae/aesm_service/source/upse/u_long_term_pairing.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_long_term_pairing.cpp index c519be8e..e5c10639 100644 --- a/psw/ae/aesm_service/source/upse/u_long_term_pairing.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_long_term_pairing.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,7 @@ #include "uecall_bridge.h" #include -#include "interface_psda.h" +//#include "interface_psda.h" #include "pse_pr_sigma_defs.h" #include "sigma_helper.h" @@ -48,6 +48,8 @@ #include "pairing_blob.h" #include "byte_order.h" +#include "pseop_service.h" + #if defined(_DEBUG) #include "PSDAService.h" @@ -55,9 +57,18 @@ #include "aesm_encode.h" #endif + + +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_pseop_service; + + #define PSEPR_LOST_ENCLAVE_RETRY_COUNT 3 + // FLOW // Verifier Prover Intel Server // uRequestS1FromME |--M1: Start Pairing->| | @@ -176,13 +187,8 @@ static ae_error_t DoLongTermPairing(bool* p_new_pairing) ae_error_t status = AE_FAILURE; - pse_pr_interface_psda* pPSDA = NULL; - do { - pPSDA = new pse_pr_interface_psda(PSDAService::instance().is_sigma20_supported()) ; - BREAK_IF_FALSE( (NULL != pPSDA), - status, AESM_PSE_PR_INSUFFICIENT_MEMORY_ERROR); //===================================================================== // Start: LONG TERM PAIRING protocol @@ -207,7 +213,14 @@ static ae_error_t DoLongTermPairing(bool* p_new_pairing) // Retrieve S1 from ME/CSE //********************************************************************* - status = pPSDA->GetS1(Helper::ltpBlobInstanceID(*pairing_blob), s1); + if(!g_pseop_service){ + AESM_DBG_ERROR("failed to load IPseopService service"); + status = AE_FAILURE; + break; + } + + + status = g_pseop_service->GetS1(Helper::ltpBlobInstanceID(*pairing_blob), s1); SGX_DBGPRINT_ONE_STRING_ONE_INT_LTP("Function: pPSDA->GetS1(s1), Return Value: ", status); BREAK_IF_FAILED(status); @@ -274,7 +287,7 @@ static ae_error_t DoLongTermPairing(bool* p_new_pairing) // Send: s2 // Receive: s3 //********************************************************************* - status = pPSDA->ExchangeS2AndS3(Helper::ltpBlobInstanceID(*pairing_blob), s2, s3); + status = g_pseop_service->ExchangeS2AndS3(pairing_blob->plaintext.pse_instance_id, s2, s3); SGX_DBGPRINT_ONE_STRING_ONE_INT_LTP("Function: pPSDA->ExchangeS2AndS3(s2, s3), Return Value: ", status); if (AESM_PSDA_LT_SESSION_INTEGRITY_ERROR == status) { AESM_LOG_ERROR("%s", g_event_string_table[SGX_EVENT_SIGMA_S2_INTEGRITY_ERROR]); @@ -326,10 +339,6 @@ static ae_error_t DoLongTermPairing(bool* p_new_pairing) #endif } while (false); - if (NULL != pPSDA) - { - delete pPSDA; - } if (PSE_PAIRING_BLOB_UNSEALING_ERROR == status || PSE_PAIRING_BLOB_INVALID_ERROR == status) { diff --git a/psw/ae/aesm_service/source/upse/u_long_term_pairing.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_long_term_pairing.h similarity index 96% rename from psw/ae/aesm_service/source/upse/u_long_term_pairing.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_long_term_pairing.h index 144027d1..35eb8811 100644 --- a/psw/ae/aesm_service/source/upse/u_long_term_pairing.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/u_long_term_pairing.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/uecall_bridge.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/uecall_bridge.cpp similarity index 98% rename from psw/ae/aesm_service/source/upse/uecall_bridge.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/uecall_bridge.cpp index 26c2e41b..5c9bf77f 100644 --- a/psw/ae/aesm_service/source/upse/uecall_bridge.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/uecall_bridge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,16 +33,18 @@ #include #include "u_certificate_provisioning.h" #include "uecall_bridge.h" -#include "PSDAService.h" #include "pse_pr_u.h" #include "pse_pr_u.c" +#include "PSEPRClass.h" #include "pse_pr_common.h" #include #include "pse_pr_sigma_defs.h" #include "le2be_macros.h" +#include "byte_order.h" + #include "aeerror.h" @@ -57,8 +59,6 @@ #define SIGMA20_SVER 0x0002 #define SIG_RL_BLOBID 0x000e #define PRIV_RL_BLOBID 0x000d - - static sgx_enclave_id_t _enclaveID; static ae_error_t check_sigrl_entries_max(const EPID_SIG_RL* pSigRL) @@ -78,7 +78,7 @@ static ae_error_t check_sigrl_header(const EPID_SIG_RL* pSigRL) { if (NULL != pSigRL) { - if (PSDAService::instance().is_sigma20_supported()) + if (CPSEPRClass::instance().is_sigma20_supported()) { if (SIGMA20_SVER != lv_htons(*((uint16_t*)pSigRL->sver)) || SIG_RL_BLOBID != lv_htons(*((uint16_t*)pSigRL->blob_id))) @@ -93,12 +93,11 @@ static ae_error_t check_sigrl_header(const EPID_SIG_RL* pSigRL) } return AE_SUCCESS; } - static ae_error_t check_privrl_header(const EPID_PRIV_RL* pPrivRL) { if (NULL != pPrivRL) { - if (PSDAService::instance().is_sigma20_supported()) + if (CPSEPRClass::instance().is_sigma20_supported()) { if (SIGMA20_SVER != lv_htons(*((uint16_t*)pPrivRL->sver)) || PRIV_RL_BLOBID != lv_htons(*((uint16_t*)pPrivRL->blob_id))) @@ -113,7 +112,6 @@ static ae_error_t check_privrl_header(const EPID_PRIV_RL* pPrivRL) } return AE_SUCCESS; } - static ae_error_t check_privrl_entries_max(const EPID_PRIV_RL* pPrivRL) { if (NULL != pPrivRL) diff --git a/psw/ae/aesm_service/source/upse/uecall_bridge.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/uecall_bridge.h similarity index 97% rename from psw/ae/aesm_service/source/upse/uecall_bridge.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/uecall_bridge.h index b1e57728..0a7adf79 100644 --- a/psw/ae/aesm_service/source/upse/uecall_bridge.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/uecall_bridge.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/upse.cpp b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/upse.cpp similarity index 83% rename from psw/ae/aesm_service/source/upse/upse.cpp rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/upse.cpp index 0e6484e4..79756176 100644 --- a/psw/ae/aesm_service/source/upse/upse.cpp +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/upse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,10 +39,13 @@ #include "provision_msg.h" #include "aesm_logic.h" -#include "endpoint_select_info.h" +#include "epid_quote_service.h" #include "oal/oal.h" - +#include "cppmicroservices/BundleContext.h" +#include +using namespace cppmicroservices; +extern std::shared_ptr g_epid_service; @@ -55,9 +58,15 @@ ae_error_t upse_certificate_provisioning(sgx_enclave_id_t enclave_id, platform_i do { + + if(!g_epid_service){ + AESM_DBG_ERROR("failed to load IEpidQuoteService service"); + status = AE_FAILURE; + break; + } endpoint_selection_infos_t es_info; - if(AE_SUCCESS == (status = (ae_error_t)AESMLogic::endpoint_selection(es_info)) ) + if(AE_SUCCESS == (status = (ae_error_t)g_epid_service->endpoint_selection(es_info)) ) { status = certificate_chain_provisioning(es_info, pib_wrapper); } diff --git a/psw/ae/aesm_service/source/upse/upse.h b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/upse.h similarity index 90% rename from psw/ae/aesm_service/source/upse/upse.h rename to psw/ae/aesm_service/source/bundles/psepr_service_bundle/upse.h index 85b1527e..35bfa56d 100644 --- a/psw/ae/aesm_service/source/upse/upse.h +++ b/psw/ae/aesm_service/source/bundles/psepr_service_bundle/upse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,8 +34,8 @@ #include "sgx_eid.h" #include "aeerror.h" -#include "../upse/platform_info_blob.h" - +//#include "../upse/platform_info_blob.h" +typedef struct _platform_info_blob_wrapper_t platform_info_blob_wrapper_t; ae_error_t upse_certificate_provisioning(sgx_enclave_id_t enclave_id, platform_info_blob_wrapper_t* pib_wrapper); diff --git a/psw/ae/aesm_service/source/aesm/application/AEClass.h b/psw/ae/aesm_service/source/common/AEClass.h similarity index 98% rename from psw/ae/aesm_service/source/aesm/application/AEClass.h rename to psw/ae/aesm_service/source/common/AEClass.h index ec60d0b9..60a24cb9 100644 --- a/psw/ae/aesm_service/source/aesm/application/AEClass.h +++ b/psw/ae/aesm_service/source/common/AEClass.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMLogicWrapper.h b/psw/ae/aesm_service/source/common/AESMLogicWrapper.h similarity index 75% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/AESMLogicWrapper.h rename to psw/ae/aesm_service/source/common/AESMLogicWrapper.h index 0235d1dc..4fb6aa18 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMLogicWrapper.h +++ b/psw/ae/aesm_service/source/common/AESMLogicWrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,18 +34,24 @@ #include #include #include "IAESMLogic.h" -#include +#include + class AESMLogicWrapper :public IAESMLogic { + long m_pseop_service_bundle_id; + long m_quote_service_bundle_id; + long m_launch_service_bundle_id; + long m_ecdsa_quote_service_bundle_id; + long m_psepr_service_bundle_id; + long m_pce_service_bundle_id; + long m_network_service_bundle_id; + public: - AESMLogicWrapper() { - } + AESMLogicWrapper(); virtual ~AESMLogicWrapper() { } - ae_error_t service_start(){ - return AESMLogic::service_start(); - } + ae_error_t service_start(); void service_stop(); @@ -70,6 +76,25 @@ class AESMLogicWrapper :public IAESMLogic { uint32_t sig_rlLength, const uint8_t* sig_rl, uint32_t bufferSize, uint8_t** quote, bool b_qe_report, uint32_t* qe_reportSize, uint8_t** qe_report); + + virtual aesm_error_t init_quote_ex( + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + uint8_t **target_info, uint32_t *target_info_size, + bool refresh_att_key, + bool b_pub_key_id, size_t *pub_key_id_size, uint8_t **pub_key_id); + + virtual aesm_error_t get_quote_size_ex( + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + uint32_t *quote_size); + + virtual aesm_error_t get_quote_ex( + uint32_t report_size, const uint8_t *report, + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t qe_report_info_size, uint8_t *qe_report_info, + uint32_t quote_size, uint8_t **quote); + virtual aesm_error_t closeSession(uint32_t sessionId); virtual aesm_error_t createSession(uint32_t *session_id, diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMQueue.h b/psw/ae/aesm_service/source/common/AESMQueue.h similarity index 98% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/AESMQueue.h rename to psw/ae/aesm_service/source/common/AESMQueue.h index 08ab05b9..92d65099 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMQueue.h +++ b/psw/ae/aesm_service/source/common/AESMQueue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMQueueManager.h b/psw/ae/aesm_service/source/common/AESMQueueManager.h similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/AESMQueueManager.h rename to psw/ae/aesm_service/source/common/AESMQueueManager.h index 2cab5408..d9ea8c47 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMQueueManager.h +++ b/psw/ae/aesm_service/source/common/AESMQueueManager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMWorkerThread.h b/psw/ae/aesm_service/source/common/AESMWorkerThread.h similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/AESMWorkerThread.h rename to psw/ae/aesm_service/source/common/AESMWorkerThread.h index 2307c543..7ac975eb 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/AESMWorkerThread.h +++ b/psw/ae/aesm_service/source/common/AESMWorkerThread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/Buffer.h b/psw/ae/aesm_service/source/common/Buffer.h similarity index 99% rename from psw/ae/aesm_service/source/upse/Buffer.h rename to psw/ae/aesm_service/source/common/Buffer.h index 7ad85b91..ff6c3a67 100644 --- a/psw/ae/aesm_service/source/upse/Buffer.h +++ b/psw/ae/aesm_service/source/common/Buffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/CAESMServer.h b/psw/ae/aesm_service/source/common/CAESMServer.h similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/CAESMServer.h rename to psw/ae/aesm_service/source/common/CAESMServer.h index 312a39c3..50ac2ca1 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/CAESMServer.h +++ b/psw/ae/aesm_service/source/common/CAESMServer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/CSelector.h b/psw/ae/aesm_service/source/common/CSelector.h similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/CSelector.h rename to psw/ae/aesm_service/source/common/CSelector.h index 45a7cd5d..a19b44c7 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/CSelector.h +++ b/psw/ae/aesm_service/source/common/CSelector.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/IAESMQueue.h b/psw/ae/aesm_service/source/common/IAESMQueue.h similarity index 96% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/IAESMQueue.h rename to psw/ae/aesm_service/source/common/IAESMQueue.h index fa1e1361..4ffe7a2d 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/IAESMQueue.h +++ b/psw/ae/aesm_service/source/common/IAESMQueue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/IServerSocket.h b/psw/ae/aesm_service/source/common/IServerSocket.h similarity index 96% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/IServerSocket.h rename to psw/ae/aesm_service/source/common/IServerSocket.h index 668a4271..c5374136 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/IServerSocket.h +++ b/psw/ae/aesm_service/source/common/IServerSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/RequestData.h b/psw/ae/aesm_service/source/common/RequestData.h similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/RequestData.h rename to psw/ae/aesm_service/source/common/RequestData.h index 8a60c84f..ca4f3649 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/RequestData.h +++ b/psw/ae/aesm_service/source/common/RequestData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/Thread.h b/psw/ae/aesm_service/source/common/Thread.h similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/Thread.h rename to psw/ae/aesm_service/source/common/Thread.h index 6fc8912b..14b4eb4d 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/Thread.h +++ b/psw/ae/aesm_service/source/common/Thread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/UnixServerSocket.h b/psw/ae/aesm_service/source/common/UnixServerSocket.h similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/UnixServerSocket.h rename to psw/ae/aesm_service/source/common/UnixServerSocket.h index 159001f1..9203b066 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/UnixServerSocket.h +++ b/psw/ae/aesm_service/source/common/UnixServerSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/application/aesm_config.h b/psw/ae/aesm_service/source/common/aesm_config.h similarity index 93% rename from psw/ae/aesm_service/source/aesm/application/aesm_config.h rename to psw/ae/aesm_service/source/common/aesm_config.h index e283bc53..766fcb1b 100644 --- a/psw/ae/aesm_service/source/aesm/application/aesm_config.h +++ b/psw/ae/aesm_service/source/common/aesm_config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,3 +40,6 @@ typedef struct _aesm_config_infos_t{ }aesm_config_infos_t; #endif +bool read_aesm_config(aesm_config_infos_t& infos); + + diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_encode.h b/psw/ae/aesm_service/source/common/aesm_encode.h similarity index 96% rename from psw/ae/aesm_service/source/aesm/extension/aesm_encode.h rename to psw/ae/aesm_service/source/common/aesm_encode.h index 03fcf0f5..3d14917b 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_encode.h +++ b/psw/ae/aesm_service/source/common/aesm_encode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,12 +31,13 @@ #ifndef _AESM_ENCODE_H_ #define _AESM_ENCODE_H_ -#include "sgx_urts.h" -#include "se_thread.h" +//#include "sgx_urts.h" +//#include "se_thread.h" #ifdef __cplusplus extern "C"{ #endif +#include uint32_t certPseSvn(); /*Function to provide an upper bound of buffer size of encoded message for an input request diff --git a/psw/ae/aesm_service/source/aesm_wrapper/inc/aesm_exception.h b/psw/ae/aesm_service/source/common/aesm_exception.h similarity index 96% rename from psw/ae/aesm_service/source/aesm_wrapper/inc/aesm_exception.h rename to psw/ae/aesm_service/source/common/aesm_exception.h index 630b6334..f4acad5a 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/inc/aesm_exception.h +++ b/psw/ae/aesm_service/source/common/aesm_exception.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/network/network_encoding_wrapper.h b/psw/ae/aesm_service/source/common/aesm_logic.h similarity index 61% rename from psw/ae/aesm_service/source/network/network_encoding_wrapper.h rename to psw/ae/aesm_service/source/common/aesm_logic.h index ba86cc50..866e539f 100644 --- a/psw/ae/aesm_service/source/network/network_encoding_wrapper.h +++ b/psw/ae/aesm_service/source/common/aesm_logic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,27 +29,51 @@ * */ -#ifndef _NETWORK_WRAPPER_H_ -#define _NETWORK_WRAPPER_H_ + +#ifndef _AESM_LOGIC_H_ +#define _AESM_LOGIC_H_ #include "sgx_urts.h" #include "aesm_error.h" #include "arch.h" #include "aeerror.h" #include "tlv_common.h" #include "se_thread.h" +#include "internal/se_stdio.h" +#include "internal/se_memcpy.h" +#include "internal/uncopyable.h" #include "oal/oal.h" +#include +#include #include "se_wrapper.h" +#include "platform_info_blob.h" -/*Class for network interface inside AESM*/ -class AESMNetworkEncoding{ -protected: - static ae_error_t aesm_send_recv_msg_encoding_internal(const char *url, const uint8_t * msg, uint32_t msg_size, uint8_t* &resp_msg, uint32_t& resp_size); +#include "default_url_info.hh" + +const uint32_t THREAD_TIMEOUT = 5000; + +class AESMLogicMutex{ + CLASS_UNCOPYABLE(AESMLogicMutex) public: - /*Function to send data to server via HTTP/HTTPS protocol*/ - static ae_error_t aesm_send_recv_msg(const char *url, const uint8_t * msg, uint32_t msg_size, uint8_t* &resp_msg, uint32_t& resp_size, http_methods_t type= POST, bool is_ocsp=false); - /*Function to send data to server via HTTP/HTTPS protocol but the data to be send will be HEX/BASE64 encoded and the respose message is decoded. It is used for ES/SGX/PSEPR Provisioning*/ - static ae_error_t aesm_send_recv_msg_encoding(const char *url, const uint8_t * msg, uint32_t msg_size, uint8_t* &resp_msg, uint32_t& resp_size); - static void aesm_free_response_msg(uint8_t *resp); /*Function to free the buffer of resp_msg from previous two functions*/ + AESMLogicMutex() {se_mutex_init(&mutex);} + ~AESMLogicMutex() { se_mutex_destroy(&mutex);} + void lock() { se_mutex_lock(&mutex); } + void unlock() { se_mutex_unlock(&mutex); } +private: + se_mutex_t mutex; }; -#endif +class AESMLogicLock { + CLASS_UNCOPYABLE(AESMLogicLock) +public: + explicit AESMLogicLock(AESMLogicMutex& cs) :_cs(cs) { _cs.lock(); } + ~AESMLogicLock() { _cs.unlock(); } +private: + AESMLogicMutex& _cs; +}; + +#define QE_PROD_ID 1 +#define PSE_PROD_ID 2 + + +typedef struct _endpoint_selection_infos_t endpoint_selection_infos_t; +#endif diff --git a/psw/ae/aesm_service/source/common/aesm_long_lived_thread.h b/psw/ae/aesm_service/source/common/aesm_long_lived_thread.h new file mode 100644 index 00000000..eac8cadf --- /dev/null +++ b/psw/ae/aesm_service/source/common/aesm_long_lived_thread.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _AESM_LONG_LIVED_THREAD_H_ +#define _AESM_LONG_LIVED_THREAD_H_ +#include "aesm_logic.h" +#include + +#define AESM_STOP_TIMEOUT (60*1000) /*waiting for 1 minute at most*/ +extern ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout=THREAD_TIMEOUT); +extern ae_error_t start_check_ltp_thread(bool& is_new_pairing, unsigned long timeout=THREAD_TIMEOUT); +//extern ae_error_t start_white_list_thread(unsigned long timeout=THREAD_TIMEOUT); +//extern ae_error_t start_update_pse_thread(const platform_info_blob_wrapper_t* update_blob, uint32_t attestation_status, unsigned long timeout=THREAD_TIMEOUT); +//extern ae_error_t start_long_term_pairing_thread(bool& is_new_paring, unsigned long timeout=THREAD_TIMEOUT); +extern bool query_pve_thread_status(void);/*return true if idle and reset clock for thread*/ +extern bool query_pse_thread_status(void);/*return true if idel and reset clock for thread*/ +extern ae_error_t wait_pve_thread(uint64_t time_out_milliseconds=AESM_THREAD_INFINITE); +extern void stop_all_long_lived_threads(uint64_t time_out_milliseconds=AESM_STOP_TIMEOUT); + +enum _thread_state +{ + ths_idle, + ths_busy, + ths_stop//The thread is to be stopped and no new job will be accepted +}; + +enum _io_cache_state +{ + ioc_idle, //thread has been finished + ioc_busy, //thread not finished yet + ioc_stop //thread stop required +}; + +#define MAX_OUTPUT_CACHE 50 +#define THREAD_INFINITE_TICK_COUNT 0xFFFFFFFFFFFFFFFFLL +class ThreadStatus; +class BaseThreadIOCache; +typedef ae_error_t (*long_lived_thread_func_t)(BaseThreadIOCache *cache); + +//Base class for cached data of each thread to fork +class BaseThreadIOCache:private Uncopyable{ + time_t timeout; //The data will timeout after the time if the state is not busy + int ref_count; //ref_count is used to track how many threads are currently referencing the data + _io_cache_state status; + //handle of the thread, some thread will be waited by other threads so that we could not + // free the handle until all other threads have got notification that the thread is terminated + aesm_thread_t thread_handle; + friend class ThreadStatus; +protected: + ae_error_t ae_ret; + BaseThreadIOCache():ref_count(0),status(ioc_busy){ + timeout=0; + thread_handle=NULL; + ae_ret = AE_FAILURE; + } + virtual ThreadStatus& get_thread()=0; +public: + virtual ae_error_t entry(void)=0; + virtual bool operator==(const BaseThreadIOCache& oc)const=0; + ae_error_t start(BaseThreadIOCache *&out_ioc, uint32_t timeout=THREAD_TIMEOUT); + void deref(void); + void set_status_finish(); +public: + virtual ~BaseThreadIOCache(){} +}; + +class ThreadStatus: private Uncopyable +{ +private: + AESMLogicMutex thread_mutex; + _thread_state thread_state; + uint64_t status_clock; + BaseThreadIOCache *cur_iocache; + std::listoutput_cache; +protected: + friend class BaseThreadIOCache; + //function to look up cached output, there will be no real thread associated with the input ioc + //If a match is found the input parameter will be free automatically and the matched value is returned + //return true if a thread will be forked for the out_ioc + bool find_or_insert_iocache(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc); + +public: + ThreadStatus(); + void set_status_finish(BaseThreadIOCache* ioc);//only called at the end of aesm_long_lived_thread_entry + void deref(BaseThreadIOCache* iocache); + ae_error_t wait_iocache_timeout(BaseThreadIOCache* ioc, uint64_t stop_tick_count); + + //create thread and wait at most 'timeout' for the thread to be finished + // It will first look up whether there is a previous run with same input before starting the thread + // we should not delete ioc after calling to this function + ae_error_t set_thread_start(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc, uint32_t timeout=THREAD_TIMEOUT); + + void stop_thread(uint64_t stop_milli_second);//We need wait for thread to be terminated and all thread_handle in list to be closed + + ~ThreadStatus(){stop_thread(THREAD_INFINITE_TICK_COUNT);}//ThreadStatus instance should be global object. Otherwise, it is possible that the object is destroyed before a thread waiting for and IOCache got notified and causing exception + + ae_error_t wait_for_cur_thread(uint64_t millisecond); + + //function to query whether current thread is idle, + //if it is idle, return true and reset clock to current clock value + bool query_status_and_reset_clock(void); +}; + +#define INIT_THREAD(cache_type, timeout, init_list) \ + BaseThreadIOCache *ioc = new cache_type init_list; \ + BaseThreadIOCache *out_ioc = NULL; \ + ae_error_t ae_ret = AE_FAILURE; \ + ae_ret = ioc->start(out_ioc, (uint32_t)(timeout)); \ + if(ae_ret != AE_SUCCESS){ \ + if(out_ioc!=NULL){out_ioc->deref();}\ + return ae_ret; \ + }\ + assert(out_ioc!=NULL);\ + cache_type *pioc = dynamic_cast(out_ioc);\ + assert(pioc!=NULL); + //now the thread has finished it's execution and we could read result without lock +#define COPY_OUTPUT(x) x=pioc->x +#define FINI_THREAD() \ + ae_ret = pioc->ae_ret;\ + pioc->deref();/*derefence the cache object after usage of it*/ \ + return ae_ret; + +#endif + diff --git a/psw/ae/aesm_service/source/aesm/application/aesm_proxy_type.h b/psw/ae/aesm_service/source/common/aesm_proxy_type.h similarity index 96% rename from psw/ae/aesm_service/source/aesm/application/aesm_proxy_type.h rename to psw/ae/aesm_service/source/common/aesm_proxy_type.h index 72b41c73..df20e3a5 100644 --- a/psw/ae/aesm_service/source/aesm/application/aesm_proxy_type.h +++ b/psw/ae/aesm_service/source/common/aesm_proxy_type.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/application/aesm_rand.h b/psw/ae/aesm_service/source/common/aesm_rand.h similarity index 96% rename from psw/ae/aesm_service/source/aesm/application/aesm_rand.h rename to psw/ae/aesm_service/source/common/aesm_rand.h index ac347b59..72217860 100644 --- a/psw/ae/aesm_service/source/aesm/application/aesm_rand.h +++ b/psw/ae/aesm_service/source/common/aesm_rand.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/common/cppmicroservices_util.h b/psw/ae/aesm_service/source/common/cppmicroservices_util.h new file mode 100644 index 00000000..fc1a05bd --- /dev/null +++ b/psw/ae/aesm_service/source/common/cppmicroservices_util.h @@ -0,0 +1,23 @@ +#include +#include +#include + +using namespace cppmicroservices; + +template +bool get_service_wrapper(std::shared_ptr &service) noexcept +{ + try + { + auto context = cppmicroservices::GetBundleContext(); + auto ref = context.GetServiceReference(); + if (S::VERSION != ref.GetBundle().GetVersion().GetMajor()) + return false; + service = context.GetService(ref); + } + catch(...) + { + return false; + } + return true; +} diff --git a/psw/ae/aesm_service/source/common/es_info.h b/psw/ae/aesm_service/source/common/es_info.h new file mode 100644 index 00000000..6ba56d84 --- /dev/null +++ b/psw/ae/aesm_service/source/common/es_info.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _ES_INFO_H_ +#define _ES_INFO_H_ + +#define AESM_DATA_SERVER_URL_INFOS 'A' +#define AESM_DATA_ENDPOINT_SELECTION_INFOS 'B' +#define AESM_DATA_SERVER_URL_VERSION_1 1 +#define AESM_DATA_SERVER_URL_VERSION 2 +#define AESM_DATA_ENDPOINT_SELECTION_VERSION 1 + +#include "se_stdio.h" +#include "epid_pve_type.h" +#pragma pack(1) + +/*Struct for PCE based url information which will be installed by PSW Installer*/ +typedef struct _aesm_server_url_infos_t{ + uint8_t aesm_data_type; + uint8_t aesm_data_version; + char endpoint_url[MAX_PATH]; /*URL for endpoint selection protocol server*/ + char pse_rl_url[MAX_PATH]; /*URL to retrieve PSE rovocation List*/ + char pse_ocsp_url[MAX_PATH]; +}aesm_server_url_infos_t; + +/*Struct for data to save endpoint selection protocol result into persistent data storage*/ +typedef struct _endpoint_selection_infos_t{ + uint8_t aesm_data_type; + uint8_t aesm_data_version; + signed_pek_t pek; + char provision_url[MAX_PATH]; +}endpoint_selection_infos_t; +#pragma pack() + +#endif /*_ES_INFO_H_*/ diff --git a/psw/ae/aesm_service/source/aesm/application/event_strings.h b/psw/ae/aesm_service/source/common/event_strings.h similarity index 98% rename from psw/ae/aesm_service/source/aesm/application/event_strings.h rename to psw/ae/aesm_service/source/common/event_strings.h index 5dc2462d..77167f81 100644 --- a/psw/ae/aesm_service/source/aesm/application/event_strings.h +++ b/psw/ae/aesm_service/source/common/event_strings.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/helper.h b/psw/ae/aesm_service/source/common/helper.h similarity index 98% rename from psw/ae/aesm_service/source/upse/helper.h rename to psw/ae/aesm_service/source/common/helper.h index 5f238ac3..c4d9d860 100644 --- a/psw/ae/aesm_service/source/upse/helper.h +++ b/psw/ae/aesm_service/source/common/helper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/include/oal/aesm_persistent_storage.h b/psw/ae/aesm_service/source/common/oal/aesm_persistent_storage.h similarity index 99% rename from psw/ae/aesm_service/include/oal/aesm_persistent_storage.h rename to psw/ae/aesm_service/source/common/oal/aesm_persistent_storage.h index 84e6efe3..117d6377 100644 --- a/psw/ae/aesm_service/include/oal/aesm_persistent_storage.h +++ b/psw/ae/aesm_service/source/common/oal/aesm_persistent_storage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/include/oal/aesm_thread.h b/psw/ae/aesm_service/source/common/oal/aesm_thread.h similarity index 97% rename from psw/ae/aesm_service/include/oal/aesm_thread.h rename to psw/ae/aesm_service/source/common/oal/aesm_thread.h index 8b0be1e5..904f593e 100644 --- a/psw/ae/aesm_service/include/oal/aesm_thread.h +++ b/psw/ae/aesm_service/source/common/oal/aesm_thread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/include/oal/error_report.h b/psw/ae/aesm_service/source/common/oal/error_report.h similarity index 97% rename from psw/ae/aesm_service/include/oal/error_report.h rename to psw/ae/aesm_service/source/common/oal/error_report.h index c2eeb8f7..b5f4a6f1 100644 --- a/psw/ae/aesm_service/include/oal/error_report.h +++ b/psw/ae/aesm_service/source/common/oal/error_report.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/include/oal/internal_log.h b/psw/ae/aesm_service/source/common/oal/internal_log.h similarity index 98% rename from psw/ae/aesm_service/include/oal/internal_log.h rename to psw/ae/aesm_service/source/common/oal/internal_log.h index bb54fc2a..ca239b6f 100644 --- a/psw/ae/aesm_service/include/oal/internal_log.h +++ b/psw/ae/aesm_service/source/common/oal/internal_log.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/include/oal/oal.h b/psw/ae/aesm_service/source/common/oal/oal.h similarity index 95% rename from psw/ae/aesm_service/include/oal/oal.h rename to psw/ae/aesm_service/source/common/oal/oal.h index c9930e90..6f92b700 100644 --- a/psw/ae/aesm_service/include/oal/oal.h +++ b/psw/ae/aesm_service/source/common/oal/oal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +31,6 @@ #ifndef _AESM_OAL_H_ #define _AESM_OAL_H_ -#include "oal/aesm_network.h" #include "oal/aesm_persistent_storage.h" #include "oal/power.h" #include "oal/error_report.h" diff --git a/psw/ae/aesm_service/include/oal/power.h b/psw/ae/aesm_service/source/common/oal/power.h similarity index 96% rename from psw/ae/aesm_service/include/oal/power.h rename to psw/ae/aesm_service/source/common/oal/power.h index 30397580..1cbdb883 100644 --- a/psw/ae/aesm_service/include/oal/power.h +++ b/psw/ae/aesm_service/source/common/oal/power.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/storage/persistent_storage_info.h b/psw/ae/aesm_service/source/common/persistent_storage_info.h similarity index 97% rename from psw/ae/aesm_service/source/storage/persistent_storage_info.h rename to psw/ae/aesm_service/source/common/persistent_storage_info.h index 2878a02b..d9529cf4 100644 --- a/psw/ae/aesm_service/source/storage/persistent_storage_info.h +++ b/psw/ae/aesm_service/source/common/persistent_storage_info.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/platform_info_blob.h b/psw/ae/aesm_service/source/common/platform_info_blob.h similarity index 98% rename from psw/ae/aesm_service/source/upse/platform_info_blob.h rename to psw/ae/aesm_service/source/common/platform_info_blob.h index 3c7e42cb..f32d8f15 100644 --- a/psw/ae/aesm_service/source/upse/platform_info_blob.h +++ b/psw/ae/aesm_service/source/common/platform_info_blob.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/application/prof_fun.h b/psw/ae/aesm_service/source/common/prof_fun.h similarity index 97% rename from psw/ae/aesm_service/source/aesm/application/prof_fun.h rename to psw/ae/aesm_service/source/common/prof_fun.h index 0bc886f1..5ff792e7 100644 --- a/psw/ae/aesm_service/source/aesm/application/prof_fun.h +++ b/psw/ae/aesm_service/source/common/prof_fun.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/ssl_wrapper/ssl_compat_wrapper.h b/psw/ae/aesm_service/source/common/ssl_compat_wrapper.h similarity index 97% rename from psw/ae/aesm_service/source/ssl_wrapper/ssl_compat_wrapper.h rename to psw/ae/aesm_service/source/common/ssl_compat_wrapper.h index 48fd1843..cc2364b7 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/ssl_compat_wrapper.h +++ b/psw/ae/aesm_service/source/common/ssl_compat_wrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/ssl_wrapper/ssl_crypto.h b/psw/ae/aesm_service/source/common/ssl_crypto.h similarity index 96% rename from psw/ae/aesm_service/source/ssl_wrapper/ssl_crypto.h rename to psw/ae/aesm_service/source/common/ssl_crypto.h index 2c7b5800..110749ef 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/ssl_crypto.h +++ b/psw/ae/aesm_service/source/common/ssl_crypto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/extension/type_length_value.h b/psw/ae/aesm_service/source/common/type_length_value.h similarity index 99% rename from psw/ae/aesm_service/source/aesm/extension/type_length_value.h rename to psw/ae/aesm_service/source/common/type_length_value.h index 7725b7c0..5372b8fb 100644 --- a/psw/ae/aesm_service/source/aesm/extension/type_length_value.h +++ b/psw/ae/aesm_service/source/common/type_length_value.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -78,6 +78,7 @@ #include "pce_cert.h" #include "sgx_report.h" #include "se_memcpy.h" +#include "aeerror.h" #define FOUR_BYTES_SIZE_TYPE 128 /*mask used in type of TLV to indicate that 'size' field uses 4 bytes*/ @@ -135,6 +136,9 @@ typedef struct _tlv_msg_t{ #define EPID_SIGNATURE_SIZE(sign_count) (sizeof(EpidSignature)+((sign_count)-1)*sizeof(NrProof)) + +ae_error_t tlv_error_2_pve_error(tlv_status_t tlv_status); + /*Function to decode a buffer which contains a list of TLV containers *msg.msg_buf: pointer to the start address of the buffer *msg.msg_size: number of bytes of the buffer diff --git a/psw/ae/aesm_service/source/core/AESMLogicWrapper.cpp b/psw/ae/aesm_service/source/core/AESMLogicWrapper.cpp new file mode 100644 index 00000000..3b1c3e78 --- /dev/null +++ b/psw/ae/aesm_service/source/core/AESMLogicWrapper.cpp @@ -0,0 +1,780 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "AESMLogicWrapper.h" +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "sgx_quote.h" +#include "launch_service.h" +#include "pseop_service.h" +#include "epid_quote_service.h" +#include "quote_ex_service.h" +#include "psepr_service.h" +#include "pce_service.h" +#include "network_service.h" + +#include "arch.h" +#include "sgx_urts.h" +#include "oal/oal.h" +//#include "sgx_quote_3.h" +//#include "sgx_ql_quote.h" + +static long g_launch_service_bundle_id = -1; +static cppmicroservices::BundleContext g_fw_ctx; +using namespace cppmicroservices; +static Framework g_fw = FrameworkFactory().NewFramework(); + + +template +bool get_service_from_id(long id, std::shared_ptr &service) noexcept +{ + if (!g_fw_ctx || -1 == id) + return false; + try + { + auto bundle = g_fw_ctx.GetBundle(id); + auto context = bundle.GetBundleContext(); + auto ref = context.GetServiceReference(); + service = context.GetService(ref); + } + catch(...) + { + return false; + } + return true; +} + +extern "C" sgx_status_t get_launch_token(const enclave_css_t *signature, + const sgx_attributes_t *attribute, + sgx_launch_token_t *launch_token) +{ + std::shared_ptr service; + if (!get_service_from_id(g_launch_service_bundle_id, service)) + { + return SGX_ERROR_SERVICE_UNAVAILABLE; + } + return service->get_launch_token(signature, attribute, launch_token); +} + +AESMLogicWrapper::AESMLogicWrapper() + :m_pseop_service_bundle_id(-1), + m_quote_service_bundle_id(-1), + m_launch_service_bundle_id(-1), + m_ecdsa_quote_service_bundle_id(-1) +{ +} + +aesm_error_t AESMLogicWrapper::init_quote_ex( + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + uint8_t **target_info, uint32_t *target_info_size, + bool refresh_att_key, + bool b_pub_key_id, size_t *pub_key_id_size, uint8_t **pub_key_id) +{ + uint8_t *output_target_info = new uint8_t[sizeof(sgx_target_info_t)](); + uint32_t output_target_info_size = sizeof(sgx_target_info_t); + uint8_t *output_pub_key_id = NULL; + size_t output_pub_key_id_size = 0; + if (b_pub_key_id) + { + output_pub_key_id = new uint8_t[sizeof(sgx_sha256_hash_t)](); + output_pub_key_id_size = *pub_key_id_size; + } + + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + + std::shared_ptr service; + if (!get_service_from_id(m_ecdsa_quote_service_bundle_id, service)) + { + delete[] output_target_info; + if (b_pub_key_id) + delete[] output_pub_key_id; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->init_quote_ex(att_key_id, att_key_id_size, certification_key_type, + output_target_info, output_target_info_size, refresh_att_key, + output_pub_key_id, &output_pub_key_id_size); + if (result == AESM_SUCCESS) + { + *target_info = output_target_info; + *target_info_size = output_target_info_size; + *pub_key_id_size = output_pub_key_id_size; + *pub_key_id = output_pub_key_id; + } + else + { + delete[] output_target_info; + delete[] output_pub_key_id; + } + return result; +} + +aesm_error_t AESMLogicWrapper::get_quote_size_ex( + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + uint32_t *quote_size) +{ + std::shared_ptr service; + if (!get_service_from_id(m_ecdsa_quote_service_bundle_id, service)) + { + return AESM_SERVICE_NOT_AVAILABLE; + } + + return service->get_quote_size_ex(att_key_id, att_key_id_size, certification_key_type, + quote_size); +} + +aesm_error_t AESMLogicWrapper::get_quote_ex( + uint32_t report_size, const uint8_t *report, + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t qe_report_info_size, uint8_t *qe_report_info, + uint32_t quote_size, uint8_t **quote) +{ + uint8_t *output_quote = new uint8_t[quote_size](); + + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + + std::shared_ptr service; + if (!get_service_from_id(m_ecdsa_quote_service_bundle_id, service)) + { + delete[] output_quote; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->get_quote_ex(report, report_size, att_key_id, att_key_id_size, qe_report_info, + qe_report_info_size, output_quote, quote_size); + if (result == AESM_SUCCESS) + { + *quote = output_quote; + } + else + { + delete[] output_quote; + } + return result; +} + +aesm_error_t AESMLogicWrapper::initQuote(uint8_t** target_info, + uint32_t* target_info_length, + uint8_t** gid, + uint32_t* gid_length) +{ + uint8_t *output_target_info = new uint8_t[sizeof(sgx_target_info_t)](); + uint8_t *output_gid = new uint8_t[sizeof(sgx_epid_group_id_t)](); + uint32_t output_target_info_length = sizeof(sgx_target_info_t); + uint32_t output_gid_length = sizeof(sgx_epid_group_id_t); + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + + std::shared_ptr service; + if (!get_service_from_id(m_quote_service_bundle_id, service)) + { + delete[] output_target_info; + delete[] output_gid; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->init_quote(output_target_info, output_target_info_length, output_gid, output_gid_length); + if (result == AESM_SUCCESS) + { + *target_info = output_target_info; + *target_info_length = output_target_info_length; + + *gid = output_gid; + *gid_length = output_gid_length; + } + else + { + delete[] output_target_info; + delete[] output_gid; + } + return result; +} + +aesm_error_t AESMLogicWrapper::getQuote(uint32_t reportLength, const uint8_t* report, + uint32_t quoteType, + uint32_t spidLength, const uint8_t* spid, + uint32_t nonceLength, const uint8_t* nonce, + uint32_t sig_rlLength, const uint8_t* sig_rl, + uint32_t bufferSize, uint8_t** quote, + bool b_qe_report, uint32_t* qe_reportSize, uint8_t** qe_report) +{ + uint8_t *output_quote = new uint8_t[bufferSize](); + uint8_t *output_qe_report = NULL; + uint32_t output_qe_reportSize = 0; + if (b_qe_report) + { + output_qe_report = new uint8_t[sizeof(sgx_report_t)](); + output_qe_reportSize = sizeof(sgx_report_t); + } + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + std::shared_ptr service; + if (!get_service_from_id(m_quote_service_bundle_id, service)) + { + delete[] output_quote; + if (output_qe_report) + delete[] output_qe_report; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->get_quote(report, reportLength, + quoteType, + spid, spidLength, + nonce, nonceLength, + sig_rl, sig_rlLength, + output_qe_report, output_qe_reportSize, + output_quote, bufferSize); + if (result == AESM_SUCCESS) + { + *quote = output_quote; + + *qe_report = output_qe_report; + *qe_reportSize = output_qe_reportSize; + } + else + { + delete[] output_quote; + if (output_qe_report) + delete[] output_qe_report; + } + return result; +} + +aesm_error_t AESMLogicWrapper::closeSession(uint32_t sessionId) +{ + std::shared_ptr service; + if (!get_service_from_id(m_pseop_service_bundle_id, service)) + { + return AESM_SERVICE_NOT_AVAILABLE; + } + return service->close_session(sessionId); +} + +aesm_error_t AESMLogicWrapper::createSession(uint32_t *session_id, + uint8_t **se_dh_msg1, + uint32_t se_dh_msg1_size) +{ + uint8_t *output_se_dh_msg1 = new uint8_t[se_dh_msg1_size](); + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + std::shared_ptr service; + if (!get_service_from_id(m_pseop_service_bundle_id, service)) + { + delete [] output_se_dh_msg1; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->create_session(session_id, output_se_dh_msg1, se_dh_msg1_size); + if(result == AESM_SUCCESS) + { + *se_dh_msg1 = output_se_dh_msg1; + } + else + { + delete [] output_se_dh_msg1; + } + return result; +} + +aesm_error_t AESMLogicWrapper::exchangeReport(uint32_t session_id, + const uint8_t* se_dh_msg2, + uint32_t se_dh_msg2_size, + uint8_t** se_dh_msg3, + uint32_t se_dh_msg3_size ) +{ + uint8_t *output_se_dh_msg3 = new uint8_t[se_dh_msg3_size](); + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + std::shared_ptr service; + if (!get_service_from_id(m_pseop_service_bundle_id, service)) + { + delete [] output_se_dh_msg3; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->exchange_report(session_id, + se_dh_msg2, + se_dh_msg2_size, + output_se_dh_msg3, + se_dh_msg3_size); + if(result == AESM_SUCCESS) + { + *se_dh_msg3 = output_se_dh_msg3; + } + else + { + delete [] output_se_dh_msg3; + } + return result; +} + +aesm_error_t AESMLogicWrapper::getLaunchToken(const uint8_t *measurement, + uint32_t measurement_size, + const uint8_t *mrsigner, + uint32_t mrsigner_size, + const uint8_t *se_attributes, + uint32_t se_attributes_size, + uint8_t **launch_token, + uint32_t *launch_token_size) +{ + uint32_t output_launch_token_size = sizeof(token_t); + uint8_t *output_launch_token = new uint8_t[sizeof(token_t)](); + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + std::shared_ptr service; + if (!get_service_from_id(m_launch_service_bundle_id, service)) + { + delete [] output_launch_token; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->get_launch_token(measurement, + measurement_size, + mrsigner, + mrsigner_size, + se_attributes, + se_attributes_size, + output_launch_token, + output_launch_token_size); + if(result == AESM_SUCCESS) + { + *launch_token = output_launch_token; + *launch_token_size = output_launch_token_size; + } + else + { + delete [] output_launch_token; + } + return result; +} + +aesm_error_t AESMLogicWrapper::invokeService(const uint8_t *pse_message_req, + uint32_t pse_message_req_size, + uint8_t **pse_message_resp, + uint32_t pse_message_resp_size) +{ + uint8_t* output_pse_message_resp = new uint8_t[pse_message_resp_size](); + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + std::shared_ptr service; + if (!get_service_from_id(m_pseop_service_bundle_id, service)) + { + delete[] output_pse_message_resp; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->invoke_service(pse_message_req, + pse_message_req_size, + output_pse_message_resp, + pse_message_resp_size); + if (result == AESM_SUCCESS) + { + *pse_message_resp = output_pse_message_resp; + } + else + { + delete[] output_pse_message_resp; + } + return result; +} + +aesm_error_t AESMLogicWrapper::getPsCap(uint64_t* ps_cap) +{ + std::shared_ptr service; + if (!get_service_from_id(m_pseop_service_bundle_id, service)) + { + return AESM_SERVICE_NOT_AVAILABLE; + } + + return service->get_ps_cap(ps_cap); +} + +aesm_error_t AESMLogicWrapper::reportAttestationStatus(uint8_t* platform_info, uint32_t platform_info_size, + uint32_t attestation_error_code, + uint8_t** update_info, uint32_t update_info_size) + +{ + uint8_t* output_update_info = new uint8_t[update_info_size](); + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + std::shared_ptr service; + if (!get_service_from_id(m_pseop_service_bundle_id, service)) + { + delete[] output_update_info; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->report_attestation_status(platform_info,platform_info_size, + attestation_error_code, + output_update_info, update_info_size); + + //update_info is valid when result is AESM_UPDATE_AVAILABLE + if (result == AESM_SUCCESS || result == AESM_UPDATE_AVAILABLE) + { + *update_info = output_update_info; + } + else + { + delete[] output_update_info; + } + return result; +} + +aesm_error_t AESMLogicWrapper::getWhiteListSize(uint32_t* white_list_size) +{ + std::shared_ptr service; + if (!get_service_from_id(m_launch_service_bundle_id, service)) + { + return AESM_SERVICE_NOT_AVAILABLE; + } + + return service->get_white_list_size(white_list_size); +} + +aesm_error_t AESMLogicWrapper::getWhiteList(uint8_t **white_list, + uint32_t white_list_size) +{ + uint8_t* output_white_list = new uint8_t[white_list_size](); + aesm_error_t result = AESM_SERVICE_NOT_AVAILABLE; + std::shared_ptr service; + if (!get_service_from_id(m_launch_service_bundle_id, service)) + { + delete[] output_white_list; + return AESM_SERVICE_NOT_AVAILABLE; + } + + result = service->get_white_list(output_white_list, white_list_size); + if (result == AESM_SUCCESS) + { + *white_list = output_white_list; + } + else + { + delete[] output_white_list; + } + return result; +} + +aesm_error_t AESMLogicWrapper::sgxGetExtendedEpidGroupId(uint32_t* x_group_id) +{ + std::shared_ptr service; + if (!get_service_from_id(m_quote_service_bundle_id, service)) + { + return AESM_SERVICE_NOT_AVAILABLE; + } + + return service->get_extended_epid_group_id(x_group_id); +} + +aesm_error_t AESMLogicWrapper::sgxSwitchExtendedEpidGroup(uint32_t x_group_id) +{ + std::shared_ptr service; + if (!get_service_from_id(m_quote_service_bundle_id, service)) + { + return AESM_SERVICE_NOT_AVAILABLE; + } + + return service->switch_extended_epid_group(x_group_id); +} + +aesm_error_t AESMLogicWrapper::sgxRegister(uint8_t* buf, uint32_t buf_size, uint32_t data_type) +{ + if(data_type == SGX_REGISTER_WHITE_LIST_CERT){ + std::shared_ptr service; + if (!get_service_from_id(m_launch_service_bundle_id, service)) + { + return AESM_SERVICE_NOT_AVAILABLE; + } + + return service->white_list_register(buf, buf_size); + }else{ + return AESM_PARAMETER_ERROR; + } +} + +#include +#include +#include +#include +#include +#include "cppmicroservices/GlobalConfig.h" + +#ifdef US_PLATFORM_POSIX +#define PATH_SEPARATOR "/" +#else +#define PATH_SEPARATOR "\\" +#endif + +#define BUNDLE_SUBFOLDER "bundles" +#include "ssl_compat_wrapper.h" + +std::vector get_bundles(const std::string &dir_name) +{ + std::vector files; + std::shared_ptr directory_ptr(opendir(dir_name.c_str()), [](DIR *dir) { dir &&closedir(dir); }); + struct dirent *dirent_ptr; + if (!directory_ptr) + { + std::cout << "Error opening : " << std::strerror(errno) << dir_name << std::endl; + return files; + } + + while ((dirent_ptr = readdir(directory_ptr.get())) != nullptr) + { + std::string file_name = std::string(dirent_ptr->d_name); + size_t length = file_name.length(); + if (file_name.length() <= strlen(US_LIB_EXT)) + continue; + else if (file_name.substr(length - strlen(US_LIB_EXT), length) != US_LIB_EXT) + continue; + files.push_back(dir_name + PATH_SEPARATOR + file_name); + } + return files; +} + +ae_error_t AESMLogicWrapper::service_start() +{ + //AESMLogic::service_start(); + + try + { + // Initialize the framework, such that we can call + // GetBundleContext() later. + g_fw.Init(); + } + catch (const std::exception &e) + { + std::cout << e.what() << std::endl; + return AE_FAILURE; + } + + // The framework inherits from the Bundle class; it is + // itself a bundle. + g_fw_ctx = g_fw.GetBundleContext(); + if (!g_fw_ctx) + { + std::cerr << "Invalid framework context" << std::endl; + return AE_FAILURE; + } + else + { + std::cout << "The path of system bundle: " << g_fw.GetLocation() << std::endl; + } + + char buf[PATH_MAX] = {0}; + Dl_info dl_info; + if (0 == dladdr(__builtin_return_address(0), &dl_info) || + NULL == dl_info.dli_fname) + return AE_FAILURE; + if (strnlen(dl_info.dli_fname, sizeof(buf)) >= sizeof(buf)) + return AE_FAILURE; + (void)strncpy(buf, dl_info.dli_fname, sizeof(buf)); + std::string aesm_path(buf); + std::string bundle_dir(""); + + size_t i = aesm_path.rfind(PATH_SEPARATOR, aesm_path.length()); + if (i != std::string::npos) + { + bundle_dir = aesm_path.substr(0, i) + PATH_SEPARATOR + BUNDLE_SUBFOLDER; + } + // Install all bundles contained in the shared libraries + // given as command line arguments. +#if defined(US_BUILD_SHARED_LIBS) + try + { + for (auto name : get_bundles(bundle_dir)) + { + g_fw.GetBundleContext().InstallBundles(name); + } + } + catch (const std::exception &e) + { + std::cerr << e.what() << std::endl; + } +#endif + + try + { + // Start the framework itself. + g_fw.Start(); + auto bundles = g_fw_ctx.GetBundles(); + for (auto &bundle : bundles) + { + bundle.Start(); + std::cerr << bundle.GetSymbolicName() << ":" << bundle.GetVersion() << std::endl; + } + + for (auto &bundle : bundles) + { + std::cout << bundle.GetSymbolicName() << std::endl; + if (bundle.GetSymbolicName() == "le_launch_service_bundle_name" + && bundle.GetVersion().GetMajor() == ILaunchService::VERSION) + { + m_launch_service_bundle_id = bundle.GetBundleId(); + g_launch_service_bundle_id = m_launch_service_bundle_id; + } + else if (bundle.GetSymbolicName() == "epid_quote_service_bundle_name" + && bundle.GetVersion().GetMajor() == IEpidQuoteService::VERSION) + { + m_quote_service_bundle_id = bundle.GetBundleId(); + } + else if (bundle.GetSymbolicName() == "local_pseop_service_bundle_name" + && bundle.GetVersion().GetMajor() == IPseopService::VERSION) + { + m_pseop_service_bundle_id = bundle.GetBundleId(); + } + else if (bundle.GetSymbolicName() == "ecdsa_quote_service_bundle_name" + && bundle.GetVersion().GetMajor() == IQuoteExService::VERSION) + { + m_ecdsa_quote_service_bundle_id = bundle.GetBundleId(); + } + else if (bundle.GetSymbolicName() == "pce_service_bundle_name" + && bundle.GetVersion().GetMajor() == IPceService::VERSION) + { + m_pce_service_bundle_id = bundle.GetBundleId(); + } + else if (bundle.GetSymbolicName() == "psepr_service_bundle_name" + && bundle.GetVersion().GetMajor() == IPseprService::VERSION) + { + m_psepr_service_bundle_id = bundle.GetBundleId(); + } + else if (bundle.GetSymbolicName() == "linux_network_service_bundle_name" + && bundle.GetVersion().GetMajor() == INetworkService::VERSION) + { + m_network_service_bundle_id = bundle.GetBundleId(); + } + } + } + catch (const std::exception &e) + { + std::cerr << e.what() << std::endl; + return AE_FAILURE; + } + + crypto_initialize(); + + AESM_LOG_INIT(); + + AESM_DBG_INFO("aesm service is starting"); + + if (-1 != m_network_service_bundle_id) + { + std::shared_ptr service; + if (!get_service_from_id(m_network_service_bundle_id, service)) + return AE_FAILURE; + if(AE_SUCCESS != service->start()) + m_network_service_bundle_id = -1; + } + if (-1 != m_pseop_service_bundle_id) + { + std::shared_ptr service; + if (!get_service_from_id(m_pseop_service_bundle_id, service)) + return AE_FAILURE; + if(AE_SUCCESS != service->start()) + m_pseop_service_bundle_id = -1; + } + if (-1 != m_quote_service_bundle_id) + { + std::shared_ptr service; + if (!get_service_from_id(m_quote_service_bundle_id, service)) + return AE_FAILURE; + if(AE_SUCCESS != service->start()) + m_quote_service_bundle_id = -1; + } + if (-1 != m_ecdsa_quote_service_bundle_id) + { + std::shared_ptr service; + if (!get_service_from_id(m_ecdsa_quote_service_bundle_id, service)) + return AE_FAILURE; + if(AE_SUCCESS != service->start()) + m_ecdsa_quote_service_bundle_id = -1; + } + if (-1 != m_launch_service_bundle_id) + { + std::shared_ptr service; + if (!get_service_from_id(m_launch_service_bundle_id, service)) + return AE_FAILURE; + if(AE_SUCCESS != service->start()) + { + m_launch_service_bundle_id = -1; + g_launch_service_bundle_id = -1; + } + } + AESM_DBG_INFO("aesm service started"); + + + return AE_SUCCESS; +} + +void AESMLogicWrapper::service_stop() +{ + AESM_DBG_INFO("AESMLogicWrapper::service_stop"); + std::shared_ptr pseop_service; + if (get_service_from_id(m_pseop_service_bundle_id, pseop_service)) + pseop_service->stop(); + std::shared_ptr psepr_service; + if (get_service_from_id(m_psepr_service_bundle_id, psepr_service)) + psepr_service->stop(); + std::shared_ptr epid_service; + if (get_service_from_id(m_quote_service_bundle_id, epid_service)) + epid_service->stop(); + std::shared_ptr ecdsa_service; + if (get_service_from_id(m_ecdsa_quote_service_bundle_id, ecdsa_service)) + ecdsa_service->stop(); + std::shared_ptr pce_service; + if (get_service_from_id(m_pce_service_bundle_id, pce_service)) + pce_service->stop(); + std::shared_ptr launch_service; + if (get_service_from_id(m_launch_service_bundle_id, launch_service)) + launch_service->stop(); + std::shared_ptr network_service; + if (get_service_from_id(m_network_service_bundle_id, network_service)) + network_service->stop(); + g_fw.Stop(); + g_fw.WaitForStop(std::chrono::minutes(1)); + crypto_cleanup(); + //sleep(60); + AESM_DBG_INFO("aesm service down"); + AESM_LOG_FINI(); +} + +#if !defined(US_BUILD_SHARED_LIBS) +CPPMICROSERVICES_IMPORT_BUNDLE(pce_service_bundle_name) +CPPMICROSERVICES_IMPORT_BUNDLE(epid_quote_service_bundle_name) +CPPMICROSERVICES_IMPORT_BUNDLE(ecdsa_quote_service_bundle_name) +CPPMICROSERVICES_IMPORT_BUNDLE(le_launch_service_bundle_name) +CPPMICROSERVICES_IMPORT_BUNDLE(local_pseop_service_bundle_name) +CPPMICROSERVICES_IMPORT_BUNDLE(psepr_service_bundle_name) +CPPMICROSERVICES_IMPORT_BUNDLE(linux_network_service_bundle_name) +#endif diff --git a/psw/ae/aesm_service/source/aesm_wrapper/src/AESMQueueManager.cpp b/psw/ae/aesm_service/source/core/AESMQueueManager.cpp similarity index 98% rename from psw/ae/aesm_service/source/aesm_wrapper/src/AESMQueueManager.cpp rename to psw/ae/aesm_service/source/core/AESMQueueManager.cpp index 4a93760c..52b632f4 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/src/AESMQueueManager.cpp +++ b/psw/ae/aesm_service/source/core/AESMQueueManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/src/AESMWorkerThread.cpp b/psw/ae/aesm_service/source/core/AESMWorkerThread.cpp similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/src/AESMWorkerThread.cpp rename to psw/ae/aesm_service/source/core/AESMWorkerThread.cpp index e5a378c8..04009c43 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/src/AESMWorkerThread.cpp +++ b/psw/ae/aesm_service/source/core/AESMWorkerThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/src/CAESMServer.cpp b/psw/ae/aesm_service/source/core/CAESMServer.cpp similarity index 98% rename from psw/ae/aesm_service/source/aesm_wrapper/src/CAESMServer.cpp rename to psw/ae/aesm_service/source/core/CAESMServer.cpp index e0c0e0ac..1a5fa6a8 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/src/CAESMServer.cpp +++ b/psw/ae/aesm_service/source/core/CAESMServer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/core/CMakeLists.txt b/psw/ae/aesm_service/source/core/CMakeLists.txt new file mode 100644 index 00000000..278a59da --- /dev/null +++ b/psw/ae/aesm_service/source/core/CMakeLists.txt @@ -0,0 +1,45 @@ +aux_source_directory(. _srcs) + +if(NOT US_BUILD_SHARED_LIBS) + # Set up dependencies to resources from static bundles + usFunctionGetResourceSource(TARGET aesm_service OUT _srcs) +endif() +add_executable(aesm_service ${_srcs}) + +target_include_directories(aesm_service PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/common/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/inc + + ${PROJECT_SOURCE_DIR}/interfaces + ipc +) + +add_subdirectory(ipc) +target_link_libraries(aesm_service + CppMicroServices + oal + utils + ipc +) + +target_compile_definitions(aesm_service PRIVATE + $<$:DBG_LOG> +) + +if(NOT US_BUILD_SHARED_LIBS) + set(_static_bundles ${SUBDIRS}) + target_link_libraries(aesm_service ${_static_bundles}) + usFunctionEmbedResources(TARGET aesm_service + # The executable is not a bundle itself but we still + # need a bundle name for it here. + BUNDLE_NAME aesm_service_bundle_name + # Merge in all resources from static bundles + ZIP_ARCHIVES ${_static_bundles} + ) +endif() diff --git a/psw/ae/aesm_service/source/aesm_wrapper/src/CSelector.cpp b/psw/ae/aesm_service/source/core/CSelector.cpp similarity index 98% rename from psw/ae/aesm_service/source/aesm_wrapper/src/CSelector.cpp rename to psw/ae/aesm_service/source/core/CSelector.cpp index 4c7a2944..dd906ca9 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/src/CSelector.cpp +++ b/psw/ae/aesm_service/source/core/CSelector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/src/Thread.cpp b/psw/ae/aesm_service/source/core/Thread.cpp similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/src/Thread.cpp rename to psw/ae/aesm_service/source/core/Thread.cpp index a26fda52..20985a3f 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/src/Thread.cpp +++ b/psw/ae/aesm_service/source/core/Thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm_wrapper/src/UnixServerSocket.cpp b/psw/ae/aesm_service/source/core/UnixServerSocket.cpp similarity index 97% rename from psw/ae/aesm_service/source/aesm_wrapper/src/UnixServerSocket.cpp rename to psw/ae/aesm_service/source/core/UnixServerSocket.cpp index 633b90d6..740e6f0f 100644 --- a/psw/ae/aesm_service/source/aesm_wrapper/src/UnixServerSocket.cpp +++ b/psw/ae/aesm_service/source/core/UnixServerSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -67,7 +67,7 @@ void UnixServerSocket::init() server_address.sun_family = AF_UNIX; memset(server_address.sun_path, 0, sizeof(server_address.sun_path)); - strncpy(server_address.sun_path, mSocketBase, sizeof(server_address.sun_path)); + strncpy(server_address.sun_path, mSocketBase, sizeof(server_address.sun_path) - 1); unlink(server_address.sun_path); socklen_t server_len = sizeof(server_address); diff --git a/psw/ae/common/src/AECloseSessionRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AECloseSessionRequest.cpp similarity index 98% rename from psw/ae/common/src/AECloseSessionRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AECloseSessionRequest.cpp index 88ed696c..5dbc3472 100644 --- a/psw/ae/common/src/AECloseSessionRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AECloseSessionRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AECloseSessionRequest.h b/psw/ae/aesm_service/source/core/ipc/AECloseSessionRequest.h similarity index 97% rename from psw/ae/common/inc/AECloseSessionRequest.h rename to psw/ae/aesm_service/source/core/ipc/AECloseSessionRequest.h index 7cfce58c..f792d7df 100644 --- a/psw/ae/common/inc/AECloseSessionRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AECloseSessionRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AECloseSessionResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AECloseSessionResponse.cpp similarity index 98% rename from psw/ae/common/src/AECloseSessionResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AECloseSessionResponse.cpp index 0c6d29e6..b89c702e 100644 --- a/psw/ae/common/src/AECloseSessionResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AECloseSessionResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AECloseSessionResponse.h b/psw/ae/aesm_service/source/core/ipc/AECloseSessionResponse.h similarity index 97% rename from psw/ae/common/inc/AECloseSessionResponse.h rename to psw/ae/aesm_service/source/core/ipc/AECloseSessionResponse.h index 0d062d0c..f7c31caf 100644 --- a/psw/ae/common/inc/AECloseSessionResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AECloseSessionResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AECreateSessionRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AECreateSessionRequest.cpp similarity index 98% rename from psw/ae/common/src/AECreateSessionRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AECreateSessionRequest.cpp index 317f9784..0837937d 100644 --- a/psw/ae/common/src/AECreateSessionRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AECreateSessionRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AECreateSessionRequest.h b/psw/ae/aesm_service/source/core/ipc/AECreateSessionRequest.h similarity index 97% rename from psw/ae/common/inc/AECreateSessionRequest.h rename to psw/ae/aesm_service/source/core/ipc/AECreateSessionRequest.h index 2a2d2df9..a379b478 100644 --- a/psw/ae/common/inc/AECreateSessionRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AECreateSessionRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AECreateSessionResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AECreateSessionResponse.cpp similarity index 98% rename from psw/ae/common/src/AECreateSessionResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AECreateSessionResponse.cpp index c01c297d..e0656148 100644 --- a/psw/ae/common/src/AECreateSessionResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AECreateSessionResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AECreateSessionResponse.h b/psw/ae/aesm_service/source/core/ipc/AECreateSessionResponse.h similarity index 97% rename from psw/ae/common/inc/AECreateSessionResponse.h rename to psw/ae/aesm_service/source/core/ipc/AECreateSessionResponse.h index aeab6985..61fab118 100644 --- a/psw/ae/common/inc/AECreateSessionResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AECreateSessionResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEExchangeReportRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportRequest.cpp similarity index 98% rename from psw/ae/common/src/AEExchangeReportRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEExchangeReportRequest.cpp index 1e480fcb..0bf335ed 100644 --- a/psw/ae/common/src/AEExchangeReportRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEExchangeReportRequest.h b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportRequest.h similarity index 97% rename from psw/ae/common/inc/AEExchangeReportRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEExchangeReportRequest.h index 37e127c1..5e13279e 100644 --- a/psw/ae/common/inc/AEExchangeReportRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEExchangeReportResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportResponse.cpp similarity index 98% rename from psw/ae/common/src/AEExchangeReportResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEExchangeReportResponse.cpp index a5b5918e..897666b4 100644 --- a/psw/ae/common/src/AEExchangeReportResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEExchangeReportResponse.h b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportResponse.h similarity index 97% rename from psw/ae/common/inc/AEExchangeReportResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEExchangeReportResponse.h index 3e5ffd28..ab57180e 100644 --- a/psw/ae/common/inc/AEExchangeReportResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEExchangeReportResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEGetLaunchTokenRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenRequest.cpp similarity index 98% rename from psw/ae/common/src/AEGetLaunchTokenRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenRequest.cpp index cf127bab..1b786ed8 100644 --- a/psw/ae/common/src/AEGetLaunchTokenRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetLaunchTokenRequest.h b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenRequest.h similarity index 97% rename from psw/ae/common/inc/AEGetLaunchTokenRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenRequest.h index cd17a67f..fe67aa34 100644 --- a/psw/ae/common/inc/AEGetLaunchTokenRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEGetLaunchTokenResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenResponse.cpp similarity index 98% rename from psw/ae/common/src/AEGetLaunchTokenResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenResponse.cpp index c9fa78b2..9b8eaa7b 100644 --- a/psw/ae/common/src/AEGetLaunchTokenResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetLaunchTokenResponse.h b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenResponse.h similarity index 97% rename from psw/ae/common/inc/AEGetLaunchTokenResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenResponse.h index c1fe5b5b..dd68a543 100644 --- a/psw/ae/common/inc/AEGetLaunchTokenResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetLaunchTokenResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEGetPsCapRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapRequest.cpp similarity index 98% rename from psw/ae/common/src/AEGetPsCapRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetPsCapRequest.cpp index 206bc87f..3cc4bd05 100644 --- a/psw/ae/common/src/AEGetPsCapRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetPsCapRequest.h b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapRequest.h similarity index 97% rename from psw/ae/common/inc/AEGetPsCapRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEGetPsCapRequest.h index 999e46d9..b66e2926 100644 --- a/psw/ae/common/inc/AEGetPsCapRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEGetPsCapResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapResponse.cpp similarity index 98% rename from psw/ae/common/src/AEGetPsCapResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetPsCapResponse.cpp index a6fbd4da..378cf920 100644 --- a/psw/ae/common/src/AEGetPsCapResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetPsCapResponse.h b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapResponse.h similarity index 97% rename from psw/ae/common/inc/AEGetPsCapResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEGetPsCapResponse.h index 5aeead18..5061d2ef 100644 --- a/psw/ae/common/inc/AEGetPsCapResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetPsCapResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExRequest.cpp new file mode 100644 index 00000000..32db253f --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExRequest.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include "IAESMLogic.h" + +#include +#include +#include + + + AEGetQuoteExRequest::AEGetQuoteExRequest(const aesm::message::Request::GetQuoteExRequest& request) : + m_request(NULL) +{ + m_request = new aesm::message::Request::GetQuoteExRequest(); + m_request->CopyFrom(request); +} + +AEGetQuoteExRequest::AEGetQuoteExRequest(uint32_t report_size, const uint8_t *report, + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t qe_report_info_size, uint8_t *qe_report_info, + uint32_t buf_size, + uint32_t timeout) + : m_request(NULL) +{ + m_request = new aesm::message::Request::GetQuoteExRequest(); + if (report_size !=0 && report != NULL) + m_request->set_report(report, report_size); + if (att_key_id_size != 0 && att_key_id != NULL) + m_request->set_att_key_id(att_key_id, att_key_id_size); + if (qe_report_info_size != 0 && qe_report_info != NULL) + m_request->set_qe_report_info(qe_report_info, qe_report_info_size); + m_request->set_buf_size(buf_size); + m_request->set_timeout(timeout); +} + +AEGetQuoteExRequest::AEGetQuoteExRequest(const AEGetQuoteExRequest& other) + : m_request(NULL) +{ + if (other.m_request != NULL) + m_request = new aesm::message::Request::GetQuoteExRequest(*other.m_request); +} + +AEGetQuoteExRequest::~AEGetQuoteExRequest() +{ + if (m_request != NULL) + delete m_request;} + +AEMessage* AEGetQuoteExRequest::serialize() +{ + AEMessage *ae_msg = NULL; + aesm::message::Request msg; + if (check()) + { + aesm::message::Request::GetQuoteExRequest* mutableReq = msg.mutable_getquoteexreq(); + mutableReq->CopyFrom(*m_request); + + if (msg.ByteSize() <= INT_MAX) { + ae_msg = new AEMessage; + ae_msg->size = (unsigned int)msg.ByteSize(); + ae_msg->data = new char[ae_msg->size]; + msg.SerializeToArray(ae_msg->data, ae_msg->size); + } + } + return ae_msg; +} + +AEGetQuoteExRequest& AEGetQuoteExRequest::operator=(const AEGetQuoteExRequest& other) +{ + if (this == &other) + return *this; + if (m_request != NULL) + { + delete m_request; + m_request = NULL; + } + if (other.m_request != NULL) + m_request = new aesm::message::Request::GetQuoteExRequest(*other.m_request); + return *this; +} + +bool AEGetQuoteExRequest::check() +{ + if (m_request == NULL) + return false; + return m_request->IsInitialized(); +} + +IAERequest::RequestClass AEGetQuoteExRequest::getRequestClass() { + return QUOTING_CLASS; +} + +IAEResponse* AEGetQuoteExRequest::execute(IAESMLogic* aesmLogic) { + aesm_error_t result = AESM_UNEXPECTED_ERROR; + + uint32_t quote_length = 0; + uint8_t* quote = NULL; + uint32_t qe_report_info_size = 0; + uint8_t *qe_report_info = NULL; + + if (check()) + { + uint32_t report_length = 0; + uint8_t* report = NULL; + uint32_t att_key_id_size = 0; + uint8_t *att_key_id = NULL; + + if (m_request->has_report()) + { + report_length = (uint32_t)m_request->report().size(); + report = (uint8_t*)const_cast(m_request->report().data()); + } + if (m_request->has_att_key_id()) + { + att_key_id_size = (uint32_t)m_request->att_key_id().size(); + att_key_id = (uint8_t*)const_cast(m_request->att_key_id().data()); + } + if (m_request->has_qe_report_info()) + { + qe_report_info_size = (unsigned int)m_request->qe_report_info().size(); + qe_report_info = (uint8_t*)const_cast(m_request->qe_report_info().data()); + } + quote_length = (uint32_t)m_request->buf_size(); + + result = aesmLogic->get_quote_ex(report_length, report, + att_key_id_size, att_key_id, + qe_report_info_size, qe_report_info, + quote_length, "e); + + } + AEGetQuoteExResponse* response = new AEGetQuoteExResponse(result, quote_length, quote, qe_report_info_size, qe_report_info); + + //free the buffer before send + if (quote) + delete[] quote; + return response; +} diff --git a/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExRequest.h b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExRequest.h new file mode 100644 index 00000000..6d3089c4 --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExRequest.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __AE_GET_QUOTE_EX_REQUEST_H +#define __AE_GET_QUOTE_EX_REQUEST_H + +#include +#include + +namespace aesm +{ + namespace message + { + class Request_GetQuoteExRequest; + }; +}; +class AEGetQuoteExRequest : public IAERequest +{ + public: + AEGetQuoteExRequest(const aesm::message::Request_GetQuoteExRequest& request); + AEGetQuoteExRequest(uint32_t report_size, const uint8_t *report, + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t qe_report_info_size, uint8_t *qe_report_info, + uint32_t buf_size, + uint32_t timeout = 0); + AEGetQuoteExRequest(const AEGetQuoteExRequest& other); + + ~AEGetQuoteExRequest(); + + AEMessage* serialize(); + //operators + AEGetQuoteExRequest& operator=(const AEGetQuoteExRequest& other); + + //checks + bool check(); + virtual IAEResponse* execute(IAESMLogic*); + + //used to determine in which queue to be placed + virtual RequestClass getRequestClass(); + + protected: + + void ReleaseMemory(); + aesm::message::Request_GetQuoteExRequest* m_request; +}; + +#endif diff --git a/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExResponse.cpp new file mode 100644 index 00000000..a21cd61c --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExResponse.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include + +#include +#include + +AEGetQuoteExResponse::AEGetQuoteExResponse() : + m_response(NULL) +{ +} + +AEGetQuoteExResponse::AEGetQuoteExResponse(aesm::message::Response::GetQuoteExResponse& response) : + m_response(NULL) +{ + m_response = new aesm::message::Response::GetQuoteExResponse(response); +} + +AEGetQuoteExResponse::AEGetQuoteExResponse(uint32_t errorCode, uint32_t quoteLength, const uint8_t* quote, + uint32_t qe_report_info_size, const uint8_t *qe_report_info) : + m_response(NULL) +{ + m_response = new aesm::message::Response::GetQuoteExResponse(); + m_response->set_errorcode(errorCode); + if (quoteLength!= 0 && quote != NULL) + m_response->set_quote(quote, quoteLength); + if (qe_report_info_size != 0 && qe_report_info != NULL) + m_response->set_qe_report_info(qe_report_info, qe_report_info_size); +} + +//copy constructor +AEGetQuoteExResponse::AEGetQuoteExResponse(const AEGetQuoteExResponse& other) : + m_response(NULL) +{ + if (other.m_response != NULL) + m_response = new aesm::message::Response::GetQuoteExResponse(*other.m_response); +} + +AEGetQuoteExResponse::~AEGetQuoteExResponse() +{ + ReleaseMemory(); +} + +void AEGetQuoteExResponse::ReleaseMemory() +{ + if (m_response != NULL) + { + delete m_response; + m_response = NULL; + } +} + +AEMessage* AEGetQuoteExResponse::serialize() +{ + AEMessage *ae_msg = NULL; + aesm::message::Response msg; + if (check()) + { + aesm::message::Response::GetQuoteExResponse* mutableResp = msg.mutable_getquoteexres(); + mutableResp->CopyFrom(*m_response); + + if (msg.ByteSize() <= INT_MAX) { + ae_msg = new AEMessage; + ae_msg->size = (unsigned int)msg.ByteSize(); + ae_msg->data = new char[ae_msg->size]; + msg.SerializeToArray(ae_msg->data, ae_msg->size); + } + } + return ae_msg; +} + +bool AEGetQuoteExResponse::inflateWithMessage(AEMessage* message) +{ + aesm::message::Response msg; + msg.ParseFromArray(message->data, message->size); + if (msg.has_getquoteexres() == false) + return false; + + ReleaseMemory(); + m_response = new aesm::message::Response::GetQuoteExResponse(msg.getquoteexres()); + return true; +} + +bool AEGetQuoteExResponse::GetValues(uint32_t* errorCode, uint32_t quoteLength, uint8_t* quote, + uint32_t qe_report_info_size, uint8_t *qe_report_info) const +{ + if (m_response->has_quote() && quote != NULL) + { + if (m_response->quote().size() <= quoteLength) + memcpy(quote, m_response->quote().c_str(), m_response->quote().size()); + else + return false; + } + if (m_response->has_qe_report_info() && qe_report_info != NULL) + { + if (m_response->qe_report_info().size() <= qe_report_info_size) + memcpy(qe_report_info, m_response->qe_report_info().c_str(), m_response->qe_report_info().size()); + else + return false; + } + + *errorCode = m_response->errorcode(); + return true; +} + +AEGetQuoteExResponse& AEGetQuoteExResponse::operator=(const AEGetQuoteExResponse& other) +{ + if (this == &other) + return *this; + + ReleaseMemory(); + if (other.m_response != NULL) + { + m_response = new aesm::message::Response::GetQuoteExResponse(*other.m_response); + } return *this; +} + +bool AEGetQuoteExResponse::check() +{ + if (m_response == NULL) + return false; + return m_response->IsInitialized(); +} diff --git a/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExResponse.h b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExResponse.h new file mode 100644 index 00000000..3b25c957 --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteExResponse.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __AE_GET_QUOTE_EX_RESPONSE_H +#define __AE_GET_QUOTE_EX_RESPONSE_H + +#include +#include +namespace aesm +{ + namespace message + { + class Response_GetQuoteExResponse; + }; +}; + +class AEGetQuoteExResponse : public IAEResponse +{ + public: + AEGetQuoteExResponse(); + AEGetQuoteExResponse(aesm::message::Response_GetQuoteExResponse& response); + AEGetQuoteExResponse(uint32_t errorCode, uint32_t quoteLength, const uint8_t* quote, + uint32_t qe_report_info_size, const uint8_t *qe_report_info); + AEGetQuoteExResponse(const AEGetQuoteExResponse& other); + + ~AEGetQuoteExResponse(); + + AEMessage* serialize(); + bool inflateWithMessage(AEMessage* message); + bool GetValues(uint32_t* errorCode, uint32_t quoteLength,uint8_t* quote, + uint32_t qe_report_info_size, uint8_t *qe_report_info) const; + + + //operators + AEGetQuoteExResponse& operator=(const AEGetQuoteExResponse& other); + + //checks + bool check(); + protected: + void ReleaseMemory(); + + aesm::message::Response_GetQuoteExResponse* m_response; +}; + +#endif diff --git a/psw/ae/common/src/AEGetQuoteRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteRequest.cpp similarity index 98% rename from psw/ae/common/src/AEGetQuoteRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetQuoteRequest.cpp index 0689a96b..d8476565 100644 --- a/psw/ae/common/src/AEGetQuoteRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetQuoteRequest.h b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteRequest.h similarity index 95% rename from psw/ae/common/inc/AEGetQuoteRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEGetQuoteRequest.h index dc3834dd..b1fc6a44 100644 --- a/psw/ae/common/inc/AEGetQuoteRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,8 +28,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -#ifndef __AE_GET_QUOTE_H -#define __AE_GET_QUOTE_H +#ifndef __AE_GET_QUOTE_REQUEST_H +#define __AE_GET_QUOTE_REQUEST_H #include #include diff --git a/psw/ae/common/src/AEGetQuoteResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteResponse.cpp similarity index 98% rename from psw/ae/common/src/AEGetQuoteResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetQuoteResponse.cpp index b1dd8796..dd483c80 100644 --- a/psw/ae/common/src/AEGetQuoteResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetQuoteResponse.h b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteResponse.h similarity index 97% rename from psw/ae/common/inc/AEGetQuoteResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEGetQuoteResponse.h index f51ba68d..1be9165f 100644 --- a/psw/ae/common/inc/AEGetQuoteResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExRequest.cpp new file mode 100644 index 00000000..4ed07911 --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExRequest.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +AEGetQuoteSizeExRequest::AEGetQuoteSizeExRequest(const aesm::message::Request::GetQuoteSizeExRequest& request) : + m_request(NULL) +{ + m_request = new aesm::message::Request::GetQuoteSizeExRequest(); + m_request->CopyFrom(request); +} + +AEGetQuoteSizeExRequest::AEGetQuoteSizeExRequest(uint32_t att_key_id_size, uint8_t* att_key_id, uint32_t certification_key_type, uint32_t timeout) + :m_request(NULL) +{ + m_request = new aesm::message::Request::GetQuoteSizeExRequest(); + if (att_key_id_size != 0 && att_key_id != NULL) + m_request->set_att_key_id(att_key_id, att_key_id_size); + m_request->set_certification_key_type(certification_key_type); + m_request->set_timeout(timeout); +} + +AEGetQuoteSizeExRequest::AEGetQuoteSizeExRequest(const AEGetQuoteSizeExRequest& other) + :m_request(NULL) +{ + if (other.m_request != NULL) + m_request = new aesm::message::Request::GetQuoteSizeExRequest(*other.m_request); +} + +AEGetQuoteSizeExRequest::~AEGetQuoteSizeExRequest() +{ + if (m_request != NULL) + delete m_request; +} + +AEMessage* AEGetQuoteSizeExRequest::serialize(){ + AEMessage *ae_msg = NULL; + aesm::message::Request msg; + if (check()) + { + aesm::message::Request::GetQuoteSizeExRequest* mutableReq = msg.mutable_getquotesizeexreq(); + mutableReq->CopyFrom(*m_request); + + if (msg.ByteSize() <= INT_MAX) { + ae_msg = new AEMessage; + ae_msg->size = (unsigned int)msg.ByteSize(); + ae_msg->data = new char[ae_msg->size]; + msg.SerializeToArray(ae_msg->data, ae_msg->size); + } + } + return ae_msg; +} + +IAERequest::RequestClass AEGetQuoteSizeExRequest::getRequestClass() { + return LAUNCH_CLASS; +} + +AEGetQuoteSizeExRequest& AEGetQuoteSizeExRequest::operator=(const AEGetQuoteSizeExRequest& other) +{ + if (this == &other) + return *this; + if (m_request != NULL) + { + delete m_request; + m_request = NULL; + } + if (other.m_request != NULL) + m_request = new aesm::message::Request::GetQuoteSizeExRequest(*other.m_request); + return *this; +} + +bool AEGetQuoteSizeExRequest::check() +{ + if (m_request == NULL) + return false; + return m_request->IsInitialized(); +} + + +IAEResponse* AEGetQuoteSizeExRequest::execute(IAESMLogic* aesmLogic) +{ + aesm_error_t result = AESM_UNEXPECTED_ERROR; + uint32_t quote_size = 0; + + if (check()) + { + uint32_t att_key_id_size = 0; + uint8_t* att_key_id = NULL; + uint32_t certification_key_type; + if (m_request->has_att_key_id()) + { + att_key_id_size = (uint32_t)m_request->att_key_id().size(); + att_key_id= (uint8_t*)const_cast(m_request->att_key_id().data()); + } + certification_key_type = (uint32_t)m_request->certification_key_type(); + result = aesmLogic->get_quote_size_ex(att_key_id_size, att_key_id, certification_key_type, "e_size); + } + + AEGetQuoteSizeExResponse * response = new AEGetQuoteSizeExResponse((uint32_t)result, quote_size); + + return response; +} diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_long_lived_thread.h b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExRequest.h similarity index 57% rename from psw/ae/aesm_service/source/aesm/extension/aesm_long_lived_thread.h rename to psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExRequest.h index 1f5c8553..3ac72c86 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_long_lived_thread.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,20 +28,39 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ +#ifndef __AE_GET_QUOTE_SIZE_EX_REQUEST_H +#define __AE_GET_QUOTE_SIZE_EX_REQUEST_H -#ifndef _AESM_LONG_LIVED_THREAD_H_ -#define _AESM_LONG_LIVED_THREAD_H_ -#include "aesm_logic.h" +#include + +namespace aesm +{ + namespace message + { + class Request_GetQuoteSizeExRequest; + }; +}; + +class AEGetQuoteSizeExRequest : public IAERequest{ + public: + AEGetQuoteSizeExRequest(const aesm::message::Request_GetQuoteSizeExRequest& request); + AEGetQuoteSizeExRequest(uint32_t att_key_id_size, uint8_t* att_key_id, uint32_t certification_key_type, uint32_t timeout = 0); + AEGetQuoteSizeExRequest(const AEGetQuoteSizeExRequest& other); + ~AEGetQuoteSizeExRequest(); + + AEMessage* serialize(); + //checks + bool check(); + virtual IAEResponse* execute(IAESMLogic*); + + //used to determine in which queue to be placed + virtual RequestClass getRequestClass(); + AEGetQuoteSizeExRequest& operator=(const AEGetQuoteSizeExRequest& other); + + protected: + //release all members + void ReleaseMemory(); + aesm::message::Request_GetQuoteSizeExRequest* m_request; +}; -#define AESM_STOP_TIMEOUT (60*1000) /*waiting for 1 minute at most*/ -extern ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout=THREAD_TIMEOUT); -extern ae_error_t start_check_ltp_thread(bool& is_new_pairing, unsigned long timeout=THREAD_TIMEOUT); -extern ae_error_t start_white_list_thread(unsigned long timeout=THREAD_TIMEOUT); -extern ae_error_t start_update_pse_thread(const platform_info_blob_wrapper_t* update_blob, uint32_t attestation_status, unsigned long timeout=THREAD_TIMEOUT); -extern ae_error_t start_long_term_pairing_thread(bool& is_new_paring, unsigned long timeout=THREAD_TIMEOUT); -extern bool query_pve_thread_status(void);/*return true if idle and reset clock for thread*/ -extern bool query_pse_thread_status(void);/*return true if idel and reset clock for thread*/ -extern ae_error_t wait_pve_thread(uint64_t time_out_milliseconds=AESM_THREAD_INFINITE); -extern void stop_all_long_lived_threads(uint64_t time_out_milliseconds=AESM_STOP_TIMEOUT); #endif - diff --git a/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExResponse.cpp new file mode 100644 index 00000000..e9cd37ed --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExResponse.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include + +#include +#include + +#include +#include + +AEGetQuoteSizeExResponse::AEGetQuoteSizeExResponse() + :m_response(NULL) +{ +} + +AEGetQuoteSizeExResponse::AEGetQuoteSizeExResponse(aesm::message::Response::GetQuoteSizeExResponse& response) + :m_response(NULL) +{ + m_response = new aesm::message::Response::GetQuoteSizeExResponse(response); +} + +AEGetQuoteSizeExResponse::AEGetQuoteSizeExResponse(uint32_t errorCode, uint32_t quote_size) + :m_response(NULL) +{ + m_response = new aesm::message::Response::GetQuoteSizeExResponse(); + m_response->set_errorcode(errorCode); + m_response->set_quote_size(quote_size); +} + +AEGetQuoteSizeExResponse::AEGetQuoteSizeExResponse(const AEGetQuoteSizeExResponse& other) + :m_response(NULL) +{ + if (other.m_response != NULL) + m_response = new aesm::message::Response::GetQuoteSizeExResponse(*other.m_response); +} + +AEGetQuoteSizeExResponse::~AEGetQuoteSizeExResponse() +{ + ReleaseMemory(); +} + +void AEGetQuoteSizeExResponse::ReleaseMemory() +{ + if (m_response != NULL) + { + delete m_response; + m_response = NULL; + } +} + + +AEMessage* AEGetQuoteSizeExResponse::serialize() +{ + AEMessage *ae_msg = NULL; + aesm::message::Response msg; + if (check()) + { + aesm::message::Response::GetQuoteSizeExResponse* mutableResp = msg.mutable_getquotesizeexres(); + mutableResp->CopyFrom(*m_response); + + if (msg.ByteSize() <= INT_MAX) { + ae_msg = new AEMessage; + ae_msg->size = (unsigned int)msg.ByteSize(); + ae_msg->data = new char[ae_msg->size]; + msg.SerializeToArray(ae_msg->data, ae_msg->size); + } + } + return ae_msg; +} + +bool AEGetQuoteSizeExResponse::inflateWithMessage(AEMessage* message) +{ + aesm::message::Response msg; + msg.ParseFromArray(message->data, message->size); + if (msg.has_getquotesizeexres() == false) + return false; + + ReleaseMemory(); + m_response = new aesm::message::Response::GetQuoteSizeExResponse(msg.getquotesizeexres()); + return true; +} + +bool AEGetQuoteSizeExResponse::GetValues(uint32_t* errorCode, uint32_t* quote_size) const +{ + *quote_size = m_response->quote_size(); + *errorCode = m_response->errorcode(); + return true; +} + +AEGetQuoteSizeExResponse & AEGetQuoteSizeExResponse::operator=(const AEGetQuoteSizeExResponse &other) +{ + if (this == &other) + return *this; + + ReleaseMemory(); + if (other.m_response != NULL) + { + m_response = new aesm::message::Response::GetQuoteSizeExResponse(*other.m_response); + } return *this; +} + +bool AEGetQuoteSizeExResponse::check() +{ + if (m_response == NULL) + return false; + return m_response->IsInitialized(); +} diff --git a/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExResponse.h b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExResponse.h new file mode 100644 index 00000000..8de1d764 --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEGetQuoteSizeExResponse.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __AE_GET_QUOTE_SIZE_EX_RESPONSE_H +#define __AE_GET_QUOTE_SIZE_EX_RESPONSE_H + +#include +#include + +namespace aesm +{ + namespace message + { + class Response_GetQuoteSizeExResponse; + }; +}; + +class AEGetQuoteSizeExResponse : public IAEResponse +{ + public: + AEGetQuoteSizeExResponse(); //default ... will prepare a response that will later be inflated + + AEGetQuoteSizeExResponse(aesm::message::Response_GetQuoteSizeExResponse& response); + AEGetQuoteSizeExResponse(uint32_t errorCode, uint32_t quote_size); + AEGetQuoteSizeExResponse(const AEGetQuoteSizeExResponse& other); + + ~AEGetQuoteSizeExResponse(); + + //inflater + bool inflateWithMessage(AEMessage* message); + + AEMessage* serialize(); + + bool GetValues(uint32_t* errorCode, uint32_t* quote_size) const; + //operators + AEGetQuoteSizeExResponse& operator=(const AEGetQuoteSizeExResponse &other); + + //checks + bool check(); + + protected: + void ReleaseMemory(); + aesm::message::Response_GetQuoteSizeExResponse* m_response; +}; + +#endif diff --git a/psw/ae/common/src/AEGetWhiteListRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListRequest.cpp similarity index 98% rename from psw/ae/common/src/AEGetWhiteListRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListRequest.cpp index 8380657a..bace1acc 100644 --- a/psw/ae/common/src/AEGetWhiteListRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetWhiteListRequest.h b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListRequest.h similarity index 97% rename from psw/ae/common/inc/AEGetWhiteListRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListRequest.h index 51aaf8a1..de1b371d 100644 --- a/psw/ae/common/inc/AEGetWhiteListRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEGetWhiteListResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListResponse.cpp similarity index 98% rename from psw/ae/common/src/AEGetWhiteListResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListResponse.cpp index 7a39ebd9..3375a9bf 100644 --- a/psw/ae/common/src/AEGetWhiteListResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetWhiteListResponse.h b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListResponse.h similarity index 97% rename from psw/ae/common/inc/AEGetWhiteListResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListResponse.h index 93f9e76d..8324ea69 100644 --- a/psw/ae/common/inc/AEGetWhiteListResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEGetWhiteListSizeRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeRequest.cpp similarity index 98% rename from psw/ae/common/src/AEGetWhiteListSizeRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeRequest.cpp index 3852eb78..8a8ba909 100644 --- a/psw/ae/common/src/AEGetWhiteListSizeRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetWhiteListSizeRequest.h b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeRequest.h similarity index 97% rename from psw/ae/common/inc/AEGetWhiteListSizeRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeRequest.h index 66aefe5f..e226a2ce 100644 --- a/psw/ae/common/inc/AEGetWhiteListSizeRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEGetWhiteListSizeResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeResponse.cpp similarity index 98% rename from psw/ae/common/src/AEGetWhiteListSizeResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeResponse.cpp index d75a1698..a083c766 100644 --- a/psw/ae/common/src/AEGetWhiteListSizeResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEGetWhiteListSizeResponse.h b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeResponse.h similarity index 97% rename from psw/ae/common/inc/AEGetWhiteListSizeResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeResponse.h index 6082a438..0a01e99d 100644 --- a/psw/ae/common/inc/AEGetWhiteListSizeResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEGetWhiteListSizeResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExRequest.cpp new file mode 100644 index 00000000..d5fecdae --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExRequest.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include +#include +#include + + +AEInitQuoteExRequest::AEInitQuoteExRequest(const aesm::message::Request::InitQuoteExRequest& request) : + m_request(NULL) +{ + m_request = new aesm::message::Request::InitQuoteExRequest(); + m_request->CopyFrom(request); +} +AEInitQuoteExRequest::AEInitQuoteExRequest(uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + bool refresh_att_key, + bool b_pub_key_id, + size_t buf_size, uint32_t timeout): + m_request(NULL) +{ + m_request = new aesm::message::Request::InitQuoteExRequest(); + if (att_key_id_size != 0 && att_key_id != NULL) + m_request->set_att_key_id(att_key_id, att_key_id_size); + m_request->set_certification_key_type(certification_key_type); + m_request->set_refresh_att_key(refresh_att_key); + m_request->set_b_pub_key_id(b_pub_key_id); + if (buf_size != 0) + m_request->set_buf_size(buf_size); + m_request->set_timeout(timeout); +} + +AEInitQuoteExRequest::AEInitQuoteExRequest(const AEInitQuoteExRequest& other) : + IAERequest(other), m_request(NULL) +{ + if (other.m_request != NULL) + m_request = new aesm::message::Request::InitQuoteExRequest(*other.m_request); +} + +AEInitQuoteExRequest::~AEInitQuoteExRequest() +{ + if (m_request != NULL) + delete m_request; +} + + +AEMessage* AEInitQuoteExRequest::serialize() +{ + AEMessage *ae_msg = NULL; + aesm::message::Request msg; + if (check()) + { + aesm::message::Request::InitQuoteExRequest* mutableReq = msg.mutable_initquoteexreq(); + mutableReq->CopyFrom(*m_request); + + if (msg.ByteSize() <= INT_MAX) { + ae_msg = new AEMessage; + ae_msg->size = (unsigned int)msg.ByteSize(); + ae_msg->data = new char[ae_msg->size]; + msg.SerializeToArray(ae_msg->data, ae_msg->size); + } + } + return ae_msg; +} + +bool AEInitQuoteExRequest::check() +{ + if (m_request == NULL) + return false; + return m_request->IsInitialized(); +} + +IAERequest::RequestClass AEInitQuoteExRequest::getRequestClass() { + return QUOTING_CLASS; +} + +AEInitQuoteExRequest& AEInitQuoteExRequest::operator=(const AEInitQuoteExRequest& other) +{ + if (this == &other) + return *this; + if (m_request != NULL) + { + delete m_request; + m_request = NULL; + } + if (other.m_request != NULL) + m_request = new aesm::message::Request::InitQuoteExRequest(*other.m_request); + return *this; +} + + +IAEResponse* AEInitQuoteExRequest::execute(IAESMLogic* aesmLogic) +{ + aesm_error_t result = AESM_UNEXPECTED_ERROR; + uint8_t* target_info = NULL; + uint32_t target_info_size = 0; + uint8_t *pub_key_id = NULL; + size_t pub_key_id_size = 0; + size_t buf_size = 0; + if (check()) + { + uint32_t att_key_id_size = 0; + uint8_t *att_key_id = NULL; + if (m_request->has_att_key_id()) + { + att_key_id_size = (unsigned int)m_request->att_key_id().size(); + att_key_id = (uint8_t*)const_cast(m_request->att_key_id().data()); + } + + uint32_t certification_key_type = m_request->certification_key_type(); + uint32_t refresh_att_key = m_request->refresh_att_key(); + uint32_t b_pub_key_id = m_request->b_pub_key_id(); + + if (m_request->has_buf_size()) + { + pub_key_id_size = (size_t)m_request->buf_size(); + buf_size = pub_key_id_size; + } + + result= aesmLogic->init_quote_ex( + att_key_id_size, att_key_id, + certification_key_type, + &target_info, &target_info_size, + refresh_att_key, + b_pub_key_id, &pub_key_id_size, &pub_key_id); + } + IAEResponse* response = new AEInitQuoteExResponse(result, target_info_size, target_info, &pub_key_id_size, buf_size, pub_key_id); + if (target_info) + delete[] target_info; + if (pub_key_id) + delete pub_key_id; + return response; +} diff --git a/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExRequest.h b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExRequest.h new file mode 100644 index 00000000..89e7fa9d --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExRequest.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __AE_INIT_QUOTE_EX_REQUEST_H +#define __AE_INIT_QUOTE_EX_REQUEST_H + +#include +namespace aesm +{ + namespace message + { + class Request_InitQuoteExRequest; + }; +}; + + +class AEInitQuoteExRequest : public IAERequest{ + public: + AEInitQuoteExRequest(const aesm::message::Request_InitQuoteExRequest& request); + AEInitQuoteExRequest(uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + bool refresh_att_key, + bool b_pub_key_id, + size_t buf_size, uint32_t timeout = 0); + AEInitQuoteExRequest(const AEInitQuoteExRequest& other); + ~AEInitQuoteExRequest(); + + AEMessage* serialize(); + //checks + bool check(); + virtual IAEResponse* execute(IAESMLogic*); + + //used to determine in which queue to be placed + virtual RequestClass getRequestClass(); + + AEInitQuoteExRequest& operator=(const AEInitQuoteExRequest& other); + + + protected: + //release all members + void ReleaseMemory(); + aesm::message::Request_InitQuoteExRequest* m_request; +}; + +#endif diff --git a/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExResponse.cpp new file mode 100644 index 00000000..c02dcee8 --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExResponse.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include +#include +#include +#include + +AEInitQuoteExResponse::AEInitQuoteExResponse() : + m_response(NULL) +{ +} + +AEInitQuoteExResponse::AEInitQuoteExResponse(aesm::message::Response::InitQuoteExResponse& response) : + m_response(NULL) +{ + m_response = new aesm::message::Response::InitQuoteExResponse(response); +} + +AEInitQuoteExResponse::AEInitQuoteExResponse(uint32_t errorCode, uint32_t target_info_size, uint8_t *target_info, + uint64_t *pub_key_id_size, uint64_t buf_size, const uint8_t *pub_key_id) : + m_response(NULL) +{ + + m_response = new aesm::message::Response::InitQuoteExResponse(); + m_response->set_errorcode(errorCode); + if (target_info_size!= 0 && target_info != NULL) + m_response->set_target_info(target_info, target_info_size); + if (pub_key_id_size!= NULL ) + m_response->set_pub_key_id_size(*pub_key_id_size); + if (buf_size!= 0 && pub_key_id != NULL) + m_response->set_pub_key_id(pub_key_id, buf_size); +} + +AEInitQuoteExResponse::AEInitQuoteExResponse(const AEInitQuoteExResponse& other) : + m_response(NULL) +{ + if (other.m_response != NULL) + m_response = new aesm::message::Response::InitQuoteExResponse(*other.m_response); +} +AEInitQuoteExResponse::~AEInitQuoteExResponse() +{ + ReleaseMemory(); +} + +void AEInitQuoteExResponse::ReleaseMemory() +{ + if (m_response != NULL) + { + delete m_response; + m_response = NULL; + } +} + + +AEMessage* AEInitQuoteExResponse::serialize() +{ + AEMessage *ae_msg = NULL; + + aesm::message::Response msg; + if (check()) + { + aesm::message::Response::InitQuoteExResponse* mutableRes = msg.mutable_initquoteexres(); + mutableRes->CopyFrom(*m_response); + + if (msg.ByteSize() <= INT_MAX) { + ae_msg = new AEMessage; + ae_msg->size = (unsigned int)msg.ByteSize(); + ae_msg->data = new char[ae_msg->size]; + msg.SerializeToArray(ae_msg->data, ae_msg->size); + } + } + return ae_msg; +} + +bool AEInitQuoteExResponse::inflateWithMessage(AEMessage* message) +{ + aesm::message::Response msg; + msg.ParseFromArray(message->data, message->size); + if (msg.has_initquoteexres() == false) + return false; + + //this is an AEGetLaunchTokenResponse + ReleaseMemory(); + m_response = new aesm::message::Response::InitQuoteExResponse(msg.initquoteexres()); + return true; +} + +bool AEInitQuoteExResponse::GetValues(uint32_t* errorCode, uint32_t target_info_size, uint8_t *target_info, + uint64_t* pub_key_id_size, uint64_t buf_size, uint8_t *pub_key_id) const +{ + if (m_response->has_target_info() && target_info != NULL) + { + if (m_response->target_info().size() <= target_info_size) + memcpy(target_info, m_response->target_info().c_str(), m_response->target_info().size()); + else + return false; + } + if (m_response->has_pub_key_id_size()) + *pub_key_id_size = m_response->pub_key_id_size(); + if (m_response->has_pub_key_id() && pub_key_id_size != NULL && m_response->pub_key_id().size() == *pub_key_id_size ) + { + if (m_response->pub_key_id().size() <= buf_size) + memcpy(pub_key_id, m_response->pub_key_id().c_str(), m_response->pub_key_id().size()); + else + return false; + } + *errorCode = m_response->errorcode(); + return true; +} + +AEInitQuoteExResponse & AEInitQuoteExResponse::operator=(const AEInitQuoteExResponse &other) +{ + if (this == &other) + return *this; + + ReleaseMemory(); + if (other.m_response != NULL) + { + m_response = new aesm::message::Response::InitQuoteExResponse(*other.m_response); + } + return *this; +} + +bool AEInitQuoteExResponse::check() +{ + if (m_response == NULL) + return false; + return m_response->IsInitialized(); +} diff --git a/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExResponse.h b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExResponse.h new file mode 100644 index 00000000..b656997b --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteExResponse.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __AE_INIT_QUOTE_EX_RESPONSE_H +#define __AE_INIT_QUOTE_EX_RESPONSE_H + +#include +#include +namespace aesm +{ + namespace message + { + class Response_InitQuoteExResponse; + }; +}; + +class AEInitQuoteExResponse : public IAEResponse +{ + public: + AEInitQuoteExResponse(); //default ... will prepare a response that will later be inflated + + AEInitQuoteExResponse(aesm::message::Response_InitQuoteExResponse& response); + AEInitQuoteExResponse(uint32_t errorCode, uint32_t target_info_size, uint8_t *target_info, + uint64_t* pub_key_id_size, uint64_t buf_size, const uint8_t *pub_key_id); + AEInitQuoteExResponse(const AEInitQuoteExResponse& other); + + ~AEInitQuoteExResponse(); + + //inflater + bool inflateWithMessage(AEMessage* message); + + AEMessage* serialize(); + + bool GetValues(uint32_t* errorCode, uint32_t target_info_size, uint8_t *target_info, + uint64_t *pub_key_id_size, uint64_t buf_size, uint8_t *pub_key_id) const; + + + //operators + AEInitQuoteExResponse& operator=(const AEInitQuoteExResponse &other); + + //checks + bool check(); + + protected: + void ReleaseMemory(); + + aesm::message::Response_InitQuoteExResponse* m_response; +}; + +#endif diff --git a/psw/ae/common/src/AEInitQuoteRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteRequest.cpp similarity index 98% rename from psw/ae/common/src/AEInitQuoteRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEInitQuoteRequest.cpp index f1dd9bc3..41aaa449 100644 --- a/psw/ae/common/src/AEInitQuoteRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEInitQuoteRequest.h b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteRequest.h similarity index 97% rename from psw/ae/common/inc/AEInitQuoteRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEInitQuoteRequest.h index b407b9a0..0ac4ec18 100644 --- a/psw/ae/common/inc/AEInitQuoteRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEInitQuoteResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteResponse.cpp similarity index 98% rename from psw/ae/common/src/AEInitQuoteResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEInitQuoteResponse.cpp index 7077614d..15d5908d 100644 --- a/psw/ae/common/src/AEInitQuoteResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEInitQuoteResponse.h b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteResponse.h similarity index 97% rename from psw/ae/common/inc/AEInitQuoteResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEInitQuoteResponse.h index 1490f8a3..a51c3a34 100644 --- a/psw/ae/common/inc/AEInitQuoteResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEInitQuoteResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEInvokeServiceRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceRequest.cpp similarity index 98% rename from psw/ae/common/src/AEInvokeServiceRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEInvokeServiceRequest.cpp index 90e8dc92..bc6f6988 100644 --- a/psw/ae/common/src/AEInvokeServiceRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEInvokeServiceRequest.h b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceRequest.h similarity index 97% rename from psw/ae/common/inc/AEInvokeServiceRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEInvokeServiceRequest.h index 068417b8..ce2ed40f 100644 --- a/psw/ae/common/inc/AEInvokeServiceRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEInvokeServiceResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceResponse.cpp similarity index 98% rename from psw/ae/common/src/AEInvokeServiceResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEInvokeServiceResponse.cpp index 1fcfc998..4de155a1 100644 --- a/psw/ae/common/src/AEInvokeServiceResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEInvokeServiceResponse.h b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceResponse.h similarity index 97% rename from psw/ae/common/inc/AEInvokeServiceResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEInvokeServiceResponse.h index 582c7ff7..18c59fff 100644 --- a/psw/ae/common/inc/AEInvokeServiceResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEInvokeServiceResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEReportAttestationRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationRequest.cpp similarity index 98% rename from psw/ae/common/src/AEReportAttestationRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AEReportAttestationRequest.cpp index 62222b5f..be426c24 100644 --- a/psw/ae/common/src/AEReportAttestationRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEReportAttestationRequest.h b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationRequest.h similarity index 97% rename from psw/ae/common/inc/AEReportAttestationRequest.h rename to psw/ae/aesm_service/source/core/ipc/AEReportAttestationRequest.h index 11cac47f..67d9cf1a 100644 --- a/psw/ae/common/inc/AEReportAttestationRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AEReportAttestationResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationResponse.cpp similarity index 98% rename from psw/ae/common/src/AEReportAttestationResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AEReportAttestationResponse.cpp index 6d83d18f..c00a5a10 100644 --- a/psw/ae/common/src/AEReportAttestationResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AEReportAttestationResponse.h b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationResponse.h similarity index 97% rename from psw/ae/common/inc/AEReportAttestationResponse.h rename to psw/ae/aesm_service/source/core/ipc/AEReportAttestationResponse.h index a33eab55..612f701e 100644 --- a/psw/ae/common/inc/AEReportAttestationResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AEReportAttestationResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AESGXGetExtendedEpidGroupIdRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdRequest.cpp similarity index 98% rename from psw/ae/common/src/AESGXGetExtendedEpidGroupIdRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdRequest.cpp index 120270d4..335ff350 100644 --- a/psw/ae/common/src/AESGXGetExtendedEpidGroupIdRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AESGXGetExtendedEpidGroupIdRequest.h b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdRequest.h similarity index 97% rename from psw/ae/common/inc/AESGXGetExtendedEpidGroupIdRequest.h rename to psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdRequest.h index f5489b41..aa509375 100644 --- a/psw/ae/common/inc/AESGXGetExtendedEpidGroupIdRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AESGXGetExtendedEpidGroupIdResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdResponse.cpp similarity index 98% rename from psw/ae/common/src/AESGXGetExtendedEpidGroupIdResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdResponse.cpp index 4e9e75f3..f8f79036 100644 --- a/psw/ae/common/src/AESGXGetExtendedEpidGroupIdResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AESGXGetExtendedEpidGroupIdResponse.h b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdResponse.h similarity index 97% rename from psw/ae/common/inc/AESGXGetExtendedEpidGroupIdResponse.h rename to psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdResponse.h index ba6357aa..ec2e284e 100644 --- a/psw/ae/common/inc/AESGXGetExtendedEpidGroupIdResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AESGXGetExtendedEpidGroupIdResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AESGXRegisterRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterRequest.cpp similarity index 98% rename from psw/ae/common/src/AESGXRegisterRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AESGXRegisterRequest.cpp index 7d906005..9bb1d1bb 100644 --- a/psw/ae/common/src/AESGXRegisterRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AESGXRegisterRequest.h b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterRequest.h similarity index 97% rename from psw/ae/common/inc/AESGXRegisterRequest.h rename to psw/ae/aesm_service/source/core/ipc/AESGXRegisterRequest.h index 7f8459ea..85362576 100644 --- a/psw/ae/common/inc/AESGXRegisterRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AESGXRegisterResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterResponse.cpp similarity index 98% rename from psw/ae/common/src/AESGXRegisterResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AESGXRegisterResponse.cpp index fd383f65..0e118b5b 100644 --- a/psw/ae/common/src/AESGXRegisterResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AESGXRegisterResponse.h b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterResponse.h similarity index 97% rename from psw/ae/common/inc/AESGXRegisterResponse.h rename to psw/ae/aesm_service/source/core/ipc/AESGXRegisterResponse.h index ab65f1e0..58267daa 100644 --- a/psw/ae/common/inc/AESGXRegisterResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AESGXRegisterResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AESGXSwitchExtendedEpidGroupRequest.cpp b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupRequest.cpp similarity index 98% rename from psw/ae/common/src/AESGXSwitchExtendedEpidGroupRequest.cpp rename to psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupRequest.cpp index bc7483b1..995963b9 100644 --- a/psw/ae/common/src/AESGXSwitchExtendedEpidGroupRequest.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AESGXSwitchExtendedEpidGroupRequest.h b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupRequest.h similarity index 97% rename from psw/ae/common/inc/AESGXSwitchExtendedEpidGroupRequest.h rename to psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupRequest.h index 06175da1..d69e8bce 100644 --- a/psw/ae/common/inc/AESGXSwitchExtendedEpidGroupRequest.h +++ b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupRequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/AESGXSwitchExtendedEpidGroupResponse.cpp b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupResponse.cpp similarity index 98% rename from psw/ae/common/src/AESGXSwitchExtendedEpidGroupResponse.cpp rename to psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupResponse.cpp index 1c3c16bd..43fd160d 100644 --- a/psw/ae/common/src/AESGXSwitchExtendedEpidGroupResponse.cpp +++ b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupResponse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/AESGXSwitchExtendedEpidGroupResponse.h b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupResponse.h similarity index 97% rename from psw/ae/common/inc/AESGXSwitchExtendedEpidGroupResponse.h rename to psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupResponse.h index 98e744ce..5f7771d4 100644 --- a/psw/ae/common/inc/AESGXSwitchExtendedEpidGroupResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/AESGXSwitchExtendedEpidGroupResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/core/ipc/CMakeLists.txt b/psw/ae/aesm_service/source/core/ipc/CMakeLists.txt new file mode 100644 index 00000000..c41841f6 --- /dev/null +++ b/psw/ae/aesm_service/source/core/ipc/CMakeLists.txt @@ -0,0 +1,27 @@ +aux_source_directory(. IPC_LIB_SRCS) +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS messages.proto) +# Print path to generated files +message ("PROTO_SRCS = ${PROTO_SRCS}") +message ("PROTO_HDRS = ${PROTO_HDRS}") +list(APPEND IPC_LIB_SRCS ${PROTO_SRCS}) +add_library (ipc ${IPC_LIB_SRCS}) +target_include_directories(ipc + PUBLIC + ${PROTOBUF_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} + ${PROJECT_SOURCE_DIR}/core/ipc + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/common/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/quote/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/pce_wrapper/inc +) + +# link the exe against the libraries +target_link_libraries(ipc + PUBLIC + ${PROTOBUF_LIBRARIES} +) + diff --git a/psw/ae/common/inc/IAEMessage.h b/psw/ae/aesm_service/source/core/ipc/IAEMessage.h similarity index 97% rename from psw/ae/common/inc/IAEMessage.h rename to psw/ae/aesm_service/source/core/ipc/IAEMessage.h index 3cc7fdc3..36b7e8a8 100644 --- a/psw/ae/common/inc/IAEMessage.h +++ b/psw/ae/aesm_service/source/core/ipc/IAEMessage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/IAERequest.h b/psw/ae/aesm_service/source/core/ipc/IAERequest.h similarity index 97% rename from psw/ae/common/inc/IAERequest.h rename to psw/ae/aesm_service/source/core/ipc/IAERequest.h index 81cc750b..eb223c83 100644 --- a/psw/ae/common/inc/IAERequest.h +++ b/psw/ae/aesm_service/source/core/ipc/IAERequest.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/IAEResponse.h b/psw/ae/aesm_service/source/core/ipc/IAEResponse.h similarity index 97% rename from psw/ae/common/inc/IAEResponse.h rename to psw/ae/aesm_service/source/core/ipc/IAEResponse.h index a72706e8..2134829c 100644 --- a/psw/ae/common/inc/IAEResponse.h +++ b/psw/ae/aesm_service/source/core/ipc/IAEResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/IAESMLogic.h b/psw/ae/aesm_service/source/core/ipc/IAESMLogic.h similarity index 82% rename from psw/ae/common/inc/IAESMLogic.h rename to psw/ae/aesm_service/source/core/ipc/IAESMLogic.h index 7c3c0ccd..94d01a90 100644 --- a/psw/ae/common/inc/IAESMLogic.h +++ b/psw/ae/aesm_service/source/core/ipc/IAESMLogic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,6 +55,24 @@ class IAESMLogic { uint32_t bufferSize, uint8_t** quote, bool b_qe_report, uint32_t* qe_reportSize, uint8_t** qe_report) = 0; + virtual aesm_error_t init_quote_ex( + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + uint8_t **target_info, uint32_t *target_info_size, + bool refresh_att_key, + bool b_pub_key_id, size_t *pub_key_id_size, uint8_t **pub_key_id) = 0; + + virtual aesm_error_t get_quote_size_ex( + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t certification_key_type, + uint32_t *quote_size) = 0; + + virtual aesm_error_t get_quote_ex( + uint32_t report_size, const uint8_t *report, + uint32_t att_key_id_size, const uint8_t *att_key_id, + uint32_t qe_report_info_size, uint8_t *qe_report_info, + uint32_t quote_size, uint8_t **quote) = 0; + virtual aesm_error_t createSession(uint32_t *session_id, uint8_t **se_dh_msg1, uint32_t se_dh_msg1_size) = 0; diff --git a/psw/ae/common/inc/ICommunicationSocket.h b/psw/ae/aesm_service/source/core/ipc/ICommunicationSocket.h similarity index 97% rename from psw/ae/common/inc/ICommunicationSocket.h rename to psw/ae/aesm_service/source/core/ipc/ICommunicationSocket.h index 1815c494..2b002ea5 100644 --- a/psw/ae/common/inc/ICommunicationSocket.h +++ b/psw/ae/aesm_service/source/core/ipc/ICommunicationSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/ISerializer.h b/psw/ae/aesm_service/source/core/ipc/ISerializer.h similarity index 96% rename from psw/ae/common/inc/ISerializer.h rename to psw/ae/aesm_service/source/core/ipc/ISerializer.h index c3f35af8..c43a3c55 100644 --- a/psw/ae/common/inc/ISerializer.h +++ b/psw/ae/aesm_service/source/core/ipc/ISerializer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/ISocketFactory.h b/psw/ae/aesm_service/source/core/ipc/ISocketFactory.h similarity index 96% rename from psw/ae/common/inc/ISocketFactory.h rename to psw/ae/aesm_service/source/core/ipc/ISocketFactory.h index ff9eb2b1..637dec00 100644 --- a/psw/ae/common/inc/ISocketFactory.h +++ b/psw/ae/aesm_service/source/core/ipc/ISocketFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/ITransporter.h b/psw/ae/aesm_service/source/core/ipc/ITransporter.h similarity index 96% rename from psw/ae/common/inc/ITransporter.h rename to psw/ae/aesm_service/source/core/ipc/ITransporter.h index efd271fa..9c89ea63 100644 --- a/psw/ae/common/inc/ITransporter.h +++ b/psw/ae/aesm_service/source/core/ipc/ITransporter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/proto/Makefile b/psw/ae/aesm_service/source/core/ipc/Makefile similarity index 95% rename from psw/ae/common/proto/Makefile rename to psw/ae/aesm_service/source/core/ipc/Makefile index 4d677a6a..f9d8da73 100644 --- a/psw/ae/common/proto/Makefile +++ b/psw/ae/aesm_service/source/core/ipc/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -29,7 +29,7 @@ # # -TOP_DIR = ../../../.. +TOP_DIR = ../../../../../.. include $(TOP_DIR)/buildenv.mk RPC_PROTO := messages.proto diff --git a/psw/ae/common/src/NonBlockingUnixCommunicationSocket.cpp b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixCommunicationSocket.cpp similarity index 99% rename from psw/ae/common/src/NonBlockingUnixCommunicationSocket.cpp rename to psw/ae/aesm_service/source/core/ipc/NonBlockingUnixCommunicationSocket.cpp index 82581865..7726783b 100644 --- a/psw/ae/common/src/NonBlockingUnixCommunicationSocket.cpp +++ b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixCommunicationSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/NonBlockingUnixCommunicationSocket.h b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixCommunicationSocket.h similarity index 97% rename from psw/ae/common/inc/NonBlockingUnixCommunicationSocket.h rename to psw/ae/aesm_service/source/core/ipc/NonBlockingUnixCommunicationSocket.h index 59555afa..86a38668 100644 --- a/psw/ae/common/inc/NonBlockingUnixCommunicationSocket.h +++ b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixCommunicationSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/NonBlockingUnixSocketFactory.cpp b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixSocketFactory.cpp similarity index 96% rename from psw/ae/common/src/NonBlockingUnixSocketFactory.cpp rename to psw/ae/aesm_service/source/core/ipc/NonBlockingUnixSocketFactory.cpp index 261e8f49..1a161cfd 100644 --- a/psw/ae/common/src/NonBlockingUnixSocketFactory.cpp +++ b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixSocketFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/NonBlockingUnixSocketFactory.h b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixSocketFactory.h similarity index 96% rename from psw/ae/common/inc/NonBlockingUnixSocketFactory.h rename to psw/ae/aesm_service/source/core/ipc/NonBlockingUnixSocketFactory.h index fbc84b37..26f2d1c2 100644 --- a/psw/ae/common/inc/NonBlockingUnixSocketFactory.h +++ b/psw/ae/aesm_service/source/core/ipc/NonBlockingUnixSocketFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/ProtobufSerializer.cpp b/psw/ae/aesm_service/source/core/ipc/ProtobufSerializer.cpp similarity index 89% rename from psw/ae/common/src/ProtobufSerializer.cpp rename to psw/ae/aesm_service/source/core/ipc/ProtobufSerializer.cpp index 87551307..f55a6499 100644 --- a/psw/ae/common/src/ProtobufSerializer.cpp +++ b/psw/ae/aesm_service/source/core/ipc/ProtobufSerializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -66,7 +66,12 @@ #include -#include +#include + +#include + +#include + IAERequest* ProtobufSerializer::inflateRequest(AEMessage* message) { if (message == NULL || message->data == NULL) @@ -106,6 +111,12 @@ IAERequest* ProtobufSerializer::inflateRequest(AEMessage* message) { request = new AESGXSwitchExtendedEpidGroupRequest(reqMsg->sgxswitchextendedepidgroupreq()); else if(reqMsg->has_sgxregisterreq() == true) request = new AESGXRegisterRequest(reqMsg->sgxregisterreq()); + else if(reqMsg->has_initquoteexreq() == true) + request = new AEInitQuoteExRequest(reqMsg->initquoteexreq()); + else if(reqMsg->has_getquotesizeexreq() == true) + request = new AEGetQuoteSizeExRequest(reqMsg->getquotesizeexreq()); + else if(reqMsg->has_getquoteexreq() == true) + request = new AEGetQuoteExRequest(reqMsg->getquoteexreq()); delete reqMsg; return request; diff --git a/psw/ae/common/inc/ProtobufSerializer.h b/psw/ae/aesm_service/source/core/ipc/ProtobufSerializer.h similarity index 96% rename from psw/ae/common/inc/ProtobufSerializer.h rename to psw/ae/aesm_service/source/core/ipc/ProtobufSerializer.h index 26d11449..165f134e 100644 --- a/psw/ae/common/inc/ProtobufSerializer.h +++ b/psw/ae/aesm_service/source/core/ipc/ProtobufSerializer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/SocketConfig.h b/psw/ae/aesm_service/source/core/ipc/SocketConfig.h similarity index 96% rename from psw/ae/common/inc/SocketConfig.h rename to psw/ae/aesm_service/source/core/ipc/SocketConfig.h index 17188711..ae237bb4 100644 --- a/psw/ae/common/inc/SocketConfig.h +++ b/psw/ae/aesm_service/source/core/ipc/SocketConfig.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/SocketTransporter.cpp b/psw/ae/aesm_service/source/core/ipc/SocketTransporter.cpp similarity index 98% rename from psw/ae/common/src/SocketTransporter.cpp rename to psw/ae/aesm_service/source/core/ipc/SocketTransporter.cpp index 2fc1ceeb..0579fa89 100644 --- a/psw/ae/common/src/SocketTransporter.cpp +++ b/psw/ae/aesm_service/source/core/ipc/SocketTransporter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/SocketTransporter.h b/psw/ae/aesm_service/source/core/ipc/SocketTransporter.h similarity index 97% rename from psw/ae/common/inc/SocketTransporter.h rename to psw/ae/aesm_service/source/core/ipc/SocketTransporter.h index 978b1e22..756cca50 100644 --- a/psw/ae/common/inc/SocketTransporter.h +++ b/psw/ae/aesm_service/source/core/ipc/SocketTransporter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/UnixCommunicationSocket.cpp b/psw/ae/aesm_service/source/core/ipc/UnixCommunicationSocket.cpp similarity index 99% rename from psw/ae/common/src/UnixCommunicationSocket.cpp rename to psw/ae/aesm_service/source/core/ipc/UnixCommunicationSocket.cpp index 649c3a4c..65da1a6c 100644 --- a/psw/ae/common/src/UnixCommunicationSocket.cpp +++ b/psw/ae/aesm_service/source/core/ipc/UnixCommunicationSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,6 +44,8 @@ UnixCommunicationSocket::UnixCommunicationSocket(const char* socketbase) :mSocketBase(NULL), mWasTimeout(false), mTimeoutMseconds(0) { + memset(&mStartTime, 0, sizeof(struct timeval)); + //doing all this manually to ensure based memory allocation across the solution size_t size = strlen(socketbase) + 1; //ensure a fairly decend size for socketbase is not overflowed @@ -55,8 +57,6 @@ UnixCommunicationSocket::UnixCommunicationSocket(const char* socketbase) strncpy(mSocketBase, socketbase, size); mSocket = -1; - - memset(&mStartTime, 0, sizeof(struct timeval)); } UnixCommunicationSocket::UnixCommunicationSocket(int socket) diff --git a/psw/ae/common/inc/UnixCommunicationSocket.h b/psw/ae/aesm_service/source/core/ipc/UnixCommunicationSocket.h similarity index 97% rename from psw/ae/common/inc/UnixCommunicationSocket.h rename to psw/ae/aesm_service/source/core/ipc/UnixCommunicationSocket.h index 247ef54b..e6a01857 100644 --- a/psw/ae/common/inc/UnixCommunicationSocket.h +++ b/psw/ae/aesm_service/source/core/ipc/UnixCommunicationSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/src/UnixSocketFactory.cpp b/psw/ae/aesm_service/source/core/ipc/UnixSocketFactory.cpp similarity index 97% rename from psw/ae/common/src/UnixSocketFactory.cpp rename to psw/ae/aesm_service/source/core/ipc/UnixSocketFactory.cpp index 107f6d78..a66cb6eb 100644 --- a/psw/ae/common/src/UnixSocketFactory.cpp +++ b/psw/ae/aesm_service/source/core/ipc/UnixSocketFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/UnixSocketFactory.h b/psw/ae/aesm_service/source/core/ipc/UnixSocketFactory.h similarity index 96% rename from psw/ae/common/inc/UnixSocketFactory.h rename to psw/ae/aesm_service/source/core/ipc/UnixSocketFactory.h index 5ebaa574..369a68ca 100644 --- a/psw/ae/common/inc/UnixSocketFactory.h +++ b/psw/ae/aesm_service/source/core/ipc/UnixSocketFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/inc/debug_log.h b/psw/ae/aesm_service/source/core/ipc/debug_log.h similarity index 96% rename from psw/ae/common/inc/debug_log.h rename to psw/ae/aesm_service/source/core/ipc/debug_log.h index 4d3f269a..81101355 100644 --- a/psw/ae/common/inc/debug_log.h +++ b/psw/ae/aesm_service/source/core/ipc/debug_log.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/proto/messages.proto b/psw/ae/aesm_service/source/core/ipc/messages.proto similarity index 80% rename from psw/ae/common/proto/messages.proto rename to psw/ae/aesm_service/source/core/ipc/messages.proto index a4bb580f..fec81f4a 100644 --- a/psw/ae/common/proto/messages.proto +++ b/psw/ae/aesm_service/source/core/ipc/messages.proto @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,7 +29,7 @@ * */ - +syntax = "proto2"; package aesm.message; message Request{ @@ -115,6 +115,29 @@ message Request{ optional uint32 timeout = 9; } + message InitQuoteExRequest{ + optional bytes att_key_id = 1; + required uint32 certification_key_type = 2; + required bool refresh_att_key = 3; + required bool b_pub_key_id = 4; + optional uint64 buf_size = 5; + optional uint32 timeout = 9; + } + + message GetQuoteSizeExRequest{ + optional bytes att_key_id = 1; + required uint32 certification_key_type = 2; + optional uint32 timeout = 9; + } + + message GetQuoteExRequest{ + required bytes report = 1; + optional bytes att_key_id = 2; + optional bytes qe_report_info = 3; + required uint32 buf_size = 4; + optional uint32 timeout = 9; + } + optional InitQuoteRequest initQuoteReq = 1; optional GetQuoteRequest getQuoteReq = 2; optional GetLaunchTokenRequest getLicTokenReq = 3; @@ -129,6 +152,9 @@ message Request{ optional SGXGetExtendedEpidGroupIdRequest sgxGetExtendedEpidGroupIdReq = 12; optional SGXSwitchExtendedEpidGroupRequest sgxSwitchExtendedEpidGroupReq = 13; optional SGXRegisterRequest sgxRegisterReq = 14; + optional InitQuoteExRequest initQuoteExReq = 15; + optional GetQuoteSizeExRequest getQuoteSizeExReq = 16; + optional GetQuoteExRequest getQuoteExReq = 17; } message Response{ @@ -203,6 +229,24 @@ message Response{ required uint32 errorCode = 1 [ default = 1]; } + message InitQuoteExResponse{ + required uint32 errorCode = 1 [default = 1]; + optional bytes target_info = 2; + optional uint64 pub_key_id_size = 3; + optional bytes pub_key_id = 4; + } + + message GetQuoteSizeExResponse{ + required uint32 errorCode = 1 [default = 1]; + optional uint32 quote_size = 2; + } + + message GetQuoteExResponse{ + required uint32 errorCode = 1 [default = 1]; + optional bytes quote = 2; + optional bytes qe_report_info = 3; + } + optional InitQuoteResponse initQuoteRes = 1; optional GetQuoteResponse getQuoteRes = 2; optional GetLaunchTokenResponse getLicTokenRes = 3; @@ -217,4 +261,7 @@ message Response{ optional SGXGetExtendedEpidGroupIdResponse sgxGetExtendedEpidGroupIdRes = 12; optional SGXSwitchExtendedEpidGroupResponse sgxSwitchExtendedEpidGroupRes = 13; optional SGXRegisterResponse sgxRegisterRes = 14; + optional InitQuoteExResponse initQuoteExRes = 15; + optional GetQuoteSizeExResponse getQuoteSizeExRes = 16; + optional GetQuoteExResponse getQuoteExRes = 17; } diff --git a/psw/ae/aesm_service/source/aesm/application/main.cpp b/psw/ae/aesm_service/source/core/main.cpp similarity index 91% rename from psw/ae/aesm_service/source/aesm/application/main.cpp rename to psw/ae/aesm_service/source/core/main.cpp index 17a59cf6..9893af3b 100644 --- a/psw/ae/aesm_service/source/aesm/application/main.cpp +++ b/psw/ae/aesm_service/source/core/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,18 +35,12 @@ #include #include #include -#include +#include #include #include -static bool curl_initialized; -bool is_curl_initialized_succ() -{ - return curl_initialized; -} - static CAESMServer* server = NULL; volatile bool reload = false; @@ -89,12 +83,6 @@ int main(int argc, char *argv[]) { AESM_LOG_FINI(); exit(1); } - CURLcode curl_code = curl_global_init(CURL_GLOBAL_DEFAULT); - if(curl_code!=CURLE_OK){ - curl_initialized = false; - }else{ - curl_initialized = true; - } signal(SIGCHLD, SIG_IGN); signal(SIGHUP, signal_handler); //ignore SIGPIPE, socket is unexpectedly closed by client diff --git a/psw/ae/aesm_service/source/interfaces/epid_quote_service.h b/psw/ae/aesm_service/source/interfaces/epid_quote_service.h new file mode 100644 index 00000000..8d0b6220 --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/epid_quote_service.h @@ -0,0 +1,34 @@ +#ifndef EPID_QUOTE_SERVICE_EXPORT_H +#define EPID_QUOTE_SERVICE_EXPORT_H +#include "quote_service.h" +#include "aesm_error.h" +#include "aeerror.h" +#include "es_info.h" +#include "tlv_common.h" + + +struct IEpidQuoteService : public IQuoteService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~IEpidQuoteService() = default; + + virtual aesm_error_t get_extended_epid_group_id( + uint32_t* x_group_id) = 0; + virtual aesm_error_t switch_extended_epid_group( + uint32_t x_group_id) = 0; + virtual uint32_t endpoint_selection( + endpoint_selection_infos_t& es_info) = 0; + virtual aesm_error_t provision( + bool performance_rekey_used, + uint32_t timeout_usec) = 0; + virtual const char *get_server_url( + aesm_network_server_enum_type_t type) = 0; + virtual const char *get_pse_provisioning_url( + const endpoint_selection_infos_t& es_info) = 0; + enum {GIDMT_UNMATCHED, GIDMT_NOT_AVAILABLE, GIDMT_MATCHED,GIDMT_UNEXPECTED_ERROR}; + virtual uint32_t is_gid_matching_result_in_epid_blob( + const GroupId& gid) = 0; +}; + +#endif /* EPID_QUOTE_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/launch_service.h b/psw/ae/aesm_service/source/interfaces/launch_service.h new file mode 100644 index 00000000..830f08cc --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/launch_service.h @@ -0,0 +1,34 @@ +#ifndef LAUNCH_SERVICE_EXPORT_H +#define LAUNCH_SERVICE_EXPORT_H +#include "service.h" +#include "stdint.h" +#include "aesm_error.h" +#include "sgx_error.h" +#include "sgx_urts.h" +#include "arch.h" + +struct ILaunchService : public IService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~ILaunchService() = default; + + virtual aesm_error_t get_launch_token( + const uint8_t *mrenclave, uint32_t mrenclave_size, + const uint8_t *public_key, uint32_t public_key_size, + const uint8_t *se_attributes, uint32_t se_attributes_size, + uint8_t *lictoken, uint32_t lictoken_size) = 0; + virtual sgx_status_t get_launch_token( + const enclave_css_t *signature, + const sgx_attributes_t *attribute, + sgx_launch_token_t *launch_token) = 0; + virtual aesm_error_t white_list_register( + const uint8_t *white_list_cert, + uint32_t white_list_cert_size) = 0; + virtual aesm_error_t get_white_list( + uint8_t *white_list_cert, uint32_t buf_size) = 0; + virtual aesm_error_t get_white_list_size( + uint32_t *white_list_cert_size) = 0; +}; + +#endif /* LAUNCH_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/network_service.h b/psw/ae/aesm_service/source/interfaces/network_service.h new file mode 100644 index 00000000..09e7f040 --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/network_service.h @@ -0,0 +1,47 @@ +#ifndef NETWORK_SERVICE_EXPORT_H +#define NETWORK_SERVICE_EXPORT_H +#include "service.h" +#include "stdint.h" +#include "aeerror.h" +#include "aesm_error.h" + + +typedef enum _network_protocol_type_t +{ + HTTP = 0, + HTTPS, +} network_protocol_type_t; + +typedef enum _http_methods_t +{ + GET = 0, + POST, +} http_methods_t; + +struct INetworkService : public IService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~INetworkService() = default; + + virtual ae_error_t aesm_send_recv_msg( + const char *url, + const uint8_t *msg, + uint32_t msg_size, + uint8_t* &resp_msg, + uint32_t& resp_size, + http_methods_t type, + bool is_ocsp) = 0; + + virtual void aesm_free_response_msg( + uint8_t *resp) = 0; + + virtual ae_error_t aesm_send_recv_msg_encoding( + const char *url, + const uint8_t *msg, + uint32_t msg_size, + uint8_t* &resp, + uint32_t& resp_size) = 0; +}; + +#endif /* NETWORK_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/pce_service.h b/psw/ae/aesm_service/source/interfaces/pce_service.h new file mode 100644 index 00000000..9bde36af --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/pce_service.h @@ -0,0 +1,47 @@ +#ifndef PCE_SERVICE_EXPORT_H +#define PCE_SERVICE_EXPORT_H +#include "service.h" +#include "sgx_report.h" +#include "aeerror.h" +#include "aesm_error.h" +#include "epid_pve_type.h" +#include "se_sig_rl.h" + + +struct IPceService : public IService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~IPceService() = default; + + //TODO: shall we remove thse 2 interfaces? + // These interfaces provide other bundles the abilities + // to manage the EPC usage and reduce latency. But it will + // increase the coupling between bundles. + virtual ae_error_t load_enclave() = 0; + virtual uint32_t pce_get_target( + sgx_target_info_t *p_target, + sgx_isv_svn_t *p_isvsvn) = 0; + + virtual uint32_t get_pce_info( + const sgx_report_t *p_report, + const uint8_t *p_pek, + uint32_t pek_size, + uint8_t crypto_suite, + uint8_t *p_encrypted_ppid, + uint32_t encrypted_ppid_size, + uint32_t *p_encrypted_ppid_out_size, + sgx_isv_svn_t* p_pce_isvsvn, + uint16_t* p_pce_id, + uint8_t *p_signature_scheme) = 0; + + virtual uint32_t pce_sign_report( + const sgx_isv_svn_t *p_isv_svn, + const sgx_cpu_svn_t *p_cpu_svn, + const sgx_report_t *p_report, + uint8_t *p_sig, + uint32_t sig_size, + uint32_t *p_sig_out_size) = 0; +}; + +#endif /* PCE_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/pseop_service.h b/psw/ae/aesm_service/source/interfaces/pseop_service.h new file mode 100644 index 00000000..3213346b --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/pseop_service.h @@ -0,0 +1,75 @@ +#ifndef PSEOP_SERVICE_EXPORT_H +#define PSEOP_SERVICE_EXPORT_H +#include "service.h" +#include "stdint.h" +#include "Buffer.h" +#include +#include + +struct IPseopService : public IService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~IPseopService() = default; + + virtual aesm_error_t create_session( + uint32_t* session_id, + uint8_t* se_dh_msg1, + uint32_t se_dh_msg1_size) = 0; + + virtual aesm_error_t exchange_report( + uint32_t session_id, + const uint8_t* se_dh_msg2, + uint32_t se_dh_msg2_size, + uint8_t* se_dh_msg3, + uint32_t se_dh_msg3_size) = 0; + + virtual aesm_error_t invoke_service( + const uint8_t* pse_message_req, + uint32_t pse_message_req_size, + uint8_t* pse_message_resp, + uint32_t pse_message_resp_size) = 0; + + virtual aesm_error_t get_ps_cap( + uint64_t* ps_cap) = 0; + + virtual aesm_error_t close_session( + uint32_t session_id) = 0; + + + virtual aesm_error_t report_attestation_status( + uint8_t* platform_info, uint32_t platform_info_size, + uint32_t attestation_status, + uint8_t* update_info, uint32_t update_info_size) = 0; + + virtual ae_error_t save_psda_capability() = 0; + + + virtual ae_error_t PSDA_send_and_recv( + int32_t nCommandId, + void* pComm, + int32_t* responseCode, + uint32_t flag) = 0; + + virtual bool PSDA_is_sigma20_supported() = 0; + + virtual ae_error_t GetS1 + ( /*in*/ const uint8_t* pse_instance_id, + /*out*/ upse::Buffer& s1 + ) = 0; + + virtual ae_error_t ExchangeS2AndS3 + ( /*in*/ const uint8_t* pse_instance_id, + /*in */ const upse::Buffer& s2, + /*out*/ upse::Buffer& s3 + ) = 0; + + virtual ae_error_t get_csme_gid( + /*out*/ uint32_t* p_cse_gid + ) = 0; + + virtual ae_error_t load_enclave() = 0; + virtual void unload_enclave() = 0; +}; + +#endif /* PSEOP_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/psepr_service.h b/psw/ae/aesm_service/source/interfaces/psepr_service.h new file mode 100644 index 00000000..55e1dce9 --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/psepr_service.h @@ -0,0 +1,25 @@ +#ifndef PSEPR_SERVICE_EXPORT_H +#define PSEPR_SERVICE_EXPORT_H +#include "service.h" +#include +#include +#include "platform_info_blob.h" + + +struct IPseprService : public IService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~IPseprService() = default; + + virtual ae_error_t certificate_provisioning( + platform_info_blob_wrapper_t* pib_wrapper) const = 0; + + virtual ae_error_t long_term_pairing( + bool* p_new_pairing) const = 0; + + virtual void unload_enclave() = 0; + +}; + +#endif /* PSEPR_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/quote_ex_service.h b/psw/ae/aesm_service/source/interfaces/quote_ex_service.h new file mode 100644 index 00000000..5ba1919f --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/quote_ex_service.h @@ -0,0 +1,32 @@ +#ifndef QUOTE_EX_SERVICE_EXPORT_H +#define QUOTE_EX_SERVICE_EXPORT_H +#include "service.h" +#include +#include +#include "aesm_error.h" + + +struct IQuoteExService : public IService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~IQuoteExService() = default; + + virtual aesm_error_t init_quote_ex( + const uint8_t *att_key_id, uint32_t att_key_id_size, + uint32_t certification_key_type, + uint8_t *target_info, uint32_t target_info_size, + bool refresh_att_key, + uint8_t *pub_key_id, size_t *pub_key_id_size) = 0; + virtual aesm_error_t get_quote_size_ex( + const uint8_t *att_key_id, uint32_t att_key_id_size, + uint32_t certification_key_type, + uint32_t *quote_size) = 0; + virtual aesm_error_t get_quote_ex( + const uint8_t *app_report, uint32_t app_report_size, + const uint8_t *att_key_id, uint32_t att_key_id_size, + uint8_t *qe_report_info, uint32_t qe_report_info_size, + uint8_t *quote, uint32_t quote_size) = 0; +}; + +#endif /* QUOTE_EX_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/quote_service.h b/psw/ae/aesm_service/source/interfaces/quote_service.h new file mode 100644 index 00000000..e2551572 --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/quote_service.h @@ -0,0 +1,30 @@ +#ifndef QUOTE_SERVICE_EXPORT_H +#define QUOTE_SERVICE_EXPORT_H +#include "service.h" +#include +#include "aesm_error.h" + +struct IQuoteService : public IService +{ + // The value should be the same as the major version in manifest.json + enum {VERSION = 1}; + virtual ~IQuoteService() = default; + + virtual aesm_error_t init_quote( + uint8_t *target_info, + uint32_t target_info_size, + uint8_t *gid, + uint32_t gid_size) = 0; + + virtual aesm_error_t get_quote( + const uint8_t *report, uint32_t report_size, + uint32_t quote_type, + const uint8_t *spid, uint32_t spid_size, + const uint8_t *nonce, uint32_t nonce_size, + const uint8_t *sigrl, uint32_t sigrl_size, + uint8_t *qe_report, uint32_t qe_report_size, + uint8_t *quote, uint32_t buf_size) = 0; + +}; + +#endif /* QUOTE_SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/interfaces/service.h b/psw/ae/aesm_service/source/interfaces/service.h new file mode 100644 index 00000000..371da4dc --- /dev/null +++ b/psw/ae/aesm_service/source/interfaces/service.h @@ -0,0 +1,12 @@ +#ifndef SERVICE_EXPORT_H +#define SERVICE_EXPORT_H +#include "aeerror.h" + +struct IService +{ + virtual ~IService() = default; + virtual ae_error_t start() = 0; + virtual void stop() = 0; +}; + +#endif /* SERVICE_EXPORT_H */ diff --git a/psw/ae/aesm_service/source/network/network_encoding_wrapper.cpp b/psw/ae/aesm_service/source/network/network_encoding_wrapper.cpp deleted file mode 100644 index 72475334..00000000 --- a/psw/ae/aesm_service/source/network/network_encoding_wrapper.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "network_encoding_wrapper.h" -#include "oal/oal.h" -#include "aesm_encode.h" - -ae_error_t AESMNetworkEncoding::aesm_send_recv_msg(const char *url, const uint8_t * msg, uint32_t msg_size, uint8_t* &resp_msg, uint32_t& resp_size, http_methods_t type, bool is_ocsp) -{ - return ::aesm_network_send_receive(url, msg, msg_size, &resp_msg, &resp_size, type, is_ocsp); -} - -ae_error_t AESMNetworkEncoding::aesm_send_recv_msg_encoding_internal(const char *url, const uint8_t * msg, uint32_t msg_size, uint8_t* &resp, uint32_t& resp_size) -{ - resp = NULL; - resp_size = 0; - - ae_error_t ae_ret = AE_SUCCESS; - uint8_t *encode_msg = NULL; - uint32_t encoding_size = get_request_encoding_length(msg); - uint8_t *recv_msg = NULL; - uint32_t decode_buffer_size = 0; - uint32_t recv_size = 0; - if(encoding_size == 0){ - AESM_DBG_WARN("invalid msg_size 0 to send to url:%s", url); - ae_ret = AE_FAILURE; - goto ret_point; - } - encode_msg = reinterpret_cast(malloc(encoding_size)); - if(encode_msg == NULL){ - AESM_DBG_ERROR("malloc failed"); - ae_ret = AE_OUT_OF_MEMORY_ERROR; - goto ret_point; - } -#ifdef DBG_LOG - char dbg_hex_string[256]; - aesm_dbg_format_hex(msg, msg_size, dbg_hex_string, 256); - AESM_DBG_TRACE("send msg \"%s\" to server:%s",dbg_hex_string, url); -#endif - memset(encode_msg, 0, encoding_size); - if(!encode_request(msg, msg_size, encode_msg, &encoding_size)){ - AESM_DBG_ERROR("message encoding error, msg size %d",msg_size); - ae_ret = AE_FAILURE; - goto ret_point; - } - AESM_DBG_TRACE("encoded msg %.*s",encoding_size, encode_msg); - ae_ret = aesm_network_send_receive(url, encode_msg, encoding_size, - &recv_msg, &recv_size, POST, false); - if(ae_ret != AE_SUCCESS ){ - AESM_DBG_ERROR("fail to send encoded msg (size=%d) to url:%s",encoding_size, url); - goto ret_point; - } - if(recv_msg == NULL){ - AESM_DBG_ERROR("recv NULL message from backend server"); - ae_ret = AE_FAILURE; - goto ret_point; - } - AESM_DBG_TRACE("response msg %.*s", recv_size, recv_msg); - decode_buffer_size= get_response_decoding_length(recv_size); - - if(decode_buffer_size == 0){ - AESM_DBG_ERROR("response 0 length message from backend server:%s",url); - ae_ret = AE_FAILURE; - goto ret_point; - } - AESM_DBG_TRACE("Succ recv msg:%.*s", recv_size, recv_msg); - - resp = reinterpret_cast(malloc(decode_buffer_size)); - if(resp == NULL){ - AESM_DBG_ERROR("malloc error"); - ae_ret = AE_OUT_OF_MEMORY_ERROR; - goto ret_point; - } - memset(resp, 0, decode_buffer_size); - if(!decode_response(recv_msg,recv_size, resp, &decode_buffer_size)){ - AESM_DBG_WARN("fail to decode message from server"); - ae_ret = AE_FAILURE; - goto ret_point; - } -#ifdef DBG_LOG - aesm_dbg_format_hex(resp, decode_buffer_size, dbg_hex_string, 256); - AESM_DBG_TRACE("succ decode msg \"%s\" ",dbg_hex_string); -#endif - resp_size = decode_buffer_size; -ret_point: - aesm_free_network_response_buffer(recv_msg); - if(ae_ret != AE_SUCCESS){ - if(resp!=NULL)free(resp); - resp = NULL; - } - if(encode_msg!=NULL)free(encode_msg); - return ae_ret; -} - - -void AESMNetworkEncoding::aesm_free_response_msg(uint8_t *resp) -{ - if(resp!=NULL){ - free(resp); - } -} - - -ae_error_t AESMNetworkEncoding::aesm_send_recv_msg_encoding(const char *url, const uint8_t * msg, uint32_t msg_size, uint8_t* &resp, uint32_t& resp_size) -{ - resp = NULL; - resp_size = 0; - AESM_DBG_TRACE("send msg to url %s",url); - //call global function to encoding message, send/receive message via HTTP POST and decode response message - return aesm_send_recv_msg_encoding_internal(url, msg, msg_size, resp, resp_size); -} - - diff --git a/psw/ae/aesm_service/source/oal/CMakeLists.txt b/psw/ae/aesm_service/source/oal/CMakeLists.txt new file mode 100644 index 00000000..d1dc271f --- /dev/null +++ b/psw/ae/aesm_service/source/oal/CMakeLists.txt @@ -0,0 +1,29 @@ +if(WIN32) + aux_source_directory(windows OAL_LIB_SRCS) +else() + aux_source_directory(linux OAL_LIB_SRCS) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) +endif() +add_library(oal SHARED ${OAL_LIB_SRCS} + "../../../../../common/src/se_thread.c" + "../../../../../common/src/se_trace.c" + "../../../../../common/src/se_time.c") + +target_include_directories(oal PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/common/oal + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk + ${PROJECT_SOURCE_DIR}/../../data/constants/linux +) + +target_compile_definitions(oal PRIVATE + $<$:DBG_LOG> +) + +target_link_libraries(oal Threads::Threads ${CMAKE_DL_LIBS}) +set_property(TARGET oal APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") diff --git a/psw/ae/aesm_service/source/oal/aesm_thread.cpp b/psw/ae/aesm_service/source/oal/linux/aesm_thread.cpp similarity index 99% rename from psw/ae/aesm_service/source/oal/aesm_thread.cpp rename to psw/ae/aesm_service/source/oal/linux/aesm_thread.cpp index 9d2a57e4..5fb429b5 100644 --- a/psw/ae/aesm_service/source/oal/aesm_thread.cpp +++ b/psw/ae/aesm_service/source/oal/linux/aesm_thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/oal/aesm_util.cpp b/psw/ae/aesm_service/source/oal/linux/aesm_util.cpp similarity index 99% rename from psw/ae/aesm_service/source/oal/aesm_util.cpp rename to psw/ae/aesm_service/source/oal/linux/aesm_util.cpp index f73ce365..20e8080c 100644 --- a/psw/ae/aesm_service/source/oal/aesm_util.cpp +++ b/psw/ae/aesm_service/source/oal/linux/aesm_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/oal/error_report.cpp b/psw/ae/aesm_service/source/oal/linux/error_report.cpp similarity index 97% rename from psw/ae/aesm_service/source/oal/error_report.cpp rename to psw/ae/aesm_service/source/oal/linux/error_report.cpp index aaaf9a4c..63a1b867 100644 --- a/psw/ae/aesm_service/source/oal/error_report.cpp +++ b/psw/ae/aesm_service/source/oal/linux/error_report.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/application/event_strings.cpp b/psw/ae/aesm_service/source/oal/linux/event_strings.cpp similarity index 99% rename from psw/ae/aesm_service/source/aesm/application/event_strings.cpp rename to psw/ae/aesm_service/source/oal/linux/event_strings.cpp index db3406e7..48e45753 100644 --- a/psw/ae/aesm_service/source/aesm/application/event_strings.cpp +++ b/psw/ae/aesm_service/source/oal/linux/event_strings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/oal/internal_log.cpp b/psw/ae/aesm_service/source/oal/linux/internal_log.cpp similarity index 99% rename from psw/ae/aesm_service/source/oal/internal_log.cpp rename to psw/ae/aesm_service/source/oal/linux/internal_log.cpp index 529e6081..6752d888 100644 --- a/psw/ae/aesm_service/source/oal/internal_log.cpp +++ b/psw/ae/aesm_service/source/oal/linux/internal_log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/oal/oal_power.cpp b/psw/ae/aesm_service/source/oal/linux/oal_power.cpp similarity index 96% rename from psw/ae/aesm_service/source/oal/oal_power.cpp rename to psw/ae/aesm_service/source/oal/linux/oal_power.cpp index 6db64f7a..9648c259 100644 --- a/psw/ae/aesm_service/source/oal/oal_power.cpp +++ b/psw/ae/aesm_service/source/oal/linux/oal_power.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/storage/persistent_storage_table.cpp b/psw/ae/aesm_service/source/oal/linux/persistent_storage_table.cpp similarity index 99% rename from psw/ae/aesm_service/source/storage/persistent_storage_table.cpp rename to psw/ae/aesm_service/source/oal/linux/persistent_storage_table.cpp index 7160d46f..3b7813c8 100644 --- a/psw/ae/aesm_service/source/storage/persistent_storage_table.cpp +++ b/psw/ae/aesm_service/source/oal/linux/persistent_storage_table.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/protobuf/Makefile b/psw/ae/aesm_service/source/protobuf/Makefile deleted file mode 100644 index c6dad894..00000000 --- a/psw/ae/aesm_service/source/protobuf/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Intel Corporation nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# - -TOP_DIR = $(shell pwd)/../../../../.. -include $(TOP_DIR)/buildenv.mk - -RPC_PROTP_DIR = $(TOP_DIR)/psw/ae/common/proto/ - -RPC_PROTO = messages.proto -RPC_PB_H = messages.pb.h -RPC_PB_C = messages.pb.cc - -PROTOC = protoc - -.PHONY: all clean - -all: $(RPC_PB_C) - -$(RPC_PROTO): - cp $(RPC_PROTP_DIR)$(RPC_PROTO) . - -$(RPC_PB_C): $(RPC_PROTO) - $(PROTOC) $^ --cpp_out=. - -CLEANFILES = $(RPC_PB_H) $(RPC_PB_C) $(RPC_PROTO) - -clean: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) diff --git a/psw/ae/aesm_service/source/qcnl/CMakeLists.txt b/psw/ae/aesm_service/source/qcnl/CMakeLists.txt new file mode 100644 index 00000000..93a17752 --- /dev/null +++ b/psw/ae/aesm_service/source/qcnl/CMakeLists.txt @@ -0,0 +1,25 @@ +find_package(CURL REQUIRED) +if(CURL_FOUND) + message ("CURL found") +else() + message (FATAL_ERROR "Cannot find CURL") +endif() +aux_source_directory(${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/qcnl _srcs) +add_library(sgx_default_qcnl_wrapper SHARED ${_srcs}) + +target_include_directories(sgx_default_qcnl_wrapper PRIVATE + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/qcnl/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/pce_wrapper/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/common/inc +) + +set_property(TARGET sgx_default_qcnl_wrapper APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") +set_property(TARGET sgx_default_qcnl_wrapper APPEND_STRING PROPERTY LINK_DEPENDS + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/qcnl/linux/sgx_default_qcnl.lds + ) + +target_link_libraries(sgx_default_qcnl_wrapper + ${CURL_LIBRARIES} +) + diff --git a/psw/ae/aesm_service/source/qpl/CMakeLists.txt b/psw/ae/aesm_service/source/qpl/CMakeLists.txt new file mode 100644 index 00000000..e50572de --- /dev/null +++ b/psw/ae/aesm_service/source/qpl/CMakeLists.txt @@ -0,0 +1,17 @@ +aux_source_directory(${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/qpl _srcs) +add_library(dcap_quoteprov SHARED ${_srcs}) + +target_include_directories(dcap_quoteprov PRIVATE + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/qcnl/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/qpl/inc + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/quote_wrapper/common/inc +) + +set_property(TARGET dcap_quoteprov APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") +set_property(TARGET dcap_quoteprov APPEND_STRING PROPERTY LINK_DEPENDS + ${PROJECT_SOURCE_DIR}/../../../../external/dcap_source/QuoteGeneration/qpl/linux/sgx_default_quote_provider.lds + ) + +target_link_libraries(dcap_quoteprov sgx_default_qcnl_wrapper) + diff --git a/psw/ae/aesm_service/source/utils/CMakeLists.txt b/psw/ae/aesm_service/source/utils/CMakeLists.txt new file mode 100644 index 00000000..929c354a --- /dev/null +++ b/psw/ae/aesm_service/source/utils/CMakeLists.txt @@ -0,0 +1,35 @@ +find_package(OpenSSL REQUIRED) +if(OPENSSL_FOUND) + message ("OpenSSL found") +else() + message (FATAL_ERROR "Cannot find OPENSSL") +endif() +aux_source_directory(. _srcs) +add_library(utils SHARED ${_srcs} + "../../../../../common/src/sgx_read_rand.cpp" + "../../../../../common/src/sgx_memset_s.cpp") + +target_include_directories(utils PRIVATE + ${PROJECT_SOURCE_DIR}/common + ${PROJECT_SOURCE_DIR}/common/oal + ${PROJECT_SOURCE_DIR}/../../inc + ${PROJECT_SOURCE_DIR}/../../inc/internal + ${PROJECT_SOURCE_DIR}/../../../../common/inc + ${PROJECT_SOURCE_DIR}/../../../../common/inc/internal + ${PROJECT_SOURCE_DIR}/../../../../external/epid-sdk + ${PROJECT_SOURCE_DIR}/../../../../external/rdrand + ${PROJECT_SOURCE_DIR}/../../data/constants/linux +) + +target_compile_definitions(utils PRIVATE + $<$:DBG_LOG> +) + +set_property(TARGET utils APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs") + +target_link_libraries(utils + ${OPENSSL_LIBRARIES} + oal + ${CMAKE_SOURCE_DIR}/../../../../external/rdrand/src/librdrand.a +) + diff --git a/psw/ae/aesm_service/source/aesm/application/aesm_config.cpp b/psw/ae/aesm_service/source/utils/aesm_config.cpp similarity index 98% rename from psw/ae/aesm_service/source/aesm/application/aesm_config.cpp rename to psw/ae/aesm_service/source/utils/aesm_config.cpp index 0ba6b81f..f3aab9a0 100644 --- a/psw/ae/aesm_service/source/aesm/application/aesm_config.cpp +++ b/psw/ae/aesm_service/source/utils/aesm_config.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,7 @@ #include "aesm_config.h" #include "aesm_proxy_type.h" -#include "oal.h" +#include "oal/oal.h" #include "default_url_info.hh" #include #include diff --git a/psw/ae/aesm_service/source/aesm/extension/aesm_long_lived_thread.cpp b/psw/ae/aesm_service/source/utils/aesm_long_lived_thread.cpp similarity index 64% rename from psw/ae/aesm_service/source/aesm/extension/aesm_long_lived_thread.cpp rename to psw/ae/aesm_service/source/utils/aesm_long_lived_thread.cpp index c6d356dc..ad67c110 100644 --- a/psw/ae/aesm_service/source/aesm/extension/aesm_long_lived_thread.cpp +++ b/psw/ae/aesm_service/source/utils/aesm_long_lived_thread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,170 +31,19 @@ #include "aesm_long_lived_thread.h" +#if 0 #include "pve_logic.h" #include "pse_op_logic.h" #include "platform_info_logic.h" +#endif #include "oal/internal_log.h" #include "se_time.h" #include "se_wrapper.h" #include #include -#include -#include "LEClass.h" +//#include "LEClass.h" -enum _thread_state -{ - ths_idle, - ths_busy, - ths_stop//The thread is to be stopped and no new job will be accepted -}; -enum _io_cache_state -{ - ioc_idle, //thread has been finished - ioc_busy, //thread not finished yet - ioc_stop //thread stop required -}; - -#define MAX_OUTPUT_CACHE 50 -#define THREAD_INFINITE_TICK_COUNT 0xFFFFFFFFFFFFFFFFLL -class ThreadStatus; -class BaseThreadIOCache; -typedef ae_error_t (*long_lived_thread_func_t)(BaseThreadIOCache *cache); - -//Base class for cached data of each thread to fork -class BaseThreadIOCache:private Uncopyable{ - time_t timeout; //The data will timeout after the time if the state is not busy - int ref_count; //ref_count is used to track how many threads are currently referencing the data - _io_cache_state status; - //handle of the thread, some thread will be waited by other threads so that we could not - // free the handle until all other threads have got notification that the thread is terminated - aesm_thread_t thread_handle; - friend class ThreadStatus; -protected: - ae_error_t ae_ret; - BaseThreadIOCache():ref_count(0),status(ioc_busy){ - timeout=0; - thread_handle=NULL; - ae_ret = AE_FAILURE; - } - virtual ThreadStatus& get_thread()=0; -public: - virtual ae_error_t entry(void)=0; - virtual bool operator==(const BaseThreadIOCache& oc)const=0; - ae_error_t start(BaseThreadIOCache *&out_ioc, uint32_t timeout=THREAD_TIMEOUT); - void deref(void); - void set_status_finish(); -public: - virtual ~BaseThreadIOCache(){} -}; - -class ThreadStatus: private Uncopyable -{ -private: - AESMLogicMutex thread_mutex; - _thread_state thread_state; - uint64_t status_clock; - BaseThreadIOCache *cur_iocache; - std::listoutput_cache; -protected: - friend class BaseThreadIOCache; - //function to look up cached output, there will be no real thread associated with the input ioc - //If a match is found the input parameter will be free automatically and the matched value is returned - //return true if a thread will be forked for the out_ioc - bool find_or_insert_iocache(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc) - { - AESMLogicLock locker(thread_mutex); - std::list::reverse_iterator it; - out_ioc=NULL; - if(thread_state == ths_stop){ - AESM_DBG_TRACE("thread %p has been stopped and ioc %p not inserted", this,ioc); - delete ioc; - return false;//never visit any item after thread is stopped - } - time_t cur=time(NULL); - AESM_DBG_TRACE("cache size %d",(int)output_cache.size()); - BaseThreadIOCache *remove_candidate = NULL; - for(it=output_cache.rbegin();it!=output_cache.rend();++it){//visit the cache in reverse order so that the newest item will be visited firstly - BaseThreadIOCache *pioc=*it; - if((pioc->status==ioc_idle)&&(pioc->timeoutref_count==0&&remove_candidate==NULL){ - remove_candidate = pioc; - } - continue;//value timeout - } - if(*pioc==*ioc){//matched value find - pioc->ref_count++;//reference it - AESM_DBG_TRACE("IOC %p matching input IOC %p (ref_count:%d,status:%d,timeout:%d) in thread %p",pioc, ioc,(int)pioc->ref_count,(int)pioc->status, (int)pioc->timeout, this); - out_ioc= pioc; - delete ioc; - return false; - } - } - if(thread_state == ths_busy){//It is not permitted to insert in busy status - AESM_DBG_TRACE("thread busy when trying insert input ioc %p",ioc); - delete ioc; - return false; - } - if(remove_candidate!=NULL){ - output_cache.remove(remove_candidate); - delete remove_candidate; - } - if(output_cache.size()>=MAX_OUTPUT_CACHE){ - std::list::iterator fit; - bool erased=false; - for(fit = output_cache.begin(); fit!=output_cache.end();++fit){ - BaseThreadIOCache *pioc=*fit; - if(pioc->ref_count==0){//find a not timeout item to remove - assert(pioc->status==ioc_idle); - AESM_DBG_TRACE("erase idle ioc %p", pioc); - output_cache.erase(fit); - erased = true; - AESM_DBG_TRACE("thread %p cache size %d",this, output_cache.size()); - delete pioc; - break; - } - } - if(!erased){//no item could be removed - AESM_DBG_TRACE("no free ioc found and cannot insert ioc %p",ioc); - delete ioc; - return false;//similar as busy status - } - } - output_cache.push_back(ioc); - out_ioc = cur_iocache = ioc; - cur_iocache->ref_count=2;//initialize to be refenced by parent thread and the thread itself - thread_state = ths_busy;//mark thread to be busy that the thread to be started - AESM_DBG_TRACE("successfully add ioc %p (status=%d,timeout=%d) into thread %p",out_ioc, (int)out_ioc->status, (int)out_ioc->timeout, this); - return true; - } - -public: - ThreadStatus():output_cache() - { - thread_state = ths_idle; - status_clock = 0; - cur_iocache = NULL; - } - void set_status_finish(BaseThreadIOCache* ioc);//only called at the end of aesm_long_lived_thread_entry - void deref(BaseThreadIOCache* iocache); - ae_error_t wait_iocache_timeout(BaseThreadIOCache* ioc, uint64_t stop_tick_count); - - //create thread and wait at most 'timeout' for the thread to be finished - // It will first look up whether there is a previous run with same input before starting the thread - // we should not delete ioc after calling to this function - ae_error_t set_thread_start(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc, uint32_t timeout=THREAD_TIMEOUT); - - void stop_thread(uint64_t stop_milli_second);//We need wait for thread to be terminated and all thread_handle in list to be closed - - ~ThreadStatus(){stop_thread(THREAD_INFINITE_TICK_COUNT);}//ThreadStatus instance should be global object. Otherwise, it is possible that the object is destroyed before a thread waiting for and IOCache got notified and causing exception - - ae_error_t wait_for_cur_thread(uint64_t millisecond); - - //function to query whether current thread is idle, - //if it is idle, return true and reset clock to current clock value - bool query_status_and_reset_clock(void); -}; ae_error_t BaseThreadIOCache::start(BaseThreadIOCache *&out_ioc, uint32_t timeout_value) { @@ -220,6 +69,82 @@ static ae_error_t aesm_long_lived_thread_entry(aesm_thread_arg_type_t arg) return ae_err; } +bool ThreadStatus::find_or_insert_iocache(BaseThreadIOCache* ioc, BaseThreadIOCache *&out_ioc) +{ + AESMLogicLock locker(thread_mutex); + std::list::reverse_iterator it; + out_ioc=NULL; + if(thread_state == ths_stop){ + AESM_DBG_TRACE("thread %p has been stopped and ioc %p not inserted", this,ioc); + delete ioc; + return false;//never visit any item after thread is stopped + } + time_t cur=time(NULL); + AESM_DBG_TRACE("cache size %d",(int)output_cache.size()); + BaseThreadIOCache *remove_candidate = NULL; + for(it=output_cache.rbegin();it!=output_cache.rend();++it){//visit the cache in reverse order so that the newest item will be visited firstly + BaseThreadIOCache *pioc=*it; + if((pioc->status==ioc_idle)&&(pioc->timeoutref_count==0&&remove_candidate==NULL){ + remove_candidate = pioc; + } + continue;//value timeout + } + if(*pioc==*ioc){//matched value find + pioc->ref_count++;//reference it + AESM_DBG_TRACE("IOC %p matching input IOC %p (ref_count:%d,status:%d,timeout:%d) in thread %p",pioc, ioc,(int)pioc->ref_count,(int)pioc->status, (int)pioc->timeout, this); + out_ioc= pioc; + delete ioc; + return false; + } + } + if(thread_state == ths_busy){//It is not permitted to insert in busy status + AESM_DBG_TRACE("thread busy when trying insert input ioc %p",ioc); + delete ioc; + return false; + } + if(remove_candidate!=NULL){ + output_cache.remove(remove_candidate); + delete remove_candidate; + } + if(output_cache.size()>=MAX_OUTPUT_CACHE){ + std::list::iterator fit; + bool erased=false; + for(fit = output_cache.begin(); fit!=output_cache.end();++fit){ + BaseThreadIOCache *pioc=*fit; + if(pioc->ref_count==0){//find a not timeout item to remove + assert(pioc->status==ioc_idle); + AESM_DBG_TRACE("erase idle ioc %p", pioc); + output_cache.erase(fit); + erased = true; + AESM_DBG_TRACE("thread %p cache size %d",this, output_cache.size()); + delete pioc; + break; + } + } + if(!erased){//no item could be removed + AESM_DBG_TRACE("no free ioc found and cannot insert ioc %p",ioc); + delete ioc; + return false;//similar as busy status + } + } + output_cache.push_back(ioc); + out_ioc = cur_iocache = ioc; + cur_iocache->ref_count=2;//initialize to be refenced by parent thread and the thread itself + thread_state = ths_busy;//mark thread to be busy that the thread to be started + AESM_DBG_TRACE("successfully add ioc %p (status=%d,timeout=%d) into thread %p",out_ioc, (int)out_ioc->status, (int)out_ioc->timeout, this); + return true; +} + +ThreadStatus::ThreadStatus():output_cache() +{ + thread_state = ths_idle; + status_clock = 0; + cur_iocache = NULL; +} + + + void ThreadStatus::stop_thread(uint64_t stop_tick_count) { //change state to stop @@ -448,47 +373,12 @@ bool ThreadStatus::query_status_and_reset_clock(void) return true; } +#if 0 //Code above implement logic of threads in the AESM Service //Code below to define IOCache of each thread -static ThreadStatus epid_thread; static ThreadStatus long_term_paring_thread; -static ThreadStatus white_list_thread; - - -class EpidProvIOCache:public BaseThreadIOCache{ - bool performance_rekey;//input -protected: - EpidProvIOCache(bool perf_rekey){ - this->performance_rekey = perf_rekey; - } - virtual ae_error_t entry(void); - virtual ThreadStatus& get_thread(); - friend ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout); -public: - virtual bool operator==(const BaseThreadIOCache& oc)const{ - const EpidProvIOCache *p=dynamic_cast(&oc); - if(p==NULL)return false; - return performance_rekey==p->performance_rekey;//only compare input - } -}; - -class WhiteListIOCache :public BaseThreadIOCache{ -//no input to be cached for white list pulling -protected: - WhiteListIOCache(void){ - } - virtual ae_error_t entry(void); - virtual ThreadStatus& get_thread(); - friend ae_error_t start_white_list_thread(unsigned long timeout); -public: - virtual bool operator==(const BaseThreadIOCache& oc)const{ - const WhiteListIOCache *p = dynamic_cast(&oc); - if (p == NULL) return false; - return true; - } -}; class CheckLtpIOCache:public BaseThreadIOCache{ bool is_new_pairing;//extra output protected: @@ -542,10 +432,6 @@ public: } }; -ThreadStatus& EpidProvIOCache::get_thread() -{ - return epid_thread; -} ThreadStatus& CheckLtpIOCache::get_thread() { @@ -561,15 +447,8 @@ ThreadStatus& CertProvLtpIOCache::get_thread() { return long_term_paring_thread; } -ThreadStatus& WhiteListIOCache::get_thread() -{ - return white_list_thread; -} -ae_error_t EpidProvIOCache::entry() -{ - return ae_ret = PvEAESMLogic::epid_provision_thread_func(performance_rekey); -} + ae_error_t CheckLtpIOCache::entry() { return ae_ret = PlatformInfoLogic::check_ltp_thread_func(is_new_pairing); @@ -584,11 +463,6 @@ ae_error_t CertProvLtpIOCache::entry() { return ae_ret = PSEOPAESMLogic::certificate_provisioning_and_long_term_pairing_func(is_new_pairing); } -ae_error_t WhiteListIOCache::entry() -{ - return ae_ret = CLEClass::update_white_list_by_url(); -} - //start implementation of external functions @@ -616,17 +490,6 @@ ae_error_t WhiteListIOCache::entry() // COPY_OUTPUT(is_new_pairing);// copy out output parameter except for return value from pioc object to output parameter, such as //FINI_THREAD(thread_used) -ae_error_t start_epid_provision_thread(bool performance_rekey, unsigned long timeout) -{ - INIT_THREAD(EpidProvIOCache, timeout, (performance_rekey)) - FINI_THREAD() -} - -ae_error_t start_white_list_thread(unsigned long timeout) -{ - INIT_THREAD(WhiteListIOCache, timeout, ()) - FINI_THREAD() -} ae_error_t start_check_ltp_thread(bool& is_new_pairing, unsigned long timeout) { INIT_THREAD(CheckLtpIOCache, timeout, ()) @@ -646,10 +509,6 @@ ae_error_t start_long_term_pairing_thread(bool& is_new_pairing, unsigned long ti COPY_OUTPUT(is_new_pairing); FINI_THREAD() } -bool query_pve_thread_status(void) -{ - return epid_thread.query_status_and_reset_clock(); -} bool query_pse_thread_status(void) { return long_term_paring_thread.query_status_and_reset_clock(); @@ -668,3 +527,4 @@ void stop_all_long_lived_threads(uint64_t time_out_milliseconds) white_list_thread.stop_thread(stop_tick_count); } +#endif diff --git a/psw/ae/aesm_service/source/aesm/application/aesm_rand.cpp b/psw/ae/aesm_service/source/utils/aesm_rand.cpp similarity index 87% rename from psw/ae/aesm_service/source/aesm/application/aesm_rand.cpp rename to psw/ae/aesm_service/source/utils/aesm_rand.cpp index 3d4f4459..42472d3d 100644 --- a/psw/ae/aesm_service/source/aesm/application/aesm_rand.cpp +++ b/psw/ae/aesm_service/source/utils/aesm_rand.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,6 +38,14 @@ #include "aesm_rand.h" #include "AEClass.h" +ae_error_t sgx_error_to_ae_error(sgx_status_t status) +{ + if(SGX_ERROR_OUT_OF_MEMORY == status) + return AE_OUT_OF_MEMORY_ERROR; + if(SGX_SUCCESS == status) + return AE_SUCCESS; + return AE_FAILURE; +} extern "C" ae_error_t aesm_read_rand(unsigned char *rand_buf, unsigned int length_in_bytes) { diff --git a/psw/ae/aesm_service/source/ssl_wrapper/crypto_aes_gcm.cpp b/psw/ae/aesm_service/source/utils/crypto_aes_gcm.cpp similarity index 98% rename from psw/ae/aesm_service/source/ssl_wrapper/crypto_aes_gcm.cpp rename to psw/ae/aesm_service/source/utils/crypto_aes_gcm.cpp index 258a4d52..329338ba 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/crypto_aes_gcm.cpp +++ b/psw/ae/aesm_service/source/utils/crypto_aes_gcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,7 +32,7 @@ #include "stdlib.h" #include "string.h" #include "ssl_crypto.h" -#include "sgx_memset_s.h"" +#include "sgx_memset_s.h" #include #include diff --git a/psw/ae/aesm_service/source/ssl_wrapper/crypto_cmac128.cpp b/psw/ae/aesm_service/source/utils/crypto_cmac128.cpp similarity index 98% rename from psw/ae/aesm_service/source/ssl_wrapper/crypto_cmac128.cpp rename to psw/ae/aesm_service/source/utils/crypto_cmac128.cpp index 251a4e1e..c856820e 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/crypto_cmac128.cpp +++ b/psw/ae/aesm_service/source/utils/crypto_cmac128.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/ssl_wrapper/crypto_ecc.cpp b/psw/ae/aesm_service/source/utils/crypto_ecc.cpp similarity index 98% rename from psw/ae/aesm_service/source/ssl_wrapper/crypto_ecc.cpp rename to psw/ae/aesm_service/source/utils/crypto_ecc.cpp index 64c63546..df020364 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/crypto_ecc.cpp +++ b/psw/ae/aesm_service/source/utils/crypto_ecc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -110,8 +110,6 @@ sgx_status_t sgx_ecdsa_verify(const uint8_t *p_data, BIGNUM *bn_pub_y = NULL; BIGNUM *bn_r = NULL; BIGNUM *bn_s = NULL; - BIGNUM *prev_bn_r = NULL; - BIGNUM *prev_bn_s = NULL; EC_POINT *public_point = NULL; ECDSA_SIG *ecdsa_sig = NULL; unsigned char digest[SGX_SHA256_HASH_SIZE] = { 0 }; diff --git a/psw/ae/aesm_service/source/ssl_wrapper/crypto_rsa.cpp b/psw/ae/aesm_service/source/utils/crypto_rsa.cpp similarity index 98% rename from psw/ae/aesm_service/source/ssl_wrapper/crypto_rsa.cpp rename to psw/ae/aesm_service/source/utils/crypto_rsa.cpp index a261866a..a8f765da 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/crypto_rsa.cpp +++ b/psw/ae/aesm_service/source/utils/crypto_rsa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -186,7 +186,6 @@ sgx_status_t sgx_rsa_pub_encrypt_sha256(void* rsa_key, unsigned char* pout_data, } sgx_status_t ret_code = SGX_ERROR_UNEXPECTED; - char * err; EVP_PKEY_CTX *ctx = NULL; do { diff --git a/psw/ae/aesm_service/source/ssl_wrapper/crypto_sha256_msg.cpp b/psw/ae/aesm_service/source/utils/crypto_sha256_msg.cpp similarity index 97% rename from psw/ae/aesm_service/source/ssl_wrapper/crypto_sha256_msg.cpp rename to psw/ae/aesm_service/source/utils/crypto_sha256_msg.cpp index 77545f20..8b686d12 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/crypto_sha256_msg.cpp +++ b/psw/ae/aesm_service/source/utils/crypto_sha256_msg.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/upse/helper.cpp b/psw/ae/aesm_service/source/utils/helper.cpp similarity index 99% rename from psw/ae/aesm_service/source/upse/helper.cpp rename to psw/ae/aesm_service/source/utils/helper.cpp index e9b27d59..9895a63a 100644 --- a/psw/ae/aesm_service/source/upse/helper.cpp +++ b/psw/ae/aesm_service/source/utils/helper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -150,10 +150,8 @@ uint32_t Helper::ltpBlobSessionProp(const pairing_blob_t& pairing_blob) { return pairing_blob.plaintext.cse_sec_prop.ps_hw_sec_info.session_prop; } - uint8_t* Helper::ltpBlobInstanceID(pairing_blob_t& pairing_blob) { - // The offsets of pse_instance_id in pairing blob v1 and v2 are same return pairing_blob.plaintext.pse_instance_id; } diff --git a/psw/ae/aesm_service/source/ssl_wrapper/ssl_compat_wrapper.cpp b/psw/ae/aesm_service/source/utils/ssl_compat_wrapper.cpp similarity index 98% rename from psw/ae/aesm_service/source/ssl_wrapper/ssl_compat_wrapper.cpp rename to psw/ae/aesm_service/source/utils/ssl_compat_wrapper.cpp index 33b39921..c67ebfbc 100644 --- a/psw/ae/aesm_service/source/ssl_wrapper/ssl_compat_wrapper.cpp +++ b/psw/ae/aesm_service/source/utils/ssl_compat_wrapper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/aesm_service/source/aesm/extension/type_length_value.cpp b/psw/ae/aesm_service/source/utils/type_length_value.cpp similarity index 96% rename from psw/ae/aesm_service/source/aesm/extension/type_length_value.cpp rename to psw/ae/aesm_service/source/utils/type_length_value.cpp index 79b461ef..e07bf42f 100644 --- a/psw/ae/aesm_service/source/aesm/extension/type_length_value.cpp +++ b/psw/ae/aesm_service/source/utils/type_length_value.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,6 +41,29 @@ #include "oal/oal.h" #include + +ae_error_t tlv_error_2_pve_error(tlv_status_t tlv_status) +{ + switch(tlv_status){ + case TLV_SUCCESS: + return AE_SUCCESS; + case TLV_INVALID_PARAMETER_ERROR: + return PVE_PARAMETER_ERROR; + case TLV_INVALID_MSG_ERROR: + case TLV_INVALID_FORMAT: + return PVE_MSG_ERROR; + case TLV_INSUFFICIENT_MEMORY: + return PVE_INSUFFICIENT_MEMORY_ERROR; + case TLV_OUT_OF_MEMORY_ERROR: + return AE_OUT_OF_MEMORY_ERROR; + case TLV_UNKNOWN_ERROR: + case TLV_MORE_TLVS: + case TLV_UNSUPPORTED: + return PVE_UNEXPECTED_ERROR; + } + return PVE_UNEXPECTED_ERROR; +} + //Function to write tlv header into a msg according to tlv info, the input buffer size should be at least MAX_TLV_HEADER_SIZE static tlv_status_t write_tlv_header(uint8_t *msg, const tlv_info_t *info) { diff --git a/psw/ae/buildenv.mk b/psw/ae/buildenv.mk index a3155096..7ccd80e5 100644 --- a/psw/ae/buildenv.mk +++ b/psw/ae/buildenv.mk @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/common/pek_pub_key.cpp b/psw/ae/common/pek_pub_key.cpp index 2dc2dda3..c7ec3893 100644 --- a/psw/ae/common/pek_pub_key.cpp +++ b/psw/ae/common/pek_pub_key.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/pse_pr_common.cpp b/psw/ae/common/pse_pr_common.cpp index 6f1e572b..4ecc2db4 100644 --- a/psw/ae/common/pse_pr_common.cpp +++ b/psw/ae/common/pse_pr_common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/pve_qe_common.cpp b/psw/ae/common/pve_qe_common.cpp index df9f7e41..54d9b29f 100644 --- a/psw/ae/common/pve_qe_common.cpp +++ b/psw/ae/common/pve_qe_common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/se_ecdsa_verify_internal.cpp b/psw/ae/common/se_ecdsa_verify_internal.cpp index 9657af53..1c09a68a 100644 --- a/psw/ae/common/se_ecdsa_verify_internal.cpp +++ b/psw/ae/common/se_ecdsa_verify_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/se_sig_rl.cpp b/psw/ae/common/se_sig_rl.cpp index 391eb4ef..30e74299 100644 --- a/psw/ae/common/se_sig_rl.cpp +++ b/psw/ae/common/se_sig_rl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/t_pairing_blob.cpp b/psw/ae/common/t_pairing_blob.cpp index f0a10b0f..e36c6bde 100644 --- a/psw/ae/common/t_pairing_blob.cpp +++ b/psw/ae/common/t_pairing_blob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/common/version.cpp b/psw/ae/common/version.cpp index 21106b6d..e86a3779 100644 --- a/psw/ae/common/version.cpp +++ b/psw/ae/common/version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/cse_provision_tool/Makefile b/psw/ae/cse_provision_tool/Makefile index 00a79240..65d0c143 100644 --- a/psw/ae/cse_provision_tool/Makefile +++ b/psw/ae/cse_provision_tool/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/cse_provision_tool/cse_provision_tool.cpp b/psw/ae/cse_provision_tool/cse_provision_tool.cpp index 89ae4e6d..f81be897 100644 --- a/psw/ae/cse_provision_tool/cse_provision_tool.cpp +++ b/psw/ae/cse_provision_tool/cse_provision_tool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/ae_debug_flag.hh b/psw/ae/data/constants/linux/ae_debug_flag.hh index 56d3bbaa..a851052b 100644 --- a/psw/ae/data/constants/linux/ae_debug_flag.hh +++ b/psw/ae/data/constants/linux/ae_debug_flag.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/default_url_info.hh b/psw/ae/data/constants/linux/default_url_info.hh index 629e4b44..8282dc8f 100644 --- a/psw/ae/data/constants/linux/default_url_info.hh +++ b/psw/ae/data/constants/linux/default_url_info.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/epid_verify_pub.hh b/psw/ae/data/constants/linux/epid_verify_pub.hh index 42986478..274ab322 100644 --- a/psw/ae/data/constants/linux/epid_verify_pub.hh +++ b/psw/ae/data/constants/linux/epid_verify_pub.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/isk_pub.hh b/psw/ae/data/constants/linux/isk_pub.hh index 24334d4e..b00e9b89 100644 --- a/psw/ae/data/constants/linux/isk_pub.hh +++ b/psw/ae/data/constants/linux/isk_pub.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/ivk_ca_root_der.hh b/psw/ae/data/constants/linux/ivk_ca_root_der.hh index b6bd239d..f72b5b76 100644 --- a/psw/ae/data/constants/linux/ivk_ca_root_der.hh +++ b/psw/ae/data/constants/linux/ivk_ca_root_der.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/launch_enclave_mrsigner.hh b/psw/ae/data/constants/linux/launch_enclave_mrsigner.hh index 0d481f2f..c16c5ba5 100644 --- a/psw/ae/data/constants/linux/launch_enclave_mrsigner.hh +++ b/psw/ae/data/constants/linux/launch_enclave_mrsigner.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/peksk_pub.hh b/psw/ae/data/constants/linux/peksk_pub.hh index b871cab8..6aa9f084 100644 --- a/psw/ae/data/constants/linux/peksk_pub.hh +++ b/psw/ae/data/constants/linux/peksk_pub.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/pibsk_pub.hh b/psw/ae/data/constants/linux/pibsk_pub.hh index 406603f1..253c1bfa 100644 --- a/psw/ae/data/constants/linux/pibsk_pub.hh +++ b/psw/ae/data/constants/linux/pibsk_pub.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/pse_pr_padding.hh b/psw/ae/data/constants/linux/pse_pr_padding.hh index 0e4bac4e..683bafae 100644 --- a/psw/ae/data/constants/linux/pse_pr_padding.hh +++ b/psw/ae/data/constants/linux/pse_pr_padding.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/pse_product_type.hh b/psw/ae/data/constants/linux/pse_product_type.hh index cf25a7df..c7719cf4 100644 --- a/psw/ae/data/constants/linux/pse_product_type.hh +++ b/psw/ae/data/constants/linux/pse_product_type.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/qsdk_pub.hh b/psw/ae/data/constants/linux/qsdk_pub.hh index 24e481c9..8666a596 100644 --- a/psw/ae/data/constants/linux/qsdk_pub.hh +++ b/psw/ae/data/constants/linux/qsdk_pub.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/service_enclave_mrsigner.hh b/psw/ae/data/constants/linux/service_enclave_mrsigner.hh index 24c12ee3..333b1964 100644 --- a/psw/ae/data/constants/linux/service_enclave_mrsigner.hh +++ b/psw/ae/data/constants/linux/service_enclave_mrsigner.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,6 +52,17 @@ const sgx_measurement_t G_SERVICE_ENCLAVE_MRSIGNER[] = } }; +const sgx_measurement_t G_ECDSA_QE_MRSIGNER = +{ + {//MR_SIGNER of QE3 provided + 0x8c, 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, + 0x96, 0x13, 0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, + 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, 0x14, 0x0b, + 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff + } +}; + + #define AE_MR_SIGNER 0 #define PCE_MR_SIGNER 1 #endif diff --git a/psw/ae/data/constants/linux/wl_pub.hh b/psw/ae/data/constants/linux/wl_pub.hh index cc17670d..72f0b6f0 100644 --- a/psw/ae/data/constants/linux/wl_pub.hh +++ b/psw/ae/data/constants/linux/wl_pub.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/data/constants/linux/xegdsk_pub.hh b/psw/ae/data/constants/linux/xegdsk_pub.hh index 74f828d9..a7e9ecb1 100644 --- a/psw/ae/data/constants/linux/xegdsk_pub.hh +++ b/psw/ae/data/constants/linux/xegdsk_pub.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/aeerror.h b/psw/ae/inc/aeerror.h index 88b2f817..d798a7de 100644 --- a/psw/ae/inc/aeerror.h +++ b/psw/ae/inc/aeerror.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/byte_order.h b/psw/ae/inc/byte_order.h index ed0c7b3f..f25b7b43 100644 --- a/psw/ae/inc/byte_order.h +++ b/psw/ae/inc/byte_order.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/Epid_rl.h b/psw/ae/inc/internal/Epid_rl.h index 7bb5ba1d..75a1117d 100644 --- a/psw/ae/inc/internal/Epid_rl.h +++ b/psw/ae/inc/internal/Epid_rl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/aesm_error.h b/psw/ae/inc/internal/aesm_error.h index 1684c9e6..2d25afdb 100644 --- a/psw/ae/inc/internal/aesm_error.h +++ b/psw/ae/inc/internal/aesm_error.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,12 +28,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - #ifndef _AESM_ERROR_H_ #define _AESM_ERROR_H_ - /*File to define aesm error code*/ - typedef enum _aesm_error_t { AESM_SUCCESS = 0, @@ -68,6 +65,24 @@ typedef enum _aesm_error_t AESM_OUT_OF_EPC = 29, AESM_SERVICE_UNAVAILABLE = 30, AESM_UNRECOGNIZED_PLATFORM = 31, + AESM_ECDSA_ID_MISMATCH = 32, + AESM_PATHNAME_BUFFER_OVERFLOW_ERROR = 33, + AESM_ERROR_STORED_KEY = 34, + AESM_PUB_KEY_ID_MISMATCH = 35, + AESM_INVALID_PCE_SIG_SCHEME = 36, + AESM_ATT_KEY_BLOB_ERROR = 37, + AESM_UNSUPPORTED_ATT_KEY_ID = 38, + AESM_UNSUPPORTED_LOADING_POLICY = 39, + AESM_INTERFACE_UNAVAILABLE = 40, + AESM_PLATFORM_LIB_UNAVAILABLE = 41, + AESM_ATT_KEY_NOT_INITIALIZED = 42, + AESM_ATT_KEY_CERT_DATA_INVALID = 43, + AESM_NO_PLATFORM_CERT_DATA = 44, + AESM_ERROR_REPORT = 45, + AESM_ENCLAVE_LOST = 46, + AESM_INVALID_REPORT = 47, + AESM_ENCLAVE_LOAD_ERROR = 48, + AESM_UNABLE_TO_GENERATE_QE_REPORT = 49, + AESM_KEY_CERTIFICATION_ERROR = 50, } aesm_error_t; #endif - diff --git a/psw/ae/inc/internal/epid_pve_type.h b/psw/ae/inc/internal/epid_pve_type.h index 3cc432b8..4d6c13e6 100644 --- a/psw/ae/inc/internal/epid_pve_type.h +++ b/psw/ae/inc/internal/epid_pve_type.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/le2be_macros.h b/psw/ae/inc/internal/le2be_macros.h index 2db0d5ee..912f53fb 100644 --- a/psw/ae/inc/internal/le2be_macros.h +++ b/psw/ae/inc/internal/le2be_macros.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pairing_blob.h b/psw/ae/inc/internal/pairing_blob.h index c237614d..278b68f3 100644 --- a/psw/ae/inc/internal/pairing_blob.h +++ b/psw/ae/inc/internal/pairing_blob.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pce_cert.h b/psw/ae/inc/internal/pce_cert.h index 2143eda2..cac92c8a 100644 --- a/psw/ae/inc/internal/pce_cert.h +++ b/psw/ae/inc/internal/pce_cert.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pek_pub_key.h b/psw/ae/inc/internal/pek_pub_key.h index 08b25664..de11cc9e 100644 --- a/psw/ae/inc/internal/pek_pub_key.h +++ b/psw/ae/inc/internal/pek_pub_key.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pse_inc.h b/psw/ae/inc/internal/pse_inc.h index 2c296213..2fff5eec 100644 --- a/psw/ae/inc/internal/pse_inc.h +++ b/psw/ae/inc/internal/pse_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pse_pr_common.h b/psw/ae/inc/internal/pse_pr_common.h index 950f2c15..2cb53c1d 100644 --- a/psw/ae/inc/internal/pse_pr_common.h +++ b/psw/ae/inc/internal/pse_pr_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pse_pr_sigma_1_1_defs.h b/psw/ae/inc/internal/pse_pr_sigma_1_1_defs.h index 19911702..6879af69 100644 --- a/psw/ae/inc/internal/pse_pr_sigma_1_1_defs.h +++ b/psw/ae/inc/internal/pse_pr_sigma_1_1_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pse_pr_sigma_common_defs.h b/psw/ae/inc/internal/pse_pr_sigma_common_defs.h index 5e638b11..358566f4 100644 --- a/psw/ae/inc/internal/pse_pr_sigma_common_defs.h +++ b/psw/ae/inc/internal/pse_pr_sigma_common_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pse_pr_sigma_defs.h b/psw/ae/inc/internal/pse_pr_sigma_defs.h index 7506c217..d0c50cf2 100644 --- a/psw/ae/inc/internal/pse_pr_sigma_defs.h +++ b/psw/ae/inc/internal/pse_pr_sigma_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pse_pr_types.h b/psw/ae/inc/internal/pse_pr_types.h index 38931695..a34abb74 100644 --- a/psw/ae/inc/internal/pse_pr_types.h +++ b/psw/ae/inc/internal/pse_pr_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pse_types.h b/psw/ae/inc/internal/pse_types.h index 2e0e6a09..834ec35e 100644 --- a/psw/ae/inc/internal/pse_types.h +++ b/psw/ae/inc/internal/pse_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/pve_qe_common.h b/psw/ae/inc/internal/pve_qe_common.h index ea6fa814..ffd6affd 100644 --- a/psw/ae/inc/internal/pve_qe_common.h +++ b/psw/ae/inc/internal/pve_qe_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/ref_le.h b/psw/ae/inc/internal/ref_le.h index 46696cd3..de42694e 100644 --- a/psw/ae/inc/internal/ref_le.h +++ b/psw/ae/inc/internal/ref_le.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/se_ecdsa_verify_internal.h b/psw/ae/inc/internal/se_ecdsa_verify_internal.h index e8600c16..2833ed44 100644 --- a/psw/ae/inc/internal/se_ecdsa_verify_internal.h +++ b/psw/ae/inc/internal/se_ecdsa_verify_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/t_pairing_blob.h b/psw/ae/inc/internal/t_pairing_blob.h index 2241a3aa..46bc29ef 100644 --- a/psw/ae/inc/internal/t_pairing_blob.h +++ b/psw/ae/inc/internal/t_pairing_blob.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/tlv_common.h b/psw/ae/inc/internal/tlv_common.h index e14357c9..1fb6558e 100644 --- a/psw/ae/inc/internal/tlv_common.h +++ b/psw/ae/inc/internal/tlv_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/internal/utility.h b/psw/ae/inc/internal/utility.h index 1de79222..ccbd0e56 100644 --- a/psw/ae/inc/internal/utility.h +++ b/psw/ae/inc/internal/utility.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/inc/se_sig_rl.h b/psw/ae/inc/se_sig_rl.h index b952f4fd..8d59d1c9 100644 --- a/psw/ae/inc/se_sig_rl.h +++ b/psw/ae/inc/se_sig_rl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/le/Makefile b/psw/ae/le/Makefile index fc3f697c..a8e810ed 100644 --- a/psw/ae/le/Makefile +++ b/psw/ae/le/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/le/launch_enclave.cpp b/psw/ae/le/launch_enclave.cpp index 89ab9dac..4faecb49 100644 --- a/psw/ae/le/launch_enclave.cpp +++ b/psw/ae/le/launch_enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,6 +38,7 @@ #include "wl_pub.hh" #include "launch_enclave_mrsigner.hh" #include "service_enclave_mrsigner.hh" +#include "tseal_migration_attr.h" #if !defined(SWAP_ENDIAN_DW) #define SWAP_ENDIAN_DW(dw) ((((dw) & 0x000000ff) << 24) \ @@ -190,10 +191,8 @@ ae_error_t le_generate_launch_token( sgx_measurement_t empty_mrsigner; sgx_report_t report; - // se_attributes must have no reserved bit set. - // urts(finally EINIT instruction)rejects EINIT Token with SGX_FLAGS_INITTED - // set. So LE doesn't need to check it here. - if((se_attributes->flags) & SGX_FLAGS_RESERVED) + // Check the reserved bits which have security implications. + if((se_attributes->flags) & FLAGS_SECURITY_BITS_RESERVED) { return LE_INVALID_ATTRIBUTE; } diff --git a/psw/ae/le/launch_enclave.edl b/psw/ae/le/launch_enclave.edl index 793bc520..12070bb4 100644 --- a/psw/ae/le/launch_enclave.edl +++ b/psw/ae/le/launch_enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/le/launch_enclave.h b/psw/ae/le/launch_enclave.h index 9877e98b..2646e69a 100644 --- a/psw/ae/le/launch_enclave.h +++ b/psw/ae/le/launch_enclave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pce/Makefile b/psw/ae/pce/Makefile index 30422a32..33c26828 100644 --- a/psw/ae/pce/Makefile +++ b/psw/ae/pce/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/pce/pce.cpp b/psw/ae/pce/pce.cpp index 426d3596..5041304b 100644 --- a/psw/ae/pce/pce.cpp +++ b/psw/ae/pce/pce.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -100,7 +100,7 @@ uint32_t get_pc_info(const sgx_report_t* report, // sgx_lfence(); - *encrypted_ppid_out_size = RSA_MOD_SIZE;//output size is same as public key module size + *encrypted_ppid_out_size = 0;//set out_size to 0. IFF all operations pass, the out_size will be set to RSA_MOD_SIZE if (encrypted_ppid_buf_size < RSA_MOD_SIZE){ return AE_INSUFFICIENT_DATA_IN_BUFFER; } @@ -148,7 +148,7 @@ uint32_t get_pc_info(const sgx_report_t* report, uint8_t *le_n = NULL; void *key = NULL; ae_error_t ae_ret = AE_FAILURE; - + size_t temp_encrypted_size = 0; do { //get ppid // @@ -180,7 +180,7 @@ uint32_t get_pc_info(const sgx_report_t* report, //get expected cipher text length // - if (sgx_rsa_pub_encrypt_sha256(key, NULL, (size_t*)encrypted_ppid_out_size, + if (sgx_rsa_pub_encrypt_sha256(key, NULL, &temp_encrypted_size, (ppid_buf.ppid), sizeof(ppid_buf.ppid)) != SGX_SUCCESS) { ae_ret = AE_FAILURE; break; @@ -188,14 +188,14 @@ uint32_t get_pc_info(const sgx_report_t* report, //validate out size match RSA_MOD_SIZE // - if (*encrypted_ppid_out_size != RSA_MOD_SIZE) { + if (temp_encrypted_size != RSA_MOD_SIZE) { ae_ret = AE_FAILURE; break; } //encrypt ppid, using RSA public key into encrypted_ppid buffer // - if (sgx_rsa_pub_encrypt_sha256(key, encrypted_ppid, (size_t*)encrypted_ppid_out_size, + if (sgx_rsa_pub_encrypt_sha256(key, encrypted_ppid, &temp_encrypted_size, (ppid_buf.ppid), sizeof(ppid_buf.ppid)) != SGX_SUCCESS) { ae_ret = AE_FAILURE; break; @@ -203,17 +203,18 @@ uint32_t get_pc_info(const sgx_report_t* report, //validate out size match RSA_MOD_SIZE // - if (*encrypted_ppid_out_size != RSA_MOD_SIZE) { + if (temp_encrypted_size != RSA_MOD_SIZE) { ae_ret = AE_FAILURE; break; } //get ISV and SVN values // - if (get_isv_svn(&pce_info->pce_isvn) != AE_SUCCESS) { + if ((ae_ret = get_isv_svn(&pce_info->pce_isvn)) != AE_SUCCESS) { break; } + *encrypted_ppid_out_size = RSA_MOD_SIZE; pce_info->pce_id = CUR_PCE_ID; *signature_scheme = NIST_P256_ECDSA_SHA256; ae_ret = AE_SUCCESS; @@ -225,8 +226,9 @@ uint32_t get_pc_info(const sgx_report_t* report, free(le_n); sgx_free_rsa_key(key, SGX_RSA_PUBLIC_KEY, RSA_MOD_SIZE, RSA_E_SIZE); memset_s(&ppid_buf, sizeof(ppid_buf), 0, sizeof(ppid_t)); - if (AE_SUCCESS != ae_ret) - memset_s(encrypted_ppid, encrypted_ppid_buf_size, 0, *encrypted_ppid_out_size); + if (AE_SUCCESS != ae_ret) { + memset_s(encrypted_ppid, encrypted_ppid_buf_size, 0, encrypted_ppid_buf_size); + } return ae_ret; } diff --git a/psw/ae/pce/pce.edl b/psw/ae/pce/pce.edl index 75cbf581..13c095f5 100644 --- a/psw/ae/pce/pce.edl +++ b/psw/ae/pce/pce.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pce/pce_helper.cpp b/psw/ae/pce/pce_helper.cpp index 73a69d29..32aabec7 100644 --- a/psw/ae/pce/pce_helper.cpp +++ b/psw/ae/pce/pce_helper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/Makefile b/psw/ae/pse/pse_op/Makefile index 28c9eac7..a5a48d28 100644 --- a/psw/ae/pse/pse_op/Makefile +++ b/psw/ae/pse/pse_op/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/createhash.pl b/psw/ae/pse/pse_op/createhash.pl index c96910df..8114ce9b 100755 --- a/psw/ae/pse/pse_op/createhash.pl +++ b/psw/ae/pse/pse_op/createhash.pl @@ -1,6 +1,6 @@ #!/usr/bin/env perl # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter.cpp b/psw/ae/pse/pse_op/monotonic_counter.cpp index 81cf691f..247bad65 100644 --- a/psw/ae/pse/pse_op/monotonic_counter.cpp +++ b/psw/ae/pse/pse_op/monotonic_counter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter.h b/psw/ae/pse/pse_op/monotonic_counter.h index 885b8f49..94494071 100644 --- a/psw/ae/pse/pse_op/monotonic_counter.h +++ b/psw/ae/pse/pse_op/monotonic_counter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.cpp b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.cpp index dfb1fbf2..bc3b43c3 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.cpp +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.h b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.h index abde82af..90f7c824 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.h +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_access_hw_mc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.cpp b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.cpp index afc23cfe..079f705d 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.cpp +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.h b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.h index a986b6cd..66598e79 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.h +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_bin_hash_tree_utility.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.cpp b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.cpp index 5ceef3ec..eba1f8fd 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.cpp +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.h b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.h index a65a6739..5b6511e7 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.h +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.cpp b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.cpp index ad627335..c712335d 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.cpp +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.h b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.h index 1752a2eb..54490a86 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.h +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_check_error.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.cpp b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.cpp index 66c3ec96..e1cdc350 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.cpp +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.h b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.h index dc0286bc..06d5851a 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.h +++ b/psw/ae/pse/pse_op/monotonic_counter_database_sqlite_rpdb.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/monotonic_counter_database_types.h b/psw/ae/pse/pse_op/monotonic_counter_database_types.h index cd4cdaf7..ad76c385 100644 --- a/psw/ae/pse/pse_op/monotonic_counter_database_types.h +++ b/psw/ae/pse/pse_op/monotonic_counter_database_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/psda_service.cpp b/psw/ae/pse/pse_op/psda_service.cpp index 7ceba920..ac0492e1 100644 --- a/psw/ae/pse/pse_op/psda_service.cpp +++ b/psw/ae/pse/pse_op/psda_service.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/psda_service.h b/psw/ae/pse/pse_op/psda_service.h index 4de5ca02..7dd1497c 100644 --- a/psw/ae/pse/pse_op/psda_service.h +++ b/psw/ae/pse/pse_op/psda_service.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/pse_op.cpp b/psw/ae/pse/pse_op/pse_op.cpp index 9f3f5a9c..e0988efd 100644 --- a/psw/ae/pse/pse_op/pse_op.cpp +++ b/psw/ae/pse/pse_op/pse_op.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/pse_op.edl b/psw/ae/pse/pse_op/pse_op.edl index 0719d5e5..a88bacdb 100644 --- a/psw/ae/pse/pse_op/pse_op.edl +++ b/psw/ae/pse/pse_op/pse_op.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/session_mgr.cpp b/psw/ae/pse/pse_op/session_mgr.cpp index 32d277e7..6e83ba5b 100644 --- a/psw/ae/pse/pse_op/session_mgr.cpp +++ b/psw/ae/pse/pse_op/session_mgr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/session_mgr.h b/psw/ae/pse/pse_op/session_mgr.h index f883a08a..057edb27 100644 --- a/psw/ae/pse/pse_op/session_mgr.h +++ b/psw/ae/pse/pse_op/session_mgr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/trusted_time.cpp b/psw/ae/pse/pse_op/trusted_time.cpp index a9fa55c5..a409b4eb 100644 --- a/psw/ae/pse/pse_op/trusted_time.cpp +++ b/psw/ae/pse/pse_op/trusted_time.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/trusted_time.h b/psw/ae/pse/pse_op/trusted_time.h index 73f43fc4..319ae9ef 100644 --- a/psw/ae/pse/pse_op/trusted_time.h +++ b/psw/ae/pse/pse_op/trusted_time.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/utility.cpp b/psw/ae/pse/pse_op/utility.cpp index ba04263b..9cccfc13 100644 --- a/psw/ae/pse/pse_op/utility.cpp +++ b/psw/ae/pse/pse_op/utility.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/vmc_db_generator/Makefile b/psw/ae/pse/pse_op/vmc_db_generator/Makefile index d1d3d615..18f8d152 100644 --- a/psw/ae/pse/pse_op/vmc_db_generator/Makefile +++ b/psw/ae/pse/pse_op/vmc_db_generator/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_op/vmc_db_generator/main.cpp b/psw/ae/pse/pse_op/vmc_db_generator/main.cpp index fc92a17c..b12892f3 100644 --- a/psw/ae/pse/pse_op/vmc_db_generator/main.cpp +++ b/psw/ae/pse/pse_op/vmc_db_generator/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/Keys.cpp b/psw/ae/pse/pse_pr/Keys.cpp index 0ee541cf..e76e8977 100644 --- a/psw/ae/pse/pse_pr/Keys.cpp +++ b/psw/ae/pse/pse_pr/Keys.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/Keys.h b/psw/ae/pse/pse_pr/Keys.h index aaca6e43..e23ee80e 100644 --- a/psw/ae/pse/pse_pr/Keys.h +++ b/psw/ae/pse/pse_pr/Keys.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/Makefile b/psw/ae/pse/pse_pr/Makefile index 109f113e..9592b6bc 100644 --- a/psw/ae/pse/pse_pr/Makefile +++ b/psw/ae/pse/pse_pr/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509Parser.cpp b/psw/ae/pse/pse_pr/X509Parser.cpp index 05fbc37a..16e428fc 100644 --- a/psw/ae/pse/pse_pr/X509Parser.cpp +++ b/psw/ae/pse/pse_pr/X509Parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509_Parser/X509AlgoType.h b/psw/ae/pse/pse_pr/X509_Parser/X509AlgoType.h index 1642f43c..bdb8cbc2 100644 --- a/psw/ae/pse/pse_pr/X509_Parser/X509AlgoType.h +++ b/psw/ae/pse/pse_pr/X509_Parser/X509AlgoType.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509_Parser/X509Cert.h b/psw/ae/pse/pse_pr/X509_Parser/X509Cert.h index be86797c..6f136d29 100644 --- a/psw/ae/pse/pse_pr/X509_Parser/X509Cert.h +++ b/psw/ae/pse/pse_pr/X509_Parser/X509Cert.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509_Parser/X509_Interface.h b/psw/ae/pse/pse_pr/X509_Parser/X509_Interface.h index a3917038..8a27dd7e 100644 --- a/psw/ae/pse/pse_pr/X509_Parser/X509_Interface.h +++ b/psw/ae/pse/pse_pr/X509_Parser/X509_Interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.cpp b/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.cpp index 4f33cca1..2ea5dc26 100644 --- a/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.cpp +++ b/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.h b/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.h index 21bf4672..f1def757 100644 --- a/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.h +++ b/psw/ae/pse/pse_pr/X509_Parser/X509_Parser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509_Parser/pse_pr_support.h b/psw/ae/pse/pse_pr/X509_Parser/pse_pr_support.h index f12fdad9..d3e58d15 100644 --- a/psw/ae/pse/pse_pr/X509_Parser/pse_pr_support.h +++ b/psw/ae/pse/pse_pr/X509_Parser/pse_pr_support.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/X509_Parser/typedef.h b/psw/ae/pse/pse_pr/X509_Parser/typedef.h index 7be9d751..8917a776 100644 --- a/psw/ae/pse/pse_pr/X509_Parser/typedef.h +++ b/psw/ae/pse/pse_pr/X509_Parser/typedef.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/X509Parser.h b/psw/ae/pse/pse_pr/include/X509Parser.h index 6907525a..36f907ac 100644 --- a/psw/ae/pse/pse_pr/include/X509Parser.h +++ b/psw/ae/pse/pse_pr/include/X509Parser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/csr_template_data.h b/psw/ae/pse/pse_pr/include/csr_template_data.h index 0a0b8354..51ec96a1 100644 --- a/psw/ae/pse/pse_pr/include/csr_template_data.h +++ b/psw/ae/pse/pse_pr/include/csr_template_data.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/prepare_hash_sha256.h b/psw/ae/pse/pse_pr/include/prepare_hash_sha256.h index 5f70ea92..bb0c0100 100644 --- a/psw/ae/pse/pse_pr/include/prepare_hash_sha256.h +++ b/psw/ae/pse/pse_pr/include/prepare_hash_sha256.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/prepare_hmac_sha256.h b/psw/ae/pse/pse_pr/include/prepare_hmac_sha256.h index 196eeaac..35e29829 100644 --- a/psw/ae/pse/pse_pr/include/prepare_hmac_sha256.h +++ b/psw/ae/pse/pse_pr/include/prepare_hmac_sha256.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/protected_output_certificates.h b/psw/ae/pse/pse_pr/include/protected_output_certificates.h index 4dc70936..beb9fe69 100644 --- a/psw/ae/pse/pse_pr/include/protected_output_certificates.h +++ b/psw/ae/pse/pse_pr/include/protected_output_certificates.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/pse_pr_inc.h b/psw/ae/pse/pse_pr/include/pse_pr_inc.h index b420a91d..b51b9036 100644 --- a/psw/ae/pse/pse_pr/include/pse_pr_inc.h +++ b/psw/ae/pse/pse_pr/include/pse_pr_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/safe_id.h b/psw/ae/pse/pse_pr/include/safe_id.h index 954b6d62..c4cbb04c 100644 --- a/psw/ae/pse/pse_pr/include/safe_id.h +++ b/psw/ae/pse/pse_pr/include/safe_id.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/sigma_crypto_layer.h b/psw/ae/pse/pse_pr/include/sigma_crypto_layer.h index e633cd41..bf936dde 100644 --- a/psw/ae/pse/pse_pr/include/sigma_crypto_layer.h +++ b/psw/ae/pse/pse_pr/include/sigma_crypto_layer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -69,7 +69,6 @@ public: void set_pub_key_gb_be(uint8_t* pGb) { memcpy(m_local_public_key_gb_big_endian, pGb, sizeof(m_local_public_key_gb_big_endian)); } void set_remote_pub_key_ga_be(uint8_t* pGa) { memcpy(m_remote_public_key_ga_big_endian, pGa, sizeof(m_remote_public_key_ga_big_endian)); } - const uint8_t* get_SMK() { return m_SMK; } const uint8_t* get_SK() { return m_SK; } const uint8_t* get_MK() { return m_MK; } diff --git a/psw/ae/pse/pse_pr/include/sigma_crypto_layer_11.h b/psw/ae/pse/pse_pr/include/sigma_crypto_layer_11.h index 69fe445e..d8faefc7 100644 --- a/psw/ae/pse/pse_pr/include/sigma_crypto_layer_11.h +++ b/psw/ae/pse/pse_pr/include/sigma_crypto_layer_11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/sign_csr.h b/psw/ae/pse/pse_pr/include/sign_csr.h index 7183444f..0c360bca 100644 --- a/psw/ae/pse/pse_pr/include/sign_csr.h +++ b/psw/ae/pse/pse_pr/include/sign_csr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/sign_template.h b/psw/ae/pse/pse_pr/include/sign_template.h index e030184b..3e74dc92 100644 --- a/psw/ae/pse/pse_pr/include/sign_template.h +++ b/psw/ae/pse/pse_pr/include/sign_template.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/signing_template_info.h b/psw/ae/pse/pse_pr/include/signing_template_info.h index 314bdef2..4aa18f13 100644 --- a/psw/ae/pse/pse_pr/include/signing_template_info.h +++ b/psw/ae/pse/pse_pr/include/signing_template_info.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/t_certificate_provisioning.h b/psw/ae/pse/pse_pr/include/t_certificate_provisioning.h index 3b541771..305feb2c 100644 --- a/psw/ae/pse/pse_pr/include/t_certificate_provisioning.h +++ b/psw/ae/pse/pse_pr/include/t_certificate_provisioning.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/include/t_long_term_pairing.h b/psw/ae/pse/pse_pr/include/t_long_term_pairing.h index 8756f53c..931bf589 100644 --- a/psw/ae/pse/pse_pr/include/t_long_term_pairing.h +++ b/psw/ae/pse/pse_pr/include/t_long_term_pairing.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/prepare_hash_sha1.cpp b/psw/ae/pse/pse_pr/prepare_hash_sha1.cpp index daab7b09..0c1df6b2 100644 --- a/psw/ae/pse/pse_pr/prepare_hash_sha1.cpp +++ b/psw/ae/pse/pse_pr/prepare_hash_sha1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/prepare_hash_sha1.h b/psw/ae/pse/pse_pr/prepare_hash_sha1.h index 2fed8ea3..5330a8d3 100644 --- a/psw/ae/pse/pse_pr/prepare_hash_sha1.h +++ b/psw/ae/pse/pse_pr/prepare_hash_sha1.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/prepare_hash_sha256.cpp b/psw/ae/pse/pse_pr/prepare_hash_sha256.cpp index e158c5f2..e65b7be0 100644 --- a/psw/ae/pse/pse_pr/prepare_hash_sha256.cpp +++ b/psw/ae/pse/pse_pr/prepare_hash_sha256.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/prepare_hmac_sha256.cpp b/psw/ae/pse/pse_pr/prepare_hmac_sha256.cpp index 8ca8b70f..7cf736fa 100644 --- a/psw/ae/pse/pse_pr/prepare_hmac_sha256.cpp +++ b/psw/ae/pse/pse_pr/prepare_hmac_sha256.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/pse_pr.cpp b/psw/ae/pse/pse_pr/pse_pr.cpp index 30064fe4..21da488d 100644 --- a/psw/ae/pse/pse_pr/pse_pr.cpp +++ b/psw/ae/pse/pse_pr/pse_pr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/pse_pr.edl b/psw/ae/pse/pse_pr/pse_pr.edl index 4b275e3c..2af59bb4 100644 --- a/psw/ae/pse/pse_pr/pse_pr.edl +++ b/psw/ae/pse/pse_pr/pse_pr.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/sigma_crypto_layer.cpp b/psw/ae/pse/pse_pr/sigma_crypto_layer.cpp index 5fd65f21..d702b6a0 100644 --- a/psw/ae/pse/pse_pr/sigma_crypto_layer.cpp +++ b/psw/ae/pse/pse_pr/sigma_crypto_layer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/sigma_crypto_layer_11.cpp b/psw/ae/pse/pse_pr/sigma_crypto_layer_11.cpp index 282efe6d..990c0fe9 100644 --- a/psw/ae/pse/pse_pr/sigma_crypto_layer_11.cpp +++ b/psw/ae/pse/pse_pr/sigma_crypto_layer_11.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/sign_csr.cpp b/psw/ae/pse/pse_pr/sign_csr.cpp index ef28af0c..e65efec2 100644 --- a/psw/ae/pse/pse_pr/sign_csr.cpp +++ b/psw/ae/pse/pse_pr/sign_csr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/t_certificate_provisioning.cpp b/psw/ae/pse/pse_pr/t_certificate_provisioning.cpp index 2a5d9d77..173843a2 100644 --- a/psw/ae/pse/pse_pr/t_certificate_provisioning.cpp +++ b/psw/ae/pse/pse_pr/t_certificate_provisioning.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/t_long_term_pairing.cpp b/psw/ae/pse/pse_pr/t_long_term_pairing.cpp index f191c3f5..b480ef2f 100644 --- a/psw/ae/pse/pse_pr/t_long_term_pairing.cpp +++ b/psw/ae/pse/pse_pr/t_long_term_pairing.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr/x509_parser_status.h b/psw/ae/pse/pse_pr/x509_parser_status.h index c7cfec63..9a91f429 100644 --- a/psw/ae/pse/pse_pr/x509_parser_status.h +++ b/psw/ae/pse/pse_pr/x509_parser_status.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr_2/Makefile b/psw/ae/pse/pse_pr_2/Makefile index 012a74f5..c0064f97 100644 --- a/psw/ae/pse/pse_pr_2/Makefile +++ b/psw/ae/pse/pse_pr_2/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.cpp b/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.cpp index 0fb53d0f..cc8ac640 100644 --- a/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.cpp +++ b/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.h b/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.h index e661a7a3..33c5486e 100644 --- a/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.h +++ b/psw/ae/pse/pse_pr_2/sigma_crypto_layer_20.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/Makefile b/psw/ae/pve/Makefile index a4a629f2..80f3ee53 100644 --- a/psw/ae/pve/Makefile +++ b/psw/ae/pve/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/cipher.h b/psw/ae/pve/cipher.h index b3dcb926..9aa05416 100644 --- a/psw/ae/pve/cipher.h +++ b/psw/ae/pve/cipher.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/endpoint_selection.cpp b/psw/ae/pve/endpoint_selection.cpp index 5f7e86c6..b91c62ce 100644 --- a/psw/ae/pve/endpoint_selection.cpp +++ b/psw/ae/pve/endpoint_selection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/helper.cpp b/psw/ae/pve/helper.cpp index fc9d5cd4..094a1001 100644 --- a/psw/ae/pve/helper.cpp +++ b/psw/ae/pve/helper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/helper.h b/psw/ae/pve/helper.h index 7ed27b21..c0db366f 100644 --- a/psw/ae/pve/helper.h +++ b/psw/ae/pve/helper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/msg3_parm.h b/psw/ae/pve/msg3_parm.h index f331866b..cba5f1e9 100644 --- a/psw/ae/pve/msg3_parm.h +++ b/psw/ae/pve/msg3_parm.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/protocol.h b/psw/ae/pve/protocol.h index 0764eb29..c17c6d3f 100644 --- a/psw/ae/pve/protocol.h +++ b/psw/ae/pve/protocol.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/provision_enclave.cpp b/psw/ae/pve/provision_enclave.cpp index 0c78a44b..ebd34589 100644 --- a/psw/ae/pve/provision_enclave.cpp +++ b/psw/ae/pve/provision_enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/provision_enclave.edl b/psw/ae/pve/provision_enclave.edl index 992d72e9..c307c873 100644 --- a/psw/ae/pve/provision_enclave.edl +++ b/psw/ae/pve/provision_enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/provision_msg.h b/psw/ae/pve/provision_msg.h index 98ecc193..3873ab0f 100644 --- a/psw/ae/pve/provision_msg.h +++ b/psw/ae/pve/provision_msg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/provision_msg1.cpp b/psw/ae/pve/provision_msg1.cpp index 8bbf4962..86ca9057 100644 --- a/psw/ae/pve/provision_msg1.cpp +++ b/psw/ae/pve/provision_msg1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/provision_msg2.cpp b/psw/ae/pve/provision_msg2.cpp index aa59f4fe..6bdd0dd2 100644 --- a/psw/ae/pve/provision_msg2.cpp +++ b/psw/ae/pve/provision_msg2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/provision_msg3.cpp b/psw/ae/pve/provision_msg3.cpp index 29bc2a41..d57929b5 100644 --- a/psw/ae/pve/provision_msg3.cpp +++ b/psw/ae/pve/provision_msg3.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/provision_msg4.cpp b/psw/ae/pve/provision_msg4.cpp index 0b5246f3..63b4385f 100644 --- a/psw/ae/pve/provision_msg4.cpp +++ b/psw/ae/pve/provision_msg4.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/pve_hardcoded_tlv_data.h b/psw/ae/pve/pve_hardcoded_tlv_data.h index 682f8b7a..b441dd7d 100644 --- a/psw/ae/pve/pve_hardcoded_tlv_data.h +++ b/psw/ae/pve/pve_hardcoded_tlv_data.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/pve_rng.cpp b/psw/ae/pve/pve_rng.cpp index 3c256aa9..644111f5 100644 --- a/psw/ae/pve/pve_rng.cpp +++ b/psw/ae/pve/pve_rng.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/pve/pve_verify_signature.cpp b/psw/ae/pve/pve_verify_signature.cpp index f8d94e65..e2111810 100644 --- a/psw/ae/pve/pve_verify_signature.cpp +++ b/psw/ae/pve/pve_verify_signature.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/qe/Makefile b/psw/ae/qe/Makefile index 9d7f07e6..be857b84 100644 --- a/psw/ae/qe/Makefile +++ b/psw/ae/qe/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/qe/quoting_enclave.cpp b/psw/ae/qe/quoting_enclave.cpp index c0fe2f34..d857e02d 100644 --- a/psw/ae/qe/quoting_enclave.cpp +++ b/psw/ae/qe/quoting_enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -93,6 +93,7 @@ extern "C" { * @param create_context[in] Flag indicates create EPID context or not. * @param plaintext_epid_data[out] Used to get the plaintext part of epid blob * @param pp_epid_context[out] Used to get the pointer of the EPID context. + * @param p_cpusvn[out] Return the raw CPUSVN. * @return ae_error_t AE_SUCCESS or other error cases. */ static ae_error_t verify_blob_internal( @@ -101,7 +102,8 @@ static ae_error_t verify_blob_internal( uint8_t *p_is_resealed, uint32_t create_context, se_plaintext_epid_data_sdk_t& plaintext_epid_data, - MemberCtx **pp_epid_context) + MemberCtx **pp_epid_context, + sgx_cpu_svn_t *p_cpusvn) { ae_error_t ret = QE_UNEXPECTED_ERROR; sgx_status_t se_ret = SGX_SUCCESS; @@ -149,16 +151,16 @@ static ae_error_t verify_blob_internal( BREAK_IF_TRUE(SGX_SUCCESS != se_ret, ret, QE_EPIDBLOB_ERROR); //QE will support both epid blob with/without member precomputation - //If the epid blob without member precomputation is used, QE will generate member precomputation and reseal epid blob + //If the epid blob without member precomputation is used, QE will generate member precomputation and reseal epid blob //blob_type and key_version are always first two fields of plaintext in both format BREAK_IF_TRUE((plaintext_old_format.seal_blob_type != PVE_SEAL_EPID_KEY_BLOB) || (plaintext_old_format.epid_key_version != EPID_KEY_BLOB_VERSION_SDK&& - plaintext_old_format.epid_key_version != EPID_KEY_BLOB_VERSION_SIK), - ret, QE_EPIDBLOB_ERROR); + plaintext_old_format.epid_key_version != EPID_KEY_BLOB_VERSION_SIK), + ret, QE_EPIDBLOB_ERROR); // Only 2 combinations are legitimate for the tuple epid_key_version|decryptedtext_length|plaintext_length: // EPID_KEY_BLOB_VERSION_SIK|sizeof(se_secret_epid_data_sik_t)|sizeof(se_plaintext_epid_data_sik_t) - // EPID_KEY_BLOB_VERSION_SDK|sizeof(se_secret_epid_data_sdk_t)|sizeof(se_plaintext_epid_data_sdk_t) + // EPID_KEY_BLOB_VERSION_SDK|sizeof(se_secret_epid_data_sdk_t)|sizeof(se_plaintext_epid_data_sdk_t) BREAK_IF_TRUE((plaintext_old_format.epid_key_version == EPID_KEY_BLOB_VERSION_SIK && (decryptedtext_length != sizeof(se_secret_epid_data_sik_t) || plaintext_length != sizeof(se_plaintext_epid_data_sik_t))) || (plaintext_old_format.epid_key_version == EPID_KEY_BLOB_VERSION_SDK && @@ -240,6 +242,7 @@ static ae_error_t verify_blob_internal( resealed = TRUE; } *p_is_resealed = resealed; + memcpy(p_cpusvn, &report.body.cpu_svn, sizeof(*p_cpusvn)); ret = AE_SUCCESS; } while (false); @@ -269,20 +272,22 @@ static ae_error_t verify_blob_internal( * @param p_blob[in, out] Pointer to EPID Blob. * @param blob_size[in] The size of EPID Blob, in bytes. * @param p_is_resealed[out] Whether the EPID Blob is resealed within this function call. + * @param p_cpusvn[out] Return the raw CPUSVN. * @return uint32_t AE_SUCCESS or other error cases. */ uint32_t verify_blob( uint8_t *p_blob, uint32_t blob_size, - uint8_t *p_is_resealed) + uint8_t *p_is_resealed, + sgx_cpu_svn_t *p_cpusvn) { se_plaintext_epid_data_sdk_t plain_text; /* Actually, some cases here will be checked with code generated by edger8r. Here we just want to defend in depth. */ - if(NULL == p_blob || NULL == p_is_resealed) + if(NULL == p_blob || NULL == p_is_resealed || NULL == p_cpusvn) return QE_PARAMETER_ERROR; - + if(SGX_TRUSTED_EPID_BLOB_SIZE_SDK != blob_size) return QE_PARAMETER_ERROR; @@ -296,7 +301,7 @@ uint32_t verify_blob( return QE_PARAMETER_ERROR; return random_stack_advance(verify_blob_internal, p_blob, blob_size, - p_is_resealed, FALSE, plain_text, (MemberCtx**) NULL); + p_is_resealed, FALSE, plain_text, (MemberCtx**) NULL, p_cpusvn); } @@ -505,7 +510,7 @@ static ae_error_t qe_epid_sign( /* Copy the AES Blob payload size into output buffer. */ memcpy(&emp_p->payload_size, &sign_size, sizeof(sign_size)); - + se_ret = sgx_aes_gcm128_enc_init( aes_key, aes_iv, //input initial vector. randomly generated value and encryption of different msg should use different iv @@ -532,7 +537,7 @@ static ae_error_t qe_epid_sign( ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } - + /* Copy the encrypted basic signature into output buffer. */ memcpy(&emp_p->basic_sign, &encrypted_basic_sig, sizeof(encrypted_basic_sig)); @@ -604,7 +609,7 @@ static ae_error_t qe_epid_sign( ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } - + memcpy(&(emp_p->rl_ver), &encrypted_rl_ver, sizeof(encrypted_rl_ver)); memcpy(&(emp_p->rl_num), &encrypted_n2, @@ -678,7 +683,7 @@ static ae_error_t qe_epid_sign( ret = QE_UNEXPECTED_ERROR; goto CLEANUP; } - + memcpy(emp_nr, &encrypted_temp_nr, sizeof(encrypted_temp_nr)); if(p_qe_report) @@ -878,11 +883,13 @@ uint32_t get_quote( se_sig_rl_t sig_rl_header; se_plaintext_epid_data_sdk_t plaintext; sgx_ec256_signature_t ec_signature; + sgx_cpu_svn_t cpusvn; memset("e_body, 0, sizeof(quote_body)); memset(&sig_rl_header, 0, sizeof(sig_rl_header)); memset(&plaintext, 0, sizeof(plaintext)); memset(&ec_signature, 0, sizeof(ec_signature)); + memset(&cpusvn, 0, sizeof(cpusvn)); /* Actually, some cases here will be checked with code generated by @@ -961,10 +968,11 @@ uint32_t get_quote( /* Verify EPID p_blob and create the context */ ret = random_stack_advance(verify_blob_internal, p_blob, blob_size, - &is_resealed, + &is_resealed, TRUE, plaintext, - &p_epid_context); + &p_epid_context, + &cpusvn); if(AE_SUCCESS != ret) goto CLEANUP; diff --git a/psw/ae/qe/quoting_enclave.edl b/psw/ae/qe/quoting_enclave.edl index 4404d6c7..ad88d997 100644 --- a/psw/ae/qe/quoting_enclave.edl +++ b/psw/ae/qe/quoting_enclave.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +37,8 @@ from "sgx_tstdc.edl" import *; trusted { public uint32_t verify_blob([size = blob_size, in, out] uint8_t *p_blob, uint32_t blob_size, - [out] uint8_t *p_is_resealed); + [out] uint8_t *p_is_resealed, + [out] sgx_cpu_svn_t *p_cpusvn); public uint32_t get_quote([size = blob_size, in, out] uint8_t *p_blob, uint32_t blob_size, diff --git a/psw/ae/ref_le/Makefile b/psw/ae/ref_le/Makefile index 5ae0a15a..8e1f2366 100644 --- a/psw/ae/ref_le/Makefile +++ b/psw/ae/ref_le/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_le.cpp b/psw/ae/ref_le/ref_le.cpp index a0d88f7f..6c5452bf 100644 --- a/psw/ae/ref_le/ref_le.cpp +++ b/psw/ae/ref_le/ref_le.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_le.edl b/psw/ae/ref_le/ref_le.edl index 01f1cdac..aaceb84d 100644 --- a/psw/ae/ref_le/ref_le.edl +++ b/psw/ae/ref_le/ref_le.edl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_wl_gen/Makefile b/psw/ae/ref_le/ref_wl_gen/Makefile index d019e480..5fcbd822 100644 --- a/psw/ae/ref_le/ref_wl_gen/Makefile +++ b/psw/ae/ref_le/ref_wl_gen/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_wl_gen/parse_key_file.cpp b/psw/ae/ref_le/ref_wl_gen/parse_key_file.cpp index 559d05c1..95187a5f 100644 --- a/psw/ae/ref_le/ref_wl_gen/parse_key_file.cpp +++ b/psw/ae/ref_le/ref_wl_gen/parse_key_file.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_wl_gen/parse_key_file.h b/psw/ae/ref_le/ref_wl_gen/parse_key_file.h index ae1f0234..6e91f769 100644 --- a/psw/ae/ref_le/ref_wl_gen/parse_key_file.h +++ b/psw/ae/ref_le/ref_wl_gen/parse_key_file.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_wl_gen/ref_wl.cpp b/psw/ae/ref_le/ref_wl_gen/ref_wl.cpp index 3f27c2d1..06ff1e13 100644 --- a/psw/ae/ref_le/ref_wl_gen/ref_wl.cpp +++ b/psw/ae/ref_le/ref_wl_gen/ref_wl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.cpp b/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.cpp index 9399b02d..69450d85 100644 --- a/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.cpp +++ b/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.h b/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.h index 739104c7..e6ad25ee 100644 --- a/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.h +++ b/psw/ae/ref_le/ref_wl_gen/ref_wl_gen.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/enclave_common/Makefile b/psw/enclave_common/Makefile index 14e1d992..2face79f 100644 --- a/psw/enclave_common/Makefile +++ b/psw/enclave_common/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/enclave_common/sgx_enclave_common.cpp b/psw/enclave_common/sgx_enclave_common.cpp index caad4c11..b7493317 100644 --- a/psw/enclave_common/sgx_enclave_common.cpp +++ b/psw/enclave_common/sgx_enclave_common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -261,6 +261,31 @@ extern "C" void* COMM_API enclave_create( se_mutex_unlock(&s_enclave_mutex); + if (s_is_kernel_driver == true && (secs->attributes.flags & SGX_FLAGS_PROVISION_KEY)) { + if (-1 != access("/sys/kernel/security/sgx/provision", F_OK)) { + int phdev = open("/sys/kernel/security/sgx/provision", O_RDWR); + if (-1 == phdev) { + if (enclave_error != NULL) + *enclave_error = ENCLAVE_NOT_AUTHORIZED; + return NULL; + } + + struct sgx_enclave_set_attribute attrp = { 0, 0 }; + attrp.addr = POINTER_TO_U64(enclave_base); + attrp.attribute_fd = phdev; + + if (0 != ioctl(s_hdevice, SGX_IOC_ENCLAVE_SET_ATTRIBUTE, &attrp)) { + close(phdev); + + if (enclave_error != NULL) + *enclave_error = ENCLAVE_NOT_AUTHORIZED; + return NULL; + } + + close(phdev); + } + } + if (enclave_error != NULL) *enclave_error = ENCLAVE_ERROR_SUCCESS; return enclave_base; diff --git a/psw/enclave_common/sgx_enclave_common.h b/psw/enclave_common/sgx_enclave_common.h index 11c5539b..a11e8622 100644 --- a/psw/enclave_common/sgx_enclave_common.h +++ b/psw/enclave_common/sgx_enclave_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/config.h b/psw/uae_service/config.h index 24b55b97..eda2ae6f 100644 --- a/psw/uae_service/config.h +++ b/psw/uae_service/config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/linux/Makefile b/psw/uae_service/linux/Makefile index 8a662e8f..7ddc8e59 100644 --- a/psw/uae_service/linux/Makefile +++ b/psw/uae_service/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -32,10 +32,10 @@ TOP_DIR = ../../.. include $(TOP_DIR)/buildenv.mk -IPC_COMMON_DIR := $(TOP_DIR)/psw/ae/common -IPC_COMMON_SRC_DIR := $(IPC_COMMON_DIR)/src -IPC_COMMON_INC_DIR := $(IPC_COMMON_DIR)/inc -IPC_COMMON_PROTO_DIR := $(IPC_COMMON_DIR)/proto +IPC_COMMON_DIR := $(TOP_DIR)/psw/ae/aesm_service/source/core/ipc +IPC_COMMON_SRC_DIR := $(IPC_COMMON_DIR) +IPC_COMMON_INC_DIR := $(IPC_COMMON_DIR) +IPC_COMMON_PROTO_DIR := $(IPC_COMMON_DIR) UAE_WRAPPER_DIR := ../uae_wrapper UAE_SRC_DIR := $(UAE_WRAPPER_DIR)/src UAE_INC_DIR := $(UAE_WRAPPER_DIR)/inc @@ -55,13 +55,18 @@ INCLUDE += -I$(LINUX_EXTERNAL_DIR)/epid-sdk \ -I$(IPC_COMMON_INC_DIR) \ -I$(UAE_INC_DIR) \ -I$(IPC_COMMON_PROTO_DIR) \ - -I$(LINUX_PSW_DIR)/ae/aesm_service/source + -I$(LINUX_PSW_DIR)/ae/aesm_service/source \ + -I$(LINUX_PSW_DIR)/ae/aesm_service/source/common \ + -I$(DCAP_DIR)/QuoteGeneration/quote_wrapper/common/inc/ \ + -I$(DCAP_DIR)/QuoteGeneration/quote_wrapper/quote/enclave/ \ + -I$(DCAP_DIR)/QuoteGeneration/quote_wrapper/quote/inc/ \ + -I$(DCAP_DIR)/QuoteGeneration/pce_wrapper/inc/ CXXFLAGS += -fPIC -Werror -Wno-unused-parameter -g -DPROTOBUF_INLINE_NOT_IN_HEADERS=0 EXTERNAL_LIB += -lprotobuf -vpath %.cpp .. $(COMMON_DIR)/src $(IPC_COMMON_SRC_DIR) $(IPC_COMMON_PROTO_DIR) $(UAE_SRC_DIR) $(AE_COMMON_DIR) +vpath %.cpp .. $(COMMON_DIR)/src $(IPC_COMMON_SRC_DIR) $(IPC_COMMON_PROTO_DIR) $(UAE_SRC_DIR) $(AE_COMMON_DIR) $(DCAP_DIR)/QuoteGeneration/quote_wrapper/quote vpath %.c $(COMMON_DIR)/src C_SRC := se_trace.c @@ -99,7 +104,13 @@ IPC_SRC := AECloseSessionRequest.cpp \ AEGetQuoteRequest.cpp \ UnixSocketFactory.cpp \ NonBlockingUnixCommunicationSocket.cpp \ - NonBlockingUnixSocketFactory.cpp + NonBlockingUnixSocketFactory.cpp \ + AEInitQuoteExRequest.cpp \ + AEInitQuoteExResponse.cpp \ + AEGetQuoteExRequest.cpp \ + AEGetQuoteExResponse.cpp \ + AEGetQuoteSizeExRequest.cpp \ + AEGetQuoteSizeExResponse.cpp PROTOBUF_SRC := messages.pb.cc @@ -111,7 +122,8 @@ SRC := AEServicesImpl.cpp \ se_sig_rl.cpp \ sgx_uae_service.cpp \ uae_service_version.cpp \ - uae_service_assert.cpp + uae_service_assert.cpp \ + sgx_ql_core_wrapper.cpp OBJ := $(C_SRC:.c=.o) $(SRC:.cpp=.o) $(IPC_SRC:.cpp=.o) $(PROTOBUF_SRC:.cc=.o) @@ -134,7 +146,7 @@ ifndef DEBUG endif $(LIBNAME): $(OBJ) - $(CXX) $(CXXFLAGS) $(OBJ) -shared $(LDUFLAGS) $(EXTERNAL_LIB) -o $@ + $(CXX) $(CXXFLAGS) $(OBJ) -shared $(LDUFLAGS) $(EXTERNAL_LIB) -Wl,-soname=$@ -o $@ $(LIBNAME_DEBUG): $(LIBNAME) ((test -f $(LIBNAME_DEBUG)) || $(MAKE) separate_debug_info) diff --git a/psw/uae_service/linux/uae_service.lds b/psw/uae_service/linux/uae_service.lds index b0f7cb62..6382cbc5 100644 --- a/psw/uae_service/linux/uae_service.lds +++ b/psw/uae_service/linux/uae_service.lds @@ -15,6 +15,10 @@ global: sgx_get_whitelist_size; sgx_get_whitelist; sgx_register_wl_cert_chain; + sgx_select_att_key_id; + sgx_init_quote_ex; + sgx_get_quote_size_ex; + sgx_get_quote_ex; local: *; }; diff --git a/psw/uae_service/sgx_uae_service.cpp b/psw/uae_service/sgx_uae_service.cpp index 37fe1e97..b776122b 100644 --- a/psw/uae_service/sgx_uae_service.cpp +++ b/psw/uae_service/sgx_uae_service.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,14 +28,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + +#include #include #include +#include "sgx_ql_quote.h" #include "sgx_uae_service.h" #include "uae_service_internal.h" #include "config.h" #include "stdint.h" #include "se_sig_rl.h" +#include "sgx_ql_core_wrapper.h" #if !defined(ntohl) #define ntohl(u32) \ @@ -58,20 +62,21 @@ #define SGX_GET_EXTENDED_GROUP_ID_MSEC (IPC_LATENCY) #define SGX_SWITCH_EXTENDED_GROUP_MSEC (IPC_LATENCY) #define REG_WL_CERT_CHAIN_MSEC (IPC_LATENCY) +#define SE_CALC_QUOTE_SIZE_TIMEOUT_MSEC (IPC_LATENCY) extern "C" { sgx_status_t get_launch_token( - const enclave_css_t* signature, - const sgx_attributes_t* attribute, + const enclave_css_t* signature, + const sgx_attributes_t* attribute, sgx_launch_token_t* launch_token) { if (signature == NULL || attribute == NULL || launch_token == NULL) return SGX_ERROR_INVALID_PARAMETER; - + aesm_error_t result = AESM_UNEXPECTED_ERROR; uae_oal_status_t status = oal_get_launch_token(signature, attribute, launch_token, GET_LAUNCH_TOKEN_TIMEOUT_MSEC*1000, &result); - + /*common mappings */ sgx_status_t mapped = oal_map_status(status); if (mapped != SGX_SUCCESS) @@ -98,7 +103,7 @@ sgx_status_t get_launch_token( mapped = SGX_ERROR_UNEXPECTED; } } - } + } return mapped; } @@ -113,13 +118,13 @@ sgx_status_t sgx_init_quote( aesm_error_t result = AESM_UNEXPECTED_ERROR; uae_oal_status_t status = oal_init_quote(p_target_info, p_gid, SE_INIT_QUOTE_TIMEOUT_MSEC*1000, &result); - - sgx_status_t mapped = oal_map_status(status); + + sgx_status_t mapped = oal_map_status(status); if (mapped != SGX_SUCCESS) return mapped; mapped = oal_map_result(result); - if (mapped != SGX_SUCCESS) + if (mapped != SGX_SUCCESS) { /*operation specific mapping */ if (mapped == SGX_ERROR_UNEXPECTED && result != AESM_UNEXPECTED_ERROR) @@ -162,7 +167,7 @@ sgx_status_t sgx_get_quote( sgx_quote_t *p_quote, uint32_t quote_size) { - + if (p_report == NULL || p_spid == NULL || p_quote == NULL || quote_size == 0 ) return SGX_ERROR_INVALID_PARAMETER; if ((p_sig_rl == NULL && sig_rl_size != 0) || @@ -171,20 +176,20 @@ sgx_status_t sgx_get_quote( aesm_error_t result = AESM_UNEXPECTED_ERROR; - uae_oal_status_t status = oal_get_quote(p_report, quote_type, p_spid, p_nonce, p_sig_rl, sig_rl_size, p_qe_report, + uae_oal_status_t status = oal_get_quote(p_report, quote_type, p_spid, p_nonce, p_sig_rl, sig_rl_size, p_qe_report, p_quote, quote_size, SE_GET_QUOTE_TIMEOUT_MSEC(p_sig_rl)*1000, &result); sgx_status_t mapped = oal_map_status(status); if (mapped != SGX_SUCCESS) return mapped; - + mapped = oal_map_result(result); if (mapped != SGX_SUCCESS) { /*operation specific mapping */ if (mapped == SGX_ERROR_UNEXPECTED && result != AESM_UNEXPECTED_ERROR) { - switch (result) + switch (result) { case AESM_EPIDBLOB_ERROR: mapped = SGX_ERROR_AE_INVALID_EPIDBLOB; @@ -226,14 +231,14 @@ sgx_status_t sgx_get_ps_cap(sgx_ps_cap_t* p_sgx_ps_cap) sgx_status_t mapped = oal_map_status(status); if (mapped != SGX_SUCCESS) return mapped; - + mapped = oal_map_result(result); if (mapped != SGX_SUCCESS) { /*operation specific mapping */ if (mapped == SGX_ERROR_UNEXPECTED && result != AESM_UNEXPECTED_ERROR) { - switch (result) + switch (result) { case AESM_LONG_TERM_PAIRING_FAILED: case AESM_EPH_SESSION_FAILED: @@ -302,16 +307,16 @@ sgx_status_t create_session_ocall( uint32_t dh_msg1_size, uint32_t timeout) { - + if(!session_id || !se_dh_msg1) return SGX_ERROR_INVALID_PARAMETER; aesm_error_t result = AESM_UNEXPECTED_ERROR; uae_oal_status_t status = oal_create_session(session_id, se_dh_msg1, dh_msg1_size, timeout*1000, &result); - + sgx_status_t mapped = oal_map_status(status); if (mapped != SGX_SUCCESS) return mapped; - + mapped = oal_map_result(result); if (mapped != SGX_SUCCESS) { @@ -409,7 +414,7 @@ sgx_status_t close_session_ocall( sgx_status_t mapped = oal_map_status(status); if (mapped != SGX_SUCCESS) return mapped; - + mapped = oal_map_result(result); if (mapped != SGX_SUCCESS) { @@ -434,10 +439,10 @@ sgx_status_t close_session_ocall( break; default: mapped = SGX_ERROR_UNEXPECTED; - } + } } } - + return mapped; } @@ -457,7 +462,7 @@ sgx_status_t invoke_service_ocall( sgx_status_t mapped = oal_map_status(status); if (mapped != SGX_SUCCESS) return mapped; - + mapped = oal_map_result(result); if (mapped != SGX_SUCCESS) { @@ -484,10 +489,10 @@ sgx_status_t invoke_service_ocall( case AESM_MSG_ERROR: default: mapped = SGX_ERROR_UNEXPECTED; - } + } } } - + return mapped; } @@ -569,7 +574,7 @@ sgx_status_t sgx_get_extended_epid_group_id( uae_oal_status_t ret = UAE_OAL_ERROR_UNEXPECTED; ret = oal_get_extended_epid_group_id(p_extended_epid_group_id, SGX_GET_EXTENDED_GROUP_ID_MSEC*1000, &result); - //common mappings + //common mappings sgx_status_t mapped = oal_map_status(ret); if (mapped != SGX_SUCCESS) return mapped; @@ -596,7 +601,7 @@ sgx_status_t sgx_switch_extended_epid_group(uint32_t extended_epid_group_id) uae_oal_status_t ret = UAE_OAL_ERROR_UNEXPECTED; ret = oal_switch_extended_epid_group(extended_epid_group_id, SGX_SWITCH_EXTENDED_GROUP_MSEC*1000, &result); - //common mappings + //common mappings sgx_status_t mapped = oal_map_status(ret); if (mapped != SGX_SUCCESS) return mapped; @@ -630,7 +635,7 @@ sgx_status_t sgx_register_wl_cert_chain(uint8_t* p_wl_cert_chain, uint32_t wl_ce oal_ret = oal_register_common(p_wl_cert_chain, wl_cert_chain_size, SGX_REGISTER_WHITE_LIST_CERT, REG_WL_CERT_CHAIN_MSEC*1000, &result); - //common mappings + //common mappings sgx_status_t mapped = oal_map_status(oal_ret); if (mapped != SGX_SUCCESS) return mapped; @@ -651,6 +656,191 @@ sgx_status_t sgx_register_wl_cert_chain(uint8_t* p_wl_cert_chain, uint32_t wl_ce return mapped; } +sgx_status_t sgx_select_att_key_id(const uint8_t *p_att_key_id_list, uint32_t att_key_id_list_size, + sgx_att_key_id_t **pp_selected_key_id) +{ + sgx_status_t result = SGX_ERROR_UNEXPECTED; + quote3_error_t ret_val = SGX_QL_ERROR_UNEXPECTED; + + if ((p_att_key_id_list == NULL && att_key_id_list_size != 0) || + (p_att_key_id_list != NULL && att_key_id_list_size == 0)) + return SGX_ERROR_INVALID_PARAMETER; + + ret_val = sgx_ql_select_att_key_id((sgx_ql_att_key_id_list_t*)p_att_key_id_list, (sgx_ql_att_key_id_t**)pp_selected_key_id); + + switch (ret_val) + { + case SGX_QL_SUCCESS: + result = SGX_SUCCESS; + break; + case SGX_QL_ERROR_INVALID_PARAMETER: + result = SGX_ERROR_INVALID_PARAMETER; + break; + case SGX_QL_UNSUPPORTED_ATT_KEY_ID: + result = SGX_ERROR_UNSUPPORTED_ATT_KEY_ID; + break; + default: + result = SGX_ERROR_UNEXPECTED; + break; + } + + return result ; + } + +sgx_status_t sgx_init_quote_ex(const sgx_att_key_id_t* p_att_key_id, + sgx_target_info_t *p_qe_target_info, + bool refresh_att_key, + size_t* p_pub_key_id_size, + uint8_t* p_pub_key_id) +{ + // Verify inputs + if(NULL == p_pub_key_id_size || NULL == p_qe_target_info || NULL == p_att_key_id || + (NULL != p_pub_key_id && (0 == *p_pub_key_id_size || *p_pub_key_id_size >= UINT32_MAX))) + { + return SGX_ERROR_INVALID_PARAMETER; + } + + sgx_ql_cert_key_type_t certification_key_type = SGX_QL_CERT_TYPE; + + aesm_error_t result = AESM_UNEXPECTED_ERROR; + uae_oal_status_t oal_ret = UAE_OAL_ERROR_UNEXPECTED; + oal_ret = oal_init_quote_ex((sgx_ql_att_key_id_t*)p_att_key_id, certification_key_type, p_qe_target_info, refresh_att_key, p_pub_key_id_size, *p_pub_key_id_size, p_pub_key_id, + SE_INIT_QUOTE_TIMEOUT_MSEC*1000, &result); + + //common mappings + sgx_status_t mapped = oal_map_status(oal_ret); + if (mapped != SGX_SUCCESS) + return mapped; + + mapped = oal_map_result(result); + if (mapped != SGX_SUCCESS) + { + //operation specific mapping + if (mapped == SGX_ERROR_UNEXPECTED && result != AESM_UNEXPECTED_ERROR) + { + switch (result) + { + case AESM_UNSUPPORTED_ATT_KEY_ID: + mapped = SGX_ERROR_UNSUPPORTED_ATT_KEY_ID; + break; + case AESM_KEY_CERTIFICATION_ERROR: + mapped = SGX_ERROR_ATT_KEY_CERTIFICATION_FAILURE; + break; + default: + mapped = SGX_ERROR_UNEXPECTED; + } + } + } + return mapped; + +} + +sgx_status_t SGXAPI sgx_get_quote_size_ex(const sgx_att_key_id_t *p_att_key_id, + uint32_t* p_quote_size) +{ + //Verify inputs + if(NULL == p_quote_size) + { + return SGX_ERROR_INVALID_PARAMETER; + } + + // Choose the certification key type supported by the reference. + sgx_ql_cert_key_type_t certification_key_type = SGX_QL_CERT_TYPE; + + aesm_error_t result = AESM_UNEXPECTED_ERROR; + uae_oal_status_t oal_ret = UAE_OAL_ERROR_UNEXPECTED; + oal_ret = oal_get_quote_size_ex((sgx_ql_att_key_id_t*)p_att_key_id, certification_key_type, p_quote_size, + SE_CALC_QUOTE_SIZE_TIMEOUT_MSEC*1000, &result); + + //common mappings + sgx_status_t mapped = oal_map_status(oal_ret); + if (mapped != SGX_SUCCESS) + return mapped; + + mapped = oal_map_result(result); + if (mapped != SGX_SUCCESS) + { + //operation specific mapping + if (mapped == SGX_ERROR_UNEXPECTED && result != AESM_UNEXPECTED_ERROR) + { + switch (result) + { + case AESM_ATT_KEY_NOT_INITIALIZED: + mapped = SGX_ERROR_ATT_KEY_UNINITIALIZED; + break; + case AESM_ATT_KEY_CERT_DATA_INVALID: + mapped = SGX_ERROR_INVALID_ATT_KEY_CERT_DATA; + break; + case AESM_UNSUPPORTED_ATT_KEY_ID: + mapped = SGX_ERROR_UNSUPPORTED_ATT_KEY_ID; + break; + default: + mapped = SGX_ERROR_UNEXPECTED; + } + } + } + return mapped; + +} + +sgx_status_t SGXAPI sgx_get_quote_ex(const sgx_report_t *p_app_report, + const sgx_att_key_id_t *p_att_key_id, + sgx_qe_report_info_t *p_qe_report_info, + uint8_t *p_quote, + uint32_t quote_size) +{ + //Verify inputs + if(NULL == p_app_report || NULL == p_att_key_id + || NULL == p_quote || 0 == quote_size) + { + return SGX_ERROR_INVALID_PARAMETER; + } + + aesm_error_t result = AESM_UNEXPECTED_ERROR; + uae_oal_status_t oal_ret = UAE_OAL_ERROR_UNEXPECTED; + oal_ret = oal_get_quote_ex(p_app_report, (sgx_ql_att_key_id_t*)p_att_key_id, (sgx_ql_qe_report_info_t*)p_qe_report_info, quote_size, p_quote, + SE_GET_QUOTE_TIMEOUT_MSEC(NULL)*1000, &result); + + //common mappings + sgx_status_t mapped = oal_map_status(oal_ret); + if (mapped != SGX_SUCCESS) + return mapped; + + mapped = oal_map_result(result); + if (mapped != SGX_SUCCESS) + { + //operation specific mapping + if (mapped == SGX_ERROR_UNEXPECTED && result != AESM_UNEXPECTED_ERROR) + { + switch (result) + { + case AESM_ATT_KEY_NOT_INITIALIZED: + mapped = SGX_ERROR_ATT_KEY_UNINITIALIZED; + break; + case AESM_ATT_KEY_CERT_DATA_INVALID: + mapped = SGX_ERROR_INVALID_ATT_KEY_CERT_DATA; + break; + case AESM_UNSUPPORTED_ATT_KEY_ID: + mapped = SGX_ERROR_UNSUPPORTED_ATT_KEY_ID; + break; + case AESM_ERROR_REPORT: + case AESM_INVALID_REPORT: + mapped = SGX_ERROR_MAC_MISMATCH; + break; + case AESM_UNABLE_TO_GENERATE_QE_REPORT: + mapped = SGX_ERROR_UNEXPECTED; + break; + default: + mapped = SGX_ERROR_UNEXPECTED; + } + } + } + return mapped; +} + + + + // common mapper function for all OAL specific error codes sgx_status_t oal_map_status(uae_oal_status_t status) @@ -701,6 +891,8 @@ sgx_status_t oal_map_result(aesm_error_t result) break; case AESM_SERVICE_STOPPED: case AESM_SERVICE_UNAVAILABLE: + case AESM_ENCLAVE_LOAD_ERROR: + case AESM_ENCLAVE_LOST: retVal = SGX_ERROR_SERVICE_UNAVAILABLE; break; case AESM_OUT_OF_MEMORY_ERROR: diff --git a/psw/uae_service/uae_service_assert.cpp b/psw/uae_service/uae_service_assert.cpp index bccdd593..afe03f73 100644 --- a/psw/uae_service/uae_service_assert.cpp +++ b/psw/uae_service/uae_service_assert.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,7 +38,10 @@ #include "aeerror.h" #include "sgx_uae_service.h" -#include "upse/platform_info_blob.h" +#include "sgx_ql_quote.h" +#include "platform_info_blob.h" #include "arch.h" se_static_assert(sizeof(sgx_platform_info_t)==sizeof(((platform_info_blob_wrapper_t*)0)->platform_info_blob)); /*size of sgx_platform_info_t is incorret*/ + +se_static_assert(sizeof(sgx_att_key_id_t)==sizeof(sgx_ql_att_key_id_t)); /*size of sgx_att_key_id_t is incorret*/ diff --git a/psw/uae_service/uae_service_version.cpp b/psw/uae_service/uae_service_version.cpp index 2592b77f..939cebdb 100644 --- a/psw/uae_service/uae_service_version.cpp +++ b/psw/uae_service/uae_service_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/uae_wrapper/inc/AEServices.h b/psw/uae_service/uae_wrapper/inc/AEServices.h index bf7db95a..d49b0a97 100644 --- a/psw/uae_service/uae_wrapper/inc/AEServices.h +++ b/psw/uae_service/uae_wrapper/inc/AEServices.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/uae_wrapper/inc/AEServicesImpl.h b/psw/uae_service/uae_wrapper/inc/AEServicesImpl.h index f6929379..bfa1fbd3 100644 --- a/psw/uae_service/uae_wrapper/inc/AEServicesImpl.h +++ b/psw/uae_service/uae_wrapper/inc/AEServicesImpl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/uae_wrapper/inc/AEServicesProvider.h b/psw/uae_service/uae_wrapper/inc/AEServicesProvider.h index 2ad60453..0c2c01b8 100644 --- a/psw/uae_service/uae_wrapper/inc/AEServicesProvider.h +++ b/psw/uae_service/uae_wrapper/inc/AEServicesProvider.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/uae_wrapper/src/AEServicesImpl.cpp b/psw/uae_service/uae_wrapper/src/AEServicesImpl.cpp index f58b3d3c..c05b1215 100644 --- a/psw/uae_service/uae_wrapper/src/AEServicesImpl.cpp +++ b/psw/uae_service/uae_wrapper/src/AEServicesImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/uae_wrapper/src/AEServicesProvider.cpp b/psw/uae_service/uae_wrapper/src/AEServicesProvider.cpp index 447976e1..cd3c5620 100644 --- a/psw/uae_service/uae_wrapper/src/AEServicesProvider.cpp +++ b/psw/uae_service/uae_wrapper/src/AEServicesProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/uae_wrapper/src/tae_ocall_api.cpp b/psw/uae_service/uae_wrapper/src/tae_ocall_api.cpp index 21164751..f062ad32 100644 --- a/psw/uae_service/uae_wrapper/src/tae_ocall_api.cpp +++ b/psw/uae_service/uae_wrapper/src/tae_ocall_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uae_service/uae_wrapper/src/uae_api.cpp b/psw/uae_service/uae_wrapper/src/uae_api.cpp index abfe2da7..f2b07633 100644 --- a/psw/uae_service/uae_wrapper/src/uae_api.cpp +++ b/psw/uae_service/uae_wrapper/src/uae_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,6 +62,16 @@ #include #include + +#include +#include + +#include +#include + +#include +#include + ////////THE COMMON STUFF aka INTEGRATION with Linux API #include #include @@ -342,3 +352,88 @@ uae_oal_status_t oal_register_common(uint8_t* buf, uint32_t buf_size, uint32_t d }); } + +extern "C" +uae_oal_status_t oal_init_quote_ex(const sgx_ql_att_key_id_t *att_key_id, + uint32_t certification_key_type, + sgx_target_info_t *target_info, + bool refresh_att_key, + size_t *pub_key_id_size, size_t buf_size, uint8_t *pub_key_id, + uint32_t timeout_usec, aesm_error_t *result) +{ + TRY_CATCH_BAD_ALLOC({ + AEServices *servicesProvider = AEServicesProvider::GetServicesProvider(); + if (servicesProvider == NULL) + return UAE_OAL_ERROR_UNEXPECTED; + + AEInitQuoteExRequest initQuoteExRequest(sizeof(sgx_ql_att_key_id_t), (uint8_t*)att_key_id, certification_key_type, refresh_att_key, (pub_key_id != NULL), buf_size, timeout_usec / 1000); + AEInitQuoteExResponse initQuoteExResponse; + uae_oal_status_t ret = servicesProvider->InternalInterface(&initQuoteExRequest, &initQuoteExResponse, timeout_usec / 1000); + if (ret == UAE_OAL_SUCCESS) + { + bool valid = initQuoteExResponse.GetValues((uint32_t*)result, sizeof(sgx_target_info_t), (uint8_t*)target_info, (uint64_t*)pub_key_id_size, buf_size, pub_key_id); + if (!valid) + ret = UAE_OAL_ERROR_UNEXPECTED; + } + return ret; + }); + +} + + +extern "C" +uae_oal_status_t oal_get_quote_size_ex( + const sgx_ql_att_key_id_t *att_key_id, + uint32_t certification_key_type, + uint32_t *quote_size, + uint32_t timeout_usec, aesm_error_t *result) +{ + TRY_CATCH_BAD_ALLOC({ + AEServices* servicesProvider = AEServicesProvider::GetServicesProvider(); + if (servicesProvider == NULL) + return UAE_OAL_ERROR_UNEXPECTED; + + AEGetQuoteSizeExRequest getQuoteSizeExRequest(sizeof(sgx_ql_att_key_id_t), (uint8_t*)att_key_id,certification_key_type, timeout_usec / 1000); + + AEGetQuoteSizeExResponse getQuoteSizeExResponse; + uae_oal_status_t ret = servicesProvider->InternalInterface(&getQuoteSizeExRequest, &getQuoteSizeExResponse, timeout_usec / 1000); + if (ret == UAE_OAL_SUCCESS) + { + bool valid = getQuoteSizeExResponse.GetValues((uint32_t*)result, quote_size); + if (!valid) + ret = UAE_OAL_ERROR_UNEXPECTED; + } + return ret; + }); +} + +extern "C" +uae_oal_status_t SGXAPI oal_get_quote_ex( + const sgx_report_t *p_report, + const sgx_ql_att_key_id_t *att_key_id, + sgx_ql_qe_report_info_t *qe_report_info, + uint32_t quote_size, uint8_t *p_quote, + uint32_t timeout_usec, + aesm_error_t *result) +{ + TRY_CATCH_BAD_ALLOC({ + AEServices *servicesProvider = AEServicesProvider::GetServicesProvider(); + if (servicesProvider == NULL) + return UAE_OAL_ERROR_UNEXPECTED; + AEGetQuoteExRequest getQuoteExRequest(sizeof(sgx_report_t), (const uint8_t*)p_report, + sizeof(sgx_ql_att_key_id_t), (uint8_t*)att_key_id, + sizeof(sgx_ql_qe_report_info_t), (uint8_t*)qe_report_info, + quote_size, + timeout_usec / 1000); + AEGetQuoteExResponse getQuoteExResponse; + uae_oal_status_t ret = servicesProvider->InternalInterface(&getQuoteExRequest, &getQuoteExResponse, timeout_usec / 1000); + if (ret == UAE_OAL_SUCCESS) + { + bool valid = getQuoteExResponse.GetValues((uint32_t*)result, quote_size, (uint8_t*)p_quote, sizeof(sgx_ql_qe_report_info_t), (uint8_t*)qe_report_info); + if (!valid) + ret = UAE_OAL_ERROR_UNEXPECTED; + } + return ret; + }); +} + diff --git a/psw/urts/cpu_features.cpp b/psw/urts/cpu_features.cpp index 50f3f86b..8fb36016 100644 --- a/psw/urts/cpu_features.cpp +++ b/psw/urts/cpu_features.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/cpu_features.h b/psw/urts/cpu_features.h index 4f78a4df..bcf86584 100644 --- a/psw/urts/cpu_features.h +++ b/psw/urts/cpu_features.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/create_param.h b/psw/urts/create_param.h index af811426..0050d697 100644 --- a/psw/urts/create_param.h +++ b/psw/urts/create_param.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/enclave.cpp b/psw/urts/enclave.cpp index b6866958..c0e8de7d 100644 --- a/psw/urts/enclave.cpp +++ b/psw/urts/enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,9 +48,8 @@ int do_ecall(const int fn, const void *ocall_table, const void *ms, CTrustThread *trust_thread); int do_ocall(const bridge_fn_t bridge, void *ms); -CEnclave::CEnclave(CLoader &ldr) - : m_loader(ldr) - , m_enclave_id(0) +CEnclave::CEnclave() + : m_enclave_id(0) , m_start_addr(NULL) , m_size(0) , m_power_event_flag(0) @@ -66,10 +65,15 @@ CEnclave::CEnclave(CLoader &ldr) , m_sealed_key(NULL) , m_uswitchless(NULL) , m_us_has_started(false) + , m_dynamic_tcs_list_size(0) { memset(&m_enclave_info, 0, sizeof(debug_enclave_info_t)); memset(&m_target_info, 0, sizeof(sgx_target_info_t)); se_init_rwlock(&m_rwlock); +#ifdef SE_SIM + m_global_data_sim_ptr = NULL; +#endif + } @@ -109,8 +113,10 @@ on_exit: return status; } -sgx_status_t CEnclave::initialize(const se_file_t& file, const secs_t& secs, const sgx_enclave_id_t enclave_id, void * const start_addr, const uint64_t enclave_size, const uint32_t tcs_policy, const uint32_t enclave_version, const uint32_t tcs_min_pool) +sgx_status_t CEnclave::initialize(const se_file_t& file, CLoader &ldr, const uint64_t enclave_size, const uint32_t tcs_policy, const uint32_t enclave_version, const uint32_t tcs_min_pool) { + const secs_t& secs = ldr.get_secs(); + if (file.name != NULL) { uint32_t name_len = file.name_len; @@ -131,8 +137,8 @@ sgx_status_t CEnclave::initialize(const se_file_t& file, const secs_t& secs, con m_enclave_info.struct_version = DEBUG_INFO_STRUCT_VERSION; - m_enclave_id = enclave_id; - m_start_addr = start_addr; + m_enclave_id = ldr.get_enclave_id(); + m_start_addr = (void*)ldr.get_start_addr(); m_size = enclave_size; m_version = enclave_version; @@ -161,14 +167,28 @@ sgx_status_t CEnclave::initialize(const se_file_t& file, const secs_t& secs, con m_enclave_info.lpFileName = NULL; return SGX_ERROR_INVALID_PARAMETER; } - + + set_dynamic_tcs_list_size(ldr); +#ifdef SE_SIM + set_global_data_sim_ptr(ldr); +#endif + if (memcpy_s(&m_target_info.mr_enclave, sizeof(sgx_measurement_t), &secs.mr_enclave, sizeof(sgx_measurement_t))) + { + free(m_enclave_info.lpFileName); + m_enclave_info.lpFileName = NULL; return SGX_ERROR_UNEXPECTED; + } + m_target_info.attributes = secs.attributes; m_target_info.config_svn = secs.config_svn; m_target_info.misc_select = secs.misc_select; if (memcpy_s(m_target_info.config_id, sizeof(sgx_config_id_t), secs.config_id, sizeof(sgx_config_id_t))) + { + free(m_enclave_info.lpFileName); + m_enclave_info.lpFileName = NULL; return SGX_ERROR_UNEXPECTED; + } return SGX_SUCCESS; } @@ -182,7 +202,7 @@ CEnclave::~CEnclave() } m_ocall_table = NULL; - + if (m_uswitchless) { sl_uswitchless_free(m_uswitchless); @@ -195,11 +215,6 @@ CEnclave::~CEnclave() m_new_thread_event = NULL; } -void * CEnclave::get_symbol_address(const char * const symbol) -{ - return m_loader.get_symbol_address(symbol); -} - sgx_enclave_id_t CEnclave::get_enclave_id() { return m_enclave_id; @@ -210,9 +225,9 @@ uint32_t CEnclave::get_enclave_version() return m_version; } -size_t CEnclave::get_dynamic_tcs_list_size() +void CEnclave::set_dynamic_tcs_list_size(CLoader &ldr) { - std::vector> tcs_list = m_loader.get_tcs_list(); + std::vector> tcs_list = ldr.get_tcs_list(); size_t count = 0; for (size_t idx = 0; idx < tcs_list.size(); ++idx) { @@ -221,9 +236,27 @@ size_t CEnclave::get_dynamic_tcs_list_size() count++; } } - return count; + + m_dynamic_tcs_list_size = count; } +size_t CEnclave::get_dynamic_tcs_list_size() +{ + return m_dynamic_tcs_list_size; +} + +#ifdef SE_SIM +void CEnclave::set_global_data_sim_ptr(CLoader &ldr) +{ + m_global_data_sim_ptr = ldr.get_symbol_address("g_global_data_sim"); +} + +void *CEnclave::get_global_data_sim_ptr() +{ + return m_global_data_sim_ptr; +} +#endif + uint8_t *CEnclave::get_sealed_key() { return m_sealed_key; @@ -512,9 +545,9 @@ void CEnclave::add_thread(CTrustThread * const trust_thread) } -int CEnclave::set_extra_debug_info(secs_t& secs) +int CEnclave::set_extra_debug_info(secs_t& secs, void* g_peak_heap_addr) { - void *g_peak_heap_used_addr = get_symbol_address("g_peak_heap_used"); + void *g_peak_heap_used_addr = g_peak_heap_addr; m_enclave_info.g_peak_heap_used_addr = g_peak_heap_used_addr; m_enclave_info.start_addr = secs.base; m_enclave_info.misc_select = secs.misc_select; diff --git a/psw/urts/enclave.h b/psw/urts/enclave.h index 4d44714a..51aaa14b 100644 --- a/psw/urts/enclave.h +++ b/psw/urts/enclave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -49,10 +49,9 @@ class CLoader; class CEnclave: private Uncopyable { public: - explicit CEnclave(CLoader &ldr); + explicit CEnclave(); ~CEnclave(); void* get_start_address(){ return m_start_addr;}; - void * get_symbol_address(const char * const symbol); sgx_enclave_id_t get_enclave_id(); uint32_t get_enclave_version(); size_t get_dynamic_tcs_list_size(); @@ -66,13 +65,13 @@ public: uint32_t get_ref() { return m_ref; } void mark_zombie() { m_zombie = true; } bool is_zombie() { return m_zombie; } - sgx_status_t initialize(const se_file_t& file, const secs_t& secs, const sgx_enclave_id_t enclave_id, void * const start_addr, const uint64_t enclave_size, const uint32_t tcs_policy, const uint32_t enclave_version, const uint32_t tcs_min_pool); + sgx_status_t initialize(const se_file_t& file, CLoader &ldr, const uint64_t enclave_size, const uint32_t tcs_policy, const uint32_t enclave_version, const uint32_t tcs_min_pool); void add_thread(tcs_t * const tcs, bool is_unallocated); void add_thread(CTrustThread * const trust_thread); const debug_enclave_info_t* get_debug_info(); void set_dbg_flag(bool dbg_flag) { m_dbg_flag = dbg_flag; } bool get_dbg_flag() { return m_dbg_flag; } - int set_extra_debug_info(secs_t& secs); + int set_extra_debug_info(secs_t& secs, void* g_peak_heap_addr); //rdunlock is used in signal handler void rdunlock() { se_rdunlock(&m_rwlock); } void push_ocall_frame(ocall_frame_t* frame_point, CTrustThread *trust_thread); @@ -86,13 +85,20 @@ public: sgx_status_t init_uswitchless(const sgx_uswitchless_config_t* config); void destroy_uswitchless(void); sgx_target_info_t get_target_info(); +#ifdef SE_SIM + void *get_global_data_sim_ptr(); +#endif private: CTrustThread * get_tcs(int ecall_cmd); void put_tcs(CTrustThread *trust_thread); sgx_status_t error_trts2urts(unsigned int trts_error); - CLoader &m_loader; + void set_dynamic_tcs_list_size(CLoader &ldr); +#ifdef SE_SIM + void set_global_data_sim_ptr(CLoader &ldr); +#endif + sgx_enclave_id_t m_enclave_id; void *m_start_addr; uint64_t m_size; @@ -113,6 +119,10 @@ private: struct sl_uswitchless* m_uswitchless; bool m_us_has_started; sgx_target_info_t m_target_info; + size_t m_dynamic_tcs_list_size; +#ifdef SE_SIM + void *m_global_data_sim_ptr; +#endif }; class CEnclavePool: private Uncopyable @@ -123,7 +133,6 @@ public: CEnclave * get_enclave(const sgx_enclave_id_t enclave_id); CEnclave * ref_enclave(const sgx_enclave_id_t enclave_id); void unref_enclave(CEnclave *enclave); - int get_symbol_ordinal(const sgx_enclave_id_t enclave_id, const char *symbol, int *ordinal); CEnclave * remove_enclave(const sgx_enclave_id_t enclave_id, sgx_status_t &status); se_handle_t get_event(const void * const); void notify_debugger(); diff --git a/psw/urts/enclave_creator_hw.h b/psw/urts/enclave_creator_hw.h index 9675bb29..1873105a 100644 --- a/psw/urts/enclave_creator_hw.h +++ b/psw/urts/enclave_creator_hw.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/enclave_creator_hw_com.cpp b/psw/urts/enclave_creator_hw_com.cpp index f0e0494b..f1d49bf3 100644 --- a/psw/urts/enclave_creator_hw_com.cpp +++ b/psw/urts/enclave_creator_hw_com.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/enclave_mutex.cpp b/psw/urts/enclave_mutex.cpp index de5428c4..322d0ae4 100644 --- a/psw/urts/enclave_mutex.cpp +++ b/psw/urts/enclave_mutex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/file.h b/psw/urts/file.h index ac05687a..cd935334 100644 --- a/psw/urts/file.h +++ b/psw/urts/file.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/launch_checker.cpp b/psw/urts/launch_checker.cpp index ce247aec..c83cd087 100644 --- a/psw/urts/launch_checker.cpp +++ b/psw/urts/launch_checker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/launch_checker.h b/psw/urts/launch_checker.h index a16671da..878219c1 100644 --- a/psw/urts/launch_checker.h +++ b/psw/urts/launch_checker.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/Makefile b/psw/urts/linux/Makefile index 4658a087..2f12876a 100644 --- a/psw/urts/linux/Makefile +++ b/psw/urts/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -55,9 +55,13 @@ INC += -I$(COMMON_DIR)/inc \ -I$(VTUNE_DIR)/sdk/src/ittnotify LDFLAGS := -lwrapper +INTERNAL_LDFLAGS := -lwrapper LDFLAGS += $(COMMON_LDFLAGS) -Wl,-Bdynamic -lsgx_enclave_common +INTERNAL_LDFLAGS += $(COMMON_LDFLAGS) LDFLAGS += -L$(VTUNE_DIR)/sdk/src/ittnotify -littnotify -ldl +INTERNAL_LDFLAGS += -L$(VTUNE_DIR)/sdk/src/ittnotify -littnotify -ldl LDFLAGS += -Wl,--version-script=urts.lds -Wl,--gc-sections +INTERNAL_LDFLAGS += -Wl,--version-script=urts_internal.lds -Wl,--gc-sections DIR1 := $(LINUX_PSW_DIR)/urts/linux DIR2 := $(LINUX_PSW_DIR)/urts @@ -112,7 +116,7 @@ vpath %.S $(DIR1):$(DIR5) LIBWRAPPER := libwrapper.a LIBSGX_ENCLAVE_COMMON := libsgx_enclave_common.a LIBURTS := libsgx_urts.so -LIBURTS_INTERNAL := liburts_internal.a +LIBURTS_INTERNAL := liburts_internal.so LIBURTS_DEBUG := libsgx_urts.so.debug # untrusted switchless settings @@ -120,6 +124,7 @@ USWITCHLESS_NAME := uswitchless USWITCHLESS_DIR := $(LINUX_PSW_DIR)/$(USWITCHLESS_NAME) LIBUSWITCHLESS := $(USWITCHLESS_DIR)/lib$(USWITCHLESS_NAME).a LDFLAGS += -L$(USWITCHLESS_DIR) -l$(USWITCHLESS_NAME) +INTERNAL_LDFLAGS += -L$(USWITCHLESS_DIR) -l$(USWITCHLESS_NAME) .PHONY: all all: $(LIBURTS) $(LIBURTS_INTERNAL) $(LIBURTS_DEBUG) | $(BUILD_DIR) @@ -129,17 +134,13 @@ ifndef DEBUG @$(CP) $(LIBURTS_DEBUG) $| endif -$(LIBURTS_INTERNAL): $(INTERNAL_OBJ) $(LIBWRAPPER) $(LIBSGX_ENCLAVE_COMMON) $(LIBUSWITCHLESS) - $(CP) $(COMMON_DIR)/se_wrapper/libwrapper.a $@ - $(MKDIR) ./.switchless_tmp - $(RM) ./.switchless_tmp/* - cd ./.switchless_tmp && \ - $(AR) x $(LIBUSWITCHLESS) +$(LIBURTS_INTERNAL): $(INTERNAL_OBJ) $(LIBWRAPPER) $(LIBSGX_ENCLAVE_COMMON) $(LIBUSWITCHLESS) ittnotify @$(MKDIR) $(BUILD_DIR)/.sgx_enclave_common @$(RM) -f $(BUILD_DIR)/.sgx_enclave_common/* - cd $(BUILD_DIR)/.sgx_enclave_common && $(AR) x $(BUILD_DIR)/$(LIBSGX_ENCLAVE_COMMON) - $(AR) rcs $@ $(INTERNAL_OBJ) ./.switchless_tmp/*.o $(BUILD_DIR)/.sgx_enclave_common/*.o - @$(RM) -rf ./.switchless_tmp + cd $(BUILD_DIR)/.sgx_enclave_common && \ + $(AR) x $(BUILD_DIR)/$(LIBSGX_ENCLAVE_COMMON) && \ + $(RM) -f edmm_utility.o + $(CXX) $(CXXFLAGS) -shared -Wl,-soname=$@ $(LIB) -o $@ $(INTERNAL_OBJ) $(BUILD_DIR)/.sgx_enclave_common/*.o $(INTERNAL_LDFLAGS) @$(RM) -rf $(BUILD_DIR)/.sgx_enclave_common $(LIBURTS): $(URTS_OBJ) $(LIBWRAPPER) $(LIBSGX_ENCLAVE_COMMON) $(LIBUSWITCHLESS) ittnotify diff --git a/psw/urts/linux/debugger_support.cpp b/psw/urts/linux/debugger_support.cpp index 749b8c1a..abbdc8df 100644 --- a/psw/urts/linux/debugger_support.cpp +++ b/psw/urts/linux/debugger_support.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/debugger_support.h b/psw/urts/linux/debugger_support.h index 0eb29336..8e1cefe2 100644 --- a/psw/urts/linux/debugger_support.h +++ b/psw/urts/linux/debugger_support.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/edmm_utility.cpp b/psw/urts/linux/edmm_utility.cpp index af72f63d..19b33830 100644 --- a/psw/urts/linux/edmm_utility.cpp +++ b/psw/urts/linux/edmm_utility.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -63,7 +63,10 @@ static bool is_urts_support_edmm() char line[1024]; if (NULL == fgets(line, sizeof(line), pipe)) + { + pclose(pipe); return false; + } if (-1 == pclose(pipe)) { diff --git a/psw/urts/linux/edmm_utility.h b/psw/urts/linux/edmm_utility.h index 73ff748c..d2b89ade 100644 --- a/psw/urts/linux/edmm_utility.h +++ b/psw/urts/linux/edmm_utility.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/enclave_creator_hw.cpp b/psw/urts/linux/enclave_creator_hw.cpp index f1d914d7..dbbc621c 100644 --- a/psw/urts/linux/enclave_creator_hw.cpp +++ b/psw/urts/linux/enclave_creator_hw.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/enter_enclave.S b/psw/urts/linux/enter_enclave.S index fcc5da86..1c21e2df 100644 --- a/psw/urts/linux/enter_enclave.S +++ b/psw/urts/linux/enter_enclave.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/enter_enclave.h b/psw/urts/linux/enter_enclave.h index 37e89653..509be6d1 100644 --- a/psw/urts/linux/enter_enclave.h +++ b/psw/urts/linux/enter_enclave.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/get_thread_id.cpp b/psw/urts/linux/get_thread_id.cpp index 955b4704..dc366609 100644 --- a/psw/urts/linux/get_thread_id.cpp +++ b/psw/urts/linux/get_thread_id.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/isgx_user.h b/psw/urts/linux/isgx_user.h index fe53782f..eead37d6 100644 --- a/psw/urts/linux/isgx_user.h +++ b/psw/urts/linux/isgx_user.h @@ -73,6 +73,8 @@ _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) #define SGX_IOC_ENCLAVE_INIT_IN_KERNEL \ _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init_in_kernel) +#define SGX_IOC_ENCLAVE_SET_ATTRIBUTE \ + _IOW(SGX_MAGIC, 0x03, struct sgx_enclave_set_attribute) #define SGX_IOC_ENCLAVE_EMODPR \ _IOW(SGX_MAGIC, 0x09, struct sgx_modification_param) #define SGX_IOC_ENCLAVE_MKTCS \ @@ -163,6 +165,17 @@ struct sgx_enclave_init_in_kernel { __u64 sigstruct; }; +/** + * struct sgx_enclave_set_attribute - parameter structure for the + * %SGX_IOC_ENCLAVE_SET_ATTRIBUTE ioctl + * @addr: address within the ELRANGE + * @attribute_fd: file handle of the attribute file in the securityfs + */ +struct sgx_enclave_set_attribute { + __u64 addr; + __u64 attribute_fd; +}; + struct sgx_enclave_destroy { __u64 addr; } __attribute__((packed)); diff --git a/psw/urts/linux/misc.cpp b/psw/urts/linux/misc.cpp index 170ffc5b..c254e011 100644 --- a/psw/urts/linux/misc.cpp +++ b/psw/urts/linux/misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/read_xcr0.h b/psw/urts/linux/read_xcr0.h index c542d24f..fa39297e 100644 --- a/psw/urts/linux/read_xcr0.h +++ b/psw/urts/linux/read_xcr0.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/sig_handler.cpp b/psw/urts/linux/sig_handler.cpp index 4711c576..7a080dea 100644 --- a/psw/urts/linux/sig_handler.cpp +++ b/psw/urts/linux/sig_handler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/sig_handler.h b/psw/urts/linux/sig_handler.h index e8a7e7ac..6ef7eaa1 100644 --- a/psw/urts/linux/sig_handler.h +++ b/psw/urts/linux/sig_handler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/urts.cpp b/psw/urts/linux/urts.cpp index d22dddb2..8e7b4067 100644 --- a/psw/urts/linux/urts.cpp +++ b/psw/urts/linux/urts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -94,7 +94,7 @@ extern "C" sgx_status_t __sgx_create_enclave_ex(const char *file_name, se_file_t file = {NULL, 0, false}; char resolved_path[PATH_MAX]; file.name = realpath(file_name, resolved_path); - file.name_len = (uint32_t)strlen(resolved_path); + file.name_len = (uint32_t)strnlen_s(resolved_path, PATH_MAX); ret = _create_enclave_ex(!!debug, fd, file, NULL, launch_token, launch_token_updated, enclave_id, misc_attr, ex_features, ex_features_p); if(SGX_SUCCESS != ret && misc_attr) diff --git a/psw/urts/linux/urts_emodpr.cpp b/psw/urts/linux/urts_emodpr.cpp index 819599b9..93cbe6ba 100644 --- a/psw/urts/linux/urts_emodpr.cpp +++ b/psw/urts/linux/urts_emodpr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/urts_emodpr.h b/psw/urts/linux/urts_emodpr.h index d19880a6..87846e2c 100644 --- a/psw/urts/linux/urts_emodpr.h +++ b/psw/urts/linux/urts_emodpr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/urts_internal.cpp b/psw/urts/linux/urts_internal.cpp index e27c1213..8f3ca595 100644 --- a/psw/urts/linux/urts_internal.cpp +++ b/psw/urts/linux/urts_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -83,3 +83,95 @@ extern "C" bool is_in_kernel_driver() return get_enclave_creator()->is_in_kernel_driver(); } +#include "binparser.h" +#ifndef PARSER +#include "elfparser.h" +#define PARSER ElfParser +#endif + +static bool get_metadata_internal(BinParser *parser, metadata_t **metadata) +{ + if (parser == NULL || metadata == NULL) + return false; + uint64_t meta_rva = parser->get_metadata_offset(); + const uint8_t *base_addr = parser->get_start_addr(); + uint64_t urts_version = META_DATA_MAKE_VERSION(MAJOR_VERSION,MINOR_VERSION); + metadata_t *target_metadata = NULL; + + //assume AE only contains one metadata + *metadata = GET_PTR(metadata_t, base_addr, meta_rva); + + if(metadata == NULL) + { + return false; + } + if((*metadata)->magic_num != METADATA_MAGIC) + { + return false; + } + if(0 == (*metadata)->size) + { + SE_TRACE(SE_TRACE_ERROR, "ERROR: metadata's size can't be zero.\n"); + return false; + } + //check metadata version + if(MAJOR_VERSION_OF_METADATA(urts_version) >= + MAJOR_VERSION_OF_METADATA((*metadata)->version)) + { + if(target_metadata == NULL || + target_metadata->version < (*metadata)->version) + { + target_metadata = *metadata; + } + } + if(target_metadata == NULL ) + { + return false; + } + else + { + *metadata = target_metadata; + } + return true; +} + +extern "C" bool get_metadata(const char* enclave_file, metadata_t *metadata) +{ + map_handle_t* mh = NULL; + metadata_t *p_metadata; + + uint32_t file_size = 0; + int fd = open(enclave_file, O_RDONLY); + if(-1 == fd) + { + SE_TRACE(SE_TRACE_ERROR, "Couldn't open the enclave file, error = %d\n", errno); + return false; + } + + + mh = map_file(fd, &file_size); + if (!mh) + { + close(fd); + return false; + } + + PARSER parser(const_cast(mh->base_addr), (uint64_t)(file_size)); + if(SGX_SUCCESS != parser.run_parser()) + { + unmap_file(mh); + close(fd); + return false; + } + + if(true != get_metadata_internal(&parser, &p_metadata)) + { + unmap_file(mh); + close(fd); + return false; + } + memcpy(metadata, p_metadata, sizeof(metadata_t)); + unmap_file(mh); + close(fd); + return true; +} diff --git a/psw/urts/linux/urts_internal.lds b/psw/urts/linux/urts_internal.lds new file mode 100644 index 00000000..3ee5c829 --- /dev/null +++ b/psw/urts/linux/urts_internal.lds @@ -0,0 +1,21 @@ +{ + global: + sgx_create_enclave; + sgx_create_enclave_ex; + sgx_destroy_enclave; + sgx_ecall; + sgx_ecall_switchless; + sgx_thread_wait_untrusted_event_ocall; + sgx_thread_set_untrusted_event_ocall; + sgx_thread_setwait_untrusted_events_ocall; + sgx_thread_set_multiple_untrusted_events_ocall; + sgx_oc_cpuidex; + sgx_get_target_info; + sgx_create_encrypted_enclave; + sgx_create_enclave_from_buffer_ex; + sgx_create_le; + is_in_kernel_driver; + get_metadata; + local: + *; +}; diff --git a/psw/urts/linux/urts_trim.cpp b/psw/urts/linux/urts_trim.cpp index 02350b39..94918d25 100644 --- a/psw/urts/linux/urts_trim.cpp +++ b/psw/urts/linux/urts_trim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/linux/urts_trim.h b/psw/urts/linux/urts_trim.h index 9c404fbc..9a37814e 100644 --- a/psw/urts/linux/urts_trim.h +++ b/psw/urts/linux/urts_trim.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/loader.cpp b/psw/urts/loader.cpp index b4cde416..9dd307b7 100644 --- a/psw/urts/loader.cpp +++ b/psw/urts/loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/loader.h b/psw/urts/loader.h index d36ff1c0..3034c604 100644 --- a/psw/urts/loader.h +++ b/psw/urts/loader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/node.cpp b/psw/urts/node.cpp index 2345cf09..8aba8376 100644 --- a/psw/urts/node.cpp +++ b/psw/urts/node.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/node.h b/psw/urts/node.h index 4b1b7333..26332644 100644 --- a/psw/urts/node.h +++ b/psw/urts/node.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/Makefile b/psw/urts/parser/Makefile index 44d0d533..76c799b9 100644 --- a/psw/urts/parser/Makefile +++ b/psw/urts/parser/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/binparser.h b/psw/urts/parser/binparser.h index c271d47a..3380e577 100644 --- a/psw/urts/parser/binparser.h +++ b/psw/urts/parser/binparser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/clearvars.h b/psw/urts/parser/clearvars.h index 33beb4f4..2f3c2d96 100644 --- a/psw/urts/parser/clearvars.h +++ b/psw/urts/parser/clearvars.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/elf32parser.cpp b/psw/urts/parser/elf32parser.cpp index 94bbe782..b98f8351 100644 --- a/psw/urts/parser/elf32parser.cpp +++ b/psw/urts/parser/elf32parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/elf32parser.h b/psw/urts/parser/elf32parser.h index 13851cf8..20d57690 100644 --- a/psw/urts/parser/elf32parser.h +++ b/psw/urts/parser/elf32parser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/elf64parser.cpp b/psw/urts/parser/elf64parser.cpp index 5b5204a5..94ebcfd3 100644 --- a/psw/urts/parser/elf64parser.cpp +++ b/psw/urts/parser/elf64parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/elf64parser.h b/psw/urts/parser/elf64parser.h index c7919246..7a932ab0 100644 --- a/psw/urts/parser/elf64parser.h +++ b/psw/urts/parser/elf64parser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/elfparser.cpp b/psw/urts/parser/elfparser.cpp index aa0d2ae6..baed2257 100644 --- a/psw/urts/parser/elfparser.cpp +++ b/psw/urts/parser/elfparser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/elfparser.h b/psw/urts/parser/elfparser.h index 16cd72d3..0d5e86dc 100644 --- a/psw/urts/parser/elfparser.h +++ b/psw/urts/parser/elfparser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/parserfactory.cpp b/psw/urts/parser/parserfactory.cpp index a599de67..97c88910 100644 --- a/psw/urts/parser/parserfactory.cpp +++ b/psw/urts/parser/parserfactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/parserfactory.h b/psw/urts/parser/parserfactory.h index f494f078..df52aed8 100644 --- a/psw/urts/parser/parserfactory.h +++ b/psw/urts/parser/parserfactory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/section.cpp b/psw/urts/parser/section.cpp index 5e8ef16c..d9993ce4 100644 --- a/psw/urts/parser/section.cpp +++ b/psw/urts/parser/section.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/section.h b/psw/urts/parser/section.h index ad7dd83a..2a81167f 100644 --- a/psw/urts/parser/section.h +++ b/psw/urts/parser/section.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/parser/update_global_data.hxx b/psw/urts/parser/update_global_data.hxx index 131e4d52..bc71a89e 100644 --- a/psw/urts/parser/update_global_data.hxx +++ b/psw/urts/parser/update_global_data.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,7 +39,6 @@ namespace { if(layout->id == id) return layout; } - assert(false); return NULL; } bool do_update_global_data(const metadata_t *const metadata, @@ -47,7 +46,10 @@ namespace { global_data_t* global_data) { layout_entry_t *layout_heap = get_entry_by_id(metadata, LAYOUT_ID_HEAP_MIN); - + if(layout_heap == NULL) + { + return false; + } global_data->enclave_size = (sys_word_t)metadata->enclave_size; global_data->heap_offset = (sys_word_t)layout_heap->rva; global_data->heap_size = (sys_word_t)(create_param->heap_init_size); diff --git a/psw/urts/prd_css_util.cpp b/psw/urts/prd_css_util.cpp index 26854645..2fc4e85e 100644 --- a/psw/urts/prd_css_util.cpp +++ b/psw/urts/prd_css_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/prd_css_util.h b/psw/urts/prd_css_util.h index da9cc3c8..033952e7 100644 --- a/psw/urts/prd_css_util.h +++ b/psw/urts/prd_css_util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/routine.cpp b/psw/urts/routine.cpp index 63c6410d..95c50da2 100644 --- a/psw/urts/routine.cpp +++ b/psw/urts/routine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/se_detect.cpp b/psw/urts/se_detect.cpp index 7371a0de..c6973073 100644 --- a/psw/urts/se_detect.cpp +++ b/psw/urts/se_detect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/se_detect.h b/psw/urts/se_detect.h index a84754db..c72aad7e 100644 --- a/psw/urts/se_detect.h +++ b/psw/urts/se_detect.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/se_ocalls.cpp b/psw/urts/se_ocalls.cpp index 02b4b0af..ac91860b 100644 --- a/psw/urts/se_ocalls.cpp +++ b/psw/urts/se_ocalls.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/section_info.h b/psw/urts/section_info.h index db117f32..5f8c765e 100644 --- a/psw/urts/section_info.h +++ b/psw/urts/section_info.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/tcs.cpp b/psw/urts/tcs.cpp index d5b9e382..98e53c80 100644 --- a/psw/urts/tcs.cpp +++ b/psw/urts/tcs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/tcs.h b/psw/urts/tcs.h index 20ba1144..00fddcfc 100644 --- a/psw/urts/tcs.h +++ b/psw/urts/tcs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/urts_com.h b/psw/urts/urts_com.h index 9cc3d989..a042b8e2 100644 --- a/psw/urts/urts_com.h +++ b/psw/urts/urts_com.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -243,8 +243,6 @@ static int __create_enclave(BinParser &parser, const uint32_t ex_features, const void* ex_features_p[32]) { - // The "parser" will be registered into "loader" and "loader" will be registered into "enclave". - // After enclave is created, "parser" and "loader" are not needed any more. debug_enclave_info_t *debug_info = NULL; int ret = SGX_SUCCESS; sgx_config_id_t *config_id = NULL; @@ -268,7 +266,7 @@ static int __create_enclave(BinParser &parser, return ret; } - CEnclave* enclave = new CEnclave(loader); + CEnclave* enclave = new CEnclave(); uint32_t enclave_version = SDK_VERSION_1_5; uint64_t urts_version = META_DATA_MAKE_VERSION(MAJOR_VERSION,MINOR_VERSION); // metadata->version has already been validated during load_encalve_ex() @@ -285,9 +283,7 @@ static int __create_enclave(BinParser &parser, // initialize the enclave object ret = enclave->initialize(file, - loader.get_secs(), - loader.get_enclave_id(), - const_cast(loader.get_start_addr()), + loader, metadata->enclave_size, metadata->tcs_policy, enclave_version, @@ -318,7 +314,7 @@ static int __create_enclave(BinParser &parser, debug_info = const_cast(enclave->get_debug_info()); - enclave->set_extra_debug_info(const_cast(loader.get_secs())); + enclave->set_extra_debug_info(const_cast(loader.get_secs()), loader.get_symbol_address("g_peak_heap_used")); //add enclave to enclave pool before init_enclave because in simualtion //mode init_enclave will rely on CEnclavePool to get Enclave instance. @@ -636,8 +632,7 @@ sgx_status_t _create_enclave_ex(const bool debug, se_file_handle_t pfile, se_fil ret = _create_enclave_from_buffer_ex(debug, mh->base_addr, (uint64_t)(file_size), file, prd_css_file, enclave_id, misc_attr, ex_features, ex_features_p); - if(mh != NULL) - unmap_file(mh); + unmap_file(mh); return (sgx_status_t)ret; } diff --git a/psw/urts/urts_version.cpp b/psw/urts/urts_version.cpp index 0c907fb8..86a46e65 100644 --- a/psw/urts/urts_version.cpp +++ b/psw/urts/urts_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/urts/urts_xsave.cpp b/psw/urts/urts_xsave.cpp index 01184aea..26a898e7 100644 --- a/psw/urts/urts_xsave.cpp +++ b/psw/urts/urts_xsave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uswitchless/Makefile b/psw/uswitchless/Makefile index a98eba74..c6c2748f 100644 --- a/psw/uswitchless/Makefile +++ b/psw/uswitchless/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/psw/uswitchless/sgx_ecall_switchless_untrusted.c b/psw/uswitchless/sgx_ecall_switchless_untrusted.c index 540b3665..998d0d13 100644 --- a/psw/uswitchless/sgx_ecall_switchless_untrusted.c +++ b/psw/uswitchless/sgx_ecall_switchless_untrusted.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uswitchless/sl_fcall_mngr_untrusted.c b/psw/uswitchless/sl_fcall_mngr_untrusted.c index d8c1a468..650f2945 100644 --- a/psw/uswitchless/sl_fcall_mngr_untrusted.c +++ b/psw/uswitchless/sl_fcall_mngr_untrusted.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uswitchless/sl_siglines_untrusted.c b/psw/uswitchless/sl_siglines_untrusted.c index 0fa584c7..b6a71e0e 100644 --- a/psw/uswitchless/sl_siglines_untrusted.c +++ b/psw/uswitchless/sl_siglines_untrusted.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uswitchless/sl_uswitchless_untrusted.c b/psw/uswitchless/sl_uswitchless_untrusted.c index f255e8b3..f1e31895 100644 --- a/psw/uswitchless/sl_uswitchless_untrusted.c +++ b/psw/uswitchless/sl_uswitchless_untrusted.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/psw/uswitchless/sl_workers_untrusted.c b/psw/uswitchless/sl_workers_untrusted.c index 8c387165..e4af32f2 100644 --- a/psw/uswitchless/sl_workers_untrusted.c +++ b/psw/uswitchless/sl_workers_untrusted.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/Makefile b/sdk/Makefile index c562d1d7..2140e209 100644 --- a/sdk/Makefile +++ b/sdk/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/Makefile.opt_lib b/sdk/Makefile.opt_lib index 330c8bdf..88f41898 100644 --- a/sdk/Makefile.opt_lib +++ b/sdk/Makefile.opt_lib @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/Makefile.source b/sdk/Makefile.source index 078faba7..7c3dea79 100644 --- a/sdk/Makefile.source +++ b/sdk/Makefile.source @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/compiler-rt/Makefile b/sdk/compiler-rt/Makefile index 11fd6bd1..30745259 100644 --- a/sdk/compiler-rt/Makefile +++ b/sdk/compiler-rt/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/compiler-rt/stack_chk.c b/sdk/compiler-rt/stack_chk.c index 5bb29f01..8227c55a 100644 --- a/sdk/compiler-rt/stack_chk.c +++ b/sdk/compiler-rt/stack_chk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/Makefile b/sdk/cpprt/Makefile index 73b3b2d6..def5834e 100644 --- a/sdk/cpprt/Makefile +++ b/sdk/cpprt/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/linux/libunwind/autogen-linux.sh b/sdk/cpprt/linux/libunwind/autogen-linux.sh index fbeff61f..38a238e7 100755 --- a/sdk/cpprt/linux/libunwind/autogen-linux.sh +++ b/sdk/cpprt/linux/libunwind/autogen-linux.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/linux/libunwind/src/se-iterate-phdr.c b/sdk/cpprt/linux/libunwind/src/se-iterate-phdr.c index 59382d98..1456b580 100644 --- a/sdk/cpprt/linux/libunwind/src/se-iterate-phdr.c +++ b/sdk/cpprt/linux/libunwind/src/se-iterate-phdr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/linux/libunwind/src/se-libc-stubs.c b/sdk/cpprt/linux/libunwind/src/se-libc-stubs.c index 200d24ec..7af99f3d 100644 --- a/sdk/cpprt/linux/libunwind/src/se-libc-stubs.c +++ b/sdk/cpprt/linux/libunwind/src/se-libc-stubs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/linux/pthread_compat.h b/sdk/cpprt/linux/pthread_compat.h index 08b8bc62..55d1c773 100644 --- a/sdk/cpprt/linux/pthread_compat.h +++ b/sdk/cpprt/linux/pthread_compat.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete1.cpp b/sdk/cpprt/memory_manage/delete1.cpp index edc57ca1..b07418b8 100644 --- a/sdk/cpprt/memory_manage/delete1.cpp +++ b/sdk/cpprt/memory_manage/delete1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete2.cpp b/sdk/cpprt/memory_manage/delete2.cpp index 3c5db642..8262c1c8 100644 --- a/sdk/cpprt/memory_manage/delete2.cpp +++ b/sdk/cpprt/memory_manage/delete2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete3.cpp b/sdk/cpprt/memory_manage/delete3.cpp index e6603121..74ba2c1b 100644 --- a/sdk/cpprt/memory_manage/delete3.cpp +++ b/sdk/cpprt/memory_manage/delete3.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete4.cpp b/sdk/cpprt/memory_manage/delete4.cpp index d09df4de..9399e149 100644 --- a/sdk/cpprt/memory_manage/delete4.cpp +++ b/sdk/cpprt/memory_manage/delete4.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete5.cpp b/sdk/cpprt/memory_manage/delete5.cpp index acfcfd00..228367bb 100644 --- a/sdk/cpprt/memory_manage/delete5.cpp +++ b/sdk/cpprt/memory_manage/delete5.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete6.cpp b/sdk/cpprt/memory_manage/delete6.cpp index c892cd48..f11d64fe 100644 --- a/sdk/cpprt/memory_manage/delete6.cpp +++ b/sdk/cpprt/memory_manage/delete6.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete7.cpp b/sdk/cpprt/memory_manage/delete7.cpp index 08b14619..d020768e 100644 --- a/sdk/cpprt/memory_manage/delete7.cpp +++ b/sdk/cpprt/memory_manage/delete7.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/delete8.cpp b/sdk/cpprt/memory_manage/delete8.cpp index 695731b1..4d23a1ee 100644 --- a/sdk/cpprt/memory_manage/delete8.cpp +++ b/sdk/cpprt/memory_manage/delete8.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/new1.cpp b/sdk/cpprt/memory_manage/new1.cpp index cb12e93e..b082cc5a 100644 --- a/sdk/cpprt/memory_manage/new1.cpp +++ b/sdk/cpprt/memory_manage/new1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/new2.cpp b/sdk/cpprt/memory_manage/new2.cpp index f041e31a..2d62a371 100644 --- a/sdk/cpprt/memory_manage/new2.cpp +++ b/sdk/cpprt/memory_manage/new2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/new3.cpp b/sdk/cpprt/memory_manage/new3.cpp index 70d0b4fb..8415ce01 100644 --- a/sdk/cpprt/memory_manage/new3.cpp +++ b/sdk/cpprt/memory_manage/new3.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/new4.cpp b/sdk/cpprt/memory_manage/new4.cpp index ea7ffbf0..819e32a8 100644 --- a/sdk/cpprt/memory_manage/new4.cpp +++ b/sdk/cpprt/memory_manage/new4.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/new5.cpp b/sdk/cpprt/memory_manage/new5.cpp index 5ce0e4b9..a09036d9 100644 --- a/sdk/cpprt/memory_manage/new5.cpp +++ b/sdk/cpprt/memory_manage/new5.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/new6.cpp b/sdk/cpprt/memory_manage/new6.cpp index 5a97d5d1..d9a056e5 100644 --- a/sdk/cpprt/memory_manage/new6.cpp +++ b/sdk/cpprt/memory_manage/new6.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/memory_manage/new_handler.cpp b/sdk/cpprt/memory_manage/new_handler.cpp index 9634019d..eff63ff1 100644 --- a/sdk/cpprt/memory_manage/new_handler.cpp +++ b/sdk/cpprt/memory_manage/new_handler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/cpprt/tcxx_version.cpp b/sdk/cpprt/tcxx_version.cpp index b957c8aa..9aff6676 100644 --- a/sdk/cpprt/tcxx_version.cpp +++ b/sdk/cpprt/tcxx_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/Makefile b/sdk/debugger_interface/linux/Makefile index 9eb429dd..42b7873b 100644 --- a/sdk/debugger_interface/linux/Makefile +++ b/sdk/debugger_interface/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_cmd b/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_cmd index b55b2f1f..785179af 100644 --- a/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_cmd +++ b/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_cmd @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py b/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py index b1442899..68c3bffb 100755 --- a/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py +++ b/sdk/debugger_interface/linux/gdb-sgx-plugin/gdb_sgx_plugin.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/gdb-sgx-plugin/load_symbol_cmd.py b/sdk/debugger_interface/linux/gdb-sgx-plugin/load_symbol_cmd.py index 9a2b436f..998c3283 100755 --- a/sdk/debugger_interface/linux/gdb-sgx-plugin/load_symbol_cmd.py +++ b/sdk/debugger_interface/linux/gdb-sgx-plugin/load_symbol_cmd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/gdb-sgx-plugin/readelf.py b/sdk/debugger_interface/linux/gdb-sgx-plugin/readelf.py index 4ce1ab6e..644df09b 100755 --- a/sdk/debugger_interface/linux/gdb-sgx-plugin/readelf.py +++ b/sdk/debugger_interface/linux/gdb-sgx-plugin/readelf.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/gdb-sgx-plugin/sgx_emmt.py b/sdk/debugger_interface/linux/gdb-sgx-plugin/sgx_emmt.py index 34eb9ed3..525c4b14 100755 --- a/sdk/debugger_interface/linux/gdb-sgx-plugin/sgx_emmt.py +++ b/sdk/debugger_interface/linux/gdb-sgx-plugin/sgx_emmt.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/ptrace_version.c b/sdk/debugger_interface/linux/ptrace_version.c index 91eb2f20..2da059b2 100644 --- a/sdk/debugger_interface/linux/ptrace_version.c +++ b/sdk/debugger_interface/linux/ptrace_version.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/debugger_interface/linux/se_ptrace.c b/sdk/debugger_interface/linux/se_ptrace.c index 4eaa4890..1e7c677a 100644 --- a/sdk/debugger_interface/linux/se_ptrace.c +++ b/sdk/debugger_interface/linux/se_ptrace.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/ec_dh_lib/Makefile b/sdk/ec_dh_lib/Makefile index 7ae371e3..ac73be8f 100644 --- a/sdk/ec_dh_lib/Makefile +++ b/sdk/ec_dh_lib/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/ec_dh_lib/ec_dh.cpp b/sdk/ec_dh_lib/ec_dh.cpp index 33d0e638..d20dcb47 100644 --- a/sdk/ec_dh_lib/ec_dh.cpp +++ b/sdk/ec_dh_lib/ec_dh.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/ec_dh_lib/sgx_dh_internal.h b/sdk/ec_dh_lib/sgx_dh_internal.h index 776f495b..98b7d3f7 100644 --- a/sdk/ec_dh_lib/sgx_dh_internal.h +++ b/sdk/ec_dh_lib/sgx_dh_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/edger8r/linux/Ast.ml b/sdk/edger8r/linux/Ast.ml index d66a5375..b9daca49 100644 --- a/sdk/edger8r/linux/Ast.ml +++ b/sdk/edger8r/linux/Ast.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -121,16 +121,22 @@ type declarator = { let is_array (declr: declarator) = declr.array_dims <> [] -(* Parameter declaration. *) +(* Parameter and Struct declaration. *) type pdecl = parameter_type * declarator -(* Structure member declaration *) +(* Union member declaration *) type mdecl = atype * declarator -(* Definition of a struct or union *) +(* Definition of a struct *) type struct_def = { sname : string; (* structure name. *) - mlist : mdecl list; (* structure members. *) + smlist : pdecl list; (* structure members. *) +} + +(* Definition of a union *) +type union_def = { + uname : string; (* union name. *) + umlist : mdecl list; (* union members. *) } (* Definition of a enum *) @@ -145,7 +151,7 @@ type enum_def = { (* Composite type - the form for struct/union definition are the same. *) type composite_type = StructDef of struct_def - | UnionDef of struct_def + | UnionDef of union_def | EnumDef of enum_def (* Function declaration. *) diff --git a/sdk/edger8r/linux/CodeGen.ml b/sdk/edger8r/linux/CodeGen.ml index 354020c1..5c576402 100644 --- a/sdk/edger8r/linux/CodeGen.ml +++ b/sdk/edger8r/linux/CodeGen.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -214,8 +214,11 @@ let ms_retval_name = mk_ms_member_name retval_name let mk_tbridge_name (fname: string) = "sgx_" ^ fname let mk_parm_accessor name = sprintf "%s->%s" ms_struct_val (mk_ms_member_name name) let mk_tmp_var name = "_tmp_" ^ name +let mk_tmp_var2 name1 name2 = "_tmp_" ^ name1 ^ "_" ^ name2 let mk_len_var name = "_len_" ^ name +let mk_len_var2 name1 name2 = "_len_" ^ name1 ^ "_" ^ name2 let mk_in_var name = "_in_" ^ name +let mk_in_var2 name1 name2 = "_in_" ^ name1 ^ "_" ^ name2 let mk_ocall_table_name enclave_name = "ocall_table_" ^ enclave_name (* Un-trusted bridge name is prefixed with enclave file short name. *) @@ -336,15 +339,99 @@ let mk_ms_member_decl (pt: Ast.parameter_type) (declr: Ast.declarator) (isecall: let dmstr = get_array_dims declr.Ast.array_dims in sprintf "\t%s%s%s %s%s;\n%s" qual tystr ptr field dmstr str_len +(* It is used to save the structures defined in EDLs. *) +let defined_structure = ref [] +let is_structure_defined s = List.exists (fun (( i, _ ): (Ast.struct_def * bool)) -> i.Ast.sname = s) !defined_structure +let get_struct_def s = List.find (fun (( i, _ ): (Ast.struct_def * bool)) -> i.Ast.sname = s) !defined_structure + +let is_structure_deep_copy (s:Ast.struct_def) = + let is_deep_copy (pd: Ast.pdecl) = + let (pt, _) = pd in + match pt with + | Ast.PTVal _ -> false + | Ast.PTPtr (_, attr) -> if attr.Ast.pa_size = Ast.empty_ptr_size then false else true + in + List.exists is_deep_copy s.Ast.smlist + +(* Check duplicated structure definition and illegal usage. + *) +let check_structure (ec: enclave_content) = + let trusted_fds = tf_list_to_fd_list ec.tfunc_decls in + let untrusted_fds = uf_list_to_fd_list ec.ufunc_decls in + List.iter(fun (st: Ast.composite_type) -> + match st with + Ast.StructDef s -> + if is_structure_defined s.Ast.sname then + failwithf "duplicated structure definition `%s'" s.Ast.sname + else + defined_structure := (s, is_structure_deep_copy s) :: !defined_structure; + | _ -> () + ) ec.comp_defs; + List.iter (fun (fd: Ast.func_decl) -> + List.iter (fun (pd: Ast.pdecl) -> + let (pt, _)= pd in + match pt with + | Ast.PTVal (Ast.Struct(s)) -> + if is_structure_defined s then + let (struct_def, deep_copy) = get_struct_def s + in + if deep_copy then + failwithf "the structure declaration \"%s\" specifies a deep copy is expected. Referenced by value in function \"%s\" detected."s fd.Ast.fname + else () + else () + | Ast.PTPtr (Ast.Ptr(Ast.Struct(s)), attr) -> + if is_structure_defined s then + let (_, deep_copy) = get_struct_def s + in + if deep_copy && attr.Ast.pa_direction = Ast.PtrOut then + failwithf "the structure declaration \"%s\" specifies a deep copy, should not be used with an `out' attribute in function \"%s\"."s fd.Ast.fname + else () + else () + | _ -> () + ) fd.Ast.plist + ) (trusted_fds @ untrusted_fds) + +(* Generate code using given function if a parameter is structure pointer. *) +let invoke_if_struct (ty: Ast.atype) (param_direction: Ast.ptr_direction) (var_name: string) + (pre:string -> string -> string) + (generator: Ast.ptr_direction -> string -> string -> Ast.atype -> Ast.ptr_attr -> Ast.declarator -> string ) + (post:string)= + match ty with + Ast.Ptr(Ast.Struct(struct_type)) -> + if is_structure_defined struct_type then + let (struct_def, deep_copy)= get_struct_def struct_type + in + if deep_copy then + let body = + List.fold_left ( + fun acc (pty, declr) -> + match pty with + Ast.PTVal _ -> acc + | Ast.PTPtr (member_ty, member_attr) -> + if member_attr.Ast.pa_size <> Ast.empty_ptr_size then + acc ^ generator param_direction struct_type var_name member_ty member_attr declr + else acc + ) "" struct_def.Ast.smlist + in + if body = "" then "" + else (pre struct_type var_name) ^ body ^ post + else "" + else "" + | _ -> "" + (* Generate data structure definition *) let gen_comp_def (st: Ast.composite_type) = - let gen_member_list mlist = - List.fold_left (fun acc (ty, declr) -> - acc ^ mk_member_decl ty declr) "" mlist + let gen_union_member_list mlist = + List.fold_left (fun acc (ty, pdeclr) -> + acc ^ mk_member_decl ty pdeclr) "" mlist + in + let gen_struct_member_list mlist = + List.fold_left (fun acc (pt, declr) -> + acc ^ mk_member_decl (Ast.get_param_atype pt) declr) "" mlist in match st with - Ast.StructDef s -> mk_struct_decl (gen_member_list s.Ast.mlist) s.Ast.sname - | Ast.UnionDef u -> mk_union_decl (gen_member_list u.Ast.mlist) u.Ast.sname + Ast.StructDef s -> mk_struct_decl (gen_struct_member_list s.Ast.smlist) s.Ast.sname + | Ast.UnionDef u -> mk_union_decl (gen_union_member_list u.Ast.umlist) u.Ast.uname | Ast.EnumDef e -> mk_enum_def e (* Generate a list of '#include' *) @@ -914,7 +1001,6 @@ let gen_check_tbridge_ptr_parms (plist: Ast.pdecl list) = if pointer_checkings = "" then "" else pointer_checkings ^ "\n\t//\n\t// fence after pointer checks\n\t//\n\tsgx_lfence();\n" - (* If a foreign type is a readonly pointer, we cast it to 'void*' for memcpy() and free() *) let mk_in_ptr_dst_name (ty: Ast.atype) (attr: Ast.ptr_attr) (ptr_name: string) = let rdonly = @@ -925,6 +1011,175 @@ let mk_in_ptr_dst_name (ty: Ast.atype) (attr: Ast.ptr_attr) (ptr_name: string) = if rdonly then "(void*)" ^ ptr_name else ptr_name +let gen_struct_ptr_size (ty: Ast.atype) (pattr: Ast.ptr_attr) (name: string) (get_parm: string -> string) = + let mk_len_size v = + match v with + Ast.AString s -> get_parm s + | Ast.ANumber n -> sprintf "%d" n in + let mk_len_count v size_str = + match v with + Ast.AString s -> sprintf "%s * %s" (get_parm s) size_str + | Ast.ANumber n -> sprintf "%d * %s" n size_str in + let do_ps_attribute (sattr: Ast.ptr_size) = + let size_str = + match sattr.Ast.ps_size with + Some a -> mk_len_size a + | None -> + match ty with + Ast.Ptr ty -> + sprintf "sizeof(%s)" (Ast.get_tystr ty) + | _ -> + if pattr.Ast.pa_isptr then + sprintf "sizeof(*%s)" (get_parm name) + else + sprintf "sizeof(%s)" (Ast.get_tystr ty) + in + match sattr.Ast.ps_count with + None -> size_str + | Some a -> mk_len_count a size_str + in + sprintf "%s" (do_ps_attribute pattr.Ast.pa_size) + +(* Generate code to check the length of buffers in structure. *) +let gen_check_member_length (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) (get_parm: string -> string) (indent: string) (break_out: string list) = + let name = declr.Ast.identifier in + let mk_len_size v = + match v with + Ast.AString s -> get_parm s + | Ast.ANumber n -> sprintf "%d" n in + + let gen_check_overflow cnt size_str = + let if_statement = + match cnt with + Ast.AString s -> sprintf "if (%s != 0 &&\n%s\t\t(size_t)%s > (SIZE_MAX / %s)) {\n" size_str indent (get_parm s) size_str + | Ast.ANumber n -> sprintf "if (%s != 0 &&\n%s\t\t%d > (SIZE_MAX / %s)) {\n" size_str indent n size_str + in + (List.fold_left (fun acc s -> acc ^ indent ^ s ^ "\n") if_statement break_out) ^ indent ^ "}" + in + let size_str = + match attr.Ast.pa_size.Ast.ps_size with + Some a -> mk_len_size a + | None -> + match ty with + Ast.Ptr ty -> + sprintf "sizeof(%s)" (Ast.get_tystr ty) + | _ -> + if attr.Ast.pa_isptr then + sprintf "sizeof(*%s)" (get_parm name) + else + sprintf "sizeof(%s)" (Ast.get_tystr ty) + in + match attr.Ast.pa_size.Ast.ps_count with + None -> "" + | Some a -> (gen_check_overflow a size_str) + +(* Generate the code to handle structure pointer deep copy, + * which is to be inserted before actually calling the trusted function. + *) +let gen_struct_ptr_direction_pre_calculate (param_direction: Ast.ptr_direction) (struct_type: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let name = declr.Ast.identifier in + let in_struct_name = mk_in_var struct_name in + let in_ptr_name = mk_in_var2 struct_name name in + let len_var = mk_len_var2 struct_name name in + let in_struct = sprintf "(%s + i)->%s" in_struct_name in + let in_struct_member = sprintf "%s" (in_struct name) in + let gen_tmp_var_for_out = + match param_direction with + Ast.PtrInOut -> + [ + sprintf "if (ADD_ASSIGN_OVERFLOW(_%s_malloc_size, sizeof(void*) + sizeof(size_t))) {" struct_name; + "\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\tgoto err;"; + "}"; + ] + | _ -> [] + in + let check_size = + match ty with + Ast.Ptr(Ast.Void) | Ast.Ptr(Ast.Foreign(_)) | Ast.Foreign(_) | Ast.Ptr(Ast.Struct(_)) -> [] + | _ -> + [ + sprintf "\tif (%s %% sizeof(*%s) != 0) {" len_var in_ptr_name; (* "size x count" is a multiple of sizeof type *) + "\t\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\t\tgoto err;"; + "\t}"; + ] + in + let code_template = + [ + gen_check_member_length ty attr declr in_struct "\t\t\t" ["\tstatus = SGX_ERROR_INVALID_PARAMETER;";"\tgoto err;"]; + sprintf "if (%s != NULL && (%s = %s) != 0) {" in_struct_member len_var (gen_struct_ptr_size ty attr name in_struct); + sprintf "\tif (!sgx_is_outside_enclave(%s, %s)) {" in_struct_member len_var; + "\t\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\t\tgoto err;"; + "\t}\n"; + ] + @ check_size @ + [ + sprintf "\tif (ADD_ASSIGN_OVERFLOW(_%s_malloc_size, %s)) {" struct_name len_var; + "\t\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\t\tgoto err;"; + "\t}"; + "}"; + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t\t" ^ s ^ "\n") "" (gen_tmp_var_for_out @ code_template) + +(* Generate the code to handle structure pointer deep copy, + * which is to be inserted before actually calling the trusted function. + *) +let gen_struct_ptr_direction_pre_copy (param_direction: Ast.ptr_direction) (struct_type: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let name = declr.Ast.identifier in + let in_struct_name = mk_in_var struct_name in + let in_ptr_name = mk_in_var2 struct_name name in + let len_var = mk_len_var2 struct_name name in + let in_ptr_dst_name = mk_in_ptr_dst_name ty attr in_ptr_name in + let in_struct = sprintf "(%s + i)->%s" in_struct_name in + let in_struct_member = sprintf "%s" (in_struct name) in + let code_template = + let gen_tmp_var_for_out = + match param_direction with + Ast.PtrInOut -> + [ + sprintf "*(%s*)__tmp_%s = %s;" (Ast.get_tystr ty) in_struct_name in_ptr_name ; + sprintf "__tmp_%s = (void *)((size_t)__tmp_%s + sizeof(void*));" in_struct_name in_struct_name; + sprintf "*(size_t*)__tmp_%s = %s;" in_struct_name len_var; + sprintf "__tmp_%s= (void *)((size_t)__tmp_%s + sizeof(size_t));" in_struct_name in_struct_name; + ] + | _ -> [] + in + let check_size = + match ty with + Ast.Ptr(Ast.Void) | Ast.Ptr(Ast.Foreign(_)) | Ast.Foreign(_) | Ast.Ptr(Ast.Struct(_)) -> [] + | _ -> + [ + sprintf "\tif (%s %% sizeof(*%s) != 0) {" len_var in_struct_member; (* "size x count" is a multiple of sizeof type *) + "\t\t\tstatus = SGX_ERROR_UNEXPECTED;"; + "\t\t\tgoto err;"; + "\t}"; + ] + in + [ + sprintf "%s = %s;" in_ptr_name in_struct_member; + sprintf "%s = %s;" len_var (gen_struct_ptr_size ty attr name in_struct); + ] @ gen_tmp_var_for_out @ + [ + sprintf "if (%s != NULL && %s != 0) {" in_ptr_dst_name len_var; + ] @ check_size @ + [ + sprintf "\tif (memcpy_s(__tmp_%s, %s, %s, %s)) {" in_struct_name len_var in_struct_member len_var; + "\t\tstatus = SGX_ERROR_UNEXPECTED;"; + "\t\tgoto err;"; + sprintf "\t}"; + sprintf "\t%s = __tmp_%s;" in_struct_member in_struct_name; + sprintf "\t__tmp_%s = (void *)((size_t)__tmp_%s + %s);" in_struct_name in_struct_name len_var ; + "}"; + "else"; + sprintf "\t%s = NULL;" in_struct_member; + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t\t" ^ s ^ "\n") "" code_template + (* Generate the code to handle function pointer parameter direction, * which is to be inserted before actually calling the trusted function. *) @@ -938,23 +1193,77 @@ let gen_parm_ptr_direction_pre (plist: Ast.pdecl list) = let in_ptr_dst_name = mk_in_ptr_dst_name ty attr in_ptr_name in let tmp_ptr_name= mk_tmp_var name in let malloc_and_copy pre_indent = + let check_size = + if attr.Ast.pa_isstr then [] else + if attr.Ast.pa_iswstr then + [ + sprintf "\tif (%s %% sizeof(wchar_t) != 0)" len_var; + "\t{"; + "\t\tstatus = SGX_ERROR_UNEXPECTED;"; + "\t\tgoto err;"; + "\t}"; + ] + else + match ty with + Ast.Ptr(Ast.Void) | Ast.Ptr(Ast.Foreign(_)) | Ast.Foreign(_) -> [] + | Ast.Ptr(Ast.Struct(struct_type)) -> + if is_structure_defined struct_type then + let (struct_def, deep_copy)= get_struct_def struct_type + in + if deep_copy then + [ + sprintf "\tif ( %s %% sizeof(*%s) != 0)" len_var tmp_ptr_name; + "\t{"; + "\t\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\t\tgoto err;"; + "\t}"; + ] + else [] + else [] + | _ -> + [ + sprintf "\tif ( %s %% sizeof(*%s) != 0)" len_var tmp_ptr_name; + "\t{"; + "\t\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\t\tgoto err;"; + "\t}"; + ] + in match attr.Ast.pa_direction with Ast.PtrIn | Ast.PtrInOut -> - let wstr_len_check = - if attr.Ast.pa_iswstr then - let wstr_len_check_template = [ - sprintf "\n\t\tif (%s %% sizeof(wchar_t) != 0)" len_var; - "\t\t{"; - "\t\t\tstatus = SGX_ERROR_UNEXPECTED;"; - "\t\t\tgoto err;"; - "\t\t}"; - ] + let struct_deep_copy_pre = + let struct_calculate = + (invoke_if_struct ty attr.Ast.pa_direction name + (fun struct_type name -> + sprintf "\t\tfor (i = 0; i < %s / sizeof(struct %s); i++){\n" (mk_len_var name) struct_type + ) + gen_struct_ptr_direction_pre_calculate "\t\t}\n") + in + let struct_malloc = + let code_template = [ + sprintf "\t__tmp_%s = malloc(_%s_malloc_size);"(mk_in_var name) name; + sprintf "\tif (__tmp_%s == NULL) {" (mk_in_var name); + "\t\tstatus = SGX_ERROR_OUT_OF_MEMORY;"; + "\t\tgoto err;"; + "\t}"; + ] in - List.fold_left (fun acc s -> acc ^ s ^ "\n") "" wstr_len_check_template - else "" + List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") "" code_template + in + let struct_copy = + (invoke_if_struct ty attr.Ast.pa_direction name + (fun struct_type name -> + sprintf "\t\t_in_member_%s = __tmp_%s;\n\t\tfor (i = 0; i < %s / sizeof(struct %s); i++){\n" name (mk_in_var name) (mk_len_var name) struct_type + ) gen_struct_ptr_direction_pre_copy "\t\t}\n") + in + struct_calculate ^ (if struct_calculate = "" then "" else struct_malloc) ^ struct_copy in - let code_template = [ - sprintf "if (%s != NULL && %s != 0) {%s" tmp_ptr_name len_var wstr_len_check; + let code_template = + [ + sprintf "if (%s != NULL && %s != 0) {" tmp_ptr_name len_var; + ] + @ check_size @ + [ sprintf "\t%s = (%s)malloc(%s);" in_ptr_name in_ptr_type len_var; sprintf "\tif (%s == NULL) {" in_ptr_name; "\t\tstatus = SGX_ERROR_OUT_OF_MEMORY;"; @@ -963,8 +1272,8 @@ let gen_parm_ptr_direction_pre (plist: Ast.pdecl list) = sprintf "\tif (memcpy_s(%s, %s, %s, %s)) {" in_ptr_dst_name len_var tmp_ptr_name len_var; "\t\tstatus = SGX_ERROR_UNEXPECTED;"; "\t\tgoto err;"; - "\t}\n"; - ] + sprintf "\t}\n%s" struct_deep_copy_pre; + ] in let s1 = List.fold_left (fun acc s -> acc ^ pre_indent ^ s ^ "\n") "" code_template in let s2 = @@ -993,8 +1302,12 @@ let gen_parm_ptr_direction_pre (plist: Ast.pdecl list) = else s1 in sprintf "%s\t}\n" s2 | Ast.PtrOut -> - let code_template = [ + let code_template = + [ sprintf "if (%s != NULL && %s != 0) {" tmp_ptr_name len_var; + ] + @ check_size @ + [ sprintf "\tif ((%s = (%s)malloc(%s)) == NULL) {" in_ptr_name in_ptr_type len_var; "\t\tstatus = SGX_ERROR_OUT_OF_MEMORY;"; "\t\tgoto err;"; @@ -1012,6 +1325,55 @@ let gen_parm_ptr_direction_pre (plist: Ast.pdecl list) = Ast.PTVal _ -> acc | Ast.PTPtr (ty, attr) -> acc ^ clone_in_ptr ty attr declr) "" plist +(* Generate the code to handle tructure pointer deep copy, + * which is to be inserted after finishing calling the trusted function. + *) +let gen_struct_ptr_direction_post (param_direction: Ast.ptr_direction) (struct_type: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let name = declr.Ast.identifier in + let in_struct_name = mk_in_var struct_name in + let in_ptr_name = mk_in_var2 struct_name name in + let in_struct = sprintf "(%s + i)->%s" in_struct_name in + let in_struct_member = sprintf "%s" (in_struct name) in + let in_len_ptr_var = mk_len_var2 struct_name name in + let out_len_ptr_var = mk_len_var2 ("out_" ^ struct_name) name in + match param_direction with + Ast.PtrIn -> "" + | Ast.PtrInOut -> + let check_size = + match ty with + Ast.Ptr(Ast.Void) | Ast.Ptr(Ast.Foreign(_)) | Ast.Foreign(_) | Ast.Ptr(Ast.Struct(_)) -> "" + | _ -> sprintf " || (%s %% sizeof(*%s) != 0)" in_len_ptr_var in_struct_member (* "size x count" is a multiple of sizeof type *) + in + let code_template = [ + sprintf "%s = *(%s*)__tmp_%s;" in_ptr_name (Ast.get_tystr ty) in_struct_name; + sprintf "__tmp_%s = (void *)((size_t)__tmp_%s + sizeof(void*));" in_struct_name in_struct_name; + sprintf "%s = *(size_t*)__tmp_%s;" in_len_ptr_var in_struct_name; + sprintf "__tmp_%s = (void *)((size_t)__tmp_%s + sizeof(size_t));" in_struct_name in_struct_name; + gen_check_member_length ty attr declr in_struct "\t\t\t" ["\tstatus = SGX_ERROR_INVALID_PARAMETER;";"\tbreak;"]; + sprintf "size_t %s = %s;" out_len_ptr_var (gen_struct_ptr_size ty attr name in_struct); + sprintf "if(%s!= NULL &&" in_struct_member; + sprintf "\t\t%s != 0) {" out_len_ptr_var; + sprintf "\tif (%s > %s%s) {" out_len_ptr_var in_len_ptr_var check_size; + "\t\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\t\tbreak;"; + "\t}"; + sprintf "\tif (!sgx_is_within_enclave(%s, %s) ||" in_struct_member out_len_ptr_var; + sprintf "\t\t\t!sgx_is_outside_enclave(%s, %s)) {" in_ptr_name in_len_ptr_var; + "\t\tstatus = SGX_ERROR_INVALID_PARAMETER;"; + "\t\tbreak;"; + "\t}"; + sprintf "\tif (memcpy_s(%s, %s, %s, %s)) {" in_ptr_name in_len_ptr_var in_struct_member out_len_ptr_var; + sprintf "\t\tstatus = SGX_ERROR_UNEXPECTED;"; + "\t\tbreak;"; + "\t}"; + "}"; + sprintf "%s = %s;" in_struct_member in_ptr_name; + sprintf "__tmp_%s = (void *)((size_t)__tmp_%s + %s);" in_struct_name in_struct_name in_len_ptr_var; + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t\t" ^ s ^ "\n") "" code_template + | _ -> "" + (* Generate the code to handle function pointer parameter direction, * which is to be inserted after finishing calling the trusted function. *) @@ -1020,9 +1382,21 @@ let gen_parm_ptr_direction_post (plist: Ast.pdecl list) = let name = declr.Ast.identifier in let in_ptr_name = mk_in_var name in let len_var = mk_len_var name in - let in_ptr_dst_name = mk_in_ptr_dst_name ty attr in_ptr_name in + let struct_deep_copy_post = + let pre struct_type name = + let code_template = [ + sprintf "__tmp_%s = _in_member_%s;" (mk_in_var name) name; + sprintf "for (i = 0; i < %s / sizeof(struct %s); i++){" (mk_len_var name) struct_type; + "\tif (status != SGX_SUCCESS)"; + "\t\tbreak;"; + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t" ^ s ^ "\n") "" code_template + in + invoke_if_struct ty attr.Ast.pa_direction name pre gen_struct_ptr_direction_post "\t\t}\n" + in match attr.Ast.pa_direction with - Ast.PtrIn -> sprintf "\tif (%s) free(%s);\n" in_ptr_name in_ptr_dst_name + Ast.PtrIn -> "" | Ast.PtrInOut | Ast.PtrOut -> if attr.Ast.pa_isstr then let code_template = [ @@ -1032,8 +1406,8 @@ let gen_parm_ptr_direction_post (plist: Ast.pdecl list) = sprintf "\t\t%s = strlen(%s) + 1;" len_var in_ptr_name; sprintf "\t\tif (memcpy_s((void*)%s, %s, %s, %s)) {" (mk_tmp_var name) len_var in_ptr_name len_var; "\t\t\tstatus = SGX_ERROR_UNEXPECTED;"; + "\t\t\tgoto err;"; "\t\t}"; - sprintf "\t\tfree(%s);" in_ptr_name; "\t}"; ] in @@ -1046,8 +1420,8 @@ let gen_parm_ptr_direction_post (plist: Ast.pdecl list) = sprintf "\t\t%s = (wcslen(%s) + 1) * sizeof(wchar_t);" len_var in_ptr_name; sprintf "\t\tif (memcpy_s((void*)%s, %s, %s, %s)) {" (mk_tmp_var name) len_var in_ptr_name len_var; "\t\t\tstatus = SGX_ERROR_UNEXPECTED;"; + "\t\t\tgoto err;"; "\t\t}"; - sprintf "\t\tfree(%s);" in_ptr_name; "\t}"; ] in @@ -1055,17 +1429,18 @@ let gen_parm_ptr_direction_post (plist: Ast.pdecl list) = else let code_template = [ sprintf "\tif (%s) {" in_ptr_name; - sprintf "\t\tif (memcpy_s(%s, %s, %s, %s)) {" (mk_tmp_var name) len_var in_ptr_name len_var; + sprintf "%s\t\tif (memcpy_s(%s, %s, %s, %s)) {" struct_deep_copy_post (mk_tmp_var name) len_var in_ptr_name len_var; "\t\t\tstatus = SGX_ERROR_UNEXPECTED;"; + "\t\t\tgoto err;"; "\t\t}"; - sprintf "\t\tfree(%s);" in_ptr_name; - "\t}" + "\t}"; ] in List.fold_left (fun acc s -> acc ^ s ^ "\n") "" code_template | _ -> "" - in List.fold_left - (fun acc (pty, declr) -> + in + List.fold_left + (fun acc (pty, declr) -> match pty with Ast.PTVal _ -> acc | Ast.PTPtr (ty, attr) -> acc ^ copy_and_free ty attr declr) "" plist @@ -1083,6 +1458,39 @@ let gen_err_mark (plist: Ast.pdecl list) = then "err:" else "" +(* Generate the code to handle function pointer parameter direction, + * which is to be inserted after finishing calling the trusted function. + *) +let gen_parm_ptr_free_post (plist: Ast.pdecl list) = + let copy_and_free (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let name = declr.Ast.identifier in + let in_ptr_name = mk_in_var name in + let in_ptr_dst_name = mk_in_ptr_dst_name ty attr in_ptr_name in + match attr.Ast.pa_direction with + Ast.PtrIn -> + let struct_free = + match ty with + Ast.Ptr(Ast.Struct(struct_type)) -> + if is_structure_defined struct_type then + let (_, deep_copy)= get_struct_def struct_type + in + if deep_copy then + sprintf "\tif (_in_member_%s) free(_in_member_%s);\n" name name + else "" + else "" + | _ -> "" + in + sprintf "\tif (%s) free(%s);\n%s" in_ptr_name in_ptr_dst_name struct_free + | Ast.PtrInOut | Ast.PtrOut -> + sprintf "\tif (%s) free(%s);\n" in_ptr_name in_ptr_name + | _ -> "" + in + List.fold_left + (fun acc (pty, declr) -> + match pty with + Ast.PTVal _ -> acc + | Ast.PTPtr (ty, attr) -> acc ^ copy_and_free ty attr declr) "" plist + (* It is used to save the parameters used as the value of size/count attribute. *) let param_cache = Hashtbl.create 1 let is_in_param_cache s = Hashtbl.mem param_cache s @@ -1166,10 +1574,20 @@ let gen_tbridge_local_vars (plist: Ast.pdecl list) = else gen_tmp_size attr plist ^ "\t" ^ gen_ptr_size ty attr name mk_tmp_var in let in_ptr = match attr.Ast.pa_direction with - Ast.PtrNoDirection -> "" - | _ -> sprintf "\t%s %s = NULL;\n" (Ast.get_tystr ty) (mk_in_var name) + Ast.PtrNoDirection -> "" + | _ -> sprintf "\t%s %s = NULL;\n" (Ast.get_tystr ty) (mk_in_var name) in - tmp_var ^ len_var ^ in_ptr + let in_ptr_struct_var = + if not attr.Ast.pa_chkptr then "" + else + let gen_struct_local_var (param_direction: Ast.ptr_direction) (struct_type: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator)= + let in_ptr_name = mk_in_var2 struct_name declr.Ast.identifier in + let in_len_ptr_name = mk_len_var2 struct_name declr.Ast.identifier in + sprintf "\t%s %s = NULL;\n\tsize_t %s = 0;\n" (Ast.get_tystr ty) in_ptr_name in_len_ptr_name + in + invoke_if_struct ty attr.Ast.pa_direction name (fun _ name -> sprintf "\tvoid* __tmp_%s = NULL;\n\tsize_t _%s_malloc_size = 0;\n\tvoid* _in_member_%s = NULL;\n" (mk_in_var name) name name) gen_struct_local_var "" + in + (tmp_var ^ len_var ^ in_ptr ^ in_ptr_struct_var, if in_ptr_struct_var <> "" then true else false) in let gen_local_var_for_foreign_array (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) = let tystr = Ast.get_tystr ty in @@ -1187,16 +1605,19 @@ let gen_tbridge_local_vars (plist: Ast.pdecl list) = let gen_local_var (pd: Ast.pdecl) = let (pty, declr) = pd in match pty with - Ast.PTVal _ -> "" - | Ast.PTPtr (ty, attr) -> + Ast.PTVal _ -> ("", false) + | Ast.PTPtr (ty, attr) -> if is_foreign_array pty - then gen_local_var_for_foreign_array ty attr declr.Ast.identifier + then (gen_local_var_for_foreign_array ty attr declr.Ast.identifier, false) else do_gen_local_var pty attr declr.Ast.identifier in let new_param_list = List.map conv_array_to_ptr plist in + let (str, deep_copy) = Hashtbl.clear param_cache; - List.fold_left (fun acc pd -> acc ^ gen_local_var pd) status_var new_param_list + List.fold_left (fun acc pd -> let (str, deep_copy) = (gen_local_var pd) in (fst acc ^ str, snd acc || deep_copy)) (status_var, false) new_param_list + in + str ^ if deep_copy then "\tsize_t i = 0;\n" else "" (* It generates trusted bridge code for a trusted function. *) let gen_func_tbridge (fd: Ast.func_decl) (dummy_var: string) = @@ -1224,7 +1645,7 @@ let gen_func_tbridge (fd: Ast.func_decl) (dummy_var: string) = in sprintf "%s%s%s\t%s\n\t%s\n%s" func_open local_vars dummy_var check_pms invoke_func func_close else - sprintf "%s%s\t%s\n%s\n%s%s\n%s\n\t%s\n%s\n%s\n%s" + sprintf "%s%s\t%s\n%s\n%s%s\n%s\n\t%s\n%s\n%s\n%s%s" func_open (mk_check_pms fd.Ast.fname) declare_ms_ptr @@ -1233,8 +1654,9 @@ let gen_func_tbridge (fd: Ast.func_decl) (dummy_var: string) = (gen_check_tbridge_ptr_parms fd.Ast.plist) (gen_parm_ptr_direction_pre fd.Ast.plist) (if fd.Ast.rtype <> Ast.Void then update_retval else invoke_func) - (gen_err_mark fd.Ast.plist) (gen_parm_ptr_direction_post fd.Ast.plist) + (gen_err_mark fd.Ast.plist) + (gen_parm_ptr_free_post fd.Ast.plist) func_close let tproxy_fill_ms_field (pd: Ast.pdecl) (is_ocall_switchless: bool) = @@ -1252,12 +1674,39 @@ let tproxy_fill_ms_field (pd: Ast.pdecl) (is_ocall_switchless: bool) = if is_ary then sprintf "%s = SGX_CAST(%s, %s);" parm_accessor tystr name else sprintf "%s = %s;" parm_accessor name else + let check_size = + match ty with + Ast.Ptr(Ast.Void) | Ast.Ptr(Ast.Foreign(_)) | Ast.Foreign(_) -> [] + | Ast.Ptr(Ast.Struct(struct_type)) -> + if is_structure_defined struct_type then + let (_, deep_copy)= get_struct_def struct_type + in + if deep_copy then + [ + sprintf "\tif (%s %% sizeof(*%s) != 0) {" len_var name; + sprintf "\t\t%s();" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_INVALID_PARAMETER;"; + "\t}"; + ] + else [] + else [] + | _ -> + [ + sprintf "\tif (%s %% sizeof(*%s) != 0) {" len_var name; + sprintf "\t\t%s();" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_INVALID_PARAMETER;"; + "\t}"; + ] + in match attr.Ast.pa_direction with Ast.PtrOut -> let code_template = [sprintf "if (%s != NULL) {" name; sprintf "\t%s = (%s)__tmp;" parm_accessor tystr; sprintf "\t__tmp_%s = __tmp;" name; + ] + @ check_size @ + [ sprintf "\tmemset(__tmp_%s, 0, %s);" name len_var; sprintf "\t__tmp = (void *)((size_t)__tmp + %s);" len_var; sprintf "\tocalloc_size -= %s;" len_var; @@ -1271,6 +1720,9 @@ let tproxy_fill_ms_field (pd: Ast.pdecl) (is_ocall_switchless: bool) = [sprintf "if (%s != NULL) {" name; sprintf "\t%s = (%s)__tmp;" parm_accessor tystr; sprintf "\t__tmp_%s = __tmp;" name; + ] + @ check_size @ + [ sprintf "\tif (memcpy_s(__tmp_%s, ocalloc_size, %s, %s)) {" name name len_var; sprintf "\t\t%s();" sgx_ocfree_fn; "\t\treturn SGX_ERROR_UNEXPECTED;"; @@ -1284,43 +1736,115 @@ let tproxy_fill_ms_field (pd: Ast.pdecl) (is_ocall_switchless: bool) = in List.fold_left (fun acc s -> acc ^ s ^ "\n\t") "" code_template | _ -> let code_template = - [sprintf "if (%s != NULL) {" name; - sprintf "\t%s = (%s)__tmp;" parm_accessor tystr; - sprintf "\tif (memcpy_s(__tmp, ocalloc_size, %s, %s)) {" name len_var; - sprintf "\t\t%s();" sgx_ocfree_fn; - "\t\treturn SGX_ERROR_UNEXPECTED;"; - "\t}"; - sprintf "\t__tmp = (void *)((size_t)__tmp + %s);" len_var; - sprintf "\tocalloc_size -= %s;" len_var; - "} else {"; - sprintf "\t%s = NULL;" parm_accessor; - "}" - ] + [sprintf "if (%s != NULL) {" name; + sprintf "\t%s = (%s)__tmp;" parm_accessor tystr; + ] + @ check_size @ + [ + sprintf "\tif (memcpy_s(__tmp, ocalloc_size, %s, %s)) {" name len_var; + sprintf "\t\t%s();" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_UNEXPECTED;"; + "\t}"; + sprintf "\t__tmp = (void *)((size_t)__tmp + %s);" len_var; + sprintf "\tocalloc_size -= %s;" len_var; + "} else {"; + sprintf "\t%s = NULL;" parm_accessor; + "}" + ] in List.fold_left (fun acc s -> acc ^ s ^ "\n\t") "" code_template -(* Generate local variables required for the trusted proxy. *) +(* Attach data pointed by structure member pointer at the end of ms. *) +let tproxy_fill_structure(pd: Ast.pdecl) (is_ocall_switchless: bool)= + let (pt, declr) = pd in + let name = declr.Ast.identifier in + let parm_accessor = mk_parm_accessor name in + let sgx_ocfree_fn = get_sgx_fname SGX_OCFREE is_ocall_switchless in + let fill_structure(param_direction: Ast.ptr_direction) (struct_type: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let member_name = declr.Ast.identifier in + let len_member_name = mk_len_var2 struct_name member_name in + let in_struct = sprintf "(%s + i)->%s" parm_accessor in + let in_struct_member = sprintf "%s" (in_struct member_name) in + let para_struct = sprintf "(%s + i)->%s" name in + let para_struct_member = sprintf "%s" (para_struct member_name) in + match param_direction with + | Ast.PtrInOut | Ast.PtrIn -> + let code_template = + [ + sprintf "%s = %s;" len_member_name (gen_struct_ptr_size ty attr name para_struct); + sprintf "\tif (%s != NULL && %s != 0) {" para_struct_member len_member_name; + sprintf "\t\tif (memcpy_s(__tmp, %s, %s, %s)) {" len_member_name para_struct_member len_member_name; + sprintf "\t\t\t%s();" sgx_ocfree_fn; + "\t\t\treturn SGX_ERROR_UNEXPECTED;"; + "\t\t}"; + sprintf "\t\t%s = (%s)__tmp;" in_struct_member (Ast.get_tystr ty); + sprintf "\t\t__tmp = (void *)((size_t)__tmp + %s);" len_member_name; + sprintf "\t\tocalloc_size -= %s;" len_member_name; + "\t} else {"; + sprintf "\t\t%s = NULL;" in_struct_member; + "\t}" + ] + in List.fold_left (fun acc s -> acc ^ "\t\t\t" ^ s ^ "\n") "" code_template + | _ -> "" + in + match pt with + Ast.PTPtr(ty, attr) -> + let pre struct_type name = + let code_template = + if attr.Ast.pa_direction = Ast.PtrInOut then + [sprintf "if (%s != NULL && %s != 0 ) {" name (mk_len_var name); + sprintf "\t__tmp_member_%s = __tmp;" name; + sprintf "\tfor (i = 0; i < %s / sizeof(struct %s); i++){" (mk_len_var name) struct_type + ] + else + [sprintf "if (%s != NULL && %s != 0 ) {" name (mk_len_var name); + sprintf "\tfor (i = 0; i < %s / sizeof(struct %s); i++){" (mk_len_var name) struct_type + ] + in + List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") "" code_template + in + invoke_if_struct ty attr.Ast.pa_direction name pre fill_structure "\t\t}\n\t}\n" + | _ -> "" + +(* Generate local variables required for the trusted proxy, inclidng variables required by structure deep copy. *) let gen_tproxy_local_vars (plist: Ast.pdecl list) = let status_var = "sgx_status_t status = SGX_SUCCESS;\n" in - let do_gen_local_var (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) = - if not attr.Ast.pa_chkptr then "" - else "\t" ^ gen_ptr_size ty attr name (fun x -> x) + let do_gen_local_vars (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) = + let do_gen_local_var = + if not attr.Ast.pa_chkptr then "" + else "\t" ^ gen_ptr_size ty attr name (fun x -> x) + in + let in_ptr_struct_var = + if not attr.Ast.pa_chkptr then "" + else + let gen_in_ptr_struct_var (_: Ast.ptr_direction) (_: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let member_name = declr.Ast.identifier in + let in_len_ptr_name = mk_len_var2 struct_name member_name in + sprintf "\tsize_t %s = 0;\n" in_len_ptr_name + in + invoke_if_struct ty attr.Ast.pa_direction name (fun _ name -> if attr.Ast.pa_direction = Ast.PtrInOut then sprintf"\tvoid* __tmp_member_%s = NULL;\n" name else "") gen_in_ptr_struct_var "" + in + (do_gen_local_var ^ in_ptr_struct_var, if in_ptr_struct_var <> "" then true else false) in let gen_local_var (pd: Ast.pdecl) = let (pty, declr) = pd in match pty with - Ast.PTVal _ -> "" - | Ast.PTPtr (ty, attr) -> do_gen_local_var ty attr declr.Ast.identifier + Ast.PTVal _ -> ("", false) + | Ast.PTPtr (ty, attr) -> do_gen_local_vars ty attr declr.Ast.identifier in let new_param_list = List.map conv_array_to_ptr plist in - List.fold_left (fun acc pd -> acc ^ gen_local_var pd) status_var new_param_list + let (str, deep_copy) = + List.fold_left (fun acc pd -> let (str, deep_copy) = (gen_local_var pd) in (fst acc ^ str, snd acc || deep_copy)) (status_var, false) new_param_list + in + str ^ if deep_copy then "\tsize_t i = 0;\n" else "" + (* Generate only one ocalloc block required for the trusted proxy. *) let gen_ocalloc_block (fname: string) (plist: Ast.pdecl list) (is_switchless: bool) = let ms_struct_name = mk_ms_struct_name fname in let new_param_list = List.map conv_array_to_ptr plist in let local_vars_block = sprintf "%s* %s = NULL;\n\tsize_t ocalloc_size = sizeof(%s);\n\tvoid *__tmp = NULL;\n\n" ms_struct_name ms_struct_val ms_struct_name in - let local_var (attr: Ast.ptr_attr) (name: string) = + let local_var (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) = if not attr.Ast.pa_chkptr then "" else match attr.Ast.pa_direction with @@ -1331,18 +1855,20 @@ let gen_ocalloc_block (fname: string) (plist: Ast.pdecl list) (is_switchless: bo let (pty, declr) = pd in match pty with Ast.PTVal _ -> "" - | Ast.PTPtr (_, attr) -> local_var attr declr.Ast.identifier + | Ast.PTPtr (ty, attr) -> local_var ty attr declr.Ast.identifier + in + let mk_check_enclave_ptr (name: string) (lenvar: string) = + let checker = "CHECK_ENCLAVE_POINTER" in + sprintf "%s(%s, %s)" checker name lenvar in - let check_enclave_ptr_block = - let check_enclave_ptr (pd: Ast.pdecl) = - let checker = "CHECK_ENCLAVE_POINTER" in + let check_enclave_ptr (pd: Ast.pdecl) = let (pty, declr) = pd in match pty with Ast.PTVal _ -> "" | Ast.PTPtr (ty, attr) -> if not attr.Ast.pa_chkptr then "" - else sprintf "\t%s(%s, %s);\n" checker declr.Ast.identifier (mk_len_var declr.Ast.identifier) + else "\t" ^ mk_check_enclave_ptr declr.Ast.identifier (mk_len_var declr.Ast.identifier) ^ ";\n" in let do_check_enclave_ptr = List.fold_left (fun acc pd -> acc ^ check_enclave_ptr pd) "" new_param_list in let break_line = if do_check_enclave_ptr = "" then "" else "\n" in @@ -1351,7 +1877,7 @@ let gen_ocalloc_block (fname: string) (plist: Ast.pdecl list) (is_switchless: bo let count_ocalloc_size (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) = if not attr.Ast.pa_chkptr then "" - else sprintf "\tocalloc_size += (%s != NULL) ? %s : 0;\n" name (mk_len_var name) + else sprintf "\tif (ADD_ASSIGN_OVERFLOW(ocalloc_size, (%s != NULL) ? %s : 0))\n\t\treturn SGX_ERROR_INVALID_PARAMETER;\n" name (mk_len_var name) in let do_count_ocalloc_size (pd: Ast.pdecl) = let (pty, declr) = pd in @@ -1376,6 +1902,75 @@ let gen_ocalloc_block (fname: string) (plist: Ast.pdecl list) (is_switchless: bo let s2 = List.fold_left (fun acc pd -> acc ^ do_count_ocalloc_size pd) (s1 ^ check_enclave_ptr_block) new_param_list in List.fold_left (fun acc s -> acc ^ s) s2 do_gen_ocalloc_block +(* Generate only one ocalloc block required for the trusted proxy. *) +let gen_ocalloc_block_struct_deep_copy (fname: string) (plist: Ast.pdecl list) (is_ocall_switchless: bool)= + let new_param_list = List.map conv_array_to_ptr plist in + let sgx_ocalloc_fn = get_sgx_fname SGX_OCALLOC is_ocall_switchless in + let sgx_ocfree_fn = get_sgx_fname SGX_OCFREE is_ocall_switchless in + let count_ocalloc_size (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) = + if not attr.Ast.pa_chkptr then "" + else + let count_struct_ocalloc_size = + let gen_member_size (_: Ast.ptr_direction) (_: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let in_len_ptr_var = mk_len_var2 struct_name declr.Ast.identifier in + let para_struct = sprintf "(%s + i)->%s" struct_name in + let check_size = + match ty with + Ast.Ptr(Ast.Void) | Ast.Ptr(Ast.Foreign(_)) | Ast.Foreign(_) | Ast.Ptr(Ast.Struct(_)) -> [] + | _ -> + [ + sprintf "if (%s %% sizeof(*%s) != 0) {" in_len_ptr_var (para_struct declr.Ast.identifier); (* "size x count" is a multiple of sizeof type *) + sprintf "\t%s();" sgx_ocfree_fn; + "\treturn SGX_ERROR_INVALID_PARAMETER;"; + "}"; + ] + in + let code_template = + [ + gen_check_member_length ty attr declr para_struct "\t\t\t" [(sprintf "\t%s();" sgx_ocfree_fn);"\treturn SGX_ERROR_INVALID_PARAMETER;"]; + sprintf "%s = %s;" in_len_ptr_var (gen_struct_ptr_size ty attr struct_name para_struct); + ] + @ check_size @ + [ + sprintf "if (%s && ! sgx_is_within_enclave(%s, %s)) {" (para_struct declr.Ast.identifier) (para_struct declr.Ast.identifier) in_len_ptr_var; + sprintf "\t%s();" sgx_ocfree_fn; + "\treturn SGX_ERROR_INVALID_PARAMETER;"; + "}"; + sprintf "\tif (ADD_ASSIGN_OVERFLOW(ocalloc_size, (%s != NULL) ? %s : 0)) {" (para_struct declr.Ast.identifier) in_len_ptr_var; + sprintf "\t%s();" sgx_ocfree_fn; + "\treturn SGX_ERROR_INVALID_PARAMETER;"; + "}"; + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t\t" ^ s ^ "\n") "" code_template + in + invoke_if_struct ty attr.Ast.pa_direction name (fun struct_type name -> sprintf "\t\tfor (i = 0; i < %s / sizeof(struct %s); i++){\n" (mk_len_var name) struct_type) gen_member_size "\t\t}\n" + in + if count_struct_ocalloc_size <> "" then + sprintf "\tif (%s != NULL && %s != 0){\n" name (mk_len_var name) ^ + sprintf "%s" count_struct_ocalloc_size ^ + "\t}\n" + else "" + in + let do_count_ocalloc_size (pd: Ast.pdecl) = + let (pty, declr) = pd in + match pty with + Ast.PTVal _ -> "" + | Ast.PTPtr (ty, attr) -> count_ocalloc_size ty attr declr.Ast.identifier + in + let do_gen_ocalloc_block = [ + sprintf "\n\t__tmp = %s(ocalloc_size);\n" sgx_ocalloc_fn; + "\tif (__tmp == NULL) {\n"; + sprintf "\t\t%s();\n" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_UNEXPECTED;\n"; + "\t}\n"; + ] + in + let s2 = List.fold_left (fun acc pd -> acc ^ do_count_ocalloc_size pd) "" new_param_list in + if s2 = "" then "" + else + List.fold_left (fun acc s -> acc ^ s) s2 do_gen_ocalloc_block + (* Generate trusted proxy code for a given untrusted function. *) let gen_func_tproxy (ufunc: Ast.untrusted_func) (idx: int) = let fd = ufunc.Ast.uf_fdecl in @@ -1383,12 +1978,13 @@ let gen_func_tproxy (ufunc: Ast.untrusted_func) (idx: int) = let func_open = sprintf "%s\n{\n" (gen_tproxy_proto fd) in let local_vars = gen_tproxy_local_vars fd.Ast.plist in let ocalloc_ms_struct = gen_ocalloc_block fd.Ast.fname fd.Ast.plist ufunc.Ast.uf_is_switchless in + let ocalloc_struct_deep_copy = gen_ocalloc_block_struct_deep_copy fd.Ast.fname fd.Ast.plist in let sgx_ocfree_fn = get_sgx_fname SGX_OCFREE ufunc.Ast.uf_is_switchless in let gen_ocfree rtype plist = if rtype = Ast.Void && plist = [] && propagate_errno = false then "" else sprintf "\t%s();\n" sgx_ocfree_fn in let handle_out_ptr plist = - let copy_memory (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let copy_memory (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = let name = declr.Ast.identifier in match attr.Ast.pa_direction with Ast.PtrInOut | Ast.PtrOut -> @@ -1423,22 +2019,91 @@ let gen_func_tproxy (ufunc: Ast.untrusted_func) (idx: int) = in List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") "" code_template else - let code_template = [ - sprintf "\tif (%s) {" name; - sprintf "\t\tif (memcpy_s((void*)%s, %s, __tmp_%s, %s)) {" name (mk_len_var name) name (mk_len_var name); - sprintf "\t\t\t%s();" sgx_ocfree_fn; - "\t\t\treturn SGX_ERROR_UNEXPECTED;"; - "\t\t}"; - "\t}"; - ] + let struct_deep_copy_post = + let copy_and_free_struct_member (_: Ast.ptr_direction) (_: string) (struct_name: string) (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) = + let name = declr.Ast.identifier in + let para_struct = sprintf "(%s + i)->%s" struct_name in + let para_struct_member = sprintf "%s" (para_struct name) in + let local_struct = sprintf "__local_%s.%s" struct_name in + let in_len_ptr_var = mk_len_var2 struct_name name in + let out_len_ptr_var = mk_len_var2 ("out_" ^ struct_name) name in + let check_size = + match ty with + Ast.Ptr(Ast.Void) -> "" + | _ -> sprintf " || (%s %% sizeof(*%s) != 0)" out_len_ptr_var para_struct_member (* "size x count" is a multiple of sizeof type *) + in + let code_template = [ + sprintf "size_t %s = 0;" out_len_ptr_var; + gen_check_member_length ty attr declr local_struct "\t\t\t\t" [(sprintf "\t%s();" sgx_ocfree_fn);"\treturn SGX_ERROR_INVALID_PARAMETER;"]; + sprintf "%s = %s;" in_len_ptr_var (gen_struct_ptr_size ty attr name para_struct); + sprintf "if(%s!= NULL &&" para_struct_member; + sprintf "\t\t(%s = %s) != 0) {" out_len_ptr_var (gen_struct_ptr_size ty attr name local_struct); + sprintf "\tif (%s != __tmp_member_%s ||" (local_struct name) struct_name;(*pointer is not changed by untrusted code *) + sprintf "\t\t\t%s > %s%s) {" out_len_ptr_var in_len_ptr_var check_size; + sprintf "\t\t%s();" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_INVALID_PARAMETER;"; + "\t}"; + sprintf "\tif (memcpy_s(%s, %s, __tmp_member_%s, %s)) {" para_struct_member in_len_ptr_var struct_name out_len_ptr_var; + sprintf "\t\t%s();" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_UNEXPECTED;"; + "\t}"; + "}"; + sprintf "%s = %s;" (local_struct name) para_struct_member; + sprintf "__tmp_member_%s = (void *)((size_t)__tmp_member_%s + (%s != NULL? %s : 0));" struct_name struct_name para_struct_member in_len_ptr_var; + + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t\t\t" ^ s ^ "\n") "" code_template + in + let pre (struct_type: string) (name: string) = + let code_template2 = [ + sprintf "for (i = 0; i < %s / sizeof(struct %s); i++){" (mk_len_var name) struct_type; + sprintf "\t%s __local_%s;" struct_type name; + sprintf "\tif (memcpy_s(&__local_%s, sizeof(%s), ((%s*)__tmp_%s + i), sizeof(%s))) {"name struct_type struct_type name struct_type; + sprintf "\t\t%s();" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_UNEXPECTED;"; + "\t}"; + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t\t" ^ s ^ "\n") "\n" code_template2 + in + let post = + let code_template3 = [ + sprintf "\tif (memcpy_s((void*)(%s + i), sizeof(__local_%s), &__local_%s, sizeof(__local_%s))) {" name name name name; + sprintf "\t\t%s();" sgx_ocfree_fn; + "\t\treturn SGX_ERROR_UNEXPECTED;"; + "\t}"; + "}"; + ] + in + List.fold_left (fun acc s -> acc ^ "\t\t\t" ^ s ^ "\n") "\n" code_template3 + in + invoke_if_struct ty attr.Ast.pa_direction name pre copy_and_free_struct_member post + in + let code_template = + if struct_deep_copy_post = "" then + [ + sprintf "\tif (%s) {" name; + sprintf "\t\tif (memcpy_s((void*)%s, %s, __tmp_%s, %s)) {" name (mk_len_var name) name (mk_len_var name); + sprintf "\t\t\t%s();" sgx_ocfree_fn; + "\t\t\treturn SGX_ERROR_UNEXPECTED;"; + "\t\t}"; + "\t}" ; + ] + else + [ + sprintf "\tif (%s) {%s" name struct_deep_copy_post; + "\t}" ; + ] in List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") "" code_template | _ -> "" - in List.fold_left (fun acc (pty, declr) -> + in + List.fold_left (fun acc (pty, declr) -> match pty with Ast.PTVal _ -> acc - | Ast.PTPtr(ty, attr) -> acc ^ copy_memory attr declr) "" plist in + | Ast.PTPtr(ty, attr) -> acc ^ copy_memory ty attr declr) "" plist in let set_errno = if propagate_errno then "\t\terrno = ms->ocall_errno;\n" else "" in let func_close = sprintf "%s%s%s\n%s%s\n" @@ -1460,10 +2125,12 @@ let gen_func_tproxy (ufunc: Ast.untrusted_func) (idx: int) = func_body := local_vars :: !func_body; func_body := ocalloc_ms_struct:: !func_body; List.iter (fun pd -> func_body := tproxy_fill_ms_field pd ufunc.Ast.uf_is_switchless :: !func_body ) fd.Ast.plist; + func_body := ocalloc_struct_deep_copy ufunc.Ast.uf_is_switchless :: !func_body; + List.iter (fun pd -> func_body := tproxy_fill_structure pd ufunc.Ast.uf_is_switchless:: !func_body) fd.Ast.plist; func_body := ocall_with_ms :: !func_body; func_body := "if (status == SGX_SUCCESS) {" :: !func_body; if fd.Ast.rtype <> Ast.Void then func_body := update_retval :: !func_body; - List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") func_open (List.rev !func_body) ^ func_close + List.fold_left (fun acc s -> if s = "" then acc else acc ^ "\t" ^ s ^ "\n") func_open (List.rev !func_body) ^ func_close end (* It generates OCALL table and the untrusted proxy to setup OCALL table. *) @@ -1535,7 +2202,12 @@ let gen_trusted_source (ec: enclave_content) = \tif ((ptr) && ! sgx_is_within_enclave((ptr), (siz)))\t\\\n\ \t\treturn SGX_ERROR_INVALID_PARAMETER;\\\n\ } while (0)\n\ -\n" in +\n\ +#define ADD_ASSIGN_OVERFLOW(a, b) (\t\\\n\ +\t((a) += (b)) < (b)\t\\\n\ +)\n\ +\n" + in let trusted_fds = tf_list_to_fd_list ec.tfunc_decls in let tbridge_list = let dummy_var = tbridge_gen_dummy_variable ec in @@ -1762,6 +2434,7 @@ let gen_enclave_code (e: Ast.enclave) (ep: edger8r_params) = create_dir ep.untrusted_dir; create_dir ep.trusted_dir; check_duplication ec; + check_structure ec; check_allow_list ec; (if not ep.header_only then check_priv_funcs ec); if Plugin.available() then diff --git a/sdk/edger8r/linux/Edger8r.ml b/sdk/edger8r/linux/Edger8r.ml index 2a8b5b21..95c134b3 100644 --- a/sdk/edger8r/linux/Edger8r.ml +++ b/sdk/edger8r/linux/Edger8r.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/edger8r/linux/Lexer.mll b/sdk/edger8r/linux/Lexer.mll index 460876ac..8bd55e35 100644 --- a/sdk/edger8r/linux/Lexer.mll +++ b/sdk/edger8r/linux/Lexer.mll @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/edger8r/linux/Makefile b/sdk/edger8r/linux/Makefile index 4706cacc..ad0ad0e6 100644 --- a/sdk/edger8r/linux/Makefile +++ b/sdk/edger8r/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/edger8r/linux/Parser.mly b/sdk/edger8r/linux/Parser.mly index 84274414..e9121dd5 100644 --- a/sdk/edger8r/linux/Parser.mly +++ b/sdk/edger8r/linux/Parser.mly @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -127,6 +127,17 @@ let get_ptr_attr (attr_list: (string * Ast.attr_value) list) = [] -> res_attr | (k,v) :: xs -> do_get_ptr_attr xs (update_attr k v res_attr) in + do_get_ptr_attr attr_list { Ast.pa_direction = Ast.PtrNoDirection; + Ast.pa_size = Ast.empty_ptr_size; + Ast.pa_isptr = false; + Ast.pa_isary = false; + Ast.pa_isstr = false; + Ast.pa_iswstr = false; + Ast.pa_rdonly = false; + Ast.pa_chkptr = true; + } + +let get_param_ptr_attr (attr_list: (string * Ast.attr_value) list) = let has_str_attr (pattr: Ast.ptr_attr) = if pattr.Ast.pa_isstr && pattr.Ast.pa_iswstr then failwith "`string' and `wstring' are mutual exclusive" @@ -168,19 +179,20 @@ let get_ptr_attr (attr_list: (string * Ast.attr_value) list) = then failwith "`isary' cannot be used with `string/wstring' together" else failwith "`isary' cannot be used with `isptr' together" in - let pattr = do_get_ptr_attr attr_list { Ast.pa_direction = Ast.PtrNoDirection; - Ast.pa_size = Ast.empty_ptr_size; - Ast.pa_isptr = false; - Ast.pa_isary = false; - Ast.pa_isstr = false; - Ast.pa_iswstr = false; - Ast.pa_rdonly = false; - Ast.pa_chkptr = true; - } + let pattr = get_ptr_attr attr_list in + if pattr.Ast.pa_isary + then check_invalid_ary_attr pattr + else check_invalid_ptr_size pattr |> check_ptr_dir + + +let get_member_ptr_attr (attr_list: (string * Ast.attr_value) list) = + let check_invalid_ptr_size (pattr: Ast.ptr_attr) = + if pattr.Ast.pa_size = Ast.empty_ptr_size + then failwith "size/count attributes must be used" + else pattr in - if pattr.Ast.pa_isary - then check_invalid_ary_attr pattr - else check_invalid_ptr_size pattr |> check_ptr_dir + let pattr = get_ptr_attr attr_list in + check_invalid_ptr_size pattr (* Untrusted functions can have these attributes: * @@ -406,7 +418,7 @@ declarator: Tidentifier { { Ast.identifier = $1; Ast.array_dims = []; } } * to tell whether the identifier is followed by array dimensions. */ param_type: attr_block all_type { - let attr = get_ptr_attr $1 in + let attr = get_param_ptr_attr $1 in (*check the type is build in type or used defined type.*) let rec is_foreign s = match s with @@ -430,10 +442,9 @@ param_type: attr_block all_type { else if attr.Ast.pa_rdonly && not (attr.Ast.pa_isptr) then failwithf "'readonly' attribute is only used with 'isptr' attribute." else match $2 with - Ast.Ptr _ -> fun x -> Ast.PTPtr($2, get_ptr_attr $1) + Ast.Ptr _ -> fun x -> Ast.PTPtr($2, get_param_ptr_attr $1) | _ -> if $1 <> [] then - let attr = get_ptr_attr $1 in match $2 with Ast.Foreign s -> if attr.Ast.pa_isptr || attr.Ast.pa_isary then fun x -> Ast.PTPtr($2, attr) @@ -448,9 +459,69 @@ param_type: attr_block all_type { else failwithf "unexpected pointer attributes for `%s'" (Ast.get_tystr $2) else fun is_ary -> - if is_ary then Ast.PTPtr($2, get_ptr_attr []) + if is_ary then Ast.PTPtr($2, get_param_ptr_attr []) else Ast.PTVal $2 } + | all_type { + match $1 with + Ast.Ptr _ -> fun x -> Ast.PTPtr($1, get_param_ptr_attr []) + | _ -> + fun is_ary -> + if is_ary then Ast.PTPtr($1, get_param_ptr_attr []) + else Ast.PTVal $1 + } + | attr_block Tconst type_spec pointer { + let attr = get_param_ptr_attr $1 + in fun x -> Ast.PTPtr($4 $3, { attr with Ast.pa_rdonly = true }) + } + | Tconst type_spec pointer { + let attr = get_param_ptr_attr [] + in fun x -> Ast.PTPtr($3 $2, { attr with Ast.pa_rdonly = true }) + } + ; + + +/* Available types as struct member. + * + * Instead of returning an value of 'Ast.parameter_type', we return + * a lambda which wraps the actual type since so far there is no way + * to tell whether the identifier is followed by array dimensions. +*/ +smember_type: attr_block all_type { + let attr = get_member_ptr_attr $1 in + (*'isptr', 'isary', 'readonly' not allowed.*) + if attr.Ast.pa_direction <> Ast.PtrNoDirection then + failwithf "direction attribute is not allowed for structure member." + else if attr.Ast.pa_isptr then + failwithf "'isptr', attribute is not allowed for structure member." + else if attr.Ast.pa_isary then + failwithf "'isary', attribute is not allowed for structure member." + else if attr.Ast.pa_rdonly then + failwithf "'readonly'attribute is not allowed for structure member." + else if attr.Ast.pa_isstr then + failwithf "'string'attribute is not allowed for structure member." + else if attr.Ast.pa_iswstr then + failwithf "'wstring' attribute is not allowed for structure member." + else + match $2 with + Ast.Ptr _ -> fun x -> Ast.PTPtr($2, get_member_ptr_attr $1) + | _ -> + if $1 <> [] then + match $2 with + Ast.Foreign s -> + (* thinking about 'user_defined_type var[4]' *) + fun is_ary -> + if is_ary then Ast.PTPtr($2, attr) + else failwithf "`%s' is considered plain type but decorated with pointer attributes" s + | _ -> + fun is_ary -> + if is_ary then Ast.PTPtr($2, attr) + else failwithf "unexpected pointer attributes for `%s'" (Ast.get_tystr $2) + else + fun is_ary -> + if is_ary then Ast.PTPtr($2, get_ptr_attr []) + else Ast.PTVal $2 + } | all_type { match $1 with Ast.Ptr _ -> fun x -> Ast.PTPtr($1, get_ptr_attr []) @@ -458,18 +529,9 @@ param_type: attr_block all_type { fun is_ary -> if is_ary then Ast.PTPtr($1, get_ptr_attr []) else Ast.PTVal $1 - } - | attr_block Tconst type_spec pointer { - let attr = get_ptr_attr $1 - in fun x -> Ast.PTPtr($4 $3, { attr with Ast.pa_rdonly = true }) - } - | Tconst type_spec pointer { - let attr = get_ptr_attr [] - in fun x -> Ast.PTPtr($3 $2, { attr with Ast.pa_rdonly = true }) - } + } ; - attr_block: TLBrack TRBrack { failwith "no attribute specified." } | TLBrack key_val_pairs TRBrack { $2 } ; @@ -487,15 +549,15 @@ struct_specifier: Tstruct Tidentifier { Ast.Struct($2) } union_specifier: Tunion Tidentifier { Ast.Union($2) } enum_specifier: Tenum Tidentifier { Ast.Enum($2) } -struct_definition: struct_specifier TLBrace member_list TRBrace { +struct_definition: struct_specifier TLBrace struct_member_list TRBrace { let s = { Ast.sname = (match $1 with Ast.Struct s -> s | _ -> ""); - Ast.mlist = List.rev $3; } + Ast.smlist = List.rev $3; } in Ast.StructDef(s) } -union_definition: union_specifier TLBrace member_list TRBrace { - let s = { Ast.sname = (match $1 with Ast.Union s -> s | _ -> ""); - Ast.mlist = List.rev $3; } +union_definition: union_specifier TLBrace union_member_list TRBrace { + let s = { Ast.uname = (match $1 with Ast.Union s -> s | _ -> ""); + Ast.umlist = List.rev $3; } in Ast.UnionDef(s) } @@ -529,11 +591,33 @@ composite_defs: struct_definition { $1 } | enum_definition { $1 } ; -member_list: member_def TSemicolon { [$1] } - | member_list member_def TSemicolon { $2 :: $1 } +struct_member_list: struct_member_def TSemicolon { [$1] } + | struct_member_list struct_member_def TSemicolon { $2 :: $1 } ; -member_def: all_type declarator { ($1, $2) } +union_member_list: union_member_def TSemicolon { [$1] } + | union_member_list union_member_def TSemicolon { $2 :: $1 } + ; + +struct_member_def: smember_type declarator { + let pt = $1 (Ast.is_array $2) in + let is_void = + match pt with + Ast.PTVal v -> v = Ast.Void + | _ -> false + in + if is_void then + failwithf "parameter `%s' has `void' type." $2.Ast.identifier + else + (pt, $2) +} + +union_member_def: all_type declarator { + if $1 = Ast.Void then + failwithf "union member `%s' has `void' type." $2.Ast.identifier + else + ($1, $2) +} /* Importing declarations. * ------------------------------------------------------------------------ diff --git a/sdk/edger8r/linux/Plugin.ml b/sdk/edger8r/linux/Plugin.ml index 1df44fee..373f8f8f 100644 --- a/sdk/edger8r/linux/Plugin.ml +++ b/sdk/edger8r/linux/Plugin.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/edger8r/linux/Preprocessor.ml b/sdk/edger8r/linux/Preprocessor.ml index 2fa9530a..76e77b74 100644 --- a/sdk/edger8r/linux/Preprocessor.ml +++ b/sdk/edger8r/linux/Preprocessor.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/edger8r/linux/SimpleStack.ml b/sdk/edger8r/linux/SimpleStack.ml index 0f0c23cd..a2c03b00 100644 --- a/sdk/edger8r/linux/SimpleStack.ml +++ b/sdk/edger8r/linux/SimpleStack.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/edger8r/linux/Util.ml b/sdk/edger8r/linux/Util.ml index 54487634..db109c0e 100644 --- a/sdk/edger8r/linux/Util.ml +++ b/sdk/edger8r/linux/Util.ml @@ -1,5 +1,5 @@ (* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/encrypt_enclave/Makefile b/sdk/encrypt_enclave/Makefile index a759f0e3..e3da0a73 100644 --- a/sdk/encrypt_enclave/Makefile +++ b/sdk/encrypt_enclave/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/encrypt_enclave/encryptip.cpp b/sdk/encrypt_enclave/encryptip.cpp index 576fc3ea..470911a4 100644 --- a/sdk/encrypt_enclave/encryptip.cpp +++ b/sdk/encrypt_enclave/encryptip.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/encrypt_enclave/encryptip.h b/sdk/encrypt_enclave/encryptip.h index 47fa561a..52b4a5e7 100644 --- a/sdk/encrypt_enclave/encryptip.h +++ b/sdk/encrypt_enclave/encryptip.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/gperftools/Makefile b/sdk/gperftools/Makefile index 7fcc1471..f0b7160d 100644 --- a/sdk/gperftools/Makefile +++ b/sdk/gperftools/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/gperftools/gperftools-2.5/autogen-linux.sh b/sdk/gperftools/gperftools-2.5/autogen-linux.sh index f83d6af9..c3958e5f 100755 --- a/sdk/gperftools/gperftools-2.5/autogen-linux.sh +++ b/sdk/gperftools/gperftools-2.5/autogen-linux.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/gperftools/gperftools-2.5/src/base/sgx_utils.cc b/sdk/gperftools/gperftools-2.5/src/base/sgx_utils.cc index 37e322f9..e19a47de 100644 --- a/sdk/gperftools/gperftools-2.5/src/base/sgx_utils.cc +++ b/sdk/gperftools/gperftools-2.5/src/base/sgx_utils.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/libcapable/linux/Makefile b/sdk/libcapable/linux/Makefile index 062644ed..daf8859b 100644 --- a/sdk/libcapable/linux/Makefile +++ b/sdk/libcapable/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -43,7 +43,9 @@ LDFLAGS += $(COMMON_LDFLAGS) INC += -I$(COMMON_DIR)/inc \ -I$(COMMON_DIR)/inc/internal \ - -I$(COMMON_DIR)/inc/internal/linux + -I$(COMMON_DIR)/inc/internal/linux \ + -I$(DCAP_DIR)/QuoteGeneration/quote_wrapper/common/inc/ \ + -I$(DCAP_DIR)/QuoteGeneration/pce_wrapper/inc/ LIB += -L$(BUILD_DIR) diff --git a/sdk/libcapable/linux/sgx_capable.cpp b/sdk/libcapable/linux/sgx_capable.cpp index 91684780..e2d643a1 100644 --- a/sdk/libcapable/linux/sgx_capable.cpp +++ b/sdk/libcapable/linux/sgx_capable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/libcapable/linux/sgx_capable_version.cpp b/sdk/libcapable/linux/sgx_capable_version.cpp index aeb3c6b5..21304a5d 100644 --- a/sdk/libcapable/linux/sgx_capable_version.cpp +++ b/sdk/libcapable/linux/sgx_capable_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/Makefile b/sdk/protected_code_loader/Makefile index ec5cf196..3ba58804 100644 --- a/sdk/protected_code_loader/Makefile +++ b/sdk/protected_code_loader/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/crypto/pcl_cmac.c b/sdk/protected_code_loader/crypto/pcl_cmac.c index e69d7831..c368f25f 100644 --- a/sdk/protected_code_loader/crypto/pcl_cmac.c +++ b/sdk/protected_code_loader/crypto/pcl_cmac.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/crypto/pcl_crypto.cpp b/sdk/protected_code_loader/crypto/pcl_crypto.cpp index 348cb14f..7c334128 100644 --- a/sdk/protected_code_loader/crypto/pcl_crypto.cpp +++ b/sdk/protected_code_loader/crypto/pcl_crypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/crypto/pcl_crypto_internal.h b/sdk/protected_code_loader/crypto/pcl_crypto_internal.h index e98f9cd7..e8dc53e6 100644 --- a/sdk/protected_code_loader/crypto/pcl_crypto_internal.h +++ b/sdk/protected_code_loader/crypto/pcl_crypto_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/crypto/pcl_gcm128.c b/sdk/protected_code_loader/crypto/pcl_gcm128.c index b7eea128..3b55ac16 100644 --- a/sdk/protected_code_loader/crypto/pcl_gcm128.c +++ b/sdk/protected_code_loader/crypto/pcl_gcm128.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/crypto/pcl_md32_common.h b/sdk/protected_code_loader/crypto/pcl_md32_common.h index 21ce11f0..e6166f7a 100644 --- a/sdk/protected_code_loader/crypto/pcl_md32_common.h +++ b/sdk/protected_code_loader/crypto/pcl_md32_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/crypto/pcl_modes_lcl.h b/sdk/protected_code_loader/crypto/pcl_modes_lcl.h index e8b97439..25c56969 100644 --- a/sdk/protected_code_loader/crypto/pcl_modes_lcl.h +++ b/sdk/protected_code_loader/crypto/pcl_modes_lcl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/crypto/pcl_sha256.c b/sdk/protected_code_loader/crypto/pcl_sha256.c index 7736003e..b9d7619a 100644 --- a/sdk/protected_code_loader/crypto/pcl_sha256.c +++ b/sdk/protected_code_loader/crypto/pcl_sha256.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/pcl_entry.cpp b/sdk/protected_code_loader/pcl_entry.cpp index 4f6674d6..e0cb49a9 100644 --- a/sdk/protected_code_loader/pcl_entry.cpp +++ b/sdk/protected_code_loader/pcl_entry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/pcl_internal.h b/sdk/protected_code_loader/pcl_internal.h index bfd4cf2c..33ca5a30 100644 --- a/sdk/protected_code_loader/pcl_internal.h +++ b/sdk/protected_code_loader/pcl_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/pcl_mem.cpp b/sdk/protected_code_loader/pcl_mem.cpp index 8c2fb76a..2876eea8 100644 --- a/sdk/protected_code_loader/pcl_mem.cpp +++ b/sdk/protected_code_loader/pcl_mem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/unseal/pcl_sgx_get_key.cpp b/sdk/protected_code_loader/unseal/pcl_sgx_get_key.cpp index 067778da..3f6f61ec 100644 --- a/sdk/protected_code_loader/unseal/pcl_sgx_get_key.cpp +++ b/sdk/protected_code_loader/unseal/pcl_sgx_get_key.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/unseal/pcl_tSeal.cpp b/sdk/protected_code_loader/unseal/pcl_tSeal.cpp index 81682cd8..5923b335 100644 --- a/sdk/protected_code_loader/unseal/pcl_tSeal.cpp +++ b/sdk/protected_code_loader/unseal/pcl_tSeal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/unseal/pcl_tSeal_internal.cpp b/sdk/protected_code_loader/unseal/pcl_tSeal_internal.cpp index 790a0002..884f4e7f 100644 --- a/sdk/protected_code_loader/unseal/pcl_tSeal_internal.cpp +++ b/sdk/protected_code_loader/unseal/pcl_tSeal_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/unseal/pcl_tSeal_util.cpp b/sdk/protected_code_loader/unseal/pcl_tSeal_util.cpp index 104fc7a3..937ad050 100644 --- a/sdk/protected_code_loader/unseal/pcl_tSeal_util.cpp +++ b/sdk/protected_code_loader/unseal/pcl_tSeal_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/unseal/pcl_unseal_internal.h b/sdk/protected_code_loader/unseal/pcl_unseal_internal.h index 09ef3d38..44ac1e0a 100644 --- a/sdk/protected_code_loader/unseal/pcl_unseal_internal.h +++ b/sdk/protected_code_loader/unseal/pcl_unseal_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/unseal/sim/pcl_deriv.cpp b/sdk/protected_code_loader/unseal/sim/pcl_deriv.cpp index 4b0e0a88..0c8a8e9a 100644 --- a/sdk/protected_code_loader/unseal/sim/pcl_deriv.cpp +++ b/sdk/protected_code_loader/unseal/sim/pcl_deriv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_code_loader/unseal/sim/pcl_t_instructions.cpp b/sdk/protected_code_loader/unseal/sim/pcl_t_instructions.cpp index 7e386f37..e8a395d5 100644 --- a/sdk/protected_code_loader/unseal/sim/pcl_t_instructions.cpp +++ b/sdk/protected_code_loader/unseal/sim/pcl_t_instructions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/Makefile b/sdk/protected_fs/sgx_tprotected_fs/Makefile index 86a51047..4e8e4ca3 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/Makefile +++ b/sdk/protected_fs/sgx_tprotected_fs/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp index b9a56451..d307a59b 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_crypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp index be43c51d..c0955a14 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_flush.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp index 9e9f4731..e92a76fa 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_init.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp index 567175c6..c6309c81 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_other.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp index 228108c5..4d150712 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_read_write.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/file_version.cpp b/sdk/protected_fs/sgx_tprotected_fs/file_version.cpp index 35610e17..efd2e7df 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/file_version.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/file_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp index 6e5600c1..aadb63c5 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h index 0b2e7169..26fb4657 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h +++ b/sdk/protected_fs/sgx_tprotected_fs/lru_cache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h index c03f7f2e..6d504182 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h +++ b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_file.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h index cdc00441..59eb5478 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h +++ b/sdk/protected_fs/sgx_tprotected_fs/protected_fs_nodes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp b/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp index a1554fef..b3f34fd7 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp +++ b/sdk/protected_fs/sgx_tprotected_fs/sgx_tprotected_fs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_tprotected_fs/tprotected_fs.h b/sdk/protected_fs/sgx_tprotected_fs/tprotected_fs.h index d349a001..3ce1d106 100644 --- a/sdk/protected_fs/sgx_tprotected_fs/tprotected_fs.h +++ b/sdk/protected_fs/sgx_tprotected_fs/tprotected_fs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_uprotected_fs/Makefile b/sdk/protected_fs/sgx_uprotected_fs/Makefile index 5c121526..8350d650 100644 --- a/sdk/protected_fs/sgx_uprotected_fs/Makefile +++ b/sdk/protected_fs/sgx_uprotected_fs/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp b/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp index 2226cedd..4fed2e31 100644 --- a/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp +++ b/sdk/protected_fs/sgx_uprotected_fs/sgx_uprotected_fs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/protected_fs/sgx_uprotected_fs/uprotected_fs.h b/sdk/protected_fs/sgx_uprotected_fs/uprotected_fs.h index 49a29b02..3c882c79 100644 --- a/sdk/protected_fs/sgx_uprotected_fs/uprotected_fs.h +++ b/sdk/protected_fs/sgx_uprotected_fs/uprotected_fs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sample_libcrypto/Makefile b/sdk/sample_libcrypto/Makefile index a3251503..d93e3c4d 100644 --- a/sdk/sample_libcrypto/Makefile +++ b/sdk/sample_libcrypto/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/sample_libcrypto/sample_libcrypto.cpp b/sdk/sample_libcrypto/sample_libcrypto.cpp index e000f928..651c8ca0 100644 --- a/sdk/sample_libcrypto/sample_libcrypto.cpp +++ b/sdk/sample_libcrypto/sample_libcrypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sample_libcrypto/sample_libcrypto.h b/sdk/sample_libcrypto/sample_libcrypto.h index 4224c6e8..df2addb5 100644 --- a/sdk/sample_libcrypto/sample_libcrypto.h +++ b/sdk/sample_libcrypto/sample_libcrypto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/selib/linux/Makefile b/sdk/selib/linux/Makefile index 8c940d03..e484e1bc 100644 --- a/sdk/selib/linux/Makefile +++ b/sdk/selib/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/selib/sgx_create_report.cpp b/sdk/selib/sgx_create_report.cpp index b0b1a94d..1a867d7e 100644 --- a/sdk/selib/sgx_create_report.cpp +++ b/sdk/selib/sgx_create_report.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -89,11 +89,17 @@ sgx_status_t sgx_create_report(const sgx_target_info_t *target_info, const sgx_r // Do EREPORT auto failed = do_ereport(&tmp_target_info, &tmp_report_data, &tmp_report); - // Copy data to the user buffer + // Copy data to the user buffer: *report = tmp_report; + // Use a loop to avoid compiler to call memcpy, + // which cannot be used during enclave initialization. // No need to cleanup the tmp_report as it is not secret. if (!failed) { - *report = tmp_report; + static_assert(sizeof(*report) % sizeof(uint64_t) == 0, "sizeof(sgx_report_t) should be multiple of 8"); + for(size_t i = 0; i < sizeof(*report)/sizeof(uint64_t); i++) + { + ((uint64_t*)report)[i] = ((uint64_t*)&tmp_report)[i]; + } } diff --git a/sdk/selib/sgx_get_key.cpp b/sdk/selib/sgx_get_key.cpp index 7876f5f1..16318002 100644 --- a/sdk/selib/sgx_get_key.cpp +++ b/sdk/selib/sgx_get_key.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/selib/sgx_verify_report.cpp b/sdk/selib/sgx_verify_report.cpp index b9df4c73..6f5e8eb6 100644 --- a/sdk/selib/sgx_verify_report.cpp +++ b/sdk/selib/sgx_verify_report.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/selib/tservice_version.cpp b/sdk/selib/tservice_version.cpp index 82d256b3..2f92c81d 100644 --- a/sdk/selib/tservice_version.cpp +++ b/sdk/selib/tservice_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/Makefile b/sdk/sign_tool/SignTool/Makefile index 3d181882..27e29655 100644 --- a/sdk/sign_tool/SignTool/Makefile +++ b/sdk/sign_tool/SignTool/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/elf_helper.h b/sdk/sign_tool/SignTool/elf_helper.h index e6958d33..7624bec3 100644 --- a/sdk/sign_tool/SignTool/elf_helper.h +++ b/sdk/sign_tool/SignTool/elf_helper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/enclave_creator_sign.cpp b/sdk/sign_tool/SignTool/enclave_creator_sign.cpp index 4763c355..33073854 100644 --- a/sdk/sign_tool/SignTool/enclave_creator_sign.cpp +++ b/sdk/sign_tool/SignTool/enclave_creator_sign.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/enclave_creator_sign.h b/sdk/sign_tool/SignTool/enclave_creator_sign.h index 1549fccd..57ffe2e8 100644 --- a/sdk/sign_tool/SignTool/enclave_creator_sign.h +++ b/sdk/sign_tool/SignTool/enclave_creator_sign.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/manage_metadata.cpp b/sdk/sign_tool/SignTool/manage_metadata.cpp index 86d4067b..f9730304 100644 --- a/sdk/sign_tool/SignTool/manage_metadata.cpp +++ b/sdk/sign_tool/SignTool/manage_metadata.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/manage_metadata.h b/sdk/sign_tool/SignTool/manage_metadata.h index 96ab46ab..ed435f1c 100644 --- a/sdk/sign_tool/SignTool/manage_metadata.h +++ b/sdk/sign_tool/SignTool/manage_metadata.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/parse_key_file.cpp b/sdk/sign_tool/SignTool/parse_key_file.cpp index b3315f74..08f16da4 100644 --- a/sdk/sign_tool/SignTool/parse_key_file.cpp +++ b/sdk/sign_tool/SignTool/parse_key_file.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/parse_key_file.h b/sdk/sign_tool/SignTool/parse_key_file.h index a3feb80c..2270f63d 100644 --- a/sdk/sign_tool/SignTool/parse_key_file.h +++ b/sdk/sign_tool/SignTool/parse_key_file.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/sign_tool.cpp b/sdk/sign_tool/SignTool/sign_tool.cpp index 550f5fd3..f1c1c315 100644 --- a/sdk/sign_tool/SignTool/sign_tool.cpp +++ b/sdk/sign_tool/SignTool/sign_tool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/util_st.cpp b/sdk/sign_tool/SignTool/util_st.cpp index 26d26cee..74e716bb 100644 --- a/sdk/sign_tool/SignTool/util_st.cpp +++ b/sdk/sign_tool/SignTool/util_st.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/sign_tool/SignTool/util_st.h b/sdk/sign_tool/SignTool/util_st.h index 25e1789c..495279f9 100644 --- a/sdk/sign_tool/SignTool/util_st.h +++ b/sdk/sign_tool/SignTool/util_st.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/Makefile b/sdk/simulation/Makefile index 8bd93f4e..00c7954d 100644 --- a/sdk/simulation/Makefile +++ b/sdk/simulation/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/SEConfigureCPUSVN/linux/Makefile b/sdk/simulation/SEConfigureCPUSVN/linux/Makefile index c7a7fb62..65cb2608 100644 --- a/sdk/simulation/SEConfigureCPUSVN/linux/Makefile +++ b/sdk/simulation/SEConfigureCPUSVN/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/SEConfigureCPUSVN/linux/config_cpusvn.cpp b/sdk/simulation/SEConfigureCPUSVN/linux/config_cpusvn.cpp index 083e25cb..ec60b4a3 100644 --- a/sdk/simulation/SEConfigureCPUSVN/linux/config_cpusvn.cpp +++ b/sdk/simulation/SEConfigureCPUSVN/linux/config_cpusvn.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/SEConfigureCPUSVN/linux/cpusvn_helper.h b/sdk/simulation/SEConfigureCPUSVN/linux/cpusvn_helper.h index fa3869a1..e40352dd 100644 --- a/sdk/simulation/SEConfigureCPUSVN/linux/cpusvn_helper.h +++ b/sdk/simulation/SEConfigureCPUSVN/linux/cpusvn_helper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/Makefile b/sdk/simulation/assembly/Makefile index 2e5220dd..13196ce2 100644 --- a/sdk/simulation/assembly/Makefile +++ b/sdk/simulation/assembly/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/linux/Makefile b/sdk/simulation/assembly/linux/Makefile index 45ba080b..87d83510 100644 --- a/sdk/simulation/assembly/linux/Makefile +++ b/sdk/simulation/assembly/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/linux/gnu_tls.h b/sdk/simulation/assembly/linux/gnu_tls.h index 5104a9d7..db47669d 100644 --- a/sdk/simulation/assembly/linux/gnu_tls.h +++ b/sdk/simulation/assembly/linux/gnu_tls.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/linux/lowlib.S b/sdk/simulation/assembly/linux/lowlib.S index 48476c58..bcae1bcb 100644 --- a/sdk/simulation/assembly/linux/lowlib.S +++ b/sdk/simulation/assembly/linux/lowlib.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/linux/sgxsim.S b/sdk/simulation/assembly/linux/sgxsim.S index 641f615f..286c576f 100644 --- a/sdk/simulation/assembly/linux/sgxsim.S +++ b/sdk/simulation/assembly/linux/sgxsim.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/linux/sw_emu.h b/sdk/simulation/assembly/linux/sw_emu.h index d3c8bdc1..b0e3f1e5 100644 --- a/sdk/simulation/assembly/linux/sw_emu.h +++ b/sdk/simulation/assembly/linux/sw_emu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/lowlib.h b/sdk/simulation/assembly/lowlib.h index cd419547..8b045802 100644 --- a/sdk/simulation/assembly/lowlib.h +++ b/sdk/simulation/assembly/lowlib.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/assembly/sgxsim.h b/sdk/simulation/assembly/sgxsim.h index ddb4e420..302778fa 100644 --- a/sdk/simulation/assembly/sgxsim.h +++ b/sdk/simulation/assembly/sgxsim.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/driver_api/Makefile b/sdk/simulation/driver_api/Makefile index 4fa3b398..1c55116d 100644 --- a/sdk/simulation/driver_api/Makefile +++ b/sdk/simulation/driver_api/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/driver_api/driver_api.cpp b/sdk/simulation/driver_api/driver_api.cpp index 3d70234a..c7cb359f 100644 --- a/sdk/simulation/driver_api/driver_api.cpp +++ b/sdk/simulation/driver_api/driver_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tae_service_sim/Makefile b/sdk/simulation/tae_service_sim/Makefile index e4640249..a39ebc0c 100644 --- a/sdk/simulation/tae_service_sim/Makefile +++ b/sdk/simulation/tae_service_sim/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tae_service_sim/tae_service_sim.cpp b/sdk/simulation/tae_service_sim/tae_service_sim.cpp index 99bf16c8..a317e71e 100644 --- a/sdk/simulation/tae_service_sim/tae_service_sim.cpp +++ b/sdk/simulation/tae_service_sim/tae_service_sim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tinst/Makefile b/sdk/simulation/tinst/Makefile index 4d2b43c4..698f3968 100644 --- a/sdk/simulation/tinst/Makefile +++ b/sdk/simulation/tinst/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tinst/deriv.cpp b/sdk/simulation/tinst/deriv.cpp index 94a5d2d2..dafd7e14 100644 --- a/sdk/simulation/tinst/deriv.cpp +++ b/sdk/simulation/tinst/deriv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tinst/deriv.h b/sdk/simulation/tinst/deriv.h index 01381b35..504a99ab 100644 --- a/sdk/simulation/tinst/deriv.h +++ b/sdk/simulation/tinst/deriv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tinst/rts_sim.h b/sdk/simulation/tinst/rts_sim.h index 1df5e7ae..92c58fba 100644 --- a/sdk/simulation/tinst/rts_sim.h +++ b/sdk/simulation/tinst/rts_sim.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tinst/t_instructions.cpp b/sdk/simulation/tinst/t_instructions.cpp index a3f80d7d..567984fa 100644 --- a/sdk/simulation/tinst/t_instructions.cpp +++ b/sdk/simulation/tinst/t_instructions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/tinst/t_instructions.h b/sdk/simulation/tinst/t_instructions.h index c28808b6..6b3765cd 100644 --- a/sdk/simulation/tinst/t_instructions.h +++ b/sdk/simulation/tinst/t_instructions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/trtssim/Makefile b/sdk/simulation/trtssim/Makefile index d0be811e..5d8859a0 100644 --- a/sdk/simulation/trtssim/Makefile +++ b/sdk/simulation/trtssim/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/trtssim/linux/Makefile b/sdk/simulation/trtssim/linux/Makefile index ad7dffcc..ce93b88c 100644 --- a/sdk/simulation/trtssim/linux/Makefile +++ b/sdk/simulation/trtssim/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uae_service_sim/licensing_sim.cpp b/sdk/simulation/uae_service_sim/licensing_sim.cpp index f42a5b69..583769e9 100644 --- a/sdk/simulation/uae_service_sim/licensing_sim.cpp +++ b/sdk/simulation/uae_service_sim/licensing_sim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uae_service_sim/linux/Makefile b/sdk/simulation/uae_service_sim/linux/Makefile index 85caf55a..fb46a0cc 100644 --- a/sdk/simulation/uae_service_sim/linux/Makefile +++ b/sdk/simulation/uae_service_sim/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -40,9 +40,11 @@ INCLUDES := -I.. \ -I$(LINUX_SDK_DIR)/simulation/urtssim \ -I$(LINUX_EXTERNAL_DIR)/epid-sdk \ -I$(LINUX_EXTERNAL_DIR)/rdrand/ \ - -I$(LINUX_PSW_DIR)/ae/inc \ - -I$(LINUX_PSW_DIR)/ae/inc/internal \ - -I$(LINUX_PSW_DIR)/ae/common + -I$(LINUX_PSW_DIR)/ae/inc \ + -I$(LINUX_PSW_DIR)/ae/inc/internal \ + -I$(LINUX_PSW_DIR)/ae/common \ + -I$(DCAP_DIR)/QuoteGeneration/quote_wrapper/common/inc/ \ + -I$(DCAP_DIR)/QuoteGeneration/pce_wrapper/inc/ CXXFLAGS += -Wall -fPIC $(INCLUDES) -Werror -g CFLAGS := $(filter-out -fPIC -Werror, $(CFLAGS)) -Wall $(INCLUDES) @@ -75,7 +77,7 @@ DLLNAME_DEBUG = libsgx_uae_service_sim.so.debug LIBUAE_SERVICE_DEPLOY := libsgx_uae_service_deploy.so .PHONY: all -all: $(DLLNAME) $(DLLNAME_DEBUG) $(LIBUAE_SERVICE_DEPLOY) | $(BUILD_DIR) +all: $(DLLNAME) $(DLLNAME_DEBUG) $(LIBUAE_SERVICE_DEPLOY)| $(BUILD_DIR) $(CP) $(DLLNAME) $| $(CP) $(LIBUAE_SERVICE_DEPLOY) $| ifndef DEBUG diff --git a/sdk/simulation/uae_service_sim/linux/platform_service_sim.cpp b/sdk/simulation/uae_service_sim/linux/platform_service_sim.cpp index 24d208f6..71db9acf 100644 --- a/sdk/simulation/uae_service_sim/linux/platform_service_sim.cpp +++ b/sdk/simulation/uae_service_sim/linux/platform_service_sim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uae_service_sim/linux/uae_service_sim.linux.version b/sdk/simulation/uae_service_sim/linux/uae_service_sim.linux.version index b0f7cb62..6382cbc5 100644 --- a/sdk/simulation/uae_service_sim/linux/uae_service_sim.linux.version +++ b/sdk/simulation/uae_service_sim/linux/uae_service_sim.linux.version @@ -15,6 +15,10 @@ global: sgx_get_whitelist_size; sgx_get_whitelist; sgx_register_wl_cert_chain; + sgx_select_att_key_id; + sgx_init_quote_ex; + sgx_get_quote_size_ex; + sgx_get_quote_ex; local: *; }; diff --git a/sdk/simulation/uae_service_sim/platform_service_sim_com.cpp b/sdk/simulation/uae_service_sim/platform_service_sim_com.cpp index 7b792dca..bacf10b7 100644 --- a/sdk/simulation/uae_service_sim/platform_service_sim_com.cpp +++ b/sdk/simulation/uae_service_sim/platform_service_sim_com.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uae_service_sim/quoting_sim.cpp b/sdk/simulation/uae_service_sim/quoting_sim.cpp index 06193d8c..94d46ffd 100644 --- a/sdk/simulation/uae_service_sim/quoting_sim.cpp +++ b/sdk/simulation/uae_service_sim/quoting_sim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -441,3 +441,48 @@ sgx_status_t SGXAPI sgx_register_wl_cert_chain(uint8_t* p_wl_cert_chain, uint32_ UNUSED(wl_cert_chain_size); return SGX_SUCCESS; } + +sgx_status_t SGXAPI sgx_select_att_key_id(const uint8_t *p_att_key_id_list, uint32_t att_key_id_list_size, + sgx_att_key_id_t **pp_selected_key_id) +{ + UNUSED(p_att_key_id_list); + UNUSED(att_key_id_list_size); + UNUSED(pp_selected_key_id); + return SGX_SUCCESS; +} + +sgx_status_t SGXAPI sgx_init_quote_ex(const sgx_att_key_id_t* p_att_key_id, + sgx_target_info_t *p_qe_target_info, + bool refresh_att_key, + size_t* p_pub_key_id_size, + uint8_t* p_pub_key_id) +{ + UNUSED(p_att_key_id); + UNUSED(p_qe_target_info); + UNUSED(refresh_att_key); + UNUSED(p_pub_key_id_size); + UNUSED(p_pub_key_id); + return SGX_SUCCESS; +} + +sgx_status_t SGXAPI sgx_get_quote_size_ex(const sgx_att_key_id_t *p_att_key_id, + uint32_t* p_quote_size) +{ + UNUSED(p_att_key_id); + UNUSED(p_quote_size); + return SGX_SUCCESS; +} + +sgx_status_t SGXAPI sgx_get_quote_ex(const sgx_report_t *p_app_report, + const sgx_att_key_id_t *p_att_key_id, + sgx_qe_report_info_t *p_qe_report_info, + uint8_t *p_quote, + uint32_t quote_size) +{ + UNUSED(p_app_report); + UNUSED(p_att_key_id); + UNUSED(p_qe_report_info); + UNUSED(p_quote); + UNUSED(quote_size); + return SGX_SUCCESS; +} diff --git a/sdk/simulation/uae_service_sim/uae_service_deploy.c b/sdk/simulation/uae_service_sim/uae_service_deploy.c index fda1e330..5de14de5 100644 --- a/sdk/simulation/uae_service_sim/uae_service_deploy.c +++ b/sdk/simulation/uae_service_sim/uae_service_deploy.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,8 +30,12 @@ */ void sgx_get_quote(){} +void sgx_get_quote_ex(){} void sgx_get_quote_size(){} +void sgx_get_quote_size_ex(){} void sgx_init_quote(){} +void sgx_init_quote_ex(){} +void sgx_select_att_key_id(){} void sgx_get_whitelist_size(){} void sgx_get_whitelist(){} void sgx_switch_extended_epid_group(){} diff --git a/sdk/simulation/uae_service_sim/uae_service_sim.h b/sdk/simulation/uae_service_sim/uae_service_sim.h index 55ef29ae..311abf5f 100644 --- a/sdk/simulation/uae_service_sim/uae_service_sim.h +++ b/sdk/simulation/uae_service_sim/uae_service_sim.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/Makefile b/sdk/simulation/uinst/Makefile index 36215d7f..9a45fba7 100644 --- a/sdk/simulation/uinst/Makefile +++ b/sdk/simulation/uinst/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/enclave_mngr.cpp b/sdk/simulation/uinst/enclave_mngr.cpp index 8f4c9291..935b2a56 100644 --- a/sdk/simulation/uinst/enclave_mngr.cpp +++ b/sdk/simulation/uinst/enclave_mngr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/enclave_mngr.h b/sdk/simulation/uinst/enclave_mngr.h index 3b8ce93a..baaafae0 100644 --- a/sdk/simulation/uinst/enclave_mngr.h +++ b/sdk/simulation/uinst/enclave_mngr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/linux/Makefile b/sdk/simulation/uinst/linux/Makefile index 759475ad..af6f60e3 100644 --- a/sdk/simulation/uinst/linux/Makefile +++ b/sdk/simulation/uinst/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/linux/get_tcs.c b/sdk/simulation/uinst/linux/get_tcs.c index 44aa0fa5..34f427a6 100644 --- a/sdk/simulation/uinst/linux/get_tcs.c +++ b/sdk/simulation/uinst/linux/get_tcs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/linux/restore_tls.c b/sdk/simulation/uinst/linux/restore_tls.c index 288e3b16..87758741 100644 --- a/sdk/simulation/uinst/linux/restore_tls.c +++ b/sdk/simulation/uinst/linux/restore_tls.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/linux/set_tls.c b/sdk/simulation/uinst/linux/set_tls.c index 225a21d2..033b27e0 100644 --- a/sdk/simulation/uinst/linux/set_tls.c +++ b/sdk/simulation/uinst/linux/set_tls.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/td_mngr.h b/sdk/simulation/uinst/td_mngr.h index ea8599a8..9fa4a80a 100644 --- a/sdk/simulation/uinst/td_mngr.h +++ b/sdk/simulation/uinst/td_mngr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/u_instructions.cpp b/sdk/simulation/uinst/u_instructions.cpp index 0b0486f6..9067c806 100644 --- a/sdk/simulation/uinst/u_instructions.cpp +++ b/sdk/simulation/uinst/u_instructions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/uinst/u_instructions.h b/sdk/simulation/uinst/u_instructions.h index bcd6a151..75d3519a 100644 --- a/sdk/simulation/uinst/u_instructions.h +++ b/sdk/simulation/uinst/u_instructions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/urtssim/Makefile b/sdk/simulation/urtssim/Makefile index d0be811e..5d8859a0 100644 --- a/sdk/simulation/urtssim/Makefile +++ b/sdk/simulation/urtssim/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/urtssim/cpusvn_util.cpp b/sdk/simulation/urtssim/cpusvn_util.cpp index f7ef658b..c95fdd5d 100644 --- a/sdk/simulation/urtssim/cpusvn_util.cpp +++ b/sdk/simulation/urtssim/cpusvn_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/urtssim/cpusvn_util.h b/sdk/simulation/urtssim/cpusvn_util.h index c3e33618..29f40b98 100644 --- a/sdk/simulation/urtssim/cpusvn_util.h +++ b/sdk/simulation/urtssim/cpusvn_util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/urtssim/enclave_creator_sim.cpp b/sdk/simulation/urtssim/enclave_creator_sim.cpp index c32c2dd1..6eb2540c 100644 --- a/sdk/simulation/urtssim/enclave_creator_sim.cpp +++ b/sdk/simulation/urtssim/enclave_creator_sim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -203,7 +203,7 @@ int EnclaveCreatorSim::initialize(sgx_enclave_id_t enclave_id) return SGX_ERROR_INVALID_ENCLAVE_ID; } - global_data_sim_t *global_data_sim_ptr = (global_data_sim_t *)enclave->get_symbol_address("g_global_data_sim"); + global_data_sim_t *global_data_sim_ptr = (global_data_sim_t *)enclave->get_global_data_sim_ptr(); //We have check the symbol of "g_global_data_sim" in urts_com.h::_create_enclave(), so here global_data_sim_ptr won't be NULL. assert(global_data_sim_ptr != NULL); diff --git a/sdk/simulation/urtssim/enclave_creator_sim.h b/sdk/simulation/urtssim/enclave_creator_sim.h index f06a66e6..959e8594 100644 --- a/sdk/simulation/urtssim/enclave_creator_sim.h +++ b/sdk/simulation/urtssim/enclave_creator_sim.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/urtssim/linux/Makefile b/sdk/simulation/urtssim/linux/Makefile index b0d4a441..c8f44599 100644 --- a/sdk/simulation/urtssim/linux/Makefile +++ b/sdk/simulation/urtssim/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/simulation/urtssim/urts_deploy.c b/sdk/simulation/urtssim/urts_deploy.c index a383efd6..1fe7cc99 100644 --- a/sdk/simulation/urtssim/urts_deploy.c +++ b/sdk/simulation/urtssim/urts_deploy.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/simulation/urtssim/urts_sim.h b/sdk/simulation/urtssim/urts_sim.h index 889c0f8b..4aa2ae44 100644 --- a/sdk/simulation/urtssim/urts_sim.h +++ b/sdk/simulation/urtssim/urts_sim.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/Makefile b/sdk/switchless/Makefile index f02b012a..e4ebc252 100644 --- a/sdk/switchless/Makefile +++ b/sdk/switchless/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sgx_ocall_switchless.c b/sdk/switchless/src/sgx_ocall_switchless.c index 1ab727e9..91c1a30f 100644 --- a/sdk/switchless/src/sgx_ocall_switchless.c +++ b/sdk/switchless/src/sgx_ocall_switchless.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sl_fcall_mngr.c b/sdk/switchless/src/sl_fcall_mngr.c index 37fa3bb3..799eff0b 100644 --- a/sdk/switchless/src/sl_fcall_mngr.c +++ b/sdk/switchless/src/sl_fcall_mngr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sl_init.c b/sdk/switchless/src/sl_init.c index 30372a5c..b5400aa5 100644 --- a/sdk/switchless/src/sl_init.c +++ b/sdk/switchless/src/sl_init.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sl_memlog.c b/sdk/switchless/src/sl_memlog.c index 46cbc203..6773945c 100644 --- a/sdk/switchless/src/sl_memlog.c +++ b/sdk/switchless/src/sl_memlog.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sl_once.c b/sdk/switchless/src/sl_once.c index 568f076c..60f96c78 100644 --- a/sdk/switchless/src/sl_once.c +++ b/sdk/switchless/src/sl_once.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sl_printk.c b/sdk/switchless/src/sl_printk.c index 4f162d8d..99f5a782 100644 --- a/sdk/switchless/src/sl_printk.c +++ b/sdk/switchless/src/sl_printk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sl_siglines.c b/sdk/switchless/src/sl_siglines.c index 8205ff46..1e155024 100644 --- a/sdk/switchless/src/sl_siglines.c +++ b/sdk/switchless/src/sl_siglines.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/switchless/src/sl_workers.c b/sdk/switchless/src/sl_workers.c index 0343fce5..fe8737fc 100644 --- a/sdk/switchless/src/sl_workers.c +++ b/sdk/switchless/src/sl_workers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tae_service/Makefile b/sdk/tae_service/Makefile index 6cb83d16..f0cad8e0 100644 --- a/sdk/tae_service/Makefile +++ b/sdk/tae_service/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tae_service/tae_config.h b/sdk/tae_service/tae_config.h index 46627e06..4e0a6320 100644 --- a/sdk/tae_service/tae_config.h +++ b/sdk/tae_service/tae_config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tae_service/tae_service.cpp b/sdk/tae_service/tae_service.cpp index c3fdce99..031ce084 100644 --- a/sdk/tae_service/tae_service.cpp +++ b/sdk/tae_service/tae_service.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tkey_exchange/Makefile b/sdk/tkey_exchange/Makefile index 79442d0e..64656282 100644 --- a/sdk/tkey_exchange/Makefile +++ b/sdk/tkey_exchange/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tkey_exchange/simple_vector.cpp b/sdk/tkey_exchange/simple_vector.cpp index 7b5372a6..d62cbec6 100644 --- a/sdk/tkey_exchange/simple_vector.cpp +++ b/sdk/tkey_exchange/simple_vector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tkey_exchange/simple_vector.h b/sdk/tkey_exchange/simple_vector.h index 2f17c3df..68f72327 100644 --- a/sdk/tkey_exchange/simple_vector.h +++ b/sdk/tkey_exchange/simple_vector.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tkey_exchange/tkey_exchange.cpp b/sdk/tkey_exchange/tkey_exchange.cpp index 2e9965fb..f178d81e 100644 --- a/sdk/tkey_exchange/tkey_exchange.cpp +++ b/sdk/tkey_exchange/tkey_exchange.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tkey_exchange/tkey_exchange_version.cpp b/sdk/tkey_exchange/tkey_exchange_version.cpp index c8a19697..4b59b495 100644 --- a/sdk/tkey_exchange/tkey_exchange_version.cpp +++ b/sdk/tkey_exchange/tkey_exchange_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/Makefile b/sdk/tlibc/Makefile index b019c865..368c03b7 100644 --- a/sdk/tlibc/Makefile +++ b/sdk/tlibc/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/gen/errno.c b/sdk/tlibc/gen/errno.c index 5a2cc2d2..c1943028 100644 --- a/sdk/tlibc/gen/errno.c +++ b/sdk/tlibc/gen/errno.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/gen/sbrk.c b/sdk/tlibc/gen/sbrk.c index 3bbd08a4..cc8326ca 100644 --- a/sdk/tlibc/gen/sbrk.c +++ b/sdk/tlibc/gen/sbrk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/gen/se_cpuid.c b/sdk/tlibc/gen/se_cpuid.c index a9f598a7..d100aac1 100644 --- a/sdk/tlibc/gen/se_cpuid.c +++ b/sdk/tlibc/gen/se_cpuid.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/gen/spinlock.c b/sdk/tlibc/gen/spinlock.c index c6eb3a34..e818c086 100644 --- a/sdk/tlibc/gen/spinlock.c +++ b/sdk/tlibc/gen/spinlock.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/math/w_dreml.c b/sdk/tlibc/math/w_dreml.c index 80eab2a7..dd67b5bb 100644 --- a/sdk/tlibc/math/w_dreml.c +++ b/sdk/tlibc/math/w_dreml.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/math/w_pow10.c b/sdk/tlibc/math/w_pow10.c index 05887ecf..6bbd918f 100644 --- a/sdk/tlibc/math/w_pow10.c +++ b/sdk/tlibc/math/w_pow10.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/math/w_pow10f.c b/sdk/tlibc/math/w_pow10f.c index 5d158719..dcc1aba8 100644 --- a/sdk/tlibc/math/w_pow10f.c +++ b/sdk/tlibc/math/w_pow10f.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/math/w_pow10l.c b/sdk/tlibc/math/w_pow10l.c index 1a7c3d63..a3e984f0 100644 --- a/sdk/tlibc/math/w_pow10l.c +++ b/sdk/tlibc/math/w_pow10l.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/string/ffs.c b/sdk/tlibc/string/ffs.c index d8a3314a..73497bba 100644 --- a/sdk/tlibc/string/ffs.c +++ b/sdk/tlibc/string/ffs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/string/ffsl.c b/sdk/tlibc/string/ffsl.c index 9f0be541..b37493ad 100644 --- a/sdk/tlibc/string/ffsl.c +++ b/sdk/tlibc/string/ffsl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/string/ffsll.c b/sdk/tlibc/string/ffsll.c index 38796338..96173451 100644 --- a/sdk/tlibc/string/ffsll.c +++ b/sdk/tlibc/string/ffsll.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/string/se_string_init.c b/sdk/tlibc/string/se_string_init.c index cbc0f89f..7aaa3a60 100644 --- a/sdk/tlibc/string/se_string_init.c +++ b/sdk/tlibc/string/se_string_init.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibc/tstdc_version.cpp b/sdk/tlibc/tstdc_version.cpp index bc85d415..667f4d3f 100644 --- a/sdk/tlibc/tstdc_version.cpp +++ b/sdk/tlibc/tstdc_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/Makefile b/sdk/tlibcrypto/Makefile index 5f085d12..3ba4f8d0 100644 --- a/sdk/tlibcrypto/Makefile +++ b/sdk/tlibcrypto/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/init_tcrypto_lib.cpp b/sdk/tlibcrypto/ipp/init_tcrypto_lib.cpp index 2a429c29..4e9dd3ce 100644 --- a/sdk/tlibcrypto/ipp/init_tcrypto_lib.cpp +++ b/sdk/tlibcrypto/ipp/init_tcrypto_lib.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00000.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00000.c index 1d95219a..fa867006 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00000.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00000.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00001.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00001.c index cfb4e815..4324c7e7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00001.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00001.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00002.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00002.c index 6f3e1c43..61eaa209 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00002.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00002.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00003.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00003.c index cb56efce..79f8d173 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00003.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00003.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00004.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00004.c index 850e147a..2381ba2c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00004.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00004.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00005.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00005.c index b7833cf8..cdf360e7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00005.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00005.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00006.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00006.c index ae7a6345..de66c44f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00006.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00006.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00007.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00007.c index d8684d4e..006e8419 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00007.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00007.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00008.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00008.c index 0595f9c0..8f8e5114 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00008.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00008.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00009.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00009.c index e8101c35..e5fcebb3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00009.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00009.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00010.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00010.c index ab889350..49ec15fa 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00010.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00010.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00011.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00011.c index a921f111..7d443c40 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00011.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00011.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00012.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00012.c index 7e298efa..6b2a4419 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00012.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00012.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00013.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00013.c index 5b0aec21..7897542f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00013.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00013.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00014.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00014.c index 048d3bcf..766035a3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00014.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00014.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00015.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00015.c index b1fb3f8f..05535c2d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00015.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00015.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00016.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00016.c index 841a45d8..b7747222 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00016.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00016.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00017.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00017.c index 97abeebe..1cd732c8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00017.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00017.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00018.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00018.c index 9f352898..6163ac99 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00018.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00018.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00019.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00019.c index f16facaf..6f76812d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00019.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00019.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00020.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00020.c index b740e0e5..c792fb6b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00020.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00020.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00021.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00021.c index a6ae76fc..6197417f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00021.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00021.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00022.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00022.c index 0ac2a3ed..c2dd731d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00022.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00022.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00023.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00023.c index 6b4a89da..e331b7c1 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00023.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00023.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00024.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00024.c index e50ce701..3fcd5a31 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00024.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00024.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00025.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00025.c index 5a5dd197..e4be9226 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00025.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00025.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00026.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00026.c index 66f38a38..771396f5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00026.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00026.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00027.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00027.c index df758680..14acf7fd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00027.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00027.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00028.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00028.c index b59833ed..cf285fd5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00028.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00028.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00029.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00029.c index 2a3e31be..3f296b96 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00029.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00029.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00030.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00030.c index 710e9f20..d54124f2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00030.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00030.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00031.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00031.c index de67c9cc..51a19824 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00031.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00031.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00032.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00032.c index 77c28776..1f87d5d5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00032.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00032.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00033.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00033.c index 48ecb3b5..ffefc70e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00033.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00033.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00034.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00034.c index 5a513233..ffdfa788 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00034.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00034.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00035.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00035.c index b36db15d..8c8bd09e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00035.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00035.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00036.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00036.c index cc4cc4d1..513171b4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00036.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00036.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00037.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00037.c index 1c97e18a..f779fa5f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00037.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00037.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00038.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00038.c index 12a65a07..f92b3aae 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00038.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00038.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00039.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00039.c index 40b02be7..77990b5b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00039.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00039.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00040.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00040.c index d9d16313..adf13e77 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00040.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00040.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00041.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00041.c index b3642ca6..61424cc7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00041.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00041.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00042.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00042.c index e3bd9b08..18cc38d4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00042.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00042.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00043.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00043.c index 9708a698..46d02c3c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00043.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00043.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00044.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00044.c index 5dfa80e8..652c0df1 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00044.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00044.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00045.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00045.c index cae50707..8f503b5a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00045.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00045.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00046.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00046.c index 1cc0fb7d..680fe4fd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00046.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00046.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00047.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00047.c index 3167e4f7..c1acb2e8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00047.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00047.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00048.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00048.c index 71928893..e1cf3e53 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00048.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00048.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00049.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00049.c index 2f9b7e14..300bd6b4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00049.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00049.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00050.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00050.c index 66b534e4..dd2f4dc8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00050.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00050.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00051.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00051.c index 85f8a4ca..77929c6e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00051.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00051.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00052.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00052.c index da1174d4..91820724 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00052.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00052.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00053.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00053.c index 92f4c4b8..bb8dbbba 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00053.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00053.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00054.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00054.c index 862b094e..1dff23cb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00054.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00054.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00055.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00055.c index e0324a87..edd460a2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00055.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00055.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00056.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00056.c index b96766df..e5121d3d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00056.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00056.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00057.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00057.c index 917d5691..cf86b498 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00057.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00057.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00058.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00058.c index 8d984ede..b7aab70c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00058.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00058.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00059.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00059.c index 35c435e9..c4376071 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00059.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00059.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00060.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00060.c index 2b276e72..6a75d268 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00060.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00060.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00061.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00061.c index ca897246..49c313e9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00061.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00061.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00062.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00062.c index b0db9481..71d783b5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00062.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00062.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00063.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00063.c index 4443870e..993b0217 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00063.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00063.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00064.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00064.c index 025615f6..57d27a82 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00064.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00064.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00065.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00065.c index b9e24b71..56738565 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00065.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00065.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00066.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00066.c index 63ce0e6b..9e56c993 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00066.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00066.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00067.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00067.c index 7ba5f57d..6c4cc8a8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00067.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00067.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00068.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00068.c index 68c9e8d1..6a666b15 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00068.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00068.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00069.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00069.c index 668ce0e4..9b80d1de 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00069.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00069.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00070.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00070.c index b171c220..99c0f7a6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00070.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00070.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00071.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00071.c index eec4b68c..28788718 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00071.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00071.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00072.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00072.c index 02fe7f84..aa146023 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00072.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00072.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00073.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00073.c index f5090051..67756bbb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00073.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00073.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00074.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00074.c index 863a7d2b..a91c49ec 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00074.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00074.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00075.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00075.c index e7c4fff2..fe78727e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00075.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00075.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00076.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00076.c index 32867d43..3bd5f405 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00076.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00076.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00077.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00077.c index e93cb850..38d98536 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00077.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00077.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00078.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00078.c index 2d2d6404..8df9e8e5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00078.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00078.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00079.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00079.c index 411ef92b..fdb8b38d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00079.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00079.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00080.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00080.c index ff7b6834..d9bb2991 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00080.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00080.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00081.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00081.c index a38a2dcd..f7a4e3a8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00081.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00081.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00082.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00082.c index 2a84b85d..ffd372a3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00082.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00082.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00083.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00083.c index f3a9a411..4e374a49 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00083.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00083.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00084.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00084.c index 55bf90d7..d858f7b5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00084.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00084.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00085.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00085.c index 856b8d63..86e887c5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00085.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00085.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00086.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00086.c index 920e6f76..a71ab36b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00086.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00086.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00087.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00087.c index d24d6725..f0c4d325 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00087.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00087.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00088.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00088.c index c61cb6c6..8887a243 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00088.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00088.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00089.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00089.c index db803647..008f644e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00089.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00089.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00090.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00090.c index cd941c1c..f34b3e65 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00090.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00090.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00091.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00091.c index e167a38f..73f33b99 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00091.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00091.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00092.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00092.c index 8cc4b138..be8cd8a1 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00092.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00092.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00093.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00093.c index bcb758be..121830c5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00093.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00093.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00094.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00094.c index 23a0179e..4ee4ae70 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00094.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00094.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00095.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00095.c index b9753e4b..8133e1b9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00095.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00095.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00096.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00096.c index f064124d..b55d17cf 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00096.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00096.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00097.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00097.c index f5b346fe..cdb5543c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00097.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00097.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00098.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00098.c index 83d66890..ccc9585d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00098.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00098.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00099.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00099.c index 85ff3f25..30d4cebb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00099.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00099.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00100.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00100.c index b795799c..7659ffdd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00100.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00100.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00101.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00101.c index 74f0ff35..47858d4c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00101.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00101.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00102.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00102.c index f74ac628..6099b5f6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00102.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00102.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00103.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00103.c index 0cfab28b..561f7ae7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00103.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00103.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00104.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00104.c index f03136f1..57e81acc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00104.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00104.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00105.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00105.c index 8f2638d0..a21e50c2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00105.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00105.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00106.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00106.c index 6888ec0b..41936397 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00106.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00106.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00107.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00107.c index d10187dc..1fb1b140 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00107.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00107.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00108.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00108.c index 132ff037..408893e6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00108.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00108.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00109.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00109.c index 40065adb..0718b3e1 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00109.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00109.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00110.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00110.c index 40497cd1..0838cadc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00110.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00110.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00111.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00111.c index 76b2ec6b..14abe36a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00111.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00111.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00112.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00112.c index 45282140..ed787374 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00112.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00112.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00113.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00113.c index 57b7bd12..025be4bd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00113.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00113.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00114.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00114.c index 997dedd4..d34a2f27 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00114.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00114.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00115.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00115.c index a0d2ba50..5c064210 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00115.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00115.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00116.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00116.c index 11160c76..aada148b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00116.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00116.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00117.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00117.c index 702f3986..f55028a7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00117.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00117.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00118.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00118.c index 0118e173..4ac2a9d0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00118.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00118.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00119.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00119.c index cf44e972..c92fe177 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00119.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00119.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00120.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00120.c index 5278cddf..f431d5f0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00120.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00120.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00121.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00121.c index 8ec11b61..948b4d8c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00121.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00121.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00122.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00122.c index f05928a1..fa658f06 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00122.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00122.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00123.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00123.c index ec44e3b4..9beff67d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00123.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00123.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00124.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00124.c index 92e74c52..0a132edb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00124.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00124.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00125.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00125.c index 5dece878..2f575d52 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00125.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00125.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00126.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00126.c index 74a9b5de..6760b507 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00126.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00126.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00127.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00127.c index 76b5582c..e24d8c6e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00127.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00127.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00128.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00128.c index 197fbfd0..5aebe7de 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00128.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00128.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00129.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00129.c index 5ee44baa..3ef9f684 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00129.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00129.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00130.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00130.c index d13e36cd..28200afc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00130.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00130.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00131.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00131.c index 14902881..86bb5c89 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00131.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00131.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00132.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00132.c index 311d5131..aa2c4c75 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00132.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00132.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00133.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00133.c index 2737f8c0..72cb8fcd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00133.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00133.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00134.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00134.c index ad70b443..3d5f0fd0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00134.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00134.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00135.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00135.c index 4719b0b3..5963c511 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00135.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00135.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00136.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00136.c index 1a8a82bc..78bf6bdf 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00136.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00136.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00137.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00137.c index c43721d6..a3ab5681 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00137.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00137.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00138.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00138.c index 4b0026f5..407d3694 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00138.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00138.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00139.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00139.c index 102ed866..534440e7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00139.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00139.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00140.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00140.c index 80982f02..3ed43adc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00140.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00140.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00141.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00141.c index 2ab52cc8..c168c220 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00141.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00141.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00142.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00142.c index 6a263dfa..2f555ef8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00142.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00142.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00143.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00143.c index f63a8b7b..f6707406 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00143.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00143.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00144.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00144.c index 34a82ab8..83299f6d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00144.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00144.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00145.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00145.c index f893ef3e..0ca05648 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00145.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00145.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00146.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00146.c index d0fef622..f61a1233 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00146.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00146.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00147.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00147.c index d135dbd8..4652408a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00147.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00147.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00148.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00148.c index 78b4cffd..08dd73fb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00148.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00148.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00149.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00149.c index 50327f30..3de76fde 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00149.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00149.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00150.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00150.c index dc6ea8a4..fa03f0a8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00150.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00150.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00151.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00151.c index 7e878b2e..9673b1dc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00151.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00151.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00152.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00152.c index 1357f82c..531e6e6e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00152.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00152.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00153.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00153.c index 5f6bd376..bac59d5d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00153.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00153.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00154.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00154.c index 1bb8b7ae..adf4c3de 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00154.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00154.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00155.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00155.c index 1dc9286d..86b19853 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00155.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00155.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00156.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00156.c index 95827d11..5cc0a4e3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00156.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00156.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00157.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00157.c index 2d9365d2..88df2fc7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00157.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00157.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00158.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00158.c index c039b2ee..e6c9eba9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00158.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00158.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00159.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00159.c index f6a94848..428441bd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00159.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00159.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00160.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00160.c index 1609d5e7..f7ec1d8c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00160.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00160.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00161.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00161.c index c7baf395..473e8afb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00161.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00161.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00162.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00162.c index e1d472bc..99ccc7a0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00162.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00162.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00163.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00163.c index c2ae8560..07beef70 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00163.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00163.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00164.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00164.c index 11cf36a8..2564e642 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00164.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00164.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00165.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00165.c index adf9305b..796100da 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00165.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00165.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00166.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00166.c index 397dab95..22e1f818 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00166.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00166.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00167.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00167.c index 63a69364..92088f93 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00167.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00167.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00168.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00168.c index 14055ade..e8d8ae5d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00168.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00168.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00169.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00169.c index fb04c743..46e09096 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00169.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00169.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00170.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00170.c index 77efe393..72dff94c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00170.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00170.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00171.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00171.c index 268348e8..2917aead 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00171.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00171.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00172.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00172.c index 71b48db2..6ba54e0c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00172.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00172.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00173.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00173.c index 9184053e..e3e290fc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00173.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00173.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00174.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00174.c index c47cd91a..8b6aae05 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00174.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00174.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00175.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00175.c index 084fa7cc..5d9a22a6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00175.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00175.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00176.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00176.c index 8432f1c1..596a4803 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00176.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00176.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00177.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00177.c index 8b7095e2..fe6e4ec0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00177.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00177.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00178.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00178.c index fa93770a..c92d7628 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00178.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00178.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00179.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00179.c index f6a01ab7..964e86c2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00179.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00179.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00180.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00180.c index f400935f..714707dd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00180.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00180.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00181.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00181.c index cc60634b..92b0b4c4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00181.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00181.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00182.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00182.c index 37d197bc..9889e80d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00182.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00182.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00183.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00183.c index ccc1f0e1..fd1f0e3b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00183.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00183.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00184.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00184.c index 435a1147..65f41754 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00184.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00184.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00185.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00185.c index 5a4fae9a..bb6c33d7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00185.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00185.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00186.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00186.c index e98939dc..03e6893f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00186.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00186.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00187.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00187.c index 72327d09..934ce80b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00187.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00187.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00188.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00188.c index f1edb97c..2757088c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00188.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00188.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00189.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00189.c index 424ece6a..e4594f28 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00189.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00189.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00190.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00190.c index 40d32c09..7ce76c7d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00190.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00190.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00191.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00191.c index b8a31905..80efaf44 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00191.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00191.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00192.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00192.c index a064b0d5..287e0255 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00192.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00192.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00193.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00193.c index aa6d4b96..c10761b6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00193.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00193.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00194.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00194.c index be2b77de..2a8d1704 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00194.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00194.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00195.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00195.c index 6ee1def8..7a752669 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00195.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00195.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00196.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00196.c index 07e27d60..1dcecacd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00196.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00196.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00197.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00197.c index 0a8e12bc..fcc4da26 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00197.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00197.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00198.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00198.c index 31d41be5..30a4abe6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00198.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00198.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00199.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00199.c index 71657e1e..dae2f7fd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00199.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00199.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00200.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00200.c index 3fbe29bb..3a84bbd7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00200.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00200.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00201.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00201.c index 533849dd..d87ad8b2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00201.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00201.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00202.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00202.c index b458dda5..c3320aba 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00202.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00202.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00203.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00203.c index 2cdf56b3..13327285 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00203.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00203.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00204.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00204.c index 1a6c678b..19bb1103 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00204.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00204.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00205.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00205.c index 259611ff..9398a861 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00205.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00205.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00206.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00206.c index c325abb5..1c13ad83 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00206.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00206.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00207.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00207.c index e1ff29d7..d53093b8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00207.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00207.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00208.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00208.c index b62c9aed..70bc527b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00208.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00208.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00209.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00209.c index 565cf989..b9ec1da9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00209.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00209.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00210.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00210.c index 20b2f4ea..0fbfd380 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00210.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00210.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00211.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00211.c index c252b7fe..31b87fb6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00211.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00211.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00212.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00212.c index b24f6237..fa2a5f30 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00212.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00212.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00213.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00213.c index 2aad4016..a623a592 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00213.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00213.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00214.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00214.c index 58946b09..50a55a44 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00214.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00214.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00215.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00215.c index f4f66fe9..5005fd98 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00215.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00215.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00216.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00216.c index ec318b28..7b54a406 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00216.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00216.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00217.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00217.c index 18d2e8c1..9f31edb5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00217.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00217.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00218.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00218.c index 361c430e..c2e77fe3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00218.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00218.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00219.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00219.c index 60d99615..1158eaa2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00219.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00219.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00220.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00220.c index ab007c23..6be2de59 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00220.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00220.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00221.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00221.c index 96eeeeeb..6bcf95f9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00221.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00221.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00222.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00222.c index 58f18183..d7d32b4d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00222.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00222.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00223.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00223.c index b4c8a372..e2ba6626 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00223.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00223.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00224.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00224.c index 37b47a1f..23ab43c5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00224.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00224.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00225.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00225.c index e6b4b9b0..c5cdf942 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00225.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00225.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00226.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00226.c index d543ef74..4deb3296 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00226.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00226.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00227.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00227.c index f2c89afb..afdbbbe8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00227.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00227.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00228.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00228.c index 7e908861..7b5395bd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00228.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00228.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00229.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00229.c index aee8c451..052ffee9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00229.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00229.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00230.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00230.c index a69af4c5..7cc4a2c4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00230.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00230.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00231.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00231.c index d67fd32a..2011cf8c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00231.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00231.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00232.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00232.c index 735b709a..a614f798 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00232.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00232.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00233.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00233.c index 7d13d54e..778b0477 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00233.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00233.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00234.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00234.c index cd5d70dc..036f5b6f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00234.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00234.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00235.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00235.c index c258a946..e17b39e4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00235.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00235.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00236.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00236.c index f42ac4f0..4ed805c7 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00236.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00236.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00237.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00237.c index 5af8d069..ca318df2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00237.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00237.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00238.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00238.c index aa3b0d72..0e08c083 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00238.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00238.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00239.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00239.c index 7e80b9a6..422dd056 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00239.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00239.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00240.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00240.c index de7ae539..579098c6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00240.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00240.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00241.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00241.c index 934c1fd1..0cce4357 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00241.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00241.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00242.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00242.c index a58b92d0..c2288d7e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00242.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00242.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00243.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00243.c index 64668d97..53aad571 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00243.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00243.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00244.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00244.c index 33276628..e0cc8a61 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00244.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00244.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00245.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00245.c index 902405f8..dfdc98af 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00245.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00245.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00246.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00246.c index d6156e9c..8b25d1f5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00246.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00246.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00247.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00247.c index e786266f..d2e2cbe2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00247.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00247.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00248.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00248.c index 9d783c0d..9dc12eb2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00248.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00248.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00249.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00249.c index fb5ad60f..c2a819e4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00249.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00249.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00250.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00250.c index 013fcff7..fc380258 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00250.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00250.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00251.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00251.c index f880afd7..dcd7823f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00251.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00251.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00252.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00252.c index 235435db..b6a4fbb1 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00252.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00252.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00253.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00253.c index 0642e6db..19907bb4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00253.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00253.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00254.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00254.c index 5d699ce7..4e583471 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00254.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00254.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00255.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00255.c index e9bb1606..7179ad74 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00255.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00255.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00256.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00256.c index 4d26e3d0..bd1700ea 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00256.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00256.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00257.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00257.c index 80ecc66a..e78a8803 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00257.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00257.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00258.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00258.c index 77eced9d..700f9ec3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00258.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00258.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00259.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00259.c index e61a98c4..1c1db441 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00259.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00259.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00260.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00260.c index b516dc5b..b9878c6c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00260.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00260.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00261.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00261.c index 019d7ae7..1bb7e180 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00261.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00261.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00262.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00262.c index 54524d86..bcfe6917 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00262.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00262.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00263.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00263.c index 607d8390..6add8936 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00263.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00263.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00264.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00264.c index 9590199e..e3fda9d0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00264.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00264.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00265.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00265.c index bc36d791..42d518b8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00265.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00265.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00266.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00266.c index c5f9c99f..95862a34 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00266.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00266.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00267.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00267.c index 6b133edd..651d65ac 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00267.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00267.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00268.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00268.c index 22d7bb84..a82fc96d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00268.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00268.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00269.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00269.c index 430cca0d..f5987bc9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00269.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00269.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00270.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00270.c index ee274b4c..cd79e161 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00270.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00270.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00271.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00271.c index 283df4b4..a594b6ed 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00271.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00271.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00272.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00272.c index 56cf68b4..e360807a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00272.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00272.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00273.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00273.c index 0cf7b550..b1361e1a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00273.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00273.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00274.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00274.c index 47cf7f4b..587dad09 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00274.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00274.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00275.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00275.c index 5de0cebc..f3020978 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00275.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00275.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00276.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00276.c index 8569ce2b..0c7a73c2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00276.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00276.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00277.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00277.c index 38bc831f..03fecb52 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00277.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00277.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00278.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00278.c index 4a196e43..8c3f3c58 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00278.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00278.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00279.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00279.c index 14877906..823ca5a2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00279.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00279.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00280.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00280.c index f49c5da5..7969d6d6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00280.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00280.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00281.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00281.c index 9afd4f99..46c5ae96 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00281.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00281.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00282.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00282.c index af5ab4de..a3907b58 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00282.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00282.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00283.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00283.c index 724884ed..a6715641 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00283.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00283.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00284.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00284.c index f6fd4994..967080cd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00284.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00284.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00285.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00285.c index 1398eaf0..8663d5ee 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00285.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00285.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00286.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00286.c index 563e93ab..f622ace9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00286.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00286.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00287.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00287.c index a64452c4..6d7b8e53 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00287.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00287.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00288.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00288.c index 3ce2e32b..9cc33368 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00288.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00288.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00289.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00289.c index f8fad453..4396577a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00289.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00289.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00290.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00290.c index b31133e1..7d810a25 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00290.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00290.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00291.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00291.c index 11b7bc46..64622c22 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00291.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00291.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00292.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00292.c index b90e1168..986dd93d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00292.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00292.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00293.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00293.c index c2d62a98..e960285e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00293.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00293.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00294.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00294.c index 301e3773..c820802e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00294.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00294.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00295.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00295.c index a4ae4eb8..b690d285 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00295.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00295.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00296.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00296.c index b113bf5b..06fe059e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00296.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00296.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00297.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00297.c index 7a7a5f2a..de538095 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00297.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00297.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00298.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00298.c index 3ac48636..17437d85 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00298.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00298.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00299.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00299.c index a647ff17..5f562745 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00299.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00299.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00300.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00300.c index 338525ff..b2a3b5b9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00300.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00300.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00301.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00301.c index 29efc944..50e46049 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00301.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00301.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00302.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00302.c index 8b438631..8c6e2d25 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00302.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00302.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00303.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00303.c index 2d0a162c..35171a01 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00303.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00303.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00304.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00304.c index c37f1c58..9e26279e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00304.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00304.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00305.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00305.c index adf28031..2fbb6309 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00305.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00305.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00306.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00306.c index f75f94a7..ab457abd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00306.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00306.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00307.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00307.c index 3fdc2bef..07c59ade 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00307.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00307.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00308.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00308.c index cdc46e5a..e321ff1f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00308.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00308.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00309.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00309.c index 3b237f8b..492cb45c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00309.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00309.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00310.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00310.c index 6ba83957..6ab59db5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00310.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00310.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00311.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00311.c index 2d049aa9..eb2d5153 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00311.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00311.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00312.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00312.c index 1877dd94..cf411e4c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00312.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00312.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00313.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00313.c index 01b80baa..c1addc91 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00313.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00313.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00314.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00314.c index 946ec1b6..8c22b8a9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00314.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00314.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00315.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00315.c index 387445b9..dbecde16 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00315.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00315.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00316.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00316.c index 2ad57807..dfb8c4b8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00316.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00316.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00317.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00317.c index 9f9d047f..c88e4ba3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00317.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00317.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00318.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00318.c index 6524ec2d..3b5171f4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00318.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00318.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00319.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00319.c index 05b7b531..5c689c35 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00319.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00319.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00320.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00320.c index 2e060c40..51cecc1d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00320.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00320.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00321.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00321.c index 068f21f5..040ef405 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00321.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00321.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00322.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00322.c index ec78763b..749c4dc9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00322.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00322.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00323.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00323.c index f2be29f5..9a890c6e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00323.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00323.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00324.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00324.c index 71da4620..9afb8167 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00324.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00324.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00325.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00325.c index c9c62a19..6ab5c495 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00325.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00325.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00326.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00326.c index 002c52ea..0eda76dc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00326.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00326.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00327.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00327.c index 988649b9..20f0dfc5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00327.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00327.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00328.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00328.c index 41923256..24c30562 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00328.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00328.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00329.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00329.c index 561474cf..83fd4ef3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00329.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00329.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00330.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00330.c index 7649cedd..0a9a514d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00330.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00330.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00331.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00331.c index 1d8e44d7..50b77f9b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00331.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00331.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00332.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00332.c index 90af0b44..835b743b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00332.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00332.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00333.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00333.c index 28b5095e..4c70e032 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00333.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00333.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00334.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00334.c index 78981b18..9afdda32 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00334.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00334.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00335.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00335.c index 4b83156e..16ed1319 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00335.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00335.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00336.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00336.c index 1dad77c2..9abb9c9e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00336.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00336.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00337.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00337.c index f2074104..2c07842c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00337.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00337.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00338.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00338.c index cee2fffb..964424b5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00338.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00338.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00339.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00339.c index 8cba0f69..4d91ec6f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00339.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00339.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00340.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00340.c index 3b1084e2..5083a312 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00340.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00340.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00341.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00341.c index dcd95f34..52146b93 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00341.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00341.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00342.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00342.c index ab45e94b..9c1bd2f5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00342.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00342.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00343.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00343.c index 9baefcbd..9c7d9062 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00343.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00343.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00344.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00344.c index 84667588..807ad0d8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00344.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00344.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00345.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00345.c index 706c02e6..299fe004 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00345.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00345.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00346.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00346.c index 296ef032..d865fbec 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00346.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00346.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00347.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00347.c index fe96b5f4..fa7eb9cb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00347.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00347.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00348.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00348.c index 0c2d25d0..890443e9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00348.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00348.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00349.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00349.c index 18404686..7c192a31 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00349.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00349.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00350.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00350.c index cbf983e2..334779db 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00350.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00350.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00351.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00351.c index 6fa7619d..49ee758a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00351.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00351.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00352.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00352.c index 2d934ade..473dafd4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00352.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00352.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00353.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00353.c index 46709aa6..06e5ee8e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00353.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00353.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00354.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00354.c index a18b4c47..d9819cfe 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00354.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00354.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00355.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00355.c index 5ad9b415..fc4ac50f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00355.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00355.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00356.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00356.c index 407763ac..9d7d8d2e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00356.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00356.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00357.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00357.c index 7b6ce8b8..561f245f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00357.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00357.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00358.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00358.c index f63b552c..f01d7b5e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00358.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00358.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00359.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00359.c index c146db9e..38cc76c2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00359.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00359.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00360.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00360.c index f10512f2..f4669227 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00360.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00360.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00361.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00361.c index b22cfc95..59c00e2d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00361.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00361.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00362.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00362.c index 832ee970..2b8ec1e5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00362.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00362.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00363.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00363.c index 19cecf88..59f8b255 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00363.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00363.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00364.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00364.c index 30c7a0ae..9a64b210 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00364.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00364.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00365.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00365.c index e1aaba1f..68d96a4a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00365.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00365.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00366.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00366.c index 4c3e7667..5acc997e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00366.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00366.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00367.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00367.c index 976eed7a..cac0dc03 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00367.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00367.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00368.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00368.c index 4cceb391..09b02653 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00368.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00368.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00369.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00369.c index 4f26dd89..ee28e7b1 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00369.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00369.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00370.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00370.c index b89b019d..20d027af 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00370.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00370.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00371.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00371.c index 5a63c00e..7a3e1c46 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00371.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00371.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00372.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00372.c index 43e2ffce..d586dffe 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00372.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00372.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00373.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00373.c index 11ea155c..b2b5e242 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00373.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00373.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00374.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00374.c index f269d184..fa26d7ce 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00374.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00374.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00375.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00375.c index 399fa243..56ae4662 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00375.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00375.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00376.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00376.c index fe766a56..f64524c9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00376.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00376.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00377.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00377.c index 8bd6d65f..9a1a8933 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00377.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00377.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00378.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00378.c index b0df3d12..aea2089f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00378.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00378.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00379.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00379.c index 884b846a..5f6c8700 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00379.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00379.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00380.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00380.c index fa3e9487..dfca7e7d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00380.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00380.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00381.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00381.c index b3c2507d..2efcf59b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00381.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00381.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00382.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00382.c index 9d8d7ca1..9a1a2a14 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00382.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00382.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00383.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00383.c index 71edd2aa..a20e7e39 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00383.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00383.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00384.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00384.c index dce91d91..bfcdc194 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00384.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00384.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00385.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00385.c index 828028df..dff3968c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00385.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00385.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00386.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00386.c index 4c259384..b79b98b0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00386.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00386.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00387.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00387.c index 8ce77449..c685326d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00387.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00387.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00388.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00388.c index 7368ffd7..3a89ac54 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00388.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00388.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00389.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00389.c index c8176b25..0859955b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00389.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00389.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00390.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00390.c index f68c98f1..b7d974c8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00390.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00390.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00391.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00391.c index 8bb2ea49..3041d282 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00391.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00391.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00392.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00392.c index 785840de..3700b365 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00392.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00392.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00393.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00393.c index 2db313bd..f31d5fa6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00393.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00393.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00394.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00394.c index 913becf5..4791fc49 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00394.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00394.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00395.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00395.c index 8131b927..8e52a74a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00395.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00395.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00396.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00396.c index 72baa76a..7af790c2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00396.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00396.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00397.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00397.c index 401de578..998c9a10 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00397.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00397.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00398.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00398.c index 797b1a4d..be1edcf4 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00398.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00398.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00399.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00399.c index eb009ab0..3f3eb191 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00399.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00399.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00400.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00400.c index 8ca66859..5d12c13e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00400.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00400.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00401.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00401.c index 1dfe5cd4..1044d16c 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00401.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00401.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00402.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00402.c index 8bf60a4a..9ee62dff 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00402.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00402.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00403.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00403.c index a18b61d6..38bca421 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00403.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00403.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00404.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00404.c index 8b191499..049bfeef 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00404.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00404.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00405.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00405.c index 38a9983b..b6bb5c4a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00405.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00405.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00406.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00406.c index 4a69f07e..25a480d8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00406.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00406.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00407.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00407.c index 52bcf772..a28f3afa 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00407.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00407.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00408.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00408.c index 9983cf34..b375d4f8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00408.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00408.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00409.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00409.c index 57bcc224..e6d4a92e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00409.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00409.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00410.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00410.c index 217743b8..541c1307 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00410.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00410.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00411.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00411.c index 1469de0b..71af4983 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00411.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00411.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00412.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00412.c index 036c4625..4fc00512 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00412.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00412.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00413.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00413.c index a229b392..fd63ba74 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00413.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00413.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00414.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00414.c index 5e9eed1a..750672bd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00414.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00414.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00415.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00415.c index 12e00b16..844a29f9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00415.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00415.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00416.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00416.c index f78dad86..71fd0707 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00416.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00416.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00417.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00417.c index 6194c3de..1c4531bd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00417.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00417.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00418.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00418.c index ee6fe88a..552b7c6d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00418.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00418.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00419.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00419.c index 1a6d740a..24bea7c0 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00419.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00419.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00420.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00420.c index 315e7772..ece8c57f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00420.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00420.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00421.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00421.c index 61a14063..1c79608f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00421.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00421.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00422.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00422.c index 96fa8529..38c04413 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00422.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00422.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00423.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00423.c index 2d765942..2ebe9c07 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00423.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00423.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00424.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00424.c index f294a1a0..29d74d6a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00424.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00424.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00425.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00425.c index 0518a55c..d12b9f2a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00425.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00425.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00426.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00426.c index a06d8364..b45cf7b5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00426.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00426.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00427.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00427.c index 2e41cea7..69272631 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00427.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00427.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00428.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00428.c index fd526ca5..86e5c249 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00428.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00428.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00429.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00429.c index be33364e..de1525f2 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00429.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00429.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00430.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00430.c index 945152dd..f2b4c923 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00430.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00430.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00431.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00431.c index 7f199dff..a3bc338a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00431.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00431.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00432.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00432.c index 5da8fa9e..134dfb11 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00432.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00432.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00433.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00433.c index 9b428b51..e39ab20a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00433.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00433.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00434.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00434.c index 924e5fda..267d04c6 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00434.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00434.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00435.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00435.c index 49ab7822..6805a828 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00435.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00435.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00436.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00436.c index 9e6f0b26..132d7b7e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00436.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00436.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00437.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00437.c index 800efcff..70dee3eb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00437.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00437.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00438.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00438.c index 7fb85d89..6c29cafd 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00438.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00438.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00439.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00439.c index 4402245e..82e5ec78 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00439.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00439.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00440.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00440.c index 5af2371e..c81a46ee 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00440.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00440.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00441.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00441.c index 3f6c65a2..62c695cf 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00441.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00441.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00442.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00442.c index b62fbd33..80c84b38 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00442.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00442.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00443.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00443.c index 71b95afd..09bd5e0b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00443.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00443.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00444.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00444.c index 25156148..a562c4ab 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00444.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00444.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00445.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00445.c index fe04087f..0310426f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00445.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00445.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00446.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00446.c index 4d8790f1..3ae2f8dc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00446.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00446.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00447.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00447.c index 1ee0804d..fbd1a360 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00447.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00447.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00448.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00448.c index 28ae72c3..2884f70a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00448.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00448.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00449.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00449.c index 804d85b5..7c5115fe 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00449.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00449.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00450.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00450.c index 38215a6d..1351aceb 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00450.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00450.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00451.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00451.c index 2731a9a8..a6a7b361 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00451.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00451.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00452.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00452.c index 8b246288..ea910779 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00452.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00452.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00453.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00453.c index baf13ea2..5a9da67a 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00453.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00453.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00454.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00454.c index 80179207..dfd21edc 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00454.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00454.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00455.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00455.c index 00e4cd8c..537bfe6d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00455.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00455.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00456.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00456.c index be7ea174..f4a3cf3d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00456.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00456.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00457.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00457.c index eebb64fc..d222fb92 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00457.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00457.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00458.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00458.c index 877e53c9..5b047d87 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00458.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00458.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00459.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00459.c index 2065d4ee..dee97b94 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00459.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00459.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00460.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00460.c index a7435c9c..f19f62e8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00460.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00460.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00461.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00461.c index deb340c0..8ef05cc8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00461.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00461.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00462.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00462.c index b9c90147..17041cd3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00462.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00462.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00463.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00463.c index 7985db3f..f21435f3 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00463.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00463.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00464.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00464.c index e56ad02b..9aead7db 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00464.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00464.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00465.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00465.c index 614d26d7..92d53d67 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00465.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00465.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00466.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00466.c index 38243411..8f5cb91d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00466.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00466.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00467.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00467.c index f2228105..ae0d6e6d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00467.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00467.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00468.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00468.c index ff9f8fa1..c613a554 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00468.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00468.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00469.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00469.c index 2dce2523..eae139ac 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00469.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00469.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00470.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00470.c index 9237e95b..8dd5cf2e 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00470.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00470.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00471.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00471.c index 3a9ba880..8f99e25d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00471.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00471.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00472.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00472.c index 610e42e3..914e54bf 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00472.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00472.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00473.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00473.c index 9f55adaa..5d716bac 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00473.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00473.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00474.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00474.c index 28623fa5..30ac6e91 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00474.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00474.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00475.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00475.c index 75e9a31b..7765d5e8 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00475.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00475.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00476.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00476.c index 1be8ab11..a764d9a5 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00476.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00476.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00477.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00477.c index 1f020ae2..c592c237 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00477.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00477.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00478.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00478.c index bd31b9fa..4d20a871 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00478.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00478.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00479.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00479.c index 532d8dbe..ddacf786 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00479.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00479.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00480.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00480.c index 4d5cc579..114d5530 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00480.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00480.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00481.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00481.c index 5dd30beb..f6947055 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00481.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00481.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00482.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00482.c index d24be6e6..323c0fad 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00482.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00482.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00483.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00483.c index 9ce028fa..aa39abc9 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00483.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00483.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00484.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00484.c index 5748295a..4738e481 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00484.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00484.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00485.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00485.c index e1e75fd6..2a351a9f 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00485.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00485.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00486.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00486.c index f13f3460..60c7c5c1 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00486.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00486.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00487.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00487.c index a6a0ea76..9cc4ea88 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00487.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00487.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00488.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00488.c index fedafdab..93afbb2b 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00488.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00488.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00489.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00489.c index 5256f8d3..c1d9c829 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00489.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00489.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00490.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00490.c index cf749956..281412be 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00490.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00490.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00491.c b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00491.c index 3a5396be..6ac7785d 100644 --- a/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00491.c +++ b/sdk/tlibcrypto/ipp/ipp_disp/ippcpsgx_disp00491.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_aes_ctr.cpp b/sdk/tlibcrypto/ipp/sgx_aes_ctr.cpp index 0fbcb7b4..7b0ae0ad 100644 --- a/sdk/tlibcrypto/ipp/sgx_aes_ctr.cpp +++ b/sdk/tlibcrypto/ipp/sgx_aes_ctr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_aes_gcm.cpp b/sdk/tlibcrypto/ipp/sgx_aes_gcm.cpp index c774aad0..3ccd5ff5 100644 --- a/sdk/tlibcrypto/ipp/sgx_aes_gcm.cpp +++ b/sdk/tlibcrypto/ipp/sgx_aes_gcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -320,7 +320,6 @@ sgx_status_t sgx_aes_gcm128_enc_update(uint8_t *p_src, uint32_t src_len, return SGX_ERROR_INVALID_PARAMETER; } if (ippsAES_GCMEncrypt(p_src, p_dst, src_len, (IppsAES_GCMState*)aes_gcm_state) != ippStsNoErr) { - CLEAR_FREE_MEM(p_dst, src_len); return SGX_ERROR_UNEXPECTED; } return SGX_SUCCESS; diff --git a/sdk/tlibcrypto/ipp/sgx_cmac128.cpp b/sdk/tlibcrypto/ipp/sgx_cmac128.cpp index 48d507ca..04ec63f8 100644 --- a/sdk/tlibcrypto/ipp/sgx_cmac128.cpp +++ b/sdk/tlibcrypto/ipp/sgx_cmac128.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_ecc256.cpp b/sdk/tlibcrypto/ipp/sgx_ecc256.cpp index 574c0a4b..348174de 100644 --- a/sdk/tlibcrypto/ipp/sgx_ecc256.cpp +++ b/sdk/tlibcrypto/ipp/sgx_ecc256.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_ecc256_ecdsa.cpp b/sdk/tlibcrypto/ipp/sgx_ecc256_ecdsa.cpp index 18e7ebe1..c5e371a8 100644 --- a/sdk/tlibcrypto/ipp/sgx_ecc256_ecdsa.cpp +++ b/sdk/tlibcrypto/ipp/sgx_ecc256_ecdsa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_ecc256_internal.cpp b/sdk/tlibcrypto/ipp/sgx_ecc256_internal.cpp index c85ee2c2..5317b071 100644 --- a/sdk/tlibcrypto/ipp/sgx_ecc256_internal.cpp +++ b/sdk/tlibcrypto/ipp/sgx_ecc256_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_hmac.cpp b/sdk/tlibcrypto/ipp/sgx_hmac.cpp index ce0a046e..aba143d4 100644 --- a/sdk/tlibcrypto/ipp/sgx_hmac.cpp +++ b/sdk/tlibcrypto/ipp/sgx_hmac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_internal.cpp b/sdk/tlibcrypto/ipp/sgx_internal.cpp index f3593ea3..99cfeaf8 100644 --- a/sdk/tlibcrypto/ipp/sgx_internal.cpp +++ b/sdk/tlibcrypto/ipp/sgx_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_rsa3072.cpp b/sdk/tlibcrypto/ipp/sgx_rsa3072.cpp index d13bfdc3..12c56b50 100644 --- a/sdk/tlibcrypto/ipp/sgx_rsa3072.cpp +++ b/sdk/tlibcrypto/ipp/sgx_rsa3072.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_rsa_encryption.cpp b/sdk/tlibcrypto/ipp/sgx_rsa_encryption.cpp index c88898f4..094ee7ed 100644 --- a/sdk/tlibcrypto/ipp/sgx_rsa_encryption.cpp +++ b/sdk/tlibcrypto/ipp/sgx_rsa_encryption.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_rsa_internal.cpp b/sdk/tlibcrypto/ipp/sgx_rsa_internal.cpp index 6717c252..6dd6bcdd 100644 --- a/sdk/tlibcrypto/ipp/sgx_rsa_internal.cpp +++ b/sdk/tlibcrypto/ipp/sgx_rsa_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_sha1.cpp b/sdk/tlibcrypto/ipp/sgx_sha1.cpp index c7b66c5e..29c28e46 100644 --- a/sdk/tlibcrypto/ipp/sgx_sha1.cpp +++ b/sdk/tlibcrypto/ipp/sgx_sha1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_sha256.cpp b/sdk/tlibcrypto/ipp/sgx_sha256.cpp index c9eef674..998411f8 100644 --- a/sdk/tlibcrypto/ipp/sgx_sha256.cpp +++ b/sdk/tlibcrypto/ipp/sgx_sha256.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_sha256_msg.cpp b/sdk/tlibcrypto/ipp/sgx_sha256_msg.cpp index b848c78b..f499130e 100644 --- a/sdk/tlibcrypto/ipp/sgx_sha256_msg.cpp +++ b/sdk/tlibcrypto/ipp/sgx_sha256_msg.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/ipp/sgx_tcrypto_common.cpp b/sdk/tlibcrypto/ipp/sgx_tcrypto_common.cpp index 98edfeb5..ed7a6391 100644 --- a/sdk/tlibcrypto/ipp/sgx_tcrypto_common.cpp +++ b/sdk/tlibcrypto/ipp/sgx_tcrypto_common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgx_common_init_ipp.cpp b/sdk/tlibcrypto/sgx_common_init_ipp.cpp index c95b6b0d..c0a65bb2 100644 --- a/sdk/tlibcrypto/sgx_common_init_ipp.cpp +++ b/sdk/tlibcrypto/sgx_common_init_ipp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/init_tcrypto_lib.cpp b/sdk/tlibcrypto/sgxssl/init_tcrypto_lib.cpp index db4eb2e7..7b53dda3 100644 --- a/sdk/tlibcrypto/sgxssl/init_tcrypto_lib.cpp +++ b/sdk/tlibcrypto/sgxssl/init_tcrypto_lib.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_aes_ctr.cpp b/sdk/tlibcrypto/sgxssl/sgx_aes_ctr.cpp index 7925c4ce..fe1cb077 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_aes_ctr.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_aes_ctr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_aes_gcm.cpp b/sdk/tlibcrypto/sgxssl/sgx_aes_gcm.cpp index 39ff8f1e..fe58d7e5 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_aes_gcm.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_aes_gcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_cmac128.cpp b/sdk/tlibcrypto/sgxssl/sgx_cmac128.cpp index 0e58c46a..a8105425 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_cmac128.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_cmac128.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_ecc256.cpp b/sdk/tlibcrypto/sgxssl/sgx_ecc256.cpp index 5613d631..85a482ec 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_ecc256.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_ecc256.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_ecc256_ecdsa.cpp b/sdk/tlibcrypto/sgxssl/sgx_ecc256_ecdsa.cpp index 887748f4..3fec9228 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_ecc256_ecdsa.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_ecc256_ecdsa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_ecc256_internal.cpp b/sdk/tlibcrypto/sgxssl/sgx_ecc256_internal.cpp index f71c82c5..933ee031 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_ecc256_internal.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_ecc256_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_hmac.cpp b/sdk/tlibcrypto/sgxssl/sgx_hmac.cpp index 93e4a546..23de8061 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_hmac.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_hmac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_internal.cpp b/sdk/tlibcrypto/sgxssl/sgx_internal.cpp index 78b049f3..692cd773 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_internal.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_rsa3072.cpp b/sdk/tlibcrypto/sgxssl/sgx_rsa3072.cpp index e5ff4405..3f375976 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_rsa3072.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_rsa3072.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_rsa_encryption.cpp b/sdk/tlibcrypto/sgxssl/sgx_rsa_encryption.cpp index ebe2e801..2489ccfc 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_rsa_encryption.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_rsa_encryption.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_sha1.cpp b/sdk/tlibcrypto/sgxssl/sgx_sha1.cpp index 7f7b90e7..74097f04 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_sha1.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_sha1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_sha256.cpp b/sdk/tlibcrypto/sgxssl/sgx_sha256.cpp index c9189e5d..997c5dcb 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_sha256.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_sha256.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/sgxssl/sgx_sha256_msg.cpp b/sdk/tlibcrypto/sgxssl/sgx_sha256_msg.cpp index 33f0a9ba..44fd1e21 100644 --- a/sdk/tlibcrypto/sgxssl/sgx_sha256_msg.cpp +++ b/sdk/tlibcrypto/sgxssl/sgx_sha256_msg.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcrypto/tcrypto_version.cpp b/sdk/tlibcrypto/tcrypto_version.cpp index 9c0f38f9..7a594e7d 100644 --- a/sdk/tlibcrypto/tcrypto_version.cpp +++ b/sdk/tlibcrypto/tcrypto_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibcxx/Makefile b/sdk/tlibcxx/Makefile index f92f8b1b..2a5902a1 100644 --- a/sdk/tlibcxx/Makefile +++ b/sdk/tlibcxx/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tlibcxx/include/__config b/sdk/tlibcxx/include/__config index e98b3491..288e22f1 100644 --- a/sdk/tlibcxx/include/__config +++ b/sdk/tlibcxx/include/__config @@ -546,14 +546,13 @@ namespace std { #endif // __GXX_EXPERIMENTAL_CXX0X__ -#define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { namespace _LIBCPP_NAMESPACE { +#define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { inline namespace _LIBCPP_NAMESPACE { #define _LIBCPP_END_NAMESPACE_STD } } #define _VSTD std::_LIBCPP_NAMESPACE namespace std { -namespace _LIBCPP_NAMESPACE { -} -using namespace _LIBCPP_NAMESPACE __attribute__((__strong__)); + inline namespace _LIBCPP_NAMESPACE { + } } #if !defined(_LIBCPP_HAS_NO_ASAN) && !defined(__SANITIZE_ADDRESS__) diff --git a/sdk/tlibcxx/include/__sgx b/sdk/tlibcxx/include/__sgx index bdc4126f..cb2fae73 100644 --- a/sdk/tlibcxx/include/__sgx +++ b/sdk/tlibcxx/include/__sgx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibthread/Makefile b/sdk/tlibthread/Makefile index 518af247..9e88b925 100755 --- a/sdk/tlibthread/Makefile +++ b/sdk/tlibthread/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tlibthread/sethread_cond.cpp b/sdk/tlibthread/sethread_cond.cpp index 0d8219ae..2cfe38b3 100644 --- a/sdk/tlibthread/sethread_cond.cpp +++ b/sdk/tlibthread/sethread_cond.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibthread/sethread_internal.h b/sdk/tlibthread/sethread_internal.h index 7acd6f42..5f242a2d 100644 --- a/sdk/tlibthread/sethread_internal.h +++ b/sdk/tlibthread/sethread_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibthread/sethread_mutex.cpp b/sdk/tlibthread/sethread_mutex.cpp index c36eff5a..971abb01 100644 --- a/sdk/tlibthread/sethread_mutex.cpp +++ b/sdk/tlibthread/sethread_mutex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tlibthread/sethread_utils.cpp b/sdk/tlibthread/sethread_utils.cpp index ee4ecbfe..a64f735e 100644 --- a/sdk/tlibthread/sethread_utils.cpp +++ b/sdk/tlibthread/sethread_utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/Makefile b/sdk/trts/Makefile index 0e23af10..6f3016f8 100644 --- a/sdk/trts/Makefile +++ b/sdk/trts/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/trts/init_enclave.cpp b/sdk/trts/init_enclave.cpp index 2a36184f..a2f90104 100644 --- a/sdk/trts/init_enclave.cpp +++ b/sdk/trts/init_enclave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/init_optimized_lib.cpp b/sdk/trts/init_optimized_lib.cpp index 802ed51b..515b4d5e 100644 --- a/sdk/trts/init_optimized_lib.cpp +++ b/sdk/trts/init_optimized_lib.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/init_optimized_lib.h b/sdk/trts/init_optimized_lib.h index 0b927dd5..f4fe7443 100644 --- a/sdk/trts/init_optimized_lib.h +++ b/sdk/trts/init_optimized_lib.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/Makefile b/sdk/trts/linux/Makefile index d0892410..df6b1ff6 100644 --- a/sdk/trts/linux/Makefile +++ b/sdk/trts/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/elf_parser.c b/sdk/trts/linux/elf_parser.c index 7c9dde57..2bf91dc1 100644 --- a/sdk/trts/linux/elf_parser.c +++ b/sdk/trts/linux/elf_parser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/elf_parser.h b/sdk/trts/linux/elf_parser.h index d190a9c9..10cda60d 100644 --- a/sdk/trts/linux/elf_parser.h +++ b/sdk/trts/linux/elf_parser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/global_init.c b/sdk/trts/linux/global_init.c index cd75078e..4b56e3fb 100644 --- a/sdk/trts/linux/global_init.c +++ b/sdk/trts/linux/global_init.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/metadata_sec.S b/sdk/trts/linux/metadata_sec.S index ef45462d..a4524ab4 100644 --- a/sdk/trts/linux/metadata_sec.S +++ b/sdk/trts/linux/metadata_sec.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/tls_support.c b/sdk/trts/linux/tls_support.c index 3cf04a54..bae58141 100644 --- a/sdk/trts/linux/tls_support.c +++ b/sdk/trts/linux/tls_support.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/trts_pic.S b/sdk/trts/linux/trts_pic.S index 1957d0d2..e2d4b04a 100644 --- a/sdk/trts/linux/trts_pic.S +++ b/sdk/trts/linux/trts_pic.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/trts_pic.h b/sdk/trts/linux/trts_pic.h index 2f35baee..80c71a8a 100644 --- a/sdk/trts/linux/trts_pic.h +++ b/sdk/trts/linux/trts_pic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/x86/Makefile b/sdk/trts/linux/x86/Makefile index 25dadb93..0e34b11c 100644 --- a/sdk/trts/linux/x86/Makefile +++ b/sdk/trts/linux/x86/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/x86/setcontext.S b/sdk/trts/linux/x86/setcontext.S index f6b7ecaf..4bc2c890 100644 --- a/sdk/trts/linux/x86/setcontext.S +++ b/sdk/trts/linux/x86/setcontext.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/linux/x86_64/Makefile b/sdk/trts/linux/x86_64/Makefile index 7dd80d7f..d63703fa 100644 --- a/sdk/trts/linux/x86_64/Makefile +++ b/sdk/trts/linux/x86_64/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts.cpp b/sdk/trts/trts.cpp index fbf00547..4953ca2a 100644 --- a/sdk/trts/trts.cpp +++ b/sdk/trts/trts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_add_trim.cpp b/sdk/trts/trts_add_trim.cpp index 230a3501..ba542d2b 100644 --- a/sdk/trts/trts_add_trim.cpp +++ b/sdk/trts/trts_add_trim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_ecall.cpp b/sdk/trts/trts_ecall.cpp index 8ee0816a..011a83e6 100644 --- a/sdk/trts/trts_ecall.cpp +++ b/sdk/trts/trts_ecall.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_emodpr.cpp b/sdk/trts/trts_emodpr.cpp index e796b11c..05e7b202 100644 --- a/sdk/trts/trts_emodpr.cpp +++ b/sdk/trts/trts_emodpr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_emodpr.h b/sdk/trts/trts_emodpr.h index 23ec6859..55a10dbf 100644 --- a/sdk/trts/trts_emodpr.h +++ b/sdk/trts/trts_emodpr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_internal.h b/sdk/trts/trts_internal.h index b99e457c..a2f1a331 100644 --- a/sdk/trts/trts_internal.h +++ b/sdk/trts/trts_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_nsp.cpp b/sdk/trts/trts_nsp.cpp index d1d72127..324aa19b 100644 --- a/sdk/trts/trts_nsp.cpp +++ b/sdk/trts/trts_nsp.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_ocall.cpp b/sdk/trts/trts_ocall.cpp index fa0a7b61..59c25547 100644 --- a/sdk/trts/trts_ocall.cpp +++ b/sdk/trts/trts_ocall.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,13 +52,6 @@ extern "C" sgx_status_t __morestack(const unsigned int index, void *ms); // sgx_status_t sgx_ocall(const unsigned int index, void *ms) { - // sgx_ocall is not allowed during exception handling - thread_data_t *thread_data = get_thread_data(); - - // we have exceptions being handled - if(thread_data->exception_flag != 0) { - return SGX_ERROR_OCALL_NOT_ALLOWED; - } // the OCALL index should be within the ocall table range // -2, -3 and -4 -5 should be allowed to test SDK 2.0 features if((index != 0) && !is_builtin_ocall((int)index) && diff --git a/sdk/trts/trts_shared_constants.h b/sdk/trts/trts_shared_constants.h index 1695b904..79fcb2ba 100644 --- a/sdk/trts/trts_shared_constants.h +++ b/sdk/trts/trts_shared_constants.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_switchless.cpp b/sdk/trts/trts_switchless.cpp index fa80171a..7106d395 100644 --- a/sdk/trts/trts_switchless.cpp +++ b/sdk/trts/trts_switchless.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,8 +35,6 @@ #include "global_data.h" #include "util.h" -struct sl_uswitchless; - extern "C" sgx_status_t dummy_init_switchless(void* ms) { UNUSED(ms); return SGX_ERROR_UNEXPECTED; @@ -51,3 +49,4 @@ extern "C" sgx_status_t dummy_run_switchless_tworker(void* ms) { } /* Switchless SGX provides the real implementation for do_run_switchless_tworker */ weak_alias(dummy_run_switchless_tworker, do_run_switchless_tworker); + diff --git a/sdk/trts/trts_trim.cpp b/sdk/trts/trts_trim.cpp index a5b4c7cb..5154e8ba 100644 --- a/sdk/trts/trts_trim.cpp +++ b/sdk/trts/trts_trim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_trim.h b/sdk/trts/trts_trim.h index 6153be52..a13fbae4 100644 --- a/sdk/trts/trts_trim.h +++ b/sdk/trts/trts_trim.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_util.cpp b/sdk/trts/trts_util.cpp index 0c117a09..e13c4062 100644 --- a/sdk/trts/trts_util.cpp +++ b/sdk/trts/trts_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_util.h b/sdk/trts/trts_util.h index 1ac90075..c235c339 100644 --- a/sdk/trts/trts_util.h +++ b/sdk/trts/trts_util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_veh.cpp b/sdk/trts/trts_veh.cpp index 706bcb60..606c413f 100644 --- a/sdk/trts/trts_veh.cpp +++ b/sdk/trts/trts_veh.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_version.cpp b/sdk/trts/trts_version.cpp index 5535a476..2a593f3c 100644 --- a/sdk/trts/trts_version.cpp +++ b/sdk/trts/trts_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/trts/trts_xsave.cpp b/sdk/trts/trts_xsave.cpp index cb87a823..8ea7c737 100644 --- a/sdk/trts/trts_xsave.cpp +++ b/sdk/trts/trts_xsave.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tsafecrt/Makefile b/sdk/tsafecrt/Makefile index 9e83dfff..0df10a3d 100644 --- a/sdk/tsafecrt/Makefile +++ b/sdk/tsafecrt/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tseal/linux/Makefile b/sdk/tseal/linux/Makefile index beb50c8c..aa7c59a8 100644 --- a/sdk/tseal/linux/Makefile +++ b/sdk/tseal/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/tseal/tSeal.cpp b/sdk/tseal/tSeal.cpp index d0f58eef..30392271 100644 --- a/sdk/tseal/tSeal.cpp +++ b/sdk/tseal/tSeal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -93,7 +93,7 @@ extern "C" sgx_status_t sgx_seal_data_ex(const uint16_t key_policy, // check key_request->key_policy: // 1. Reserved bits are not set // 2. Either MRENCLAVE or MRSIGNER is set - if ((key_policy & ~(SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER | (KEY_POLICY_KSS))) || + if ((key_policy & ~(SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER | (KEY_POLICY_KSS) | SGX_KEYPOLICY_NOISVPRODID)) || (key_policy & (SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER)) == 0) { return SGX_ERROR_INVALID_PARAMETER; diff --git a/sdk/tseal/tSeal_aad.cpp b/sdk/tseal/tSeal_aad.cpp index 663d428b..304af53b 100644 --- a/sdk/tseal/tSeal_aad.cpp +++ b/sdk/tseal/tSeal_aad.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,8 +48,15 @@ extern "C" sgx_status_t sgx_mac_aadata(const uint32_t additional_MACtext_length, sgx_attributes_t attribute_mask; attribute_mask.flags = TSEAL_DEFAULT_FLAGSMASK; attribute_mask.xfrm = 0x0; + uint16_t key_policy = SGX_KEYPOLICY_MRSIGNER; - err = sgx_mac_aadata_ex(SGX_KEYPOLICY_MRSIGNER, attribute_mask, TSEAL_DEFAULT_MISCMASK, additional_MACtext_length, + const sgx_report_t* report = sgx_self_report(); + if (report->body.attributes.flags & SGX_FLAGS_KSS) + { + key_policy = SGX_KEYPOLICY_MRSIGNER | KEY_POLICY_KSS; + } + + err = sgx_mac_aadata_ex(key_policy, attribute_mask, TSEAL_DEFAULT_MISCMASK, additional_MACtext_length, p_additional_MACtext, sealed_data_size, p_sealed_data); return err; } @@ -63,7 +70,6 @@ extern "C" sgx_status_t sgx_mac_aadata_ex(const uint16_t key_policy, sgx_sealed_data_t *p_sealed_data) { sgx_status_t err = SGX_ERROR_UNEXPECTED; - sgx_report_t report; sgx_key_id_t keyID; sgx_key_request_t tmp_key_request; uint8_t payload_iv[SGX_SEAL_IV_SIZE]; @@ -79,13 +85,16 @@ extern "C" sgx_status_t sgx_mac_aadata_ex(const uint16_t key_policy, // // Check parameters // - // check key_request->key_policy reserved bits are not set and one of policy bits are set - if ((key_policy & ~(SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER)) || + // check key_request->key_policy + // 1. Reserved bits are not set + // 2. Either MRENCLAVE or MRSIGNER is set + if ((key_policy & ~(SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER | (KEY_POLICY_KSS) | SGX_KEYPOLICY_NOISVPRODID)) || ((key_policy & (SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER)) == 0)) { return SGX_ERROR_INVALID_PARAMETER; } - if ((attribute_mask.flags & 0x3) != 0x3) + if (!(attribute_mask.flags & SGX_FLAGS_INITTED) + || !(attribute_mask.flags & SGX_FLAGS_DEBUG)) { return SGX_ERROR_INVALID_PARAMETER; } @@ -109,17 +118,12 @@ extern "C" sgx_status_t sgx_mac_aadata_ex(const uint16_t key_policy, { return SGX_ERROR_INVALID_PARAMETER; } - memset(&report, 0, sizeof(sgx_report_t)); memset(p_sealed_data, 0, sealedDataSize); memset(&keyID, 0, sizeof(sgx_key_id_t)); memset(&tmp_key_request, 0, sizeof(sgx_key_request_t)); // Get the report to obtain isv_svn and cpu_svn - err = sgx_create_report(NULL, NULL, &report); - if (err != SGX_SUCCESS) - { - goto clear_return; - } + const sgx_report_t *report = sgx_self_report(); // Get a random number to populate the key_id of the key_request err = sgx_read_rand(reinterpret_cast(&keyID), sizeof(sgx_key_id_t)); @@ -128,8 +132,9 @@ extern "C" sgx_status_t sgx_mac_aadata_ex(const uint16_t key_policy, goto clear_return; } - memcpy(&(tmp_key_request.cpu_svn), &(report.body.cpu_svn), sizeof(sgx_cpu_svn_t)); - memcpy(&(tmp_key_request.isv_svn), &(report.body.isv_svn), sizeof(sgx_isv_svn_t)); + memcpy(&(tmp_key_request.cpu_svn), &(report->body.cpu_svn), sizeof(sgx_cpu_svn_t)); + memcpy(&(tmp_key_request.isv_svn), &(report->body.isv_svn), sizeof(sgx_isv_svn_t)); + tmp_key_request.config_svn = report->body.config_svn; tmp_key_request.key_name = SGX_KEYSELECT_SEAL; tmp_key_request.key_policy = key_policy; tmp_key_request.attribute_mask.flags = attribute_mask.flags; @@ -148,7 +153,6 @@ extern "C" sgx_status_t sgx_mac_aadata_ex(const uint16_t key_policy, clear_return: // Clear temp state - memset_s(&report, sizeof(sgx_report_t), 0, sizeof(sgx_report_t)); memset_s(&keyID, sizeof(sgx_key_id_t), 0, sizeof(sgx_key_id_t)); return err; } diff --git a/sdk/tseal/tSeal_internal.cpp b/sdk/tseal/tSeal_internal.cpp index 2223401e..12cd31ae 100644 --- a/sdk/tseal/tSeal_internal.cpp +++ b/sdk/tseal/tSeal_internal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tseal/tSeal_internal.h b/sdk/tseal/tSeal_internal.h index d85cb0f4..9c5d48b0 100644 --- a/sdk/tseal/tSeal_internal.h +++ b/sdk/tseal/tSeal_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tseal/tSeal_util.cpp b/sdk/tseal/tSeal_util.cpp index f6d98a17..7cc0219d 100644 --- a/sdk/tseal/tSeal_util.cpp +++ b/sdk/tseal/tSeal_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sdk/tsetjmp/Makefile b/sdk/tsetjmp/Makefile index 14a40a88..b22cb4fa 100644 --- a/sdk/tsetjmp/Makefile +++ b/sdk/tsetjmp/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions diff --git a/sdk/ukey_exchange/Makefile b/sdk/ukey_exchange/Makefile index 9be7f0a1..1318c29f 100644 --- a/sdk/ukey_exchange/Makefile +++ b/sdk/ukey_exchange/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2011-2018 Intel Corporation. All rights reserved. +# Copyright (C) 2011-2019 Intel Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -36,7 +36,11 @@ CFLAGS += -Werror CXXFLAGS += -Werror INCLUDE += -I$(COMMON_DIR)/inc/internal \ - -I$(COMMON_DIR)/inc + -I$(COMMON_DIR)/inc \ + -I$(LINUX_PSW_DIR)/ae/data/constants/linux/ \ + -I$(DCAP_DIR)/QuoteGeneration/quote_wrapper/quote/inc/ \ + -I$(DCAP_DIR)/QuoteGeneration/quote_wrapper/common/inc/ \ + -I$(DCAP_DIR)/QuoteGeneration/pce_wrapper/inc/ INCLUDE += -I$(SGX_IPP_INC) diff --git a/sdk/ukey_exchange/ukey_exchange.cpp b/sdk/ukey_exchange/ukey_exchange.cpp index 2dd7a976..8108e672 100644 --- a/sdk/ukey_exchange/ukey_exchange.cpp +++ b/sdk/ukey_exchange/ukey_exchange.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,8 +47,12 @@ #include "se_lock.hpp" #include "se_cdefs.h" +#include "sgx_ql_core_wrapper.h" +#include "service_enclave_mrsigner.hh" + SGX_ACCESS_VERSION(ukey_exchange, 1) +static sgx_ql_att_key_id_t g_att_key_id; static sgx_target_info_t g_qe_target_info; static Mutex g_ukey_spin_lock; @@ -76,6 +80,7 @@ sgx_status_t sgx_ra_get_msg1( if(SGX_SUCCESS != ret) return ret; g_ukey_spin_lock.lock(); + memset(&g_att_key_id, 0, sizeof(sgx_att_key_id_t)); if(memcpy_s(&g_qe_target_info, sizeof(g_qe_target_info), &qe_target_info, sizeof(qe_target_info)) != 0) { @@ -115,8 +120,10 @@ sgx_status_t sgx_ra_proc_msg2( sgx_status_t ret = SGX_ERROR_UNEXPECTED; sgx_report_t report; sgx_ra_msg3_t *p_msg3 = NULL; + sgx_att_key_id_t empty_att_key_id; memset(&report, 0, sizeof(report)); + memset(&empty_att_key_id, 0, sizeof(empty_att_key_id)); { sgx_quote_nonce_t nonce; @@ -128,6 +135,12 @@ sgx_status_t sgx_ra_proc_msg2( sgx_status_t status; g_ukey_spin_lock.lock(); + if(0 != memcmp(&g_att_key_id, &empty_att_key_id, sizeof(g_att_key_id))) + { + ret = SGX_ERROR_INVALID_STATE; + g_ukey_spin_lock.unlock(); + goto CLEANUP; + } if(memcpy_s(&qe_target_info, sizeof(qe_target_info), &g_qe_target_info, sizeof(g_qe_target_info)) != 0) { @@ -209,3 +222,241 @@ CLEANUP: SAFE_FREE(p_msg3); return ret; } + + +sgx_status_t SGXAPI sgx_ra_get_msg1_ex( + const sgx_att_key_id_t *p_att_key_id, + sgx_ra_context_t context, + sgx_enclave_id_t eid, + sgx_ecall_get_ga_trusted_t p_get_ga, + sgx_ra_msg1_t *p_msg1) +{ + sgx_ql_att_key_id_t *p_ql_att_key_id; + if(NULL == p_att_key_id) + return SGX_ERROR_INVALID_PARAMETER; + p_ql_att_key_id = (sgx_ql_att_key_id_t *)p_att_key_id; + if (0 != p_ql_att_key_id->id) + return SGX_ERROR_INVALID_PARAMETER; + if (0 != p_ql_att_key_id->version) + return SGX_ERROR_INVALID_PARAMETER; + // Both QE and QE3 use 1 as prod_id + if(1 != p_ql_att_key_id->prod_id) + return SGX_ERROR_INVALID_PARAMETER; + if (SGX_QL_ALG_EPID == p_ql_att_key_id->algorithm_id) + { + if (sizeof(G_SERVICE_ENCLAVE_MRSIGNER[AE_MR_SIGNER]) != p_ql_att_key_id->mrsigner_length) + return SGX_ERROR_INVALID_PARAMETER; + if (0 != memcmp(p_ql_att_key_id->mrsigner, &G_SERVICE_ENCLAVE_MRSIGNER[AE_MR_SIGNER], + sizeof(G_SERVICE_ENCLAVE_MRSIGNER[AE_MR_SIGNER]))) + return SGX_ERROR_INVALID_PARAMETER; + return sgx_ra_get_msg1(context, eid, p_get_ga, p_msg1); + } + else if (SGX_QL_ALG_ECDSA_P256 == p_ql_att_key_id->algorithm_id) + { + if (sizeof(G_ECDSA_QE_MRSIGNER) != p_ql_att_key_id->mrsigner_length) + return SGX_ERROR_INVALID_PARAMETER; + if (0 != memcmp(p_ql_att_key_id->mrsigner, &G_ECDSA_QE_MRSIGNER, sizeof(G_ECDSA_QE_MRSIGNER))) + return SGX_ERROR_INVALID_PARAMETER; + + if(!p_msg1 || !p_get_ga) + return SGX_ERROR_INVALID_PARAMETER; + size_t pub_key_id_size = 0; + sgx_target_info_t qe_target_info; + + memset(&qe_target_info, 0, sizeof(qe_target_info)); + sgx_status_t ret = sgx_init_quote_ex(p_att_key_id, &qe_target_info, false, &pub_key_id_size, NULL); + if(SGX_SUCCESS != ret) + return ret; + uint8_t *p_pub_key_id = (uint8_t *)malloc(pub_key_id_size); + if (NULL == p_pub_key_id) + return SGX_ERROR_OUT_OF_MEMORY; + ret = sgx_init_quote_ex(p_att_key_id, &qe_target_info, false, &pub_key_id_size, p_pub_key_id); + if(SGX_SUCCESS != ret) + { + free(p_pub_key_id); + return ret; + } + free(p_pub_key_id); + g_ukey_spin_lock.lock(); + if(memcpy_s(&g_att_key_id, sizeof(sgx_att_key_id_t), + p_ql_att_key_id, sizeof(sgx_att_key_id_t)) != 0) + { + g_ukey_spin_lock.unlock(); + return SGX_ERROR_UNEXPECTED; + } + if(memcpy_s(&g_qe_target_info, sizeof(g_qe_target_info), + &qe_target_info, sizeof(qe_target_info)) != 0) + { + g_ukey_spin_lock.unlock(); + return SGX_ERROR_UNEXPECTED; + } + g_ukey_spin_lock.unlock(); + memset(&p_msg1->gid, 0, sizeof(p_msg1->gid)); + + sgx_ec256_public_t g_a; + sgx_status_t status = SGX_ERROR_UNEXPECTED; + memset(&g_a, 0, sizeof(g_a)); + ret = p_get_ga(eid, &status, context, &g_a); + if(SGX_SUCCESS !=ret) + return ret; + if (SGX_SUCCESS != status) + return status; + memcpy_s(&p_msg1->g_a, sizeof(p_msg1->g_a), &g_a, sizeof(g_a)); + return SGX_SUCCESS; + } + else + return SGX_ERROR_FEATURE_NOT_SUPPORTED; +} + +sgx_status_t SGXAPI sgx_ra_proc_msg2_ex( + const sgx_att_key_id_t *p_att_key_id, + sgx_ra_context_t context, + sgx_enclave_id_t eid, + sgx_ecall_proc_msg2_trusted_t p_proc_msg2, + sgx_ecall_get_msg3_trusted_t p_get_msg3, + const sgx_ra_msg2_t *p_msg2, + uint32_t msg2_size, + sgx_ra_msg3_t **pp_msg3, + uint32_t *p_msg3_size) +{ + sgx_ql_att_key_id_t *p_ql_att_key_id; + if(NULL == p_att_key_id) + return SGX_ERROR_INVALID_PARAMETER; + p_ql_att_key_id = (sgx_ql_att_key_id_t *)p_att_key_id; + if (0 != p_ql_att_key_id->id) + return SGX_ERROR_INVALID_PARAMETER; + if (0 != p_ql_att_key_id->version) + return SGX_ERROR_INVALID_PARAMETER; + // Both QE and QE3 use 1 as prod_id + if(1 != p_ql_att_key_id->prod_id) + return SGX_ERROR_INVALID_PARAMETER; + if (SGX_QL_ALG_EPID == p_ql_att_key_id->algorithm_id) + { + if (sizeof(G_SERVICE_ENCLAVE_MRSIGNER[AE_MR_SIGNER]) != p_ql_att_key_id->mrsigner_length) + return SGX_ERROR_INVALID_PARAMETER; + if (0 != memcmp(p_ql_att_key_id->mrsigner, &G_SERVICE_ENCLAVE_MRSIGNER[AE_MR_SIGNER], + sizeof(G_SERVICE_ENCLAVE_MRSIGNER[AE_MR_SIGNER]))) + return SGX_ERROR_INVALID_PARAMETER; + return sgx_ra_proc_msg2(context, eid, p_proc_msg2, p_get_msg3, p_msg2, msg2_size, pp_msg3, p_msg3_size); + } + else if (SGX_QL_ALG_ECDSA_P256 == p_ql_att_key_id->algorithm_id) + { + if (sizeof(G_ECDSA_QE_MRSIGNER) != p_ql_att_key_id->mrsigner_length) + return SGX_ERROR_INVALID_PARAMETER; + if (0 != memcmp(p_ql_att_key_id->mrsigner, &G_ECDSA_QE_MRSIGNER, sizeof(G_ECDSA_QE_MRSIGNER))) + return SGX_ERROR_INVALID_PARAMETER; + + if(!p_msg2 || !p_proc_msg2 || !p_get_msg3 || !p_msg3_size || !pp_msg3) + return SGX_ERROR_INVALID_PARAMETER; + if(p_msg2->sig_rl_size) + return SGX_ERROR_UNEXPECTED; // No SigRL for ECDSA attestation + if(msg2_size != sizeof(sgx_ra_msg2_t) + p_msg2->sig_rl_size) + return SGX_ERROR_INVALID_PARAMETER; + + sgx_status_t ret = SGX_ERROR_UNEXPECTED; + sgx_report_t report; + sgx_ra_msg3_t *p_msg3 = NULL; + + memset(&report, 0, sizeof(report)); + + { + sgx_quote_nonce_t nonce; + sgx_target_info_t qe_target_info; + + memset(&nonce, 0, sizeof(nonce)); + + sgx_status_t status; + g_ukey_spin_lock.lock(); + if(0 != memcmp(&g_att_key_id, p_ql_att_key_id, sizeof(g_att_key_id))) + { + ret = SGX_ERROR_INVALID_STATE; + g_ukey_spin_lock.unlock(); + goto CLEANUP; + } + if(memcpy_s(&qe_target_info, sizeof(qe_target_info), + &g_qe_target_info, sizeof(g_qe_target_info)) != 0) + { + ret = SGX_ERROR_UNEXPECTED; + g_ukey_spin_lock.unlock(); + goto CLEANUP; + } + g_ukey_spin_lock.unlock(); + ret = p_proc_msg2(eid, &status, context, p_msg2, &qe_target_info, + &report, &nonce); + if(SGX_SUCCESS!=ret) + { + goto CLEANUP; + } + if(SGX_SUCCESS!=status) + { + ret = status; + goto CLEANUP; + } + + uint32_t quote_size = 0; + ret = sgx_get_quote_size_ex(p_att_key_id, "e_size); + if(SGX_SUCCESS!=ret) + { + goto CLEANUP; + } + + //check integer overflow of quote_size + if (UINT32_MAX - quote_size < sizeof(sgx_ra_msg3_t)) + { + ret = SGX_ERROR_UNEXPECTED; + goto CLEANUP; + } + uint32_t msg3_size = static_cast(sizeof(sgx_ra_msg3_t)) + quote_size; + p_msg3 = (sgx_ra_msg3_t *)malloc(msg3_size); + if(!p_msg3) + { + ret = SGX_ERROR_OUT_OF_MEMORY; + goto CLEANUP; + } + memset(p_msg3, 0, msg3_size); + + sgx_qe_report_info_t qe_report_info; + memset(&qe_report_info.app_enclave_target_info, 0, sizeof(qe_report_info.app_enclave_target_info)); + memcpy_s(&(qe_report_info.app_enclave_target_info.attributes), + sizeof(qe_report_info.app_enclave_target_info.attributes), + &report.body.attributes, + sizeof(report.body.attributes)); + memcpy_s(&(qe_report_info.app_enclave_target_info.mr_enclave), + sizeof(qe_report_info.app_enclave_target_info.mr_enclave), + &report.body.mr_enclave, + sizeof(report.body.mr_enclave)); + memcpy_s(&(qe_report_info.app_enclave_target_info.misc_select), + sizeof(qe_report_info.app_enclave_target_info.misc_select), + &report.body.misc_select, + sizeof(report.body.misc_select)); + memcpy_s(&qe_report_info.nonce, sizeof(qe_report_info.nonce), &nonce, sizeof(nonce)); + ret = sgx_get_quote_ex(&report, p_att_key_id, &qe_report_info, p_msg3->quote, quote_size); + if(SGX_SUCCESS!=ret) + { + goto CLEANUP; + } + + ret = p_get_msg3(eid, &status, context, quote_size, &qe_report_info.qe_report, + p_msg3, msg3_size); + if(SGX_SUCCESS!=ret) + { + goto CLEANUP; + } + if(SGX_SUCCESS!=status) + { + ret = status; + goto CLEANUP; + } + *pp_msg3 = p_msg3; + *p_msg3_size = msg3_size; + } + + CLEANUP: + if(ret) + SAFE_FREE(p_msg3); + return ret; + } + else + return SGX_ERROR_FEATURE_NOT_SUPPORTED; +} + diff --git a/sdk/ukey_exchange/ukey_exchange_version.cpp b/sdk/ukey_exchange/ukey_exchange_version.cpp index abe3f6c2..9091d8b0 100644 --- a/sdk/ukey_exchange/ukey_exchange_version.cpp +++ b/sdk/ukey_exchange/ukey_exchange_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Intel Corporation. All rights reserved. + * Copyright (C) 2011-2019 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions